forked from tornado-packages/noble-curves
tests: Use describe()
This commit is contained in:
parent
5312d92b2c
commit
f4cf21b9c8
@ -31,7 +31,7 @@
|
||||
"@types/node": "18.11.3",
|
||||
"fast-check": "3.0.0",
|
||||
"micro-bmark": "0.2.0",
|
||||
"micro-should": "0.2.0",
|
||||
"micro-should": "0.3.0",
|
||||
"prettier": "2.6.2",
|
||||
"rollup": "2.75.5",
|
||||
"typescript": "4.7.3"
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { deepStrictEqual, throws } from 'assert';
|
||||
import { should } from 'micro-should';
|
||||
import { should, describe } from 'micro-should';
|
||||
import * as fc from 'fast-check';
|
||||
import * as mod from '../lib/esm/abstract/modular.js';
|
||||
import { bytesToHex as toHex } from '../lib/esm/abstract/utils.js';
|
||||
@ -62,7 +62,8 @@ for (const c in FIELDS) {
|
||||
const FC_BIGINT = curve[f][1] ? curve[f][1] : fc.bigInt(1n, Fp.ORDER - 1n);
|
||||
|
||||
const create = curve[f][2] ? curve[f][2].bind(null, Fp) : (num) => Fp.create(num);
|
||||
should(`${name} equality`, () => {
|
||||
describe(name, () => {
|
||||
should('equality', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (num) => {
|
||||
const a = create(num);
|
||||
@ -72,7 +73,7 @@ for (const c in FIELDS) {
|
||||
})
|
||||
);
|
||||
});
|
||||
should(`${name} non-equality`, () => {
|
||||
should('non-equality', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, (num1, num2) => {
|
||||
const a = create(num1);
|
||||
@ -82,7 +83,7 @@ for (const c in FIELDS) {
|
||||
})
|
||||
);
|
||||
});
|
||||
should(`${name} add/subtract/commutativity`, () => {
|
||||
should('add/subtract/commutativity', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, (num1, num2) => {
|
||||
const a = create(num1);
|
||||
@ -91,7 +92,7 @@ for (const c in FIELDS) {
|
||||
})
|
||||
);
|
||||
});
|
||||
should(`${name} add/subtract/associativity`, () => {
|
||||
should('add/subtract/associativity', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, FC_BIGINT, (num1, num2, num3) => {
|
||||
const a = create(num1);
|
||||
@ -101,7 +102,7 @@ for (const c in FIELDS) {
|
||||
})
|
||||
);
|
||||
});
|
||||
should(`${name} add/subtract/x+0=x`, () => {
|
||||
should('add/subtract/x+0=x', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (num) => {
|
||||
const a = create(num);
|
||||
@ -109,7 +110,7 @@ for (const c in FIELDS) {
|
||||
})
|
||||
);
|
||||
});
|
||||
should(`${name} add/subtract/x-0=x`, () => {
|
||||
should('add/subtract/x-0=x', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (num) => {
|
||||
const a = create(num);
|
||||
@ -118,7 +119,7 @@ for (const c in FIELDS) {
|
||||
})
|
||||
);
|
||||
});
|
||||
should(`${name} add/subtract/negate equality`, () => {
|
||||
should('add/subtract/negate equality', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (num1) => {
|
||||
const a = create(num1);
|
||||
@ -129,7 +130,7 @@ for (const c in FIELDS) {
|
||||
})
|
||||
);
|
||||
});
|
||||
should(`${name} add/subtract/negate`, () => {
|
||||
should('add/subtract/negate', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (num) => {
|
||||
const a = create(num);
|
||||
@ -138,11 +139,11 @@ for (const c in FIELDS) {
|
||||
})
|
||||
);
|
||||
});
|
||||
should(`${name} negate(0)`, () => {
|
||||
should('negate(0)', () => {
|
||||
deepStrictEqual(Fp.negate(Fp.ZERO), Fp.ZERO);
|
||||
});
|
||||
|
||||
should(`${name} multiply/commutativity`, () => {
|
||||
should('multiply/commutativity', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, (num1, num2) => {
|
||||
const a = create(num1);
|
||||
@ -151,7 +152,7 @@ for (const c in FIELDS) {
|
||||
})
|
||||
);
|
||||
});
|
||||
should(`${name} multiply/associativity`, () => {
|
||||
should('multiply/associativity', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, FC_BIGINT, (num1, num2, num3) => {
|
||||
const a = create(num1);
|
||||
@ -161,7 +162,7 @@ for (const c in FIELDS) {
|
||||
})
|
||||
);
|
||||
});
|
||||
should(`${name} multiply/distributivity`, () => {
|
||||
should('multiply/distributivity', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, FC_BIGINT, (num1, num2, num3) => {
|
||||
const a = create(num1);
|
||||
@ -171,7 +172,7 @@ for (const c in FIELDS) {
|
||||
})
|
||||
);
|
||||
});
|
||||
should(`${name} multiply/add equality`, () => {
|
||||
should('multiply/add equality', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (num) => {
|
||||
const a = create(num);
|
||||
@ -185,7 +186,7 @@ for (const c in FIELDS) {
|
||||
})
|
||||
);
|
||||
});
|
||||
should(`${name} multiply/square equality`, () => {
|
||||
should('multiply/square equality', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (num) => {
|
||||
const a = create(num);
|
||||
@ -193,7 +194,7 @@ for (const c in FIELDS) {
|
||||
})
|
||||
);
|
||||
});
|
||||
should(`${name} multiply/pow equality`, () => {
|
||||
should('multiply/pow equality', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (num) => {
|
||||
const a = create(num);
|
||||
@ -205,17 +206,17 @@ for (const c in FIELDS) {
|
||||
);
|
||||
});
|
||||
|
||||
should(`${name} square(0)`, () => {
|
||||
should('square(0)', () => {
|
||||
deepStrictEqual(Fp.square(Fp.ZERO), Fp.ZERO);
|
||||
deepStrictEqual(Fp.mul(Fp.ZERO, Fp.ZERO), Fp.ZERO);
|
||||
});
|
||||
|
||||
should(`${name} square(1)`, () => {
|
||||
should('square(1)', () => {
|
||||
deepStrictEqual(Fp.square(Fp.ONE), Fp.ONE);
|
||||
deepStrictEqual(Fp.mul(Fp.ONE, Fp.ONE), Fp.ONE);
|
||||
});
|
||||
|
||||
should(`${name} square(-1)`, () => {
|
||||
should('square(-1)', () => {
|
||||
const minus1 = Fp.negate(Fp.ONE);
|
||||
deepStrictEqual(Fp.square(minus1), Fp.ONE);
|
||||
deepStrictEqual(Fp.mul(minus1, minus1), Fp.ONE);
|
||||
@ -224,7 +225,7 @@ for (const c in FIELDS) {
|
||||
const isSquare = mod.FpIsSquare(Fp);
|
||||
// Not implemented
|
||||
if (Fp !== bls12_381.CURVE.Fp12) {
|
||||
should(`${name} multiply/sqrt`, () => {
|
||||
should('multiply/sqrt', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (num) => {
|
||||
const a = create(num);
|
||||
@ -242,7 +243,7 @@ for (const c in FIELDS) {
|
||||
);
|
||||
});
|
||||
|
||||
should(`${name} sqrt(0)`, () => {
|
||||
should('sqrt(0)', () => {
|
||||
deepStrictEqual(Fp.sqrt(Fp.ZERO), Fp.ZERO);
|
||||
const sqrt1 = Fp.sqrt(Fp.ONE);
|
||||
deepStrictEqual(
|
||||
@ -253,7 +254,7 @@ for (const c in FIELDS) {
|
||||
});
|
||||
}
|
||||
|
||||
should(`${name} div/division by one equality`, () => {
|
||||
should('div/division by one equality', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (num) => {
|
||||
const a = create(num);
|
||||
@ -263,7 +264,7 @@ for (const c in FIELDS) {
|
||||
})
|
||||
);
|
||||
});
|
||||
should(`${name} zero division equality`, () => {
|
||||
should('zero division equality', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (num) => {
|
||||
const a = create(num);
|
||||
@ -271,7 +272,7 @@ for (const c in FIELDS) {
|
||||
})
|
||||
);
|
||||
});
|
||||
should(`${name} div/division distributivity`, () => {
|
||||
should('div/division distributivity', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, FC_BIGINT, (num1, num2, num3) => {
|
||||
const a = create(num1);
|
||||
@ -281,7 +282,7 @@ for (const c in FIELDS) {
|
||||
})
|
||||
);
|
||||
});
|
||||
should(`${name} div/division and multiplication equality`, () => {
|
||||
should('div/division and multiplication equality', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, (num1, num2) => {
|
||||
const a = create(num1);
|
||||
@ -290,6 +291,7 @@ for (const c in FIELDS) {
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -311,12 +313,12 @@ const NUM_RUNS = 5;
|
||||
const getXY = (p) => ({ x: p.x, y: p.y });
|
||||
|
||||
function equal(a, b, comment) {
|
||||
deepStrictEqual(a.equals(b), true, `eq(${comment})`);
|
||||
deepStrictEqual(a.equals(b), true, 'eq(${comment})');
|
||||
if (a.toAffine && b.toAffine) {
|
||||
deepStrictEqual(getXY(a.toAffine()), getXY(b.toAffine()), `eqToAffine(${comment})`);
|
||||
deepStrictEqual(getXY(a.toAffine()), getXY(b.toAffine()), 'eqToAffine(${comment})');
|
||||
} else if (!a.toAffine && !b.toAffine) {
|
||||
// Already affine
|
||||
deepStrictEqual(getXY(a), getXY(b), `eqAffine(${comment})`);
|
||||
deepStrictEqual(getXY(a), getXY(b), 'eqAffine(${comment})');
|
||||
} else throw new Error('Different point types');
|
||||
}
|
||||
|
||||
@ -341,46 +343,49 @@ for (const name in CURVES) {
|
||||
|
||||
const G = [p.ZERO, p.BASE];
|
||||
for (let i = 2; i < 10; i++) G.push(G[1].multiply(i));
|
||||
const title = `${name}/${pointName}`;
|
||||
describe(title, () => {
|
||||
describe('basic group laws', () => {
|
||||
// Here we check basic group laws, to verify that points works as group
|
||||
should(`${name}/${pointName}/Basic group laws (zero)`, () => {
|
||||
should('(zero)', () => {
|
||||
equal(G[0].double(), G[0], '(0*G).double() = 0');
|
||||
equal(G[0].add(G[0]), G[0], '0*G + 0*G = 0');
|
||||
equal(G[0].subtract(G[0]), G[0], '0*G - 0*G = 0');
|
||||
equal(G[0].negate(), G[0], '-0 = 0');
|
||||
for (let i = 0; i < G.length; i++) {
|
||||
const p = G[i];
|
||||
equal(p, p.add(G[0]), `${i}*G + 0 = ${i}*G`);
|
||||
equal(G[0].multiply(i + 1), G[0], `${i + 1}*0 = 0`);
|
||||
equal(p, p.add(G[0]), '${i}*G + 0 = ${i}*G');
|
||||
equal(G[0].multiply(i + 1), G[0], '${i + 1}*0 = 0');
|
||||
}
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (one)`, () => {
|
||||
should('(one)', () => {
|
||||
equal(G[1].double(), G[2], '(1*G).double() = 2*G');
|
||||
equal(G[1].subtract(G[1]), G[0], '1*G - 1*G = 0');
|
||||
equal(G[1].add(G[1]), G[2], '1*G + 1*G = 2*G');
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (sanity tests)`, () => {
|
||||
equal(G[2].double(), G[4], `(2*G).double() = 4*G`);
|
||||
equal(G[2].add(G[2]), G[4], `2*G + 2*G = 4*G`);
|
||||
equal(G[7].add(G[3].negate()), G[4], `7*G - 3*G = 4*G`);
|
||||
should('(sanity tests)', () => {
|
||||
equal(G[2].double(), G[4], '(2*G).double() = 4*G');
|
||||
equal(G[2].add(G[2]), G[4], '2*G + 2*G = 4*G');
|
||||
equal(G[7].add(G[3].negate()), G[4], '7*G - 3*G = 4*G');
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (addition commutativity)`, () => {
|
||||
equal(G[4].add(G[3]), G[3].add(G[4]), `4*G + 3*G = 3*G + 4*G`);
|
||||
equal(G[4].add(G[3]), G[3].add(G[2]).add(G[2]), `4*G + 3*G = 3*G + 2*G + 2*G`);
|
||||
should('(addition commutativity)', () => {
|
||||
equal(G[4].add(G[3]), G[3].add(G[4]), '4*G + 3*G = 3*G + 4*G');
|
||||
equal(G[4].add(G[3]), G[3].add(G[2]).add(G[2]), '4*G + 3*G = 3*G + 2*G + 2*G');
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (double)`, () => {
|
||||
should('(double)', () => {
|
||||
equal(G[3].double(), G[6], '(3*G).double() = 6*G');
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (multiply)`, () => {
|
||||
should('(multiply)', () => {
|
||||
equal(G[2].multiply(3), G[6], '(2*G).multiply(3) = 6*G');
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (same point addition)`, () => {
|
||||
equal(G[3].add(G[3]), G[6], `3*G + 3*G = 6*G`);
|
||||
should('(same point addition)', () => {
|
||||
equal(G[3].add(G[3]), G[6], '3*G + 3*G = 6*G');
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (same point (negative) addition)`, () => {
|
||||
should('(same point (negative) addition)', () => {
|
||||
equal(G[3].add(G[3].negate()), G[0], '3*G + (- 3*G) = 0*G');
|
||||
equal(G[3].subtract(G[3]), G[0], '3*G - 3*G = 0*G');
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (curve order)`, () => {
|
||||
should('(curve order)', () => {
|
||||
equal(G[1].multiply(CURVE_ORDER - 1n).add(G[1]), G[0], '(N-1)*G + G = 0');
|
||||
equal(G[1].multiply(CURVE_ORDER - 1n).add(G[2]), G[1], '(N-1)*G + 2*G = 1*G');
|
||||
equal(G[1].multiply(CURVE_ORDER - 2n).add(G[2]), G[0], '(N-2)*G + 2*G = 0');
|
||||
@ -388,7 +393,7 @@ for (const name in CURVES) {
|
||||
const carry = CURVE_ORDER % 2n === 1n ? G[1] : G[0];
|
||||
equal(G[1].multiply(half).double().add(carry), G[0], '((N/2) * G).double() = 0');
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (inversion)`, () => {
|
||||
should('(inversion)', () => {
|
||||
const a = 1234n;
|
||||
const b = 5678n;
|
||||
const c = a * b;
|
||||
@ -396,7 +401,7 @@ for (const name in CURVES) {
|
||||
const inv = mod.invert(b, CURVE_ORDER);
|
||||
equal(G[1].multiply(c).multiply(inv), G[1].multiply(a), 'c*G * (1/b)*G = a*G');
|
||||
});
|
||||
should(`${name}/${pointName}/Basic group laws (multiply, rand)`, () =>
|
||||
should('(multiply, rand)', () =>
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, (a, b) => {
|
||||
const c = mod.mod(a + b, CURVE_ORDER);
|
||||
@ -404,27 +409,29 @@ for (const name in CURVES) {
|
||||
const pA = G[1].multiply(a);
|
||||
const pB = G[1].multiply(b);
|
||||
const pC = G[1].multiply(c);
|
||||
equal(pA.add(pB), pB.add(pA), `pA + pB = pB + pA`);
|
||||
equal(pA.add(pB), pC, `pA + pB = pC`);
|
||||
equal(pA.add(pB), pB.add(pA), 'pA + pB = pB + pA');
|
||||
equal(pA.add(pB), pC, 'pA + pB = pC');
|
||||
}),
|
||||
{ numRuns: NUM_RUNS }
|
||||
)
|
||||
);
|
||||
should(`${name}/${pointName}/Basic group laws (multiply2, rand)`, () =>
|
||||
should('(multiply2, rand)', () =>
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, (a, b) => {
|
||||
const c = mod.mod(a * b, CURVE_ORDER);
|
||||
const pA = G[1].multiply(a);
|
||||
const pB = G[1].multiply(b);
|
||||
equal(pA.multiply(b), pB.multiply(a), `b*pA = a*pB`);
|
||||
equal(pA.multiply(b), G[1].multiply(c), `b*pA = c*G`);
|
||||
equal(pA.multiply(b), pB.multiply(a), 'b*pA = a*pB');
|
||||
equal(pA.multiply(b), G[1].multiply(c), 'b*pA = c*G');
|
||||
}),
|
||||
{ numRuns: NUM_RUNS }
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
for (const op of ['add', 'subtract']) {
|
||||
should(`${name}/${pointName}/${op} type check`, () => {
|
||||
describe(op, () => {
|
||||
should('type check', () => {
|
||||
throws(() => G[1][op](0), '0');
|
||||
throws(() => G[1][op](0n), '0n');
|
||||
G[1][op](G[2]);
|
||||
@ -432,17 +439,21 @@ for (const name in CURVES) {
|
||||
throws(() => G[1][op](123.456), '123.456');
|
||||
throws(() => G[1][op](true), 'true');
|
||||
throws(() => G[1][op]('1'), "'1'");
|
||||
throws(() => G[1][op]({ x: 1n, y: 1n, z: 1n, t: 1n }), '{ x: 1n, y: 1n, z: 1n, t: 1n }');
|
||||
throws(
|
||||
() => G[1][op]({ x: 1n, y: 1n, z: 1n, t: 1n }),
|
||||
'{ x: 1n, y: 1n, z: 1n, t: 1n }'
|
||||
);
|
||||
throws(() => G[1][op](new Uint8Array([])), 'ui8a([])');
|
||||
throws(() => G[1][op](new Uint8Array([0])), 'ui8a([0])');
|
||||
throws(() => G[1][op](new Uint8Array([1])), 'ui8a([1])');
|
||||
throws(() => G[1][op](new Uint8Array(4096).fill(1)), 'ui8a(4096*[1])');
|
||||
if (G[1].toAffine) throws(() => G[1][op](C.Point.BASE), `Point ${op} ${pointName}`);
|
||||
throws(() => G[1][op](o.BASE), `${op}/other curve point`);
|
||||
if (G[1].toAffine) throws(() => G[1][op](C.Point.BASE), 'Point ${op} ${pointName}');
|
||||
throws(() => G[1][op](o.BASE), '${op}/other curve point');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
should(`${name}/${pointName}/equals type check`, () => {
|
||||
should('equals type check', () => {
|
||||
throws(() => G[1].equals(0), '0');
|
||||
throws(() => G[1].equals(0n), '0n');
|
||||
deepStrictEqual(G[1].equals(G[2]), false, '1*G != 2*G');
|
||||
@ -457,13 +468,14 @@ for (const name in CURVES) {
|
||||
throws(() => G[1].equals(new Uint8Array([0])), 'ui8a([0])');
|
||||
throws(() => G[1].equals(new Uint8Array([1])), 'ui8a([1])');
|
||||
throws(() => G[1].equals(new Uint8Array(4096).fill(1)), 'ui8a(4096*[1])');
|
||||
if (G[1].toAffine) throws(() => G[1].equals(C.Point.BASE), `Point.equals(${pointName})`);
|
||||
if (G[1].toAffine) throws(() => G[1].equals(C.Point.BASE), 'Point.equals(${pointName})');
|
||||
throws(() => G[1].equals(o.BASE), 'other curve point');
|
||||
});
|
||||
|
||||
for (const op of ['multiply', 'multiplyUnsafe']) {
|
||||
if (!p.BASE[op]) continue;
|
||||
should(`${name}/${pointName}/${op} type check`, () => {
|
||||
describe(op, () => {
|
||||
should('type check', () => {
|
||||
if (op !== 'multiplyUnsafe') {
|
||||
throws(() => G[1][op](0), '0');
|
||||
throws(() => G[1][op](0n), '0n');
|
||||
@ -482,23 +494,24 @@ for (const name in CURVES) {
|
||||
throws(() => G[1][op](new Uint8Array(4096).fill(1)), 'ui8a(4096*[1])');
|
||||
throws(() => G[1][op](o.BASE), 'other curve point');
|
||||
});
|
||||
});
|
||||
}
|
||||
// Complex point (Extended/Jacobian/Projective?)
|
||||
if (p.BASE.toAffine) {
|
||||
should(`${name}/${pointName}/toAffine()`, () => {
|
||||
equal(p.ZERO.toAffine(), C.Point.ZERO, `0 = 0`);
|
||||
equal(p.BASE.toAffine(), C.Point.BASE, `1 = 1`);
|
||||
should('toAffine()', () => {
|
||||
equal(p.ZERO.toAffine(), C.Point.ZERO, '0 = 0');
|
||||
equal(p.BASE.toAffine(), C.Point.BASE, '1 = 1');
|
||||
});
|
||||
}
|
||||
if (p.fromAffine) {
|
||||
should(`${name}/${pointName}/fromAffine()`, () => {
|
||||
equal(p.ZERO, p.fromAffine(C.Point.ZERO), `0 = 0`);
|
||||
equal(p.BASE, p.fromAffine(C.Point.BASE), `1 = 1`);
|
||||
should('fromAffine()', () => {
|
||||
equal(p.ZERO, p.fromAffine(C.Point.ZERO), '0 = 0');
|
||||
equal(p.BASE, p.fromAffine(C.Point.BASE), '1 = 1');
|
||||
});
|
||||
}
|
||||
// toHex/fromHex (if available)
|
||||
if (p.fromHex && p.BASE.toHex) {
|
||||
should(`${name}/${pointName}/fromHex(toHex()) roundtrip`, () => {
|
||||
should('fromHex(toHex()) roundtrip', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (x) => {
|
||||
const hex = p.BASE.multiply(x).toHex();
|
||||
@ -507,9 +520,11 @@ for (const name in CURVES) {
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
describe(name, () => {
|
||||
// Generic complex things (getPublicKey/sign/verify/getSharedSecret)
|
||||
should(`${name}/getPublicKey type check`, () => {
|
||||
should('getPublicKey type check', () => {
|
||||
throws(() => C.getPublicKey(0), '0');
|
||||
throws(() => C.getPublicKey(0n), '0n');
|
||||
throws(() => C.getPublicKey(false), 'false');
|
||||
@ -524,7 +539,7 @@ for (const name in CURVES) {
|
||||
throws(() => C.getPublicKey(new Uint8Array([1])));
|
||||
throws(() => C.getPublicKey(new Uint8Array(4096).fill(1)));
|
||||
});
|
||||
should(`${name}.verify()/should verify random signatures`, () =>
|
||||
should('.verify() should verify random signatures', () =>
|
||||
fc.assert(
|
||||
fc.property(fc.hexaString({ minLength: 64, maxLength: 64 }), (msg) => {
|
||||
const priv = C.utils.randomPrivateKey();
|
||||
@ -533,18 +548,18 @@ for (const name in CURVES) {
|
||||
deepStrictEqual(
|
||||
C.verify(sig, msg, pub),
|
||||
true,
|
||||
`priv=${toHex(priv)},pub=${toHex(pub)},msg=${msg}`
|
||||
'priv=${toHex(priv)},pub=${toHex(pub)},msg=${msg}'
|
||||
);
|
||||
}),
|
||||
{ numRuns: NUM_RUNS }
|
||||
)
|
||||
);
|
||||
should(`${name}.sign()/edge cases`, () => {
|
||||
should('.sign() edge cases', () => {
|
||||
throws(() => C.sign());
|
||||
throws(() => C.sign(''));
|
||||
});
|
||||
|
||||
should(`${name}.verify()/should not verify signature with wrong hash`, () => {
|
||||
should('.verify() should not verify signature with wrong hash', () => {
|
||||
const MSG = '01'.repeat(32);
|
||||
const PRIV_KEY = 0x2n;
|
||||
const WRONG_MSG = '11'.repeat(32);
|
||||
@ -554,7 +569,7 @@ for (const name in CURVES) {
|
||||
});
|
||||
// NOTE: fails for ed, because of empty message. Since we convert it to scalar,
|
||||
// need to check what other implementations do. Empty message != new Uint8Array([0]), but what scalar should be in that case?
|
||||
// should(`${name}/should not verify signature with wrong message`, () => {
|
||||
// should('should not verify signature with wrong message', () => {
|
||||
// fc.assert(
|
||||
// fc.property(
|
||||
// fc.array(fc.integer({ min: 0x00, max: 0xff })),
|
||||
@ -576,7 +591,7 @@ for (const name in CURVES) {
|
||||
// });
|
||||
|
||||
if (C.getSharedSecret) {
|
||||
should(`${name}/getSharedSecret() should be commutative`, () => {
|
||||
should('getSharedSecret() should be commutative', () => {
|
||||
for (let i = 0; i < NUM_RUNS; i++) {
|
||||
const asec = C.utils.randomPrivateKey();
|
||||
const apub = C.getPublicKey(asec);
|
||||
@ -591,6 +606,7 @@ for (const name in CURVES) {
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
should('secp224k1 sqrt bug', () => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { bls12_381 } from '../lib/esm/bls12-381.js';
|
||||
import { should } from 'micro-should';
|
||||
import { describe, should } from 'micro-should';
|
||||
import { deepStrictEqual, notDeepStrictEqual, throws } from 'assert';
|
||||
import { sha512 } from '@noble/hashes/sha512';
|
||||
import * as fc from 'fast-check';
|
||||
@ -38,11 +38,11 @@ const B_384_40 = '40'.padEnd(384, '0'); // [0x40, 0, 0...]
|
||||
const getPubKey = (priv) => bls.getPublicKey(priv);
|
||||
|
||||
// Fp
|
||||
{
|
||||
describe('bls12-381 Fp', () => {
|
||||
const Fp = bls.Fp;
|
||||
const FC_BIGINT = fc.bigInt(1n, Fp.ORDER - 1n);
|
||||
|
||||
should('bls12-381/Fp/multiply/sqrt', () => {
|
||||
should('multiply/sqrt', () => {
|
||||
let sqr1 = Fp.sqrt(Fp.create(300855555557n));
|
||||
deepStrictEqual(
|
||||
sqr1 && sqr1.toString(),
|
||||
@ -50,16 +50,16 @@ const getPubKey = (priv) => bls.getPublicKey(priv);
|
||||
);
|
||||
throws(() => Fp.sqrt(Fp.create(72057594037927816n)));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Fp2
|
||||
{
|
||||
describe('bls12-381 Fp2', () => {
|
||||
const Fp = bls.Fp;
|
||||
const Fp2 = bls.Fp2;
|
||||
const FC_BIGINT = fc.bigInt(1n, Fp.ORDER - 1n);
|
||||
const FC_BIGINT_2 = fc.array(FC_BIGINT, { minLength: 2, maxLength: 2 });
|
||||
|
||||
should('bls12-381 Fp2/non-equality', () => {
|
||||
should('non-equality', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT_2, FC_BIGINT_2, (num1, num2) => {
|
||||
const a = Fp2.fromBigTuple([num1[0], num1[1]]);
|
||||
@ -70,7 +70,7 @@ const getPubKey = (priv) => bls.getPublicKey(priv);
|
||||
);
|
||||
});
|
||||
|
||||
should('bls12-381 Fp2/div/x/1=x', () => {
|
||||
should('div/x/1=x', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT_2, (num) => {
|
||||
const a = Fp2.fromBigTuple([num[0], num[1]]);
|
||||
@ -81,7 +81,7 @@ const getPubKey = (priv) => bls.getPublicKey(priv);
|
||||
);
|
||||
});
|
||||
|
||||
should('bls12-381 Fp2/frobenius', () => {
|
||||
should('frobenius', () => {
|
||||
// expect(Fp2.FROBENIUS_COEFFICIENTS[0].equals(Fp.ONE)).toBe(true);
|
||||
// expect(
|
||||
// Fp2.FROBENIUS_COEFFICIENTS[1].equals(
|
||||
@ -139,16 +139,17 @@ const getPubKey = (priv) => bls.getPublicKey(priv);
|
||||
true
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Point
|
||||
{
|
||||
describe('bls12-381 Point', () => {
|
||||
const Fp = bls.Fp;
|
||||
const FC_BIGINT = fc.bigInt(1n, Fp.ORDER - 1n);
|
||||
const PointG1 = bls.G1.Point;
|
||||
const PointG2 = bls.G2.Point;
|
||||
|
||||
should('bls12-381 Point/Point with Fp coordinates/Point equality', () => {
|
||||
describe('with Fp coordinates', () => {
|
||||
should('Point equality', () => {
|
||||
fc.assert(
|
||||
fc.property(
|
||||
fc.array(FC_BIGINT, { minLength: 3, maxLength: 3 }),
|
||||
@ -164,16 +165,16 @@ const getPubKey = (priv) => bls.getPublicKey(priv);
|
||||
)
|
||||
);
|
||||
});
|
||||
should('bls12-381 Point/Point with Fp coordinates/should be placed on curve vector 1', () => {
|
||||
should('be placed on curve vector 1', () => {
|
||||
const a = new PointG1(Fp.create(0n), Fp.create(0n));
|
||||
a.assertValidity();
|
||||
});
|
||||
should('bls12-381 Point/Point with Fp coordinates/should not be placed on curve vector 1', () => {
|
||||
should('not be placed on curve vector 1', () => {
|
||||
const a = new PointG1(Fp.create(0n), Fp.create(1n));
|
||||
throws(() => a.assertValidity());
|
||||
});
|
||||
|
||||
should('bls12-381 Point/Point with Fp coordinates/should be placed on curve vector 2', () => {
|
||||
should('be placed on curve vector 2', () => {
|
||||
const a = new PointG1(
|
||||
Fp.create(
|
||||
0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bbn
|
||||
@ -184,7 +185,7 @@ const getPubKey = (priv) => bls.getPublicKey(priv);
|
||||
);
|
||||
a.assertValidity();
|
||||
});
|
||||
should('bls12-381 Point/Point with Fp coordinates/should be placed on curve vector 3', () => {
|
||||
should('be placed on curve vector 3', () => {
|
||||
const a = new PointG1(
|
||||
Fp.create(
|
||||
3971675556538908004130084773503021351583407620890695272226385332452194486153316625183061567093226342405194446632851n
|
||||
@ -196,7 +197,7 @@ const getPubKey = (priv) => bls.getPublicKey(priv);
|
||||
|
||||
a.assertValidity();
|
||||
});
|
||||
should('bls12-381 Point/Point with Fp coordinates/should not be placed on curve vector 3', () => {
|
||||
should('not be placed on curve vector 3', () => {
|
||||
const a = new PointG1(
|
||||
Fp.create(
|
||||
622186380008502900120948444810967255157373993223369845903602988014033704418470621816206856882891545628885272576827n
|
||||
@ -207,7 +208,7 @@ const getPubKey = (priv) => bls.getPublicKey(priv);
|
||||
);
|
||||
throws(() => a.assertValidity());
|
||||
});
|
||||
should('bls12-381 Point/Point with Fp coordinates/should not be placed on curve vector 2', () => {
|
||||
should('not be placed on curve vector 2', () => {
|
||||
const a = new PointG1(
|
||||
Fp.create(
|
||||
0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6ban
|
||||
@ -219,9 +220,7 @@ const getPubKey = (priv) => bls.getPublicKey(priv);
|
||||
throws(() => a.assertValidity());
|
||||
});
|
||||
|
||||
should(
|
||||
'bls12-381 Point/Point with Fp coordinates/should be doubled and placed on curve vector 1',
|
||||
() => {
|
||||
should('be doubled and placed on curve vector 1', () => {
|
||||
const a = new PointG1(
|
||||
Fp.create(
|
||||
0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bbn
|
||||
@ -245,11 +244,8 @@ const getPubKey = (priv) => bls.getPublicKey(priv);
|
||||
);
|
||||
deepStrictEqual(double, a.multiply(2n));
|
||||
deepStrictEqual(double, a.add(a));
|
||||
}
|
||||
);
|
||||
should(
|
||||
'bls12-381 Point/Point with Fp coordinates/should be pdoubled and placed on curve vector 2',
|
||||
() => {
|
||||
});
|
||||
should('be pdoubled and placed on curve vector 2', () => {
|
||||
const a = new PointG1(
|
||||
Fp.create(
|
||||
3971675556538908004130084773503021351583407620890695272226385332452194486153316625183061567093226342405194446632851n
|
||||
@ -273,9 +269,8 @@ const getPubKey = (priv) => bls.getPublicKey(priv);
|
||||
);
|
||||
deepStrictEqual(double, a.multiply(2n));
|
||||
deepStrictEqual(double, a.add(a));
|
||||
}
|
||||
);
|
||||
should('bls12-381 Point/Point with Fp coordinates/should not validate incorrect point', () => {
|
||||
});
|
||||
should('not validate incorrect point', () => {
|
||||
const x =
|
||||
499001545268060011619089734015590154568173930614466321429631711131511181286230338880376679848890024401335766847607n;
|
||||
const y =
|
||||
@ -284,8 +279,10 @@ const getPubKey = (priv) => bls.getPublicKey(priv);
|
||||
const p = new PointG1(Fp.create(x), Fp.create(y));
|
||||
throws(() => p.assertValidity());
|
||||
});
|
||||
});
|
||||
|
||||
should('bls12-381 Point/Point with Fp2 coordinates/Point equality', () => {
|
||||
describe('with Fp2 coordinates', () => {
|
||||
should('Point equality', () => {
|
||||
fc.assert(
|
||||
fc.property(
|
||||
fc.array(fc.array(FC_BIGINT, { minLength: 2, maxLength: 2 }), {
|
||||
@ -297,8 +294,16 @@ const getPubKey = (priv) => bls.getPublicKey(priv);
|
||||
maxLength: 3,
|
||||
}),
|
||||
([x1, y1, z1], [x2, y2, z2]) => {
|
||||
const p1 = new PointG2(Fp2.fromBigTuple(x1), Fp2.fromBigTuple(y1), Fp2.fromBigTuple(z1));
|
||||
const p2 = new PointG2(Fp2.fromBigTuple(x2), Fp2.fromBigTuple(y2), Fp2.fromBigTuple(z2));
|
||||
const p1 = new PointG2(
|
||||
Fp2.fromBigTuple(x1),
|
||||
Fp2.fromBigTuple(y1),
|
||||
Fp2.fromBigTuple(z1)
|
||||
);
|
||||
const p2 = new PointG2(
|
||||
Fp2.fromBigTuple(x2),
|
||||
Fp2.fromBigTuple(y2),
|
||||
Fp2.fromBigTuple(z2)
|
||||
);
|
||||
deepStrictEqual(p1.equals(p1), true);
|
||||
deepStrictEqual(p2.equals(p2), true);
|
||||
deepStrictEqual(p1.equals(p2), false);
|
||||
@ -307,11 +312,11 @@ const getPubKey = (priv) => bls.getPublicKey(priv);
|
||||
)
|
||||
);
|
||||
});
|
||||
// should('bls12-381 Point/Point with Fp2 coordinates/should be placed on curve vector 1', () => {
|
||||
// should('be placed on curve vector 1', () => {
|
||||
// const a = new PointG2(Fp2.fromBigTuple([0n, 0n]), Fp2.fromBigTuple([0n, 0n]));
|
||||
// a.assertValidity();
|
||||
// });
|
||||
should('bls12-381 Point/Point with Fp2 coordinates/should be placed on curve vector 2', () => {
|
||||
should('be placed on curve vector 2', () => {
|
||||
const a = new PointG2(
|
||||
Fp2.fromBigTuple([
|
||||
0x024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8n,
|
||||
@ -325,7 +330,7 @@ const getPubKey = (priv) => bls.getPublicKey(priv);
|
||||
);
|
||||
a.assertValidity();
|
||||
});
|
||||
should('bls12-381 Point/Point with Fp2 coordinates/should be placed on curve vector 3', () => {
|
||||
should('be placed on curve vector 3', () => {
|
||||
const a = new PointG2(
|
||||
Fp2.fromBigTuple([
|
||||
233289878585407360737561818812172281900488265436962145913969074168503452745466655442125797664134009339799716079103n,
|
||||
@ -338,20 +343,15 @@ const getPubKey = (priv) => bls.getPublicKey(priv);
|
||||
);
|
||||
a.assertValidity();
|
||||
});
|
||||
should(
|
||||
'bls12-381 Point/Point with Fp2 coordinates/should not be placed on curve vector 1',
|
||||
() => {
|
||||
should('not be placed on curve vector 1', () => {
|
||||
const a = new PointG2(
|
||||
Fp2.fromBigTuple([0n, 0n]),
|
||||
Fp2.fromBigTuple([1n, 0n]),
|
||||
Fp2.fromBigTuple([1n, 0n])
|
||||
);
|
||||
throws(() => a.assertValidity());
|
||||
}
|
||||
);
|
||||
should(
|
||||
'bls12-381 Point/Point with Fp2 coordinates/should not be placed on curve vector 2',
|
||||
() => {
|
||||
});
|
||||
should('not be placed on curve vector 2', () => {
|
||||
const a = new PointG2(
|
||||
Fp2.fromBigTuple([
|
||||
0x024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4410b647ae3d1770bac0326a805bbefd48056c8c121bdb8n,
|
||||
@ -364,11 +364,8 @@ const getPubKey = (priv) => bls.getPublicKey(priv);
|
||||
Fp2.fromBigTuple([1n, 0n])
|
||||
);
|
||||
throws(() => a.assertValidity());
|
||||
}
|
||||
);
|
||||
should(
|
||||
'bls12-381 Point/Point with Fp2 coordinates/should not be placed on curve vector 3',
|
||||
() => {
|
||||
});
|
||||
should('not be placed on curve vector 3', () => {
|
||||
const a = new PointG2(
|
||||
Fp2.fromBigTuple([
|
||||
0x877d52dd65245f8908a03288adcd396f489ef87ae23fe110c5aa48bc208fbd1a0ed403df5b1ac137922b915f1f38ec37n,
|
||||
@ -384,10 +381,10 @@ const getPubKey = (priv) => bls.getPublicKey(priv);
|
||||
])
|
||||
);
|
||||
throws(() => a.assertValidity());
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
should('bls12-381 Point/should be doubled and placed on curve vector 1', () => {
|
||||
should('be doubled and placed on curve vector 1', () => {
|
||||
const a = new PointG2(
|
||||
Fp2.fromBigTuple([
|
||||
0x024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8n,
|
||||
@ -417,7 +414,7 @@ const getPubKey = (priv) => bls.getPublicKey(priv);
|
||||
deepStrictEqual(double, a.multiply(2n));
|
||||
deepStrictEqual(double, a.add(a));
|
||||
});
|
||||
should('bls12-381 Point/should be doubled and placed on curve vector 2', () => {
|
||||
should('be doubled and placed on curve vector 2', () => {
|
||||
const a = new PointG2(
|
||||
Fp2.fromBigTuple([
|
||||
233289878585407360737561818812172281900488265436962145913969074168503452745466655442125797664134009339799716079103n,
|
||||
@ -455,49 +452,51 @@ const getPubKey = (priv) => bls.getPublicKey(priv);
|
||||
0x53eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001n,
|
||||
0x63eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000n,
|
||||
];
|
||||
should('bls12-381 Point/wNAF multiplication same as unsafe (G1, W=1)', () => {
|
||||
describe('wNAF multiplication same as unsafe', () => {
|
||||
should('(G1, W=1)', () => {
|
||||
let G = PointG1.BASE.negate().negate(); // create new point
|
||||
G._setWindowSize(1);
|
||||
for (let k of wNAF_VECTORS) {
|
||||
deepStrictEqual(G.multiply(k).equals(G.multiplyUnsafe(k)), true);
|
||||
}
|
||||
});
|
||||
should('bls12-381 Point/wNAF multiplication same as unsafe (G1, W=4)', () => {
|
||||
should('(G1, W=4)', () => {
|
||||
let G = PointG1.BASE.negate().negate();
|
||||
G._setWindowSize(4);
|
||||
for (let k of wNAF_VECTORS) {
|
||||
deepStrictEqual(G.multiply(k).equals(G.multiplyUnsafe(k)), true);
|
||||
}
|
||||
});
|
||||
should('bls12-381 Point/wNAF multiplication same as unsafe (G1, W=5)', () => {
|
||||
should('(G1, W=5)', () => {
|
||||
let G = PointG1.BASE.negate().negate();
|
||||
G._setWindowSize(5);
|
||||
for (let k of wNAF_VECTORS) {
|
||||
deepStrictEqual(G.multiply(k).equals(G.multiplyUnsafe(k)), true);
|
||||
}
|
||||
});
|
||||
should('bls12-381 Point/wNAF multiplication same as unsafe (G2, W=1)', () => {
|
||||
should('(G2, W=1)', () => {
|
||||
let G = PointG2.BASE.negate().negate();
|
||||
G._setWindowSize(1);
|
||||
for (let k of wNAF_VECTORS) {
|
||||
deepStrictEqual(G.multiply(k).equals(G.multiplyUnsafe(k)), true);
|
||||
}
|
||||
});
|
||||
should('bls12-381 Point/wNAF multiplication same as unsafe (G2, W=4)', () => {
|
||||
should('(G2, W=4)', () => {
|
||||
let G = PointG2.BASE.negate().negate();
|
||||
G._setWindowSize(4);
|
||||
for (let k of wNAF_VECTORS) {
|
||||
deepStrictEqual(G.multiply(k).equals(G.multiplyUnsafe(k)), true);
|
||||
}
|
||||
});
|
||||
should('bls12-381 Point/wNAF multiplication same as unsafe (G2, W=5)', () => {
|
||||
should('(G2, W=5)', () => {
|
||||
let G = PointG2.BASE.negate().negate();
|
||||
G._setWindowSize(5);
|
||||
for (let k of wNAF_VECTORS) {
|
||||
deepStrictEqual(G.multiply(k).equals(G.multiplyUnsafe(k)), true);
|
||||
}
|
||||
});
|
||||
should('bls12-381 Point/PSI cofactor cleaning same as multiplication', () => {
|
||||
});
|
||||
should('PSI cofactor cleaning same as multiplication', () => {
|
||||
const points = [
|
||||
new PointG2(
|
||||
Fp2.fromBigTuple([
|
||||
@ -558,14 +557,15 @@ const getPubKey = (priv) => bls.getPublicKey(priv);
|
||||
deepStrictEqual(ours.equals(shouldBe), true, 'clearLast');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// index.ts
|
||||
|
||||
// bls.PointG1.BASE.clearMultiplyPrecomputes();
|
||||
// bls.PointG1.BASE.calcMultiplyPrecomputes(4);
|
||||
|
||||
should('bls12-381/basic/should construct point G1 from its uncompressed form (Raw Bytes)', () => {
|
||||
describe('bls12-381/basic', () => {
|
||||
should('construct point G1 from its uncompressed form (Raw Bytes)', () => {
|
||||
// Test Zero
|
||||
const g1 = bls.G1.Point.fromHex(B_192_40);
|
||||
deepStrictEqual(g1.x, bls.G1.Point.ZERO.x);
|
||||
@ -588,9 +588,9 @@ should('bls12-381/basic/should construct point G1 from its uncompressed form (Ra
|
||||
|
||||
deepStrictEqual(g1_.x, x);
|
||||
deepStrictEqual(g1_.y, y);
|
||||
});
|
||||
});
|
||||
|
||||
should('bls12-381/basic/should construct point G1 from its uncompressed form (Hex)', () => {
|
||||
should('construct point G1 from its uncompressed form (Hex)', () => {
|
||||
// Test Zero
|
||||
const g1 = bls.G1.Point.fromHex(B_192_40);
|
||||
|
||||
@ -614,9 +614,9 @@ should('bls12-381/basic/should construct point G1 from its uncompressed form (He
|
||||
|
||||
deepStrictEqual(g1_.x, x);
|
||||
deepStrictEqual(g1_.y, y);
|
||||
});
|
||||
});
|
||||
|
||||
should('bls12-381/basic/should construct point G2 from its uncompressed form (Raw Bytes)', () => {
|
||||
should('construct point G2 from its uncompressed form (Raw Bytes)', () => {
|
||||
// Test Zero
|
||||
const g2 = bls.G2.Point.fromHex(B_384_40);
|
||||
deepStrictEqual(g2.x, bls.G2.Point.ZERO.x, 'zero(x)');
|
||||
@ -645,9 +645,9 @@ should('bls12-381/basic/should construct point G2 from its uncompressed form (Ra
|
||||
|
||||
deepStrictEqual(g2_.x, x);
|
||||
deepStrictEqual(g2_.y, y);
|
||||
});
|
||||
});
|
||||
|
||||
should('bls12-381/basic/should construct point G2 from its uncompressed form (Hex)', () => {
|
||||
should('construct point G2 from its uncompressed form (Hex)', () => {
|
||||
// Test Zero
|
||||
const g2 = bls.G2.Point.fromHex(B_384_40);
|
||||
|
||||
@ -677,9 +677,9 @@ should('bls12-381/basic/should construct point G2 from its uncompressed form (He
|
||||
|
||||
deepStrictEqual(g2_.x, x);
|
||||
deepStrictEqual(g2_.y, y);
|
||||
});
|
||||
});
|
||||
|
||||
should('bls12-381/basic/should get uncompressed form of point G1 (Raw Bytes)', () => {
|
||||
should('get uncompressed form of point G1 (Raw Bytes)', () => {
|
||||
// Test Zero
|
||||
deepStrictEqual(bls.G1.Point.ZERO.toHex(false), B_192_40);
|
||||
// Test Non-Zero
|
||||
@ -698,9 +698,9 @@ should('bls12-381/basic/should get uncompressed form of point G1 (Raw Bytes)', (
|
||||
g1.toHex(false),
|
||||
'17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
should('bls12-381/basic/should get uncompressed form of point G1 (Hex)', () => {
|
||||
should('get uncompressed form of point G1 (Hex)', () => {
|
||||
// Test Zero
|
||||
deepStrictEqual(bls.G1.Point.ZERO.toHex(false), B_192_40);
|
||||
// Test Non-Zero
|
||||
@ -719,9 +719,9 @@ should('bls12-381/basic/should get uncompressed form of point G1 (Hex)', () => {
|
||||
g1.toHex(false),
|
||||
'17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
should('bls12-381/basic/should get uncompressed form of point G2 (Raw Bytes)', () => {
|
||||
should('get uncompressed form of point G2 (Raw Bytes)', () => {
|
||||
// Test Zero
|
||||
deepStrictEqual(bls.G2.Point.ZERO.toHex(false), B_384_40);
|
||||
// Test Non-Zero
|
||||
@ -746,9 +746,9 @@ should('bls12-381/basic/should get uncompressed form of point G2 (Raw Bytes)', (
|
||||
g2.toHex(false),
|
||||
'13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
should('bls12-381/basic/should get uncompressed form of point G2 (Hex)', () => {
|
||||
should('get uncompressed form of point G2 (Hex)', () => {
|
||||
// Test Zero
|
||||
deepStrictEqual(bls.G2.Point.ZERO.toHex(false), B_384_40);
|
||||
|
||||
@ -774,53 +774,53 @@ should('bls12-381/basic/should get uncompressed form of point G2 (Hex)', () => {
|
||||
g2.toHex(false),
|
||||
'13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
should('bls12-381/basic/should compress and decompress G1 points', async () => {
|
||||
should('compress and decompress G1 points', async () => {
|
||||
const priv = bls.G1.Point.fromPrivateKey(42n);
|
||||
const publicKey = priv.toHex(true);
|
||||
const decomp = bls.G1.Point.fromHex(publicKey);
|
||||
deepStrictEqual(publicKey, decomp.toHex(true));
|
||||
});
|
||||
should('bls12-381/basic/should not compress and decompress zero G1 point', () => {
|
||||
});
|
||||
should('not compress and decompress zero G1 point', () => {
|
||||
throws(() => bls.G1.Point.fromPrivateKey(0n));
|
||||
});
|
||||
should('bls12-381/basic/should compress and decompress G2 points', () => {
|
||||
});
|
||||
should('compress and decompress G2 points', () => {
|
||||
const priv = bls.G2.Point.fromPrivateKey(42n);
|
||||
const publicKey = priv.toHex(true);
|
||||
const decomp = bls.G2.Point.fromHex(publicKey);
|
||||
deepStrictEqual(publicKey, decomp.toHex(true));
|
||||
});
|
||||
should('bls12-381/basic/should not compress and decompress zero G2 point', () => {
|
||||
});
|
||||
should('not compress and decompress zero G2 point', () => {
|
||||
throws(() => bls.G2.Point.fromPrivateKey(0n));
|
||||
});
|
||||
const VALID_G1 = new bls.G1.Point(
|
||||
});
|
||||
const VALID_G1 = new bls.G1.Point(
|
||||
bls.Fp.create(
|
||||
3609742242174788176010452839163620388872641749536604986743596621604118973777515189035770461528205168143692110933639n
|
||||
),
|
||||
bls.Fp.create(
|
||||
1619277690257184054444116778047375363103842303863153349133480657158810226683757397206929105479676799650932070320089n
|
||||
)
|
||||
);
|
||||
const VALID_G1_2 = new bls.G1.Point(
|
||||
);
|
||||
const VALID_G1_2 = new bls.G1.Point(
|
||||
bls.Fp.create(
|
||||
1206972466279728255044019580914616126536509750250979180256809997983196363639429409634110400978470384566664128085207n
|
||||
),
|
||||
bls.Fp.create(
|
||||
2991142246317096160788653339959532007292638191110818490939476869616372888657136539642598243964263069435065725313423n
|
||||
)
|
||||
);
|
||||
);
|
||||
|
||||
const INVALID_G1 = new bls.G1.Point(
|
||||
const INVALID_G1 = new bls.G1.Point(
|
||||
bls.Fp.create(
|
||||
499001545268060011619089734015590154568173930614466321429631711131511181286230338880376679848890024401335766847607n
|
||||
),
|
||||
bls.Fp.create(
|
||||
3934582309586258715640230772291917282844636728991757779640464479794033391537662970190753981664259511166946374555673n
|
||||
)
|
||||
);
|
||||
);
|
||||
|
||||
should('bls12-381/basic/should aggregate pubkeys', () => {
|
||||
should('aggregate pubkeys', () => {
|
||||
const agg = bls.aggregatePublicKeys([VALID_G1, VALID_G1_2]);
|
||||
deepStrictEqual(
|
||||
agg.x,
|
||||
@ -830,21 +830,21 @@ should('bls12-381/basic/should aggregate pubkeys', () => {
|
||||
agg.y,
|
||||
2200256264293372104833346444532839112556752874984721583125881868863625579979779052307146195064914375388929781136724n
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
should('bls12-381/basic/should not aggregate invalid pubkeys', () => {
|
||||
should('not aggregate invalid pubkeys', () => {
|
||||
throws(() => bls.aggregatePublicKeys([VALID_G1, INVALID_G1]));
|
||||
});
|
||||
// should aggregate signatures
|
||||
});
|
||||
// should aggregate signatures
|
||||
|
||||
should(`should produce correct signatures (${G2_VECTORS.length} vectors)`, async () => {
|
||||
should(`produce correct signatures (${G2_VECTORS.length} vectors)`, async () => {
|
||||
for (let vector of G2_VECTORS) {
|
||||
const [priv, msg, expected] = vector;
|
||||
const sig = await bls.sign(msg, priv);
|
||||
deepStrictEqual(bls.utils.bytesToHex(sig), expected);
|
||||
}
|
||||
});
|
||||
should(`should produce correct scalars (${SCALAR_VECTORS.length} vectors)`, async () => {
|
||||
});
|
||||
should(`produce correct scalars (${SCALAR_VECTORS.length} vectors)`, async () => {
|
||||
const options = {
|
||||
p: bls.CURVE.r,
|
||||
m: 1,
|
||||
@ -857,8 +857,8 @@ should(`should produce correct scalars (${SCALAR_VECTORS.length} vectors)`, asyn
|
||||
const scalars = await bls.utils.hashToField(okm, 1, options);
|
||||
deepStrictEqual(scalars[0][0], expected);
|
||||
}
|
||||
});
|
||||
should('bls12-381/basic/should verify signed message', async () => {
|
||||
});
|
||||
should('verify signed message', async () => {
|
||||
for (let i = 0; i < NUM_RUNS; i++) {
|
||||
const [priv, msg] = G2_VECTORS[i];
|
||||
const sig = await bls.sign(msg, priv);
|
||||
@ -866,8 +866,8 @@ should('bls12-381/basic/should verify signed message', async () => {
|
||||
const res = await bls.verify(sig, msg, pub);
|
||||
deepStrictEqual(res, true);
|
||||
}
|
||||
});
|
||||
should('bls12-381/basic/should not verify signature with wrong message', async () => {
|
||||
});
|
||||
should('not verify signature with wrong message', async () => {
|
||||
for (let i = 0; i < NUM_RUNS; i++) {
|
||||
const [priv, msg] = G2_VECTORS[i];
|
||||
const invMsg = G2_VECTORS[i + 1][1];
|
||||
@ -876,8 +876,8 @@ should('bls12-381/basic/should not verify signature with wrong message', async (
|
||||
const res = await bls.verify(sig, invMsg, pub);
|
||||
deepStrictEqual(res, false);
|
||||
}
|
||||
});
|
||||
should('bls12-381/basic/should not verify signature with wrong key', async () => {
|
||||
});
|
||||
should('not verify signature with wrong key', async () => {
|
||||
for (let i = 0; i < NUM_RUNS; i++) {
|
||||
const [priv, msg] = G2_VECTORS[i];
|
||||
const sig = await bls.sign(msg, priv);
|
||||
@ -886,8 +886,8 @@ should('bls12-381/basic/should not verify signature with wrong key', async () =>
|
||||
const res = await bls.verify(sig, msg, invPub);
|
||||
deepStrictEqual(res, false);
|
||||
}
|
||||
});
|
||||
should('bls12-381/basic/should verify multi-signature', async () => {
|
||||
});
|
||||
should('verify multi-signature', async () => {
|
||||
await fc.assert(
|
||||
fc.asyncProperty(FC_MSG_5, FC_BIGINT_5, async (messages, privateKeys) => {
|
||||
privateKeys = privateKeys.slice(0, messages.length);
|
||||
@ -900,8 +900,8 @@ should('bls12-381/basic/should verify multi-signature', async () => {
|
||||
deepStrictEqual(await bls.verifyBatch(aggregatedSignature, messages, publicKey), true);
|
||||
})
|
||||
);
|
||||
});
|
||||
should('bls12-381/basic/should batch verify multi-signatures', async () => {
|
||||
});
|
||||
should('batch verify multi-signatures', async () => {
|
||||
await fc.assert(
|
||||
fc.asyncProperty(
|
||||
FC_MSG_5,
|
||||
@ -925,8 +925,8 @@ should('bls12-381/basic/should batch verify multi-signatures', async () => {
|
||||
}
|
||||
)
|
||||
);
|
||||
});
|
||||
should('bls12-381/basic/should not verify multi-signature with wrong public keys', async () => {
|
||||
});
|
||||
should('not verify multi-signature with wrong public keys', async () => {
|
||||
await fc.assert(
|
||||
fc.asyncProperty(
|
||||
FC_MSG_5,
|
||||
@ -950,8 +950,8 @@ should('bls12-381/basic/should not verify multi-signature with wrong public keys
|
||||
}
|
||||
)
|
||||
);
|
||||
});
|
||||
should('bls12-381/basic/should verify multi-signature as simple signature', async () => {
|
||||
});
|
||||
should('verify multi-signature as simple signature', async () => {
|
||||
await fc.assert(
|
||||
fc.asyncProperty(FC_MSG, FC_BIGINT_5, async (message, privateKeys) => {
|
||||
const publicKey = await Promise.all(privateKeys.map(getPubKey));
|
||||
@ -963,8 +963,8 @@ should('bls12-381/basic/should verify multi-signature as simple signature', asyn
|
||||
deepStrictEqual(await bls.verify(aggregatedSignature, message, aggregatedPublicKey), true);
|
||||
})
|
||||
);
|
||||
});
|
||||
should('bls12-381/basic/should not verify wrong multi-signature as simple signature', async () => {
|
||||
});
|
||||
should('not verify wrong multi-signature as simple signature', async () => {
|
||||
await fc.assert(
|
||||
fc.asyncProperty(FC_MSG, FC_MSG, FC_BIGINT_5, async (message, wrongMessage, privateKeys) => {
|
||||
const publicKey = await Promise.all(privateKeys.map(getPubKey));
|
||||
@ -979,35 +979,36 @@ should('bls12-381/basic/should not verify wrong multi-signature as simple signat
|
||||
);
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// Pairing
|
||||
{
|
||||
describe('pairing', () => {
|
||||
const { pairing, Fp12 } = bls;
|
||||
const G1 = bls.G1.Point.BASE;
|
||||
const G2 = bls.G2.Point.BASE;
|
||||
|
||||
should('pairing/creates negative G1 pairing', () => {
|
||||
should('creates negative G1 pairing', () => {
|
||||
const p1 = pairing(G1, G2);
|
||||
const p2 = pairing(G1.negate(), G2);
|
||||
deepStrictEqual(Fp12.mul(p1, p2), Fp12.ONE);
|
||||
});
|
||||
should('pairing/creates negative G2 pairing', () => {
|
||||
should('creates negative G2 pairing', () => {
|
||||
const p2 = pairing(G1.negate(), G2);
|
||||
const p3 = pairing(G1, G2.negate());
|
||||
deepStrictEqual(p2, p3);
|
||||
});
|
||||
should('pairing/creates proper pairing output order', () => {
|
||||
should('creates proper pairing output order', () => {
|
||||
const p1 = pairing(G1, G2);
|
||||
const p2 = Fp12.pow(p1, CURVE_ORDER);
|
||||
deepStrictEqual(p2, Fp12.ONE);
|
||||
});
|
||||
should('pairing/G1 billinearity', () => {
|
||||
should('G1 billinearity', () => {
|
||||
const p1 = pairing(G1, G2);
|
||||
const p2 = pairing(G1.multiply(2n), G2);
|
||||
deepStrictEqual(Fp12.mul(p1, p1), p2);
|
||||
});
|
||||
should('pairing/should not degenerate', () => {
|
||||
should('should not degenerate', () => {
|
||||
const p1 = pairing(G1, G2);
|
||||
const p2 = pairing(G1.multiply(2n), G2);
|
||||
const p3 = pairing(G1, G2.negate());
|
||||
@ -1015,17 +1016,17 @@ should('bls12-381/basic/should not verify wrong multi-signature as simple signat
|
||||
notDeepStrictEqual(p1, p3);
|
||||
notDeepStrictEqual(p2, p3);
|
||||
});
|
||||
should('pairing/G2 billinearity', () => {
|
||||
should('G2 billinearity', () => {
|
||||
const p1 = pairing(G1, G2);
|
||||
const p2 = pairing(G1, G2.multiply(2n));
|
||||
deepStrictEqual(Fp12.mul(p1, p1), p2);
|
||||
});
|
||||
should('pairing/proper pairing composite check', () => {
|
||||
should('proper pairing composite check', () => {
|
||||
const p1 = pairing(G1.multiply(37n), G2.multiply(27n));
|
||||
const p2 = pairing(G1.multiply(999n), G2);
|
||||
deepStrictEqual(p1, p2);
|
||||
});
|
||||
should('pairing/vectors from https://github.com/zkcrypto/pairing', () => {
|
||||
should('vectors from https://github.com/zkcrypto/pairing', () => {
|
||||
const p1 = pairing(G1, G2);
|
||||
deepStrictEqual(
|
||||
p1,
|
||||
@ -1045,7 +1046,7 @@ should('bls12-381/basic/should not verify wrong multi-signature as simple signat
|
||||
])
|
||||
);
|
||||
});
|
||||
should('pairing/finalExponentiate is correct', () => {
|
||||
should('finalExponentiate is correct', () => {
|
||||
const p1 = Fp12.fromBigTwelve([
|
||||
690392658038414015999440694435086329841032295415825549843130960252222448232974816207293269712691075396080336239827n,
|
||||
1673244384695948045466836192250093912021245353707563547917201356526057153141766171738038843400145227470982267854187n,
|
||||
@ -1078,9 +1079,9 @@ should('bls12-381/basic/should not verify wrong multi-signature as simple signat
|
||||
])
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
// hashToCurve
|
||||
{
|
||||
describe('hash-to-curve', () => {
|
||||
const DST = 'QUUX-V01-CS02-with-expander-SHA256-128';
|
||||
const VECTORS = [
|
||||
{
|
||||
@ -1824,9 +1825,9 @@ should('bls12-381/basic/should not verify wrong multi-signature as simple signat
|
||||
deepStrictEqual(p.toHex(), t.expected);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
// Deterministic
|
||||
{
|
||||
describe('bls12-381 deterministic', () => {
|
||||
// NOTE: Killic returns all items in reversed order, which looks strange:
|
||||
// instead of `Fp2(${this.c0} + ${this.c1}×i)`; it returns `Fp2(${this.c0}×i + ${this.c1})`;
|
||||
const killicHex = (lst) =>
|
||||
@ -1934,7 +1935,7 @@ should('bls12-381/basic/should not verify wrong multi-signature as simple signat
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// ESM is broken.
|
||||
import url from 'url';
|
||||
|
@ -1,7 +1,14 @@
|
||||
import { deepStrictEqual, throws } from 'assert';
|
||||
import { should } from 'micro-should';
|
||||
import { deepEqual, deepStrictEqual, strictEqual, throws } from 'assert';
|
||||
import { describe, should } from 'micro-should';
|
||||
import * as fc from 'fast-check';
|
||||
import { ed25519, ed25519ctx, ed25519ph, x25519, RistrettoPoint } from '../lib/esm/ed25519.js';
|
||||
import {
|
||||
ed25519,
|
||||
ed25519ctx,
|
||||
ed25519ph,
|
||||
x25519,
|
||||
RistrettoPoint,
|
||||
ED25519_TORSION_SUBGROUP,
|
||||
} from '../lib/esm/ed25519.js';
|
||||
import { readFileSync } from 'fs';
|
||||
import { default as zip215 } from './ed25519/zip215.json' assert { type: 'json' };
|
||||
import { hexToBytes, bytesToHex, randomBytes } from '@noble/hashes/utils';
|
||||
@ -10,29 +17,30 @@ import { sha512 } from '@noble/hashes/sha512';
|
||||
import { default as ed25519vectors } from './wycheproof/eddsa_test.json' assert { type: 'json' };
|
||||
import { default as x25519vectors } from './wycheproof/x25519_test.json' assert { type: 'json' };
|
||||
|
||||
const ed = ed25519;
|
||||
const hex = bytesToHex;
|
||||
describe('ed25519', () => {
|
||||
const ed = ed25519;
|
||||
const hex = bytesToHex;
|
||||
|
||||
function to32Bytes(numOrStr) {
|
||||
function to32Bytes(numOrStr) {
|
||||
let hex = typeof numOrStr === 'string' ? numOrStr : numOrStr.toString(16);
|
||||
return hexToBytes(hex.padStart(64, '0'));
|
||||
}
|
||||
}
|
||||
|
||||
function utf8ToBytes(str) {
|
||||
function utf8ToBytes(str) {
|
||||
if (typeof str !== 'string') {
|
||||
throw new TypeError(`utf8ToBytes expected string, got ${typeof str}`);
|
||||
}
|
||||
return new TextEncoder().encode(str);
|
||||
}
|
||||
}
|
||||
|
||||
ed.utils.precompute(8);
|
||||
ed.utils.precompute(8);
|
||||
|
||||
should('ed25519/should not accept >32byte private keys', () => {
|
||||
should('not accept >32byte private keys', () => {
|
||||
const invalidPriv =
|
||||
100000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800073278156000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000n;
|
||||
throws(() => ed.getPublicKey(invalidPriv));
|
||||
});
|
||||
should('ed25519/should verify recent signature', () => {
|
||||
});
|
||||
should('verify recent signature', () => {
|
||||
fc.assert(
|
||||
fc.property(
|
||||
fc.hexaString({ minLength: 2, maxLength: 32 }),
|
||||
@ -47,8 +55,8 @@ should('ed25519/should verify recent signature', () => {
|
||||
),
|
||||
{ numRuns: 5 }
|
||||
);
|
||||
});
|
||||
should('ed25519/should not verify signature with wrong message', () => {
|
||||
});
|
||||
should('not verify signature with wrong message', () => {
|
||||
fc.assert(
|
||||
fc.property(
|
||||
fc.array(fc.integer({ min: 0x00, max: 0xff })),
|
||||
@ -68,44 +76,46 @@ should('ed25519/should not verify signature with wrong message', () => {
|
||||
),
|
||||
{ numRuns: 5 }
|
||||
);
|
||||
});
|
||||
const privKey = to32Bytes('a665a45920422f9d417e4867ef');
|
||||
const msg = hexToBytes('874f9960c5d2b7a9b5fad383e1ba44719ebb743a');
|
||||
const wrongMsg = hexToBytes('589d8c7f1da0a24bc07b7381ad48b1cfc211af1c');
|
||||
should('ed25519/basic methods/should sign and verify', () => {
|
||||
});
|
||||
const privKey = to32Bytes('a665a45920422f9d417e4867ef');
|
||||
const msg = hexToBytes('874f9960c5d2b7a9b5fad383e1ba44719ebb743a');
|
||||
const wrongMsg = hexToBytes('589d8c7f1da0a24bc07b7381ad48b1cfc211af1c');
|
||||
describe('basic methods', () => {
|
||||
should('sign and verify', () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), true);
|
||||
});
|
||||
should('ed25519/basic methods/should not verify signature with wrong public key', () => {
|
||||
});
|
||||
should('not verify signature with wrong public key', () => {
|
||||
const publicKey = ed.getPublicKey(12);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), false);
|
||||
});
|
||||
should('ed25519/basic methods/should not verify signature with wrong hash', () => {
|
||||
});
|
||||
should('not verify signature with wrong hash', () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, wrongMsg, publicKey), false);
|
||||
});
|
||||
|
||||
should('ed25519/sync methods/should sign and verify', () => {
|
||||
});
|
||||
});
|
||||
describe('sync methods', () => {
|
||||
should('sign and verify', () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), true);
|
||||
});
|
||||
should('ed25519/sync methods/should not verify signature with wrong public key', () => {
|
||||
});
|
||||
should('not verify signature with wrong public key', () => {
|
||||
const publicKey = ed.getPublicKey(12);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), false);
|
||||
});
|
||||
should('ed25519/sync methods/should not verify signature with wrong hash', () => {
|
||||
});
|
||||
should('not verify signature with wrong hash', () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, wrongMsg, publicKey), false);
|
||||
});
|
||||
|
||||
// https://xmr.llcoins.net/addresstests.html
|
||||
should(
|
||||
});
|
||||
});
|
||||
// https://xmr.llcoins.net/addresstests.html
|
||||
should(
|
||||
'ed25519/BASE_POINT.multiply()/should create right publicKey without SHA-512 hashing TEST 1',
|
||||
() => {
|
||||
const publicKey =
|
||||
@ -115,8 +125,8 @@ should(
|
||||
'0f3b913371411b27e646b537e888f685bf929ea7aab93c950ed84433f064480d'
|
||||
);
|
||||
}
|
||||
);
|
||||
should(
|
||||
);
|
||||
should(
|
||||
'ed25519/BASE_POINT.multiply()/should create right publicKey without SHA-512 hashing TEST 2',
|
||||
() => {
|
||||
const publicKey =
|
||||
@ -126,8 +136,8 @@ should(
|
||||
'ad545340b58610f0cd62f17d55af1ab11ecde9c084d5476865ddb4dbda015349'
|
||||
);
|
||||
}
|
||||
);
|
||||
should(
|
||||
);
|
||||
should(
|
||||
'ed25519/BASE_POINT.multiply()/should create right publicKey without SHA-512 hashing TEST 3',
|
||||
() => {
|
||||
const publicKey =
|
||||
@ -137,8 +147,8 @@ should(
|
||||
'e097c4415fe85724d522b2e449e8fd78dd40d20097bdc9ae36fe8ec6fe12cb8c'
|
||||
);
|
||||
}
|
||||
);
|
||||
should(
|
||||
);
|
||||
should(
|
||||
'ed25519/BASE_POINT.multiply()/should create right publicKey without SHA-512 hashing TEST 4',
|
||||
() => {
|
||||
const publicKey =
|
||||
@ -148,21 +158,21 @@ should(
|
||||
'f12cb7c43b59971395926f278ce7c2eaded9444fbce62ca717564cb508a0db1d'
|
||||
);
|
||||
}
|
||||
);
|
||||
should('ed25519/BASE_POINT.multiply()/should throw Point#multiply on TEST 5', () => {
|
||||
);
|
||||
should('ed25519/BASE_POINT.multiply()/should throw Point#multiply on TEST 5', () => {
|
||||
for (const num of [0n, 0, -1n, -1, 1.1]) {
|
||||
throws(() => ed.Point.BASE.multiply(num));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// https://ed25519.cr.yp.to/python/sign.py
|
||||
// https://ed25519.cr.yp.to/python/sign.input
|
||||
const data = readFileSync('./test/ed25519/vectors.txt', 'utf-8');
|
||||
const vectors = data
|
||||
// https://ed25519.cr.yp.to/python/sign.py
|
||||
// https://ed25519.cr.yp.to/python/sign.input
|
||||
const data = readFileSync('./test/ed25519/vectors.txt', 'utf-8');
|
||||
const vectors = data
|
||||
.trim()
|
||||
.split('\n')
|
||||
.map((line) => line.split(':'));
|
||||
should('ed25519 official vectors/should match 1024 official vectors', () => {
|
||||
should('ed25519 official vectors/should match 1024 official vectors', () => {
|
||||
for (let i = 0; i < vectors.length; i++) {
|
||||
const vector = vectors[i];
|
||||
// Extract.
|
||||
@ -181,10 +191,10 @@ should('ed25519 official vectors/should match 1024 official vectors', () => {
|
||||
// expect(pub).toBe(expectedPub);
|
||||
deepStrictEqual(signature, expectedSignature);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// https://tools.ietf.org/html/rfc8032#section-7
|
||||
should('rfc8032 vectors/should create right signature for 0x9d and empty string', () => {
|
||||
// https://tools.ietf.org/html/rfc8032#section-7
|
||||
should('rfc8032 vectors/should create right signature for 0x9d and empty string', () => {
|
||||
const privateKey = '9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60';
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
const message = '';
|
||||
@ -197,8 +207,8 @@ should('rfc8032 vectors/should create right signature for 0x9d and empty string'
|
||||
hex(signature),
|
||||
'e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b'
|
||||
);
|
||||
});
|
||||
should('rfc8032 vectors/should create right signature for 0x4c and 72', () => {
|
||||
});
|
||||
should('rfc8032 vectors/should create right signature for 0x4c and 72', () => {
|
||||
const privateKey = '4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb';
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
const message = '72';
|
||||
@ -211,8 +221,8 @@ should('rfc8032 vectors/should create right signature for 0x4c and 72', () => {
|
||||
hex(signature),
|
||||
'92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00'
|
||||
);
|
||||
});
|
||||
should('rfc8032 vectors/should create right signature for 0x00 and 5a', () => {
|
||||
});
|
||||
should('rfc8032 vectors/should create right signature for 0x00 and 5a', () => {
|
||||
const privateKey = '002fdd1f7641793ab064bb7aa848f762e7ec6e332ffc26eeacda141ae33b1783';
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
const message =
|
||||
@ -226,8 +236,8 @@ should('rfc8032 vectors/should create right signature for 0x00 and 5a', () => {
|
||||
hex(signature),
|
||||
'0df3aa0d0999ad3dc580378f52d152700d5b3b057f56a66f92112e441e1cb9123c66f18712c87efe22d2573777296241216904d7cdd7d5ea433928bd2872fa0c'
|
||||
);
|
||||
});
|
||||
should('rfc8032 vectors/should create right signature for 0xf5 and long msg', () => {
|
||||
});
|
||||
should('rfc8032 vectors/should create right signature for 0xf5 and long msg', () => {
|
||||
const privateKey = 'f5e5767cf153319517630f226876b86c8160cc583bc013744c6bf255f5cc0ee5';
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
const message =
|
||||
@ -241,66 +251,66 @@ should('rfc8032 vectors/should create right signature for 0xf5 and long msg', ()
|
||||
hex(signature),
|
||||
'0aab4c900501b3e24d7cdf4663326a3a87df5e4843b2cbdb67cbf6e460fec350aa5371b1508f9f4528ecea23c436d94b5e8fcd4f681e30a6ac00a9704a188a03'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// const PRIVATE_KEY = 0xa665a45920422f9d417e4867efn;
|
||||
// const MESSAGE = ripemd160(new Uint8Array([97, 98, 99, 100, 101, 102, 103]));
|
||||
// prettier-ignore
|
||||
// const MESSAGE = new Uint8Array([
|
||||
// 135, 79, 153, 96, 197, 210, 183, 169, 181, 250, 211, 131, 225, 186, 68, 113, 158, 187, 116, 58,
|
||||
// ]);
|
||||
// const WRONG_MESSAGE = ripemd160(new Uint8Array([98, 99, 100, 101, 102, 103]));
|
||||
// prettier-ignore
|
||||
// const WRONG_MESSAGE = new Uint8Array([
|
||||
// 88, 157, 140, 127, 29, 160, 162, 75, 192, 123, 115, 129, 173, 72, 177, 207, 194, 17, 175, 28,
|
||||
// ]);
|
||||
// // it("should verify just signed message", async () => {
|
||||
// // await fc.assert(fc.asyncProperty(
|
||||
// // fc.hexa(),
|
||||
// // fc.bigInt(2n, ristretto25519.PRIME_ORDER),
|
||||
// // async (message, privateKey) => {
|
||||
// // const publicKey = await ristretto25519.getPublicKey(privateKey);
|
||||
// // const signature = await ristretto25519.sign(message, privateKey);
|
||||
// // expect(publicKey.length).toBe(32);
|
||||
// // expect(signature.length).toBe(64);
|
||||
// // expect(await ristretto25519.verify(signature, message, publicKey)).toBe(true);
|
||||
// // }),
|
||||
// // { numRuns: 1 }
|
||||
// // );
|
||||
// // });
|
||||
// // it("should not verify sign with wrong message", async () => {
|
||||
// // await fc.assert(fc.asyncProperty(
|
||||
// // fc.array(fc.integer(0x00, 0xff)),
|
||||
// // fc.array(fc.integer(0x00, 0xff)),
|
||||
// // fc.bigInt(2n, ristretto25519.PRIME_ORDER),
|
||||
// // async (bytes, wrongBytes, privateKey) => {
|
||||
// // const message = new Uint8Array(bytes);
|
||||
// // const wrongMessage = new Uint8Array(wrongBytes);
|
||||
// // const publicKey = await ristretto25519.getPublicKey(privateKey);
|
||||
// // const signature = await ristretto25519.sign(message, privateKey);
|
||||
// // expect(await ristretto25519.verify(signature, wrongMessage, publicKey)).toBe(
|
||||
// // bytes.toString() === wrongBytes.toString()
|
||||
// // );
|
||||
// // }),
|
||||
// // { numRuns: 1 }
|
||||
// // );
|
||||
// // });
|
||||
// // it("should sign and verify", async () => {
|
||||
// // const publicKey = await ristretto25519.getPublicKey(PRIVATE_KEY);
|
||||
// // const signature = await ristretto25519.sign(MESSAGE, PRIVATE_KEY);
|
||||
// // expect(await ristretto25519.verify(signature, MESSAGE, publicKey)).toBe(true);
|
||||
// // });
|
||||
// // it("should not verify signature with wrong public key", async () => {
|
||||
// // const publicKey = await ristretto25519.getPublicKey(12);
|
||||
// // const signature = await ristretto25519.sign(MESSAGE, PRIVATE_KEY);
|
||||
// // expect(await ristretto25519.verify(signature, MESSAGE, publicKey)).toBe(false);
|
||||
// // });
|
||||
// // it("should not verify signature with wrong hash", async () => {
|
||||
// // const publicKey = await ristretto25519.getPublicKey(PRIVATE_KEY);
|
||||
// // const signature = await ristretto25519.sign(MESSAGE, PRIVATE_KEY);
|
||||
// // expect(await ristretto25519.verify(signature, WRONG_MESSAGE, publicKey)).toBe(false);
|
||||
// // });
|
||||
should('ristretto255/should follow the byte encodings of small multiples', () => {
|
||||
// const PRIVATE_KEY = 0xa665a45920422f9d417e4867efn;
|
||||
// const MESSAGE = ripemd160(new Uint8Array([97, 98, 99, 100, 101, 102, 103]));
|
||||
// prettier-ignore
|
||||
// const MESSAGE = new Uint8Array([
|
||||
// 135, 79, 153, 96, 197, 210, 183, 169, 181, 250, 211, 131, 225, 186, 68, 113, 158, 187, 116, 58,
|
||||
// ]);
|
||||
// const WRONG_MESSAGE = ripemd160(new Uint8Array([98, 99, 100, 101, 102, 103]));
|
||||
// prettier-ignore
|
||||
// const WRONG_MESSAGE = new Uint8Array([
|
||||
// 88, 157, 140, 127, 29, 160, 162, 75, 192, 123, 115, 129, 173, 72, 177, 207, 194, 17, 175, 28,
|
||||
// ]);
|
||||
// // it("should verify just signed message", async () => {
|
||||
// // await fc.assert(fc.asyncProperty(
|
||||
// // fc.hexa(),
|
||||
// // fc.bigInt(2n, ristretto25519.PRIME_ORDER),
|
||||
// // async (message, privateKey) => {
|
||||
// // const publicKey = await ristretto25519.getPublicKey(privateKey);
|
||||
// // const signature = await ristretto25519.sign(message, privateKey);
|
||||
// // expect(publicKey.length).toBe(32);
|
||||
// // expect(signature.length).toBe(64);
|
||||
// // expect(await ristretto25519.verify(signature, message, publicKey)).toBe(true);
|
||||
// // }),
|
||||
// // { numRuns: 1 }
|
||||
// // );
|
||||
// // });
|
||||
// // it("should not verify sign with wrong message", async () => {
|
||||
// // await fc.assert(fc.asyncProperty(
|
||||
// // fc.array(fc.integer(0x00, 0xff)),
|
||||
// // fc.array(fc.integer(0x00, 0xff)),
|
||||
// // fc.bigInt(2n, ristretto25519.PRIME_ORDER),
|
||||
// // async (bytes, wrongBytes, privateKey) => {
|
||||
// // const message = new Uint8Array(bytes);
|
||||
// // const wrongMessage = new Uint8Array(wrongBytes);
|
||||
// // const publicKey = await ristretto25519.getPublicKey(privateKey);
|
||||
// // const signature = await ristretto25519.sign(message, privateKey);
|
||||
// // expect(await ristretto25519.verify(signature, wrongMessage, publicKey)).toBe(
|
||||
// // bytes.toString() === wrongBytes.toString()
|
||||
// // );
|
||||
// // }),
|
||||
// // { numRuns: 1 }
|
||||
// // );
|
||||
// // });
|
||||
// // it("should sign and verify", async () => {
|
||||
// // const publicKey = await ristretto25519.getPublicKey(PRIVATE_KEY);
|
||||
// // const signature = await ristretto25519.sign(MESSAGE, PRIVATE_KEY);
|
||||
// // expect(await ristretto25519.verify(signature, MESSAGE, publicKey)).toBe(true);
|
||||
// // });
|
||||
// // it("should not verify signature with wrong public key", async () => {
|
||||
// // const publicKey = await ristretto25519.getPublicKey(12);
|
||||
// // const signature = await ristretto25519.sign(MESSAGE, PRIVATE_KEY);
|
||||
// // expect(await ristretto25519.verify(signature, MESSAGE, publicKey)).toBe(false);
|
||||
// // });
|
||||
// // it("should not verify signature with wrong hash", async () => {
|
||||
// // const publicKey = await ristretto25519.getPublicKey(PRIVATE_KEY);
|
||||
// // const signature = await ristretto25519.sign(MESSAGE, PRIVATE_KEY);
|
||||
// // expect(await ristretto25519.verify(signature, WRONG_MESSAGE, publicKey)).toBe(false);
|
||||
// // });
|
||||
should('ristretto255/should follow the byte encodings of small multiples', () => {
|
||||
const encodingsOfSmallMultiples = [
|
||||
// This is the identity point
|
||||
'0000000000000000000000000000000000000000000000000000000000000000',
|
||||
@ -329,8 +339,8 @@ should('ristretto255/should follow the byte encodings of small multiples', () =>
|
||||
deepStrictEqual(RistrettoPoint.fromHex(encoded).toHex(), encoded);
|
||||
P = P.add(B);
|
||||
}
|
||||
});
|
||||
should('ristretto255/should not convert bad bytes encoding', () => {
|
||||
});
|
||||
should('ristretto255/should not convert bad bytes encoding', () => {
|
||||
const badEncodings = [
|
||||
// These are all bad because they're non-canonical field encodings.
|
||||
'00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
|
||||
@ -371,8 +381,8 @@ should('ristretto255/should not convert bad bytes encoding', () => {
|
||||
const b = hexToBytes(badBytes);
|
||||
throws(() => RistrettoPoint.fromHex(b), badBytes);
|
||||
}
|
||||
});
|
||||
should('ristretto255/should create right points from uniform hash', async () => {
|
||||
});
|
||||
should('ristretto255/should create right points from uniform hash', async () => {
|
||||
const labels = [
|
||||
'Ristretto is traditionally a short shot of espresso coffee',
|
||||
'made with the normal amount of ground coffee but extracted with',
|
||||
@ -397,9 +407,9 @@ should('ristretto255/should create right points from uniform hash', async () =>
|
||||
const point = RistrettoPoint.hashToCurve(hash);
|
||||
deepStrictEqual(point.toHex(), encodedHashToPoints[i]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
should('input immutability: sign/verify are immutable', () => {
|
||||
should('input immutability: sign/verify are immutable', () => {
|
||||
const privateKey = ed.utils.randomPrivateKey();
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
|
||||
@ -417,11 +427,11 @@ should('input immutability: sign/verify are immutable', () => {
|
||||
if (!ed.verify(signatureCopy, payload, publicKey))
|
||||
throw new Error('Copied signature verification failed');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// https://zips.z.cash/zip-0215
|
||||
// Vectors from https://gist.github.com/hdevalence/93ed42d17ecab8e42138b213812c8cc7
|
||||
should('ZIP-215 compliance tests/should pass all of them', () => {
|
||||
// https://zips.z.cash/zip-0215
|
||||
// Vectors from https://gist.github.com/hdevalence/93ed42d17ecab8e42138b213812c8cc7
|
||||
should('ZIP-215 compliance tests/should pass all of them', () => {
|
||||
const str = utf8ToBytes('Zcash');
|
||||
for (let v of zip215) {
|
||||
let noble = false;
|
||||
@ -432,14 +442,14 @@ should('ZIP-215 compliance tests/should pass all of them', () => {
|
||||
}
|
||||
deepStrictEqual(noble, v.valid_zip215);
|
||||
}
|
||||
});
|
||||
should('ZIP-215 compliance tests/disallows sig.s >= CURVE.n', () => {
|
||||
});
|
||||
should('ZIP-215 compliance tests/disallows sig.s >= CURVE.n', () => {
|
||||
const sig = new ed.Signature(ed.Point.BASE, 1n);
|
||||
sig.s = ed.CURVE.n + 1n;
|
||||
throws(() => ed.verify(sig, 'deadbeef', ed.Point.BASE));
|
||||
});
|
||||
});
|
||||
|
||||
const rfc7748Mul = [
|
||||
const rfc7748Mul = [
|
||||
{
|
||||
scalar: 'a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4',
|
||||
u: 'e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c',
|
||||
@ -450,29 +460,29 @@ const rfc7748Mul = [
|
||||
u: 'e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493',
|
||||
outputU: '95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957',
|
||||
},
|
||||
];
|
||||
for (let i = 0; i < rfc7748Mul.length; i++) {
|
||||
];
|
||||
for (let i = 0; i < rfc7748Mul.length; i++) {
|
||||
const v = rfc7748Mul[i];
|
||||
should(`RFC7748: scalarMult (${i})`, () => {
|
||||
deepStrictEqual(hex(x25519.scalarMult(v.scalar, v.u)), v.outputU);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const rfc7748Iter = [
|
||||
const rfc7748Iter = [
|
||||
{ scalar: '422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079', iters: 1 },
|
||||
{ scalar: '684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d99532c51', iters: 1000 },
|
||||
// { scalar: '7c3911e0ab2586fd864497297e575e6f3bc601c0883c30df5f4dd2d24f665424', iters: 1000000 },
|
||||
];
|
||||
for (let i = 0; i < rfc7748Iter.length; i++) {
|
||||
];
|
||||
for (let i = 0; i < rfc7748Iter.length; i++) {
|
||||
const { scalar, iters } = rfc7748Iter[i];
|
||||
should(`RFC7748: scalarMult iteration (${i})`, () => {
|
||||
let k = x25519.Gu;
|
||||
for (let i = 0, u = k; i < iters; i++) [k, u] = [x25519.scalarMult(k, u), k];
|
||||
deepStrictEqual(hex(k), scalar);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
should('RFC7748 getSharedKey', () => {
|
||||
should('RFC7748 getSharedKey', () => {
|
||||
const alicePrivate = '77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a';
|
||||
const alicePublic = '8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a';
|
||||
const bobPrivate = '5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb';
|
||||
@ -482,31 +492,31 @@ should('RFC7748 getSharedKey', () => {
|
||||
deepStrictEqual(bobPublic, hex(x25519.getPublicKey(bobPrivate)));
|
||||
deepStrictEqual(hex(x25519.scalarMult(alicePrivate, bobPublic)), shared);
|
||||
deepStrictEqual(hex(x25519.scalarMult(bobPrivate, alicePublic)), shared);
|
||||
});
|
||||
});
|
||||
|
||||
// should('X25519/getSharedSecret() should be commutative', () => {
|
||||
// for (let i = 0; i < 512; i++) {
|
||||
// const asec = ed.utils.randomPrivateKey();
|
||||
// const apub = ed.getPublicKey(asec);
|
||||
// const bsec = ed.utils.randomPrivateKey();
|
||||
// const bpub = ed.getPublicKey(bsec);
|
||||
// try {
|
||||
// deepStrictEqual(ed.getSharedSecret(asec, bpub), ed.getSharedSecret(bsec, apub));
|
||||
// } catch (error) {
|
||||
// console.error('not commutative', { asec, apub, bsec, bpub });
|
||||
// throw error;
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// should('X25519/getSharedSecret() should be commutative', () => {
|
||||
// for (let i = 0; i < 512; i++) {
|
||||
// const asec = ed.utils.randomPrivateKey();
|
||||
// const apub = ed.getPublicKey(asec);
|
||||
// const bsec = ed.utils.randomPrivateKey();
|
||||
// const bpub = ed.getPublicKey(bsec);
|
||||
// try {
|
||||
// deepStrictEqual(ed.getSharedSecret(asec, bpub), ed.getSharedSecret(bsec, apub));
|
||||
// } catch (error) {
|
||||
// console.error('not commutative', { asec, apub, bsec, bpub });
|
||||
// throw error;
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
// should('X25519: should convert base point to montgomery using fromPoint', () => {
|
||||
// deepStrictEqual(
|
||||
// hex(ed.montgomeryCurve.UfromPoint(ed.Point.BASE)),
|
||||
// ed.montgomeryCurve.BASE_POINT_U
|
||||
// );
|
||||
// });
|
||||
// should('X25519: should convert base point to montgomery using fromPoint', () => {
|
||||
// deepStrictEqual(
|
||||
// hex(ed.montgomeryCurve.UfromPoint(ed.Point.BASE)),
|
||||
// ed.montgomeryCurve.BASE_POINT_U
|
||||
// );
|
||||
// });
|
||||
|
||||
{
|
||||
{
|
||||
const group = x25519vectors.testGroups[0];
|
||||
should(`Wycheproof/X25519`, () => {
|
||||
for (let i = 0; i < group.tests.length; i++) {
|
||||
@ -533,9 +543,9 @@ should('RFC7748 getSharedKey', () => {
|
||||
} else throw new Error('unknown test result');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
should(`Wycheproof/ED25519`, () => {
|
||||
should(`Wycheproof/ED25519`, () => {
|
||||
for (let g = 0; g < ed25519vectors.testGroups.length; g++) {
|
||||
const group = ed25519vectors.testGroups[g];
|
||||
const key = group.key;
|
||||
@ -557,16 +567,16 @@ should(`Wycheproof/ED25519`, () => {
|
||||
} else throw new Error('unknown test result');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
should('Property test issue #1', () => {
|
||||
should('Property test issue #1', () => {
|
||||
const message = new Uint8Array([12, 12, 12]);
|
||||
const signature = ed.sign(message, to32Bytes(1n));
|
||||
const publicKey = ed.getPublicKey(to32Bytes(1n)); // <- was 1n
|
||||
deepStrictEqual(ed.verify(signature, message, publicKey), true);
|
||||
});
|
||||
});
|
||||
|
||||
const VECTORS_RFC8032_CTX = [
|
||||
const VECTORS_RFC8032_CTX = [
|
||||
{
|
||||
secretKey: '0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6',
|
||||
publicKey: 'dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292',
|
||||
@ -611,18 +621,18 @@ const VECTORS_RFC8032_CTX = [
|
||||
'e9b86a7b6005ea868337ff2d20a7f5fb' +
|
||||
'd4cd10b0be49a68da2b2e0dc0ad8960f',
|
||||
},
|
||||
];
|
||||
];
|
||||
|
||||
for (let i = 0; i < VECTORS_RFC8032_CTX.length; i++) {
|
||||
for (let i = 0; i < VECTORS_RFC8032_CTX.length; i++) {
|
||||
const v = VECTORS_RFC8032_CTX[i];
|
||||
should(`RFC8032ctx/${i}`, () => {
|
||||
deepStrictEqual(hex(ed25519ctx.getPublicKey(v.secretKey)), v.publicKey);
|
||||
deepStrictEqual(hex(ed25519ctx.sign(v.message, v.secretKey, v.context)), v.signature);
|
||||
deepStrictEqual(ed25519ctx.verify(v.signature, v.message, v.publicKey, v.context), true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const VECTORS_RFC8032_PH = [
|
||||
const VECTORS_RFC8032_PH = [
|
||||
{
|
||||
secretKey: '833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42',
|
||||
publicKey: 'ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf',
|
||||
@ -633,22 +643,34 @@ const VECTORS_RFC8032_PH = [
|
||||
'31f85042463c2a355a2003d062adf5aa' +
|
||||
'a10b8c61e636062aaad11c2a26083406',
|
||||
},
|
||||
];
|
||||
];
|
||||
|
||||
for (let i = 0; i < VECTORS_RFC8032_PH.length; i++) {
|
||||
for (let i = 0; i < VECTORS_RFC8032_PH.length; i++) {
|
||||
const v = VECTORS_RFC8032_PH[i];
|
||||
should(`RFC8032ph/${i}`, () => {
|
||||
deepStrictEqual(hex(ed25519ph.getPublicKey(v.secretKey)), v.publicKey);
|
||||
deepStrictEqual(hex(ed25519ph.sign(v.message, v.secretKey)), v.signature);
|
||||
deepStrictEqual(ed25519ph.verify(v.signature, v.message, v.publicKey), true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
should('X25519 base point', () => {
|
||||
should('X25519 base point', () => {
|
||||
const { y } = ed25519.Point.BASE;
|
||||
const { Fp } = ed25519.CURVE;
|
||||
const u = Fp.create((y + 1n) * Fp.invert(1n - y));
|
||||
deepStrictEqual(hex(numberToBytesLE(u, 32)), x25519.Gu);
|
||||
});
|
||||
|
||||
should('isTorsionFree()', () => {
|
||||
const orig = ed.utils.getExtendedPublicKey(ed.utils.randomPrivateKey()).point;
|
||||
for (const hex of ED25519_TORSION_SUBGROUP.slice(1)) {
|
||||
const dirty = orig.add(ed.Point.fromHex(hex));
|
||||
const cleared = dirty.clearCofactor();
|
||||
strictEqual(orig.isTorsionFree(), true, `orig must be torsionFree: ${hex}`);
|
||||
strictEqual(dirty.isTorsionFree(), false, `dirty must not be torsionFree: ${hex}`);
|
||||
strictEqual(cleared.isTorsionFree(), true, `cleared must be torsionFree: ${hex}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// ESM is broken.
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { deepStrictEqual, throws } from 'assert';
|
||||
import { should } from 'micro-should';
|
||||
import { describe, should } from 'micro-should';
|
||||
import * as fc from 'fast-check';
|
||||
import { ed448, ed448ph, x448 } from '../lib/esm/ed448.js';
|
||||
import { hexToBytes, bytesToHex, randomBytes } from '@noble/hashes/utils';
|
||||
@ -7,11 +7,12 @@ import { numberToBytesLE } from '../lib/esm/abstract/utils.js';
|
||||
import { default as ed448vectors } from './wycheproof/ed448_test.json' assert { type: 'json' };
|
||||
import { default as x448vectors } from './wycheproof/x448_test.json' assert { type: 'json' };
|
||||
|
||||
const ed = ed448;
|
||||
const hex = bytesToHex;
|
||||
ed.utils.precompute(4);
|
||||
describe('ed448', () => {
|
||||
const ed = ed448;
|
||||
const hex = bytesToHex;
|
||||
ed.utils.precompute(4);
|
||||
|
||||
should(`Basic`, () => {
|
||||
should(`Basic`, () => {
|
||||
const G1 = ed.Point.BASE;
|
||||
deepStrictEqual(
|
||||
G1.x,
|
||||
@ -39,18 +40,18 @@ should(`Basic`, () => {
|
||||
G3.y,
|
||||
636046652612779686502873775776967954190574036985351036782021535703553242737829645273154208057988851307101009474686328623630835377952508n
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
should('Basic/decompress', () => {
|
||||
should('Basic/decompress', () => {
|
||||
const G1 = ed.Point.BASE;
|
||||
const G2 = ed.Point.BASE.multiply(2n);
|
||||
const G3 = ed.Point.BASE.multiply(3n);
|
||||
const points = [G1, G2, G3];
|
||||
const getXY = (p) => ({ x: p.x, y: p.y });
|
||||
for (const p of points) deepStrictEqual(getXY(ed.Point.fromHex(p.toHex())), getXY(p));
|
||||
});
|
||||
});
|
||||
|
||||
const VECTORS_RFC8032 = [
|
||||
const VECTORS_RFC8032 = [
|
||||
{
|
||||
secretKey:
|
||||
'6c82a562cb808d10d632be89c8513ebf' +
|
||||
@ -312,29 +313,29 @@ const VECTORS_RFC8032 = [
|
||||
'3603ce30d8bb761785dc30dbc320869e' +
|
||||
'1a00',
|
||||
},
|
||||
];
|
||||
];
|
||||
|
||||
for (let i = 0; i < VECTORS_RFC8032.length; i++) {
|
||||
for (let i = 0; i < VECTORS_RFC8032.length; i++) {
|
||||
const v = VECTORS_RFC8032[i];
|
||||
should(`RFC8032/${i}`, () => {
|
||||
deepStrictEqual(hex(ed.getPublicKey(v.secretKey)), v.publicKey);
|
||||
deepStrictEqual(hex(ed.sign(v.message, v.secretKey)), v.signature);
|
||||
deepStrictEqual(ed.verify(v.signature, v.message, v.publicKey), true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
should('ed448/should not accept >57byte private keys', async () => {
|
||||
should('not accept >57byte private keys', async () => {
|
||||
const invalidPriv =
|
||||
100000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800073278156000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000n;
|
||||
throws(() => ed.getPublicKey(invalidPriv));
|
||||
});
|
||||
});
|
||||
|
||||
function to57Bytes(numOrStr) {
|
||||
function to57Bytes(numOrStr) {
|
||||
let hex = typeof numOrStr === 'string' ? numOrStr : numOrStr.toString(16);
|
||||
return hexToBytes(hex.padStart(114, '0'));
|
||||
}
|
||||
}
|
||||
|
||||
should('ed448/should verify recent signature', () => {
|
||||
should('verify recent signature', () => {
|
||||
fc.assert(
|
||||
fc.property(
|
||||
fc.hexaString({ minLength: 2, maxLength: 57 }),
|
||||
@ -349,8 +350,8 @@ should('ed448/should verify recent signature', () => {
|
||||
),
|
||||
{ numRuns: 5 }
|
||||
);
|
||||
});
|
||||
should('ed448/should not verify signature with wrong message', () => {
|
||||
});
|
||||
should('not verify signature with wrong message', () => {
|
||||
fc.assert(
|
||||
fc.property(
|
||||
fc.array(fc.integer({ min: 0x00, max: 0xff })),
|
||||
@ -370,49 +371,53 @@ should('ed448/should not verify signature with wrong message', () => {
|
||||
),
|
||||
{ numRuns: 5 }
|
||||
);
|
||||
});
|
||||
const privKey = to57Bytes('a665a45920422f9d417e4867ef');
|
||||
const msg = hexToBytes('874f9960c5d2b7a9b5fad383e1ba44719ebb743a');
|
||||
const wrongMsg = hexToBytes('589d8c7f1da0a24bc07b7381ad48b1cfc211af1c');
|
||||
should('ed25519/basic methods/should sign and verify', () => {
|
||||
});
|
||||
const privKey = to57Bytes('a665a45920422f9d417e4867ef');
|
||||
const msg = hexToBytes('874f9960c5d2b7a9b5fad383e1ba44719ebb743a');
|
||||
const wrongMsg = hexToBytes('589d8c7f1da0a24bc07b7381ad48b1cfc211af1c');
|
||||
describe('basic methods', () => {
|
||||
should('sign and verify', () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), true);
|
||||
});
|
||||
should('ed25519/basic methods/should not verify signature with wrong public key', () => {
|
||||
});
|
||||
should('not verify signature with wrong public key', () => {
|
||||
const publicKey = ed.getPublicKey(12);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), false);
|
||||
});
|
||||
should('ed25519/basic methods/should not verify signature with wrong hash', () => {
|
||||
});
|
||||
should('not verify signature with wrong hash', () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, wrongMsg, publicKey), false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
should('ed25519/sync methods/should sign and verify', () => {
|
||||
describe('sync methods', () => {
|
||||
should('sign and verify', () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), true);
|
||||
});
|
||||
should('ed25519/sync methods/should not verify signature with wrong public key', async () => {
|
||||
});
|
||||
should('not verify signature with wrong public key', async () => {
|
||||
const publicKey = ed.getPublicKey(12);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), false);
|
||||
});
|
||||
should('ed25519/sync methods/should not verify signature with wrong hash', async () => {
|
||||
});
|
||||
should('not verify signature with wrong hash', async () => {
|
||||
const publicKey = ed.getPublicKey(privKey);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, wrongMsg, publicKey), false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
should('ed25519/BASE_POINT.multiply()/should throw Point#multiply on TEST 5', () => {
|
||||
should('BASE_POINT.multiply() throws in Point#multiply on TEST 5', () => {
|
||||
for (const num of [0n, 0, -1n, -1, 1.1]) {
|
||||
throws(() => ed.Point.BASE.multiply(num));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
should('input immutability: sign/verify are immutable', () => {
|
||||
should('input immutability: sign/verify are immutable', () => {
|
||||
const privateKey = ed.utils.randomPrivateKey();
|
||||
const publicKey = ed.getPublicKey(privateKey);
|
||||
|
||||
@ -430,9 +435,9 @@ should('input immutability: sign/verify are immutable', () => {
|
||||
if (!ed.verify(signatureCopy, payload, publicKey))
|
||||
throw new Error('Copied signature verification failed');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
{
|
||||
{
|
||||
for (let g = 0; g < ed448vectors.testGroups.length; g++) {
|
||||
const group = ed448vectors.testGroups[g];
|
||||
const key = group.key;
|
||||
@ -458,10 +463,10 @@ should('input immutability: sign/verify are immutable', () => {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ECDH
|
||||
const rfc7748Mul = [
|
||||
// ECDH
|
||||
const rfc7748Mul = [
|
||||
{
|
||||
scalar:
|
||||
'3d262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3',
|
||||
@ -476,15 +481,15 @@ const rfc7748Mul = [
|
||||
outputU:
|
||||
'884a02576239ff7a2f2f63b2db6a9ff37047ac13568e1e30fe63c4a7ad1b3ee3a5700df34321d62077e63633c575c1c954514e99da7c179d',
|
||||
},
|
||||
];
|
||||
for (let i = 0; i < rfc7748Mul.length; i++) {
|
||||
];
|
||||
for (let i = 0; i < rfc7748Mul.length; i++) {
|
||||
const v = rfc7748Mul[i];
|
||||
should(`RFC7748: scalarMult (${i})`, () => {
|
||||
deepStrictEqual(hex(x448.scalarMult(v.scalar, v.u)), v.outputU);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const rfc7748Iter = [
|
||||
const rfc7748Iter = [
|
||||
{
|
||||
scalar:
|
||||
'3f482c8a9f19b01e6c46ee9711d9dc14fd4bf67af30765c2ae2b846a4d23a8cd0db897086239492caf350b51f833868b9bc2b3bca9cf4113',
|
||||
@ -496,17 +501,17 @@ const rfc7748Iter = [
|
||||
iters: 1000,
|
||||
},
|
||||
// { scalar: '077f453681caca3693198420bbe515cae0002472519b3e67661a7e89cab94695c8f4bcd66e61b9b9c946da8d524de3d69bd9d9d66b997e37', iters: 1000000 },
|
||||
];
|
||||
for (let i = 0; i < rfc7748Iter.length; i++) {
|
||||
];
|
||||
for (let i = 0; i < rfc7748Iter.length; i++) {
|
||||
const { scalar, iters } = rfc7748Iter[i];
|
||||
should(`RFC7748: scalarMult iteration (${i})`, () => {
|
||||
let k = x448.Gu;
|
||||
for (let i = 0, u = k; i < iters; i++) [k, u] = [x448.scalarMult(k, u), k];
|
||||
deepStrictEqual(hex(k), scalar);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
should('RFC7748 getSharedKey', () => {
|
||||
should('RFC7748 getSharedKey', () => {
|
||||
const alicePrivate =
|
||||
'9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b';
|
||||
const alicePublic =
|
||||
@ -521,9 +526,9 @@ should('RFC7748 getSharedKey', () => {
|
||||
deepStrictEqual(bobPublic, hex(x448.getPublicKey(bobPrivate)));
|
||||
deepStrictEqual(hex(x448.scalarMult(alicePrivate, bobPublic)), shared);
|
||||
deepStrictEqual(hex(x448.scalarMult(bobPrivate, alicePublic)), shared);
|
||||
});
|
||||
});
|
||||
|
||||
{
|
||||
{
|
||||
const group = x448vectors.testGroups[0];
|
||||
should(`Wycheproof/X448`, () => {
|
||||
for (let i = 0; i < group.tests.length; i++) {
|
||||
@ -551,31 +556,31 @@ should('RFC7748 getSharedKey', () => {
|
||||
} else throw new Error('unknown test result');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// should('X448: should convert base point to montgomery using fromPoint', () => {
|
||||
// deepStrictEqual(
|
||||
// hex(ed.montgomeryCurve.UfromPoint(ed.Point.BASE)),
|
||||
// ed.montgomeryCurve.BASE_POINT_U
|
||||
// );
|
||||
// });
|
||||
// should('X448: should convert base point to montgomery using fromPoint', () => {
|
||||
// deepStrictEqual(
|
||||
// hex(ed.montgomeryCurve.UfromPoint(ed.Point.BASE)),
|
||||
// ed.montgomeryCurve.BASE_POINT_U
|
||||
// );
|
||||
// });
|
||||
|
||||
// should('X448/getSharedSecret() should be commutative', async () => {
|
||||
// for (let i = 0; i < 512; i++) {
|
||||
// const asec = ed.utils.randomPrivateKey();
|
||||
// const apub = ed.getPublicKey(asec);
|
||||
// const bsec = ed.utils.randomPrivateKey();
|
||||
// const bpub = ed.getPublicKey(bsec);
|
||||
// try {
|
||||
// deepStrictEqual(ed.getSharedSecret(asec, bpub), ed.getSharedSecret(bsec, apub));
|
||||
// } catch (error) {
|
||||
// console.error('not commutative', { asec, apub, bsec, bpub });
|
||||
// throw error;
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// should('X448/getSharedSecret() should be commutative', async () => {
|
||||
// for (let i = 0; i < 512; i++) {
|
||||
// const asec = ed.utils.randomPrivateKey();
|
||||
// const apub = ed.getPublicKey(asec);
|
||||
// const bsec = ed.utils.randomPrivateKey();
|
||||
// const bpub = ed.getPublicKey(bsec);
|
||||
// try {
|
||||
// deepStrictEqual(ed.getSharedSecret(asec, bpub), ed.getSharedSecret(bsec, apub));
|
||||
// } catch (error) {
|
||||
// console.error('not commutative', { asec, apub, bsec, bpub });
|
||||
// throw error;
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
const VECTORS_RFC8032_CTX = [
|
||||
const VECTORS_RFC8032_CTX = [
|
||||
{
|
||||
secretKey:
|
||||
'c4eab05d357007c632f3dbb48489924d552b08fe0c353a0d4a1f00acda2c463afbea67c5e8d2877c5e3bc397a659949ef8021e954e0a12274e',
|
||||
@ -593,18 +598,18 @@ const VECTORS_RFC8032_CTX = [
|
||||
'5428407e85dcbc98a49155c13764e66c' +
|
||||
'3c00',
|
||||
},
|
||||
];
|
||||
];
|
||||
|
||||
for (let i = 0; i < VECTORS_RFC8032_CTX.length; i++) {
|
||||
for (let i = 0; i < VECTORS_RFC8032_CTX.length; i++) {
|
||||
const v = VECTORS_RFC8032_CTX[i];
|
||||
should(`RFC8032ctx/${i}`, () => {
|
||||
deepStrictEqual(hex(ed.getPublicKey(v.secretKey)), v.publicKey);
|
||||
deepStrictEqual(hex(ed.sign(v.message, v.secretKey, v.context)), v.signature);
|
||||
deepStrictEqual(ed.verify(v.signature, v.message, v.publicKey, v.context), true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const VECTORS_RFC8032_PH = [
|
||||
const VECTORS_RFC8032_PH = [
|
||||
{
|
||||
secretKey:
|
||||
'833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42ef7822e0d5104127dc05d6dbefde69e3ab2cec7c867c6e2c49',
|
||||
@ -638,24 +643,25 @@ const VECTORS_RFC8032_PH = [
|
||||
'4f8d0704a608c54a6b62d97beb511d13' +
|
||||
'2100',
|
||||
},
|
||||
];
|
||||
];
|
||||
|
||||
for (let i = 0; i < VECTORS_RFC8032_PH.length; i++) {
|
||||
for (let i = 0; i < VECTORS_RFC8032_PH.length; i++) {
|
||||
const v = VECTORS_RFC8032_PH[i];
|
||||
should(`RFC8032ph/${i}`, () => {
|
||||
deepStrictEqual(hex(ed448ph.getPublicKey(v.secretKey)), v.publicKey);
|
||||
deepStrictEqual(hex(ed448ph.sign(v.message, v.secretKey, v.context)), v.signature);
|
||||
deepStrictEqual(ed448ph.verify(v.signature, v.message, v.publicKey, v.context), true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
should('X448 base point', () => {
|
||||
should('X448 base point', () => {
|
||||
const { x, y } = ed448.Point.BASE;
|
||||
const { Fp } = ed448.CURVE;
|
||||
// const invX = Fp.invert(x * x); // x²
|
||||
const u = Fp.div(Fp.create(y * y), Fp.create(x * x)); // (y²/x²)
|
||||
// const u = Fp.create(y * y * invX);
|
||||
deepStrictEqual(hex(numberToBytesLE(u, 56)), x448.Gu);
|
||||
});
|
||||
});
|
||||
|
||||
// ESM is broken.
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { deepStrictEqual } from 'assert';
|
||||
import { should } from 'micro-should';
|
||||
import { describe, should } from 'micro-should';
|
||||
import { bytesToHex } from '@noble/hashes/utils';
|
||||
// Generic tests for all curves in package
|
||||
import { sha256 } from '@noble/hashes/sha256';
|
||||
@ -51,9 +51,10 @@ import { default as ed448_ro } from './hash-to-curve/edwards448_XOF:SHAKE256_ELL
|
||||
import { default as ed448_nu } from './hash-to-curve/edwards448_XOF:SHAKE256_ELL2_NU_.json' assert { type: 'json' };
|
||||
|
||||
function testExpandXMD(hash, vectors) {
|
||||
describe(`${vectors.hash}/${vectors.DST.length}`, () => {
|
||||
for (let i = 0; i < vectors.tests.length; i++) {
|
||||
const t = vectors.tests[i];
|
||||
should(`expand_message_xmd/${vectors.hash}/${vectors.DST.length}/${i}`, () => {
|
||||
should(`${vectors.hash}/${vectors.DST.length}/${i}`, () => {
|
||||
const p = expand_message_xmd(
|
||||
stringToBytes(t.msg),
|
||||
stringToBytes(vectors.DST),
|
||||
@ -63,16 +64,20 @@ function testExpandXMD(hash, vectors) {
|
||||
deepStrictEqual(bytesToHex(p), t.uniform_bytes);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
testExpandXMD(sha256, xmd_sha256_38);
|
||||
testExpandXMD(sha256, xmd_sha256_256);
|
||||
testExpandXMD(sha512, xmd_sha512_38);
|
||||
describe('expand_message_xmd', () => {
|
||||
testExpandXMD(sha256, xmd_sha256_38);
|
||||
testExpandXMD(sha256, xmd_sha256_256);
|
||||
testExpandXMD(sha512, xmd_sha512_38);
|
||||
});
|
||||
|
||||
function testExpandXOF(hash, vectors) {
|
||||
describe(`${vectors.hash}/${vectors.DST.length}`, () => {
|
||||
for (let i = 0; i < vectors.tests.length; i++) {
|
||||
const t = vectors.tests[i];
|
||||
should(`expand_message_xof/${vectors.hash}/${vectors.DST.length}/${i}`, () => {
|
||||
should(`${i}`, () => {
|
||||
const p = expand_message_xof(
|
||||
stringToBytes(t.msg),
|
||||
stringToBytes(vectors.DST),
|
||||
@ -83,11 +88,14 @@ function testExpandXOF(hash, vectors) {
|
||||
deepStrictEqual(bytesToHex(p), t.uniform_bytes);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
testExpandXOF(shake128, xof_shake128_36);
|
||||
testExpandXOF(shake128, xof_shake128_256);
|
||||
testExpandXOF(shake256, xof_shake256_36);
|
||||
describe('expand_message_xof', () => {
|
||||
testExpandXOF(shake128, xof_shake128_36);
|
||||
testExpandXOF(shake128, xof_shake128_256);
|
||||
testExpandXOF(shake256, xof_shake256_36);
|
||||
});
|
||||
|
||||
function stringToFp(s) {
|
||||
// bls-G2 support
|
||||
@ -99,9 +107,10 @@ function stringToFp(s) {
|
||||
}
|
||||
|
||||
function testCurve(curve, ro, nu) {
|
||||
describe(`${ro.curve}/${ro.ciphersuite}`, () => {
|
||||
for (let i = 0; i < ro.vectors.length; i++) {
|
||||
const t = ro.vectors[i];
|
||||
should(`${ro.curve}/${ro.ciphersuite}(${i})`, () => {
|
||||
should(`(${i})`, () => {
|
||||
const p = curve.Point.hashToCurve(stringToBytes(t.msg), {
|
||||
DST: ro.dst,
|
||||
});
|
||||
@ -109,9 +118,11 @@ function testCurve(curve, ro, nu) {
|
||||
deepStrictEqual(p.y, stringToFp(t.P.y), 'Py');
|
||||
});
|
||||
}
|
||||
});
|
||||
describe(`${nu.curve}/${nu.ciphersuite}`, () => {
|
||||
for (let i = 0; i < nu.vectors.length; i++) {
|
||||
const t = nu.vectors[i];
|
||||
should(`${nu.curve}/${nu.ciphersuite}(${i})`, () => {
|
||||
should(`(${i})`, () => {
|
||||
const p = curve.Point.encodeToCurve(stringToBytes(t.msg), {
|
||||
DST: nu.dst,
|
||||
});
|
||||
@ -119,6 +130,7 @@ function testCurve(curve, ro, nu) {
|
||||
deepStrictEqual(p.y, stringToFp(t.P.y), 'Py');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
testCurve(secp256r1, p256_ro, p256_nu);
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { jubjub, findGroupHash } from '../lib/esm/jubjub.js';
|
||||
import { should } from 'micro-should';
|
||||
import { describe, should } from 'micro-should';
|
||||
import { deepStrictEqual, throws } from 'assert';
|
||||
import { hexToBytes, bytesToHex } from '@noble/hashes/utils';
|
||||
|
||||
@ -18,7 +18,8 @@ const G_PROOF = new jubjub.ExtendedPoint(
|
||||
|
||||
const getXY = (p) => ({ x: p.x, y: p.y });
|
||||
|
||||
should('toHex/fromHex', () => {
|
||||
describe('jubjub', () => {
|
||||
should('toHex/fromHex', () => {
|
||||
// More than field
|
||||
throws(() =>
|
||||
jubjub.Point.fromHex(
|
||||
@ -58,13 +59,14 @@ should('toHex/fromHex', () => {
|
||||
deepStrictEqual(getXY(G_SPEND.double().toAffine()), getXY(S2_exp));
|
||||
deepStrictEqual(getXY(G_PROOF.toAffine()), getXY(P_exp));
|
||||
deepStrictEqual(getXY(G_PROOF.double().toAffine()), getXY(P2_exp));
|
||||
});
|
||||
});
|
||||
|
||||
should('Find generators', () => {
|
||||
should('Find generators', () => {
|
||||
const spend = findGroupHash(new Uint8Array(), new Uint8Array([90, 99, 97, 115, 104, 95, 71, 95]));
|
||||
const proof = findGroupHash(new Uint8Array(), new Uint8Array([90, 99, 97, 115, 104, 95, 72, 95]));
|
||||
deepStrictEqual(getXY(spend.toAffine()), getXY(G_SPEND.toAffine()));
|
||||
deepStrictEqual(getXY(proof.toAffine()), getXY(G_PROOF.toAffine()));
|
||||
});
|
||||
});
|
||||
|
||||
// ESM is broken.
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { deepStrictEqual, throws } from 'assert';
|
||||
import { should } from 'micro-should';
|
||||
import { describe, should } from 'micro-should';
|
||||
import { secp192r1, P192 } from '../lib/esm/p192.js';
|
||||
import { secp224r1, P224 } from '../lib/esm/p224.js';
|
||||
import { secp256r1, P256 } from '../lib/esm/p256.js';
|
||||
@ -344,10 +344,11 @@ function runWycheproof(name, CURVE, group, index) {
|
||||
|
||||
for (const name in WYCHEPROOF_ECDSA) {
|
||||
const { curve, hashes } = WYCHEPROOF_ECDSA[name];
|
||||
describe('Wycheproof/WYCHEPROOF_ECDSA', () => {
|
||||
for (const hName in hashes) {
|
||||
const { hash, tests } = hashes[hName];
|
||||
const CURVE = curve.create(hash);
|
||||
should(`Wycheproof/WYCHEPROOF_ECDSA ${name}/${hName}`, () => {
|
||||
should(`${name}/${hName}`, () => {
|
||||
for (let i = 0; i < tests.length; i++) {
|
||||
const groups = tests[i].testGroups;
|
||||
for (let j = 0; j < groups.length; j++) {
|
||||
@ -357,6 +358,7 @@ for (const name in WYCHEPROOF_ECDSA) {
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const hexToBigint = (hex) => BigInt(`0x${hex}`);
|
||||
|
@ -7,7 +7,7 @@ import { default as ecdh } from './vectors/ecdh.json' assert { type: 'json' };
|
||||
import { default as privates } from './vectors/privates.json' assert { type: 'json' };
|
||||
import { default as points } from './vectors/points.json' assert { type: 'json' };
|
||||
import { default as wp } from './vectors/wychenproof.json' assert { type: 'json' };
|
||||
import { should } from 'micro-should';
|
||||
import { should, describe } from 'micro-should';
|
||||
import { deepStrictEqual, throws } from 'assert';
|
||||
import { hexToBytes, bytesToHex } from '@noble/hashes/utils';
|
||||
|
||||
@ -30,7 +30,8 @@ function hexToNumber(hex) {
|
||||
return BigInt(`0x${hex}`);
|
||||
}
|
||||
|
||||
should('secp256k1.getPublicKey()', () => {
|
||||
describe('secp256k1', () => {
|
||||
should('getPublicKey()', () => {
|
||||
const data = privatesTxt
|
||||
.split('\n')
|
||||
.filter((line) => line)
|
||||
@ -48,13 +49,13 @@ should('secp256k1.getPublicKey()', () => {
|
||||
deepStrictEqual(toBEHex(point3.x), x);
|
||||
deepStrictEqual(toBEHex(point3.y), y);
|
||||
}
|
||||
});
|
||||
should('secp256k1.getPublicKey() rejects invalid keys', () => {
|
||||
});
|
||||
should('getPublicKey() rejects invalid keys', () => {
|
||||
for (const item of INVALID_ITEMS) {
|
||||
throws(() => secp.getPublicKey(item));
|
||||
}
|
||||
});
|
||||
should('secp256k1.precompute', () => {
|
||||
});
|
||||
should('precompute', () => {
|
||||
secp.utils.precompute(4);
|
||||
const data = privatesTxt
|
||||
.split('\n')
|
||||
@ -73,9 +74,9 @@ should('secp256k1.precompute', () => {
|
||||
deepStrictEqual(toBEHex(point3.x), x);
|
||||
deepStrictEqual(toBEHex(point3.y), y);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
should('secp256k1.Point.isValidPoint()', () => {
|
||||
should('Point.isValidPoint()', () => {
|
||||
for (const vector of points.valid.isPoint) {
|
||||
const { P, expected } = vector;
|
||||
if (expected) {
|
||||
@ -84,34 +85,34 @@ should('secp256k1.Point.isValidPoint()', () => {
|
||||
throws(() => secp.Point.fromHex(P));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
should('secp256k1.Point.fromPrivateKey()', () => {
|
||||
should('Point.fromPrivateKey()', () => {
|
||||
for (const vector of points.valid.pointFromScalar) {
|
||||
const { d, expected } = vector;
|
||||
let p = secp.Point.fromPrivateKey(d);
|
||||
deepStrictEqual(p.toHex(true), expected);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
should('secp256k1.Point#toHex(compressed)', () => {
|
||||
should('Point#toHex(compressed)', () => {
|
||||
for (const vector of points.valid.pointCompress) {
|
||||
const { P, compress, expected } = vector;
|
||||
let p = secp.Point.fromHex(P);
|
||||
deepStrictEqual(p.toHex(compress), expected);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
should('secp256k1.Point#toHex() roundtrip (failed case)', () => {
|
||||
should('Point#toHex() roundtrip (failed case)', () => {
|
||||
const point1 =
|
||||
secp.Point.fromPrivateKey(
|
||||
88572218780422190464634044548753414301110513745532121983949500266768436236425n
|
||||
);
|
||||
// const hex = point1.toHex(true);
|
||||
// deepStrictEqual(secp.Point.fromHex(hex).toHex(true), hex);
|
||||
});
|
||||
});
|
||||
|
||||
should('secp256k1.Point#toHex() roundtrip', () => {
|
||||
should('Point#toHex() roundtrip', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (x) => {
|
||||
const point1 = secp.Point.fromPrivateKey(x);
|
||||
@ -119,9 +120,9 @@ should('secp256k1.Point#toHex() roundtrip', () => {
|
||||
deepStrictEqual(secp.Point.fromHex(hex).toHex(true), hex);
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
should('secp256k1.Point#add(other)', () => {
|
||||
should('Point#add(other)', () => {
|
||||
for (const vector of points.valid.pointAdd) {
|
||||
const { P, Q, expected } = vector;
|
||||
let p = secp.Point.fromHex(P);
|
||||
@ -134,9 +135,9 @@ should('secp256k1.Point#add(other)', () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
should('secp256k1.Point#multiply(privateKey)', () => {
|
||||
should('Point#multiply(privateKey)', () => {
|
||||
for (const vector of points.valid.pointMultiply) {
|
||||
const { P, d, expected } = vector;
|
||||
const p = secp.Point.fromHex(P);
|
||||
@ -161,39 +162,39 @@ should('secp256k1.Point#multiply(privateKey)', () => {
|
||||
for (const num of [0n, 0, -1n, -1, 1.1]) {
|
||||
throws(() => secp.Point.BASE.multiply(num));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// multiply() should equal multiplyUnsafe()
|
||||
// should('ProjectivePoint#multiplyUnsafe', () => {
|
||||
// const p0 = new secp.ProjectivePoint(
|
||||
// 55066263022277343669578718895168534326250603453777594175500187360389116729240n,
|
||||
// 32670510020758816978083085130507043184471273380659243275938904335757337482424n,
|
||||
// 1n
|
||||
// );
|
||||
// const z = 106011723082030650010038151861333186846790370053628296836951575624442507889495n;
|
||||
// console.log(p0.multiply(z));
|
||||
// console.log(secp.ProjectivePoint.normalizeZ([p0.multiplyUnsafe(z)])[0])
|
||||
// });
|
||||
// multiply() should equal multiplyUnsafe()
|
||||
// should('ProjectivePoint#multiplyUnsafe', () => {
|
||||
// const p0 = new secp.ProjectivePoint(
|
||||
// 55066263022277343669578718895168534326250603453777594175500187360389116729240n,
|
||||
// 32670510020758816978083085130507043184471273380659243275938904335757337482424n,
|
||||
// 1n
|
||||
// );
|
||||
// const z = 106011723082030650010038151861333186846790370053628296836951575624442507889495n;
|
||||
// console.log(p0.multiply(z));
|
||||
// console.log(secp.ProjectivePoint.normalizeZ([p0.multiplyUnsafe(z)])[0])
|
||||
// });
|
||||
|
||||
should('secp256k1.Signature.fromCompactHex() roundtrip', () => {
|
||||
should('Signature.fromCompactHex() roundtrip', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, (r, s) => {
|
||||
const sig = new secp.Signature(r, s);
|
||||
deepStrictEqual(secp.Signature.fromCompact(sig.toCompactHex()), sig);
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
should('secp256k1.Signature.fromDERHex() roundtrip', () => {
|
||||
should('Signature.fromDERHex() roundtrip', () => {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, (r, s) => {
|
||||
const sig = new secp.Signature(r, s);
|
||||
deepStrictEqual(secp.Signature.fromDER(sig.toDERHex()), sig);
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
should('secp256k1.sign()/should create deterministic signatures with RFC 6979', () => {
|
||||
should('sign()/should create deterministic signatures with RFC 6979', () => {
|
||||
for (const vector of ecdsa.valid) {
|
||||
let usig = secp.sign(vector.m, vector.d);
|
||||
let sig = usig.toCompactHex();
|
||||
@ -201,20 +202,23 @@ should('secp256k1.sign()/should create deterministic signatures with RFC 6979',
|
||||
deepStrictEqual(sig.slice(0, 64), vsig.slice(0, 64));
|
||||
deepStrictEqual(sig.slice(64, 128), vsig.slice(64, 128));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
should('secp256k1.sign()/should not create invalid deterministic signatures with RFC 6979', () => {
|
||||
should(
|
||||
'secp256k1.sign()/should not create invalid deterministic signatures with RFC 6979',
|
||||
() => {
|
||||
for (const vector of ecdsa.invalid.sign) {
|
||||
throws(() => secp.sign(vector.m, vector.d));
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
should('secp256k1.sign()/edge cases', () => {
|
||||
should('sign()/edge cases', () => {
|
||||
throws(() => secp.sign());
|
||||
throws(() => secp.sign(''));
|
||||
});
|
||||
});
|
||||
|
||||
should('secp256k1.sign()/should create correct DER encoding against libsecp256k1', () => {
|
||||
should('sign()/should create correct DER encoding against libsecp256k1', () => {
|
||||
const CASES = [
|
||||
[
|
||||
'd1a9dc8ed4e46a6a3e5e594615ca351d7d7ef44df1e4c94c1802f3592183794b',
|
||||
@ -236,8 +240,8 @@ should('secp256k1.sign()/should create correct DER encoding against libsecp256k1
|
||||
const rs = secp.Signature.fromDER(res.toDERHex()).toCompactHex();
|
||||
deepStrictEqual(secp.Signature.fromCompact(rs).toDERHex(), exp);
|
||||
}
|
||||
});
|
||||
should('secp256k1.sign()/sign ecdsa extraData', () => {
|
||||
});
|
||||
should('sign()/sign ecdsa extraData', () => {
|
||||
const ent1 = '0000000000000000000000000000000000000000000000000000000000000000';
|
||||
const ent2 = '0000000000000000000000000000000000000000000000000000000000000001';
|
||||
const ent3 = '6e723d3fd94ed5d2b6bdd4f123364b0f3ca52af829988a63f8afe91d29db1c33';
|
||||
@ -256,17 +260,17 @@ should('secp256k1.sign()/sign ecdsa extraData', () => {
|
||||
deepStrictEqual(sign(ent4), e.extraEntropyN);
|
||||
deepStrictEqual(sign(ent5), e.extraEntropyMax);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
should('secp256k1.verify()/should verify signature', () => {
|
||||
should('verify()/should verify signature', () => {
|
||||
const MSG = '01'.repeat(32);
|
||||
const PRIV_KEY = 0x2n;
|
||||
const signature = secp.sign(MSG, PRIV_KEY);
|
||||
const publicKey = secp.getPublicKey(PRIV_KEY);
|
||||
deepStrictEqual(publicKey.length, 65);
|
||||
deepStrictEqual(secp.verify(signature, MSG, publicKey), true);
|
||||
});
|
||||
should('secp256k1.verify()/should not verify signature with wrong public key', () => {
|
||||
});
|
||||
should('verify()/should not verify signature with wrong public key', () => {
|
||||
const MSG = '01'.repeat(32);
|
||||
const PRIV_KEY = 0x2n;
|
||||
const WRONG_PRIV_KEY = 0x22n;
|
||||
@ -274,8 +278,8 @@ should('secp256k1.verify()/should not verify signature with wrong public key', (
|
||||
const publicKey = secp.Point.fromPrivateKey(WRONG_PRIV_KEY).toHex();
|
||||
deepStrictEqual(publicKey.length, 130);
|
||||
deepStrictEqual(secp.verify(signature, MSG, publicKey), false);
|
||||
});
|
||||
should('secp256k1.verify()/should not verify signature with wrong hash', () => {
|
||||
});
|
||||
should('verify()/should not verify signature with wrong hash', () => {
|
||||
const MSG = '01'.repeat(32);
|
||||
const PRIV_KEY = 0x2n;
|
||||
const WRONG_MSG = '11'.repeat(32);
|
||||
@ -283,8 +287,8 @@ should('secp256k1.verify()/should not verify signature with wrong hash', () => {
|
||||
const publicKey = secp.getPublicKey(PRIV_KEY);
|
||||
deepStrictEqual(publicKey.length, 65);
|
||||
deepStrictEqual(secp.verify(signature, WRONG_MSG, publicKey), false);
|
||||
});
|
||||
should('secp256k1.verify()/should verify random signatures', () =>
|
||||
});
|
||||
should('verify()/should verify random signatures', () =>
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, fc.hexaString({ minLength: 64, maxLength: 64 }), (privKey, msg) => {
|
||||
const pub = secp.getPublicKey(privKey);
|
||||
@ -292,11 +296,12 @@ should('secp256k1.verify()/should verify random signatures', () =>
|
||||
deepStrictEqual(secp.verify(sig, msg, pub), true);
|
||||
})
|
||||
)
|
||||
);
|
||||
should('secp256k1.verify()/should not verify signature with invalid r/s', () => {
|
||||
);
|
||||
should('verify()/should not verify signature with invalid r/s', () => {
|
||||
const msg = new Uint8Array([
|
||||
0xbb, 0x5a, 0x52, 0xf4, 0x2f, 0x9c, 0x92, 0x61, 0xed, 0x43, 0x61, 0xf5, 0x94, 0x22, 0xa1, 0xe3,
|
||||
0x00, 0x36, 0xe7, 0xc3, 0x2b, 0x27, 0x0c, 0x88, 0x07, 0xa4, 0x19, 0xfe, 0xca, 0x60, 0x50, 0x23,
|
||||
0xbb, 0x5a, 0x52, 0xf4, 0x2f, 0x9c, 0x92, 0x61, 0xed, 0x43, 0x61, 0xf5, 0x94, 0x22, 0xa1,
|
||||
0xe3, 0x00, 0x36, 0xe7, 0xc3, 0x2b, 0x27, 0x0c, 0x88, 0x07, 0xa4, 0x19, 0xfe, 0xca, 0x60,
|
||||
0x50, 0x23,
|
||||
]);
|
||||
const x = 100260381870027870612475458630405506840396644859280795015145920502443964769584n;
|
||||
const y = 41096923727651821103518389640356553930186852801619204169823347832429067794568n;
|
||||
@ -311,8 +316,8 @@ should('secp256k1.verify()/should not verify signature with invalid r/s', () =>
|
||||
const verified = secp.verify(signature, msg, pub);
|
||||
// Verifies, but it shouldn't, because signature S > curve order
|
||||
deepStrictEqual(verified, false);
|
||||
});
|
||||
should('secp256k1.verify()/should not verify msg = curve order', () => {
|
||||
});
|
||||
should('verify()/should not verify msg = curve order', () => {
|
||||
const msg = 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141';
|
||||
const x = 55066263022277343669578718895168534326250603453777594175500187360389116729240n;
|
||||
const y = 32670510020758816978083085130507043184471273380659243275938904335757337482424n;
|
||||
@ -321,8 +326,8 @@ should('secp256k1.verify()/should not verify msg = curve order', () => {
|
||||
const pub = new secp.Point(x, y);
|
||||
const sig = new secp.Signature(r, s);
|
||||
deepStrictEqual(secp.verify(sig, msg, pub), false);
|
||||
});
|
||||
should('secp256k1.verify()/should verify non-strict msg bb5a...', () => {
|
||||
});
|
||||
should('verify()/should verify non-strict msg bb5a...', () => {
|
||||
const msg = 'bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023';
|
||||
const x = 3252872872578928810725465493269682203671229454553002637820453004368632726370n;
|
||||
const y = 17482644437196207387910659778872952193236850502325156318830589868678978890912n;
|
||||
@ -331,8 +336,8 @@ should('secp256k1.verify()/should verify non-strict msg bb5a...', () => {
|
||||
const pub = new secp.Point(x, y);
|
||||
const sig = new secp.Signature(r, s);
|
||||
deepStrictEqual(secp.verify(sig, msg, pub, { strict: false }), true);
|
||||
});
|
||||
should(
|
||||
});
|
||||
should(
|
||||
'secp256k1.verify()/should not verify invalid deterministic signatures with RFC 6979',
|
||||
() => {
|
||||
for (const vector of ecdsa.invalid.verify) {
|
||||
@ -340,14 +345,14 @@ should(
|
||||
deepStrictEqual(res, false);
|
||||
}
|
||||
}
|
||||
);
|
||||
);
|
||||
|
||||
// index,secret key,public key,aux_rand,message,signature,verification result,comment
|
||||
const vectors = schCsv
|
||||
// index,secret key,public key,aux_rand,message,signature,verification result,comment
|
||||
const vectors = schCsv
|
||||
.split('\n')
|
||||
.map((line) => line.split(','))
|
||||
.slice(1, -1);
|
||||
for (let vec of vectors) {
|
||||
for (let vec of vectors) {
|
||||
const [index, sec, pub, rnd, msg, expSig, passes, comment] = vec;
|
||||
should(`sign with Schnorr scheme vector ${index}`, () => {
|
||||
if (sec) {
|
||||
@ -360,9 +365,9 @@ for (let vec of vectors) {
|
||||
deepStrictEqual(passed, passes === 'TRUE');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
should('secp256k1.recoverPublicKey()/should recover public key from recovery bit', () => {
|
||||
should('recoverPublicKey()/should recover public key from recovery bit', () => {
|
||||
const message = '00000000000000000000000000000000000000000000000000000000deadbeef';
|
||||
const privateKey = 123456789n;
|
||||
const publicKey = secp.Point.fromHex(secp.getPublicKey(privateKey)).toHex(false);
|
||||
@ -372,23 +377,23 @@ should('secp256k1.recoverPublicKey()/should recover public key from recovery bit
|
||||
deepStrictEqual(recoveredPubkey !== null, true);
|
||||
deepStrictEqual(recoveredPubkey.toHex(false), publicKey);
|
||||
deepStrictEqual(secp.verify(sig, message, publicKey), true);
|
||||
});
|
||||
should('secp256k1.recoverPublicKey()/should not recover zero points', () => {
|
||||
});
|
||||
should('recoverPublicKey()/should not recover zero points', () => {
|
||||
const msgHash = '6b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a9';
|
||||
const sig =
|
||||
'79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817986b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a9';
|
||||
const recovery = 0;
|
||||
throws(() => secp.recoverPublicKey(msgHash, sig, recovery));
|
||||
});
|
||||
should('secp256k1.recoverPublicKey()/should handle all-zeros msghash', () => {
|
||||
});
|
||||
should('recoverPublicKey()/should handle all-zeros msghash', () => {
|
||||
const privKey = secp.utils.randomPrivateKey();
|
||||
const pub = secp.getPublicKey(privKey);
|
||||
const zeros = '0000000000000000000000000000000000000000000000000000000000000000';
|
||||
const sig = secp.sign(zeros, privKey, { recovered: true });
|
||||
const recoveredKey = sig.recoverPublicKey(zeros);
|
||||
deepStrictEqual(recoveredKey.toRawBytes(), pub);
|
||||
});
|
||||
should('secp256k1.recoverPublicKey()/should handle RFC 6979 vectors', () => {
|
||||
});
|
||||
should('recoverPublicKey()/should handle RFC 6979 vectors', () => {
|
||||
for (const vector of ecdsa.valid) {
|
||||
let usig = secp.sign(vector.m, vector.d);
|
||||
let sig = usig.toDERHex();
|
||||
@ -396,13 +401,13 @@ should('secp256k1.recoverPublicKey()/should handle RFC 6979 vectors', () => {
|
||||
const recovered = usig.recoverPublicKey(vector.m);
|
||||
deepStrictEqual(recovered.toHex(), hex(vpub));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// TODO: Real implementation.
|
||||
function derToPub(der) {
|
||||
// TODO: Real implementation.
|
||||
function derToPub(der) {
|
||||
return der.slice(46);
|
||||
}
|
||||
should('secp256k1.getSharedSecret()/should produce correct results', () => {
|
||||
}
|
||||
should('getSharedSecret()/should produce correct results', () => {
|
||||
// TODO: Once der is there, run all tests.
|
||||
for (const vector of ecdh.testGroups[0].tests.slice(0, 230)) {
|
||||
if (vector.result === 'invalid' || vector.private.length !== 64) {
|
||||
@ -414,8 +419,8 @@ should('secp256k1.getSharedSecret()/should produce correct results', () => {
|
||||
deepStrictEqual(hex(res.slice(1)), `${vector.shared}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
should('secp256k1.getSharedSecret()/priv/pub order matters', () => {
|
||||
});
|
||||
should('getSharedSecret()/priv/pub order matters', () => {
|
||||
for (const vector of ecdh.testGroups[0].tests.slice(0, 100)) {
|
||||
if (vector.result === 'valid') {
|
||||
let priv = vector.private;
|
||||
@ -423,28 +428,28 @@ should('secp256k1.getSharedSecret()/priv/pub order matters', () => {
|
||||
throws(() => secp.getSharedSecret(derToPub(vector.public), priv, true));
|
||||
}
|
||||
}
|
||||
});
|
||||
should('secp256k1.getSharedSecret()/rejects invalid keys', () => {
|
||||
});
|
||||
should('getSharedSecret()/rejects invalid keys', () => {
|
||||
throws(() => secp.getSharedSecret('01', '02'));
|
||||
});
|
||||
});
|
||||
|
||||
should('secp256k1.utils.isValidPrivateKey()', () => {
|
||||
should('utils.isValidPrivateKey()', () => {
|
||||
for (const vector of privates.valid.isPrivate) {
|
||||
const { d, expected } = vector;
|
||||
deepStrictEqual(secp.utils.isValidPrivateKey(d), expected);
|
||||
}
|
||||
});
|
||||
should('have proper curve equation in assertValidity()', () => {
|
||||
});
|
||||
should('have proper curve equation in assertValidity()', () => {
|
||||
throws(() => {
|
||||
const { Fp } = secp.CURVE;
|
||||
let point = new secp.Point(Fp.create(-2n), Fp.create(-1n));
|
||||
point.assertValidity();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const Fn = Fp(secp.CURVE.n);
|
||||
const normal = secp.utils._normalizePrivateKey;
|
||||
const tweakUtils = {
|
||||
const Fn = Fp(secp.CURVE.n);
|
||||
const normal = secp.utils._normalizePrivateKey;
|
||||
const tweakUtils = {
|
||||
privateAdd: (privateKey, tweak) => {
|
||||
const p = normal(privateKey);
|
||||
const t = normal(tweak);
|
||||
@ -470,47 +475,47 @@ const tweakUtils = {
|
||||
const t = BigInt(`0x${h}`);
|
||||
return P.multiply(t).toRawBytes(isCompressed);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
should('secp256k1.privateAdd()', () => {
|
||||
should('privateAdd()', () => {
|
||||
for (const vector of privates.valid.add) {
|
||||
const { a, b, expected } = vector;
|
||||
deepStrictEqual(bytesToHex(tweakUtils.privateAdd(a, b)), expected);
|
||||
}
|
||||
});
|
||||
should('secp256k1.privateNegate()', () => {
|
||||
});
|
||||
should('privateNegate()', () => {
|
||||
for (const vector of privates.valid.negate) {
|
||||
const { a, expected } = vector;
|
||||
deepStrictEqual(bytesToHex(tweakUtils.privateNegate(a)), expected);
|
||||
}
|
||||
});
|
||||
should('secp256k1.pointAddScalar()', () => {
|
||||
});
|
||||
should('pointAddScalar()', () => {
|
||||
for (const vector of points.valid.pointAddScalar) {
|
||||
const { description, P, d, expected } = vector;
|
||||
const compressed = !!expected && expected.length === 66; // compressed === 33 bytes
|
||||
deepStrictEqual(bytesToHex(tweakUtils.pointAddScalar(P, d, compressed)), expected);
|
||||
}
|
||||
});
|
||||
should('secp256k1.pointAddScalar() invalid', () => {
|
||||
});
|
||||
should('pointAddScalar() invalid', () => {
|
||||
for (const vector of points.invalid.pointAddScalar) {
|
||||
const { P, d, exception } = vector;
|
||||
throws(() => tweakUtils.pointAddScalar(P, d));
|
||||
}
|
||||
});
|
||||
should('secp256k1.pointMultiply()', () => {
|
||||
});
|
||||
should('pointMultiply()', () => {
|
||||
for (const vector of points.valid.pointMultiply) {
|
||||
const { P, d, expected } = vector;
|
||||
deepStrictEqual(bytesToHex(tweakUtils.pointMultiply(P, d, true)), expected);
|
||||
}
|
||||
});
|
||||
should('secp256k1.pointMultiply() invalid', () => {
|
||||
});
|
||||
should('pointMultiply() invalid', () => {
|
||||
for (const vector of points.invalid.pointMultiply) {
|
||||
const { P, d, exception } = vector;
|
||||
throws(() => tweakUtils.pointMultiply(P, d));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
should('secp256k1.wychenproof vectors', () => {
|
||||
should('wychenproof vectors', () => {
|
||||
for (let group of wp.testGroups) {
|
||||
const pubKey = secp.Point.fromHex(group.key.uncompressed);
|
||||
for (let test of group.tests) {
|
||||
@ -536,6 +541,7 @@ should('secp256k1.wychenproof vectors', () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// ESM is broken.
|
||||
|
Loading…
Reference in New Issue
Block a user