Restructure tests
This commit is contained in:
parent
c46914f1bc
commit
3d77422731
@ -68,8 +68,8 @@ for (const c in FIELDS) {
|
||||
fc.property(FC_BIGINT, (num) => {
|
||||
const a = create(num);
|
||||
const b = create(num);
|
||||
deepStrictEqual(Fp.equals(a, b), true);
|
||||
deepStrictEqual(Fp.equals(b, a), true);
|
||||
deepStrictEqual(Fp.eql(a, b), true);
|
||||
deepStrictEqual(Fp.eql(b, a), true);
|
||||
})
|
||||
);
|
||||
});
|
||||
@ -78,8 +78,8 @@ for (const c in FIELDS) {
|
||||
fc.property(FC_BIGINT, FC_BIGINT, (num1, num2) => {
|
||||
const a = create(num1);
|
||||
const b = create(num2);
|
||||
deepStrictEqual(Fp.equals(a, b), num1 === num2);
|
||||
deepStrictEqual(Fp.equals(b, a), num1 === num2);
|
||||
deepStrictEqual(Fp.eql(a, b), num1 === num2);
|
||||
deepStrictEqual(Fp.eql(b, a), num1 === num2);
|
||||
})
|
||||
);
|
||||
});
|
||||
@ -124,8 +124,8 @@ for (const c in FIELDS) {
|
||||
fc.property(FC_BIGINT, (num1) => {
|
||||
const a = create(num1);
|
||||
const b = create(num1);
|
||||
deepStrictEqual(Fp.sub(Fp.ZERO, a), Fp.negate(a));
|
||||
deepStrictEqual(Fp.sub(a, b), Fp.add(a, Fp.negate(b)));
|
||||
deepStrictEqual(Fp.sub(Fp.ZERO, a), Fp.neg(a));
|
||||
deepStrictEqual(Fp.sub(a, b), Fp.add(a, Fp.neg(b)));
|
||||
deepStrictEqual(Fp.sub(a, b), Fp.add(a, Fp.mul(b, Fp.create(-1n))));
|
||||
})
|
||||
);
|
||||
@ -134,13 +134,13 @@ for (const c in FIELDS) {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (num) => {
|
||||
const a = create(num);
|
||||
deepStrictEqual(Fp.negate(a), Fp.sub(Fp.ZERO, a));
|
||||
deepStrictEqual(Fp.negate(a), Fp.mul(a, Fp.create(-1n)));
|
||||
deepStrictEqual(Fp.neg(a), Fp.sub(Fp.ZERO, a));
|
||||
deepStrictEqual(Fp.neg(a), Fp.mul(a, Fp.create(-1n)));
|
||||
})
|
||||
);
|
||||
});
|
||||
should('negate(0)', () => {
|
||||
deepStrictEqual(Fp.negate(Fp.ZERO), Fp.ZERO);
|
||||
deepStrictEqual(Fp.neg(Fp.ZERO), Fp.ZERO);
|
||||
});
|
||||
|
||||
should('multiply/commutativity', () => {
|
||||
@ -190,7 +190,7 @@ for (const c in FIELDS) {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (num) => {
|
||||
const a = create(num);
|
||||
deepStrictEqual(Fp.square(a), Fp.mul(a, a));
|
||||
deepStrictEqual(Fp.sqr(a), Fp.mul(a, a));
|
||||
})
|
||||
);
|
||||
});
|
||||
@ -207,18 +207,18 @@ for (const c in FIELDS) {
|
||||
});
|
||||
|
||||
should('square(0)', () => {
|
||||
deepStrictEqual(Fp.square(Fp.ZERO), Fp.ZERO);
|
||||
deepStrictEqual(Fp.sqr(Fp.ZERO), Fp.ZERO);
|
||||
deepStrictEqual(Fp.mul(Fp.ZERO, Fp.ZERO), Fp.ZERO);
|
||||
});
|
||||
|
||||
should('square(1)', () => {
|
||||
deepStrictEqual(Fp.square(Fp.ONE), Fp.ONE);
|
||||
deepStrictEqual(Fp.sqr(Fp.ONE), Fp.ONE);
|
||||
deepStrictEqual(Fp.mul(Fp.ONE, Fp.ONE), Fp.ONE);
|
||||
});
|
||||
|
||||
should('square(-1)', () => {
|
||||
const minus1 = Fp.negate(Fp.ONE);
|
||||
deepStrictEqual(Fp.square(minus1), Fp.ONE);
|
||||
const minus1 = Fp.neg(Fp.ONE);
|
||||
deepStrictEqual(Fp.sqr(minus1), Fp.ONE);
|
||||
deepStrictEqual(Fp.mul(minus1, minus1), Fp.ONE);
|
||||
});
|
||||
|
||||
@ -237,8 +237,8 @@ for (const c in FIELDS) {
|
||||
return;
|
||||
}
|
||||
deepStrictEqual(isSquare(a), true);
|
||||
deepStrictEqual(Fp.equals(Fp.square(root), a), true, 'sqrt(a)^2 == a');
|
||||
deepStrictEqual(Fp.equals(Fp.square(Fp.negate(root)), a), true, '(-sqrt(a))^2 == a');
|
||||
deepStrictEqual(Fp.eql(Fp.sqr(root), a), true, 'sqrt(a)^2 == a');
|
||||
deepStrictEqual(Fp.eql(Fp.sqr(Fp.neg(root)), a), true, '(-sqrt(a))^2 == a');
|
||||
})
|
||||
);
|
||||
});
|
||||
@ -247,7 +247,7 @@ for (const c in FIELDS) {
|
||||
deepStrictEqual(Fp.sqrt(Fp.ZERO), Fp.ZERO);
|
||||
const sqrt1 = Fp.sqrt(Fp.ONE);
|
||||
deepStrictEqual(
|
||||
Fp.equals(sqrt1, Fp.ONE) || Fp.equals(sqrt1, Fp.negate(Fp.ONE)),
|
||||
Fp.eql(sqrt1, Fp.ONE) || Fp.eql(sqrt1, Fp.neg(Fp.ONE)),
|
||||
true,
|
||||
'sqrt(1) = 1 or -1'
|
||||
);
|
||||
@ -258,7 +258,7 @@ for (const c in FIELDS) {
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, (num) => {
|
||||
const a = create(num);
|
||||
if (Fp.equals(a, Fp.ZERO)) return; // No division by zero
|
||||
if (Fp.eql(a, Fp.ZERO)) return; // No division by zero
|
||||
deepStrictEqual(Fp.div(a, Fp.ONE), a);
|
||||
deepStrictEqual(Fp.div(a, a), Fp.ONE);
|
||||
})
|
||||
@ -287,7 +287,7 @@ for (const c in FIELDS) {
|
||||
fc.property(FC_BIGINT, FC_BIGINT, (num1, num2) => {
|
||||
const a = create(num1);
|
||||
const b = create(num2);
|
||||
deepStrictEqual(Fp.div(a, b), Fp.mul(a, Fp.invert(b)));
|
||||
deepStrictEqual(Fp.div(a, b), Fp.mul(a, Fp.inv(b)));
|
||||
})
|
||||
);
|
||||
});
|
||||
@ -347,7 +347,7 @@ for (const name in CURVES) {
|
||||
describe(title, () => {
|
||||
describe('basic group laws', () => {
|
||||
// Here we check basic group laws, to verify that points works as group
|
||||
should('(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');
|
||||
@ -358,34 +358,34 @@ for (const name in CURVES) {
|
||||
equal(G[0].multiply(BigInt(i + 1)), G[0], `${i + 1}*0 = 0`);
|
||||
}
|
||||
});
|
||||
should('(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('(sanity tests)', () => {
|
||||
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('(addition commutativity)', () => {
|
||||
should('add 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('(double)', () => {
|
||||
should('double', () => {
|
||||
equal(G[3].double(), G[6], '(3*G).double() = 6*G');
|
||||
});
|
||||
should('(multiply)', () => {
|
||||
should('multiply', () => {
|
||||
equal(G[2].multiply(3n), G[6], '(2*G).multiply(3) = 6*G');
|
||||
});
|
||||
should('(same point addition)', () => {
|
||||
should('add same-point', () => {
|
||||
equal(G[3].add(G[3]), G[6], '3*G + 3*G = 6*G');
|
||||
});
|
||||
should('(same point (negative) addition)', () => {
|
||||
should('add same-point negative', () => {
|
||||
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('(curve order)', () => {
|
||||
should('mul by 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');
|
||||
@ -393,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('(inversion)', () => {
|
||||
should('inversion', () => {
|
||||
const a = 1234n;
|
||||
const b = 5678n;
|
||||
const c = a * b;
|
||||
@ -401,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('(multiply, rand)', () =>
|
||||
should('multiply, rand', () =>
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, (a, b) => {
|
||||
const c = mod.mod(a + b, CURVE_ORDER);
|
||||
@ -415,7 +415,7 @@ for (const name in CURVES) {
|
||||
{ numRuns: NUM_RUNS }
|
||||
)
|
||||
);
|
||||
should('(multiply2, rand)', () =>
|
||||
should('multiply2, rand', () =>
|
||||
fc.assert(
|
||||
fc.property(FC_BIGINT, FC_BIGINT, (a, b) => {
|
||||
const c = mod.mod(a * b, CURVE_ORDER);
|
||||
@ -524,20 +524,23 @@ for (const name in CURVES) {
|
||||
}
|
||||
describe(name, () => {
|
||||
// Generic complex things (getPublicKey/sign/verify/getSharedSecret)
|
||||
should('getPublicKey type check', () => {
|
||||
should('.getPublicKey() type check', () => {
|
||||
throws(() => C.getPublicKey(0), '0');
|
||||
throws(() => C.getPublicKey(0n), '0n');
|
||||
throws(() => C.getPublicKey(false), 'false');
|
||||
throws(() => C.getPublicKey(123), '123');
|
||||
throws(() => C.getPublicKey(123.456), '123.456');
|
||||
throws(() => C.getPublicKey(true), 'true');
|
||||
throws(() => C.getPublicKey(''), "''");
|
||||
// NOTE: passes because of disabled hex padding checks for starknet, maybe enable?
|
||||
//throws(() => C.getPublicKey('1'), "'1'");
|
||||
// throws(() => C.getPublicKey('1'), "'1'");
|
||||
throws(() => C.getPublicKey('key'), "'key'");
|
||||
throws(() => C.getPublicKey({}));
|
||||
throws(() => C.getPublicKey(new Uint8Array([])));
|
||||
throws(() => C.getPublicKey(new Uint8Array([0])));
|
||||
throws(() => C.getPublicKey(new Uint8Array([1])));
|
||||
throws(() => C.getPublicKey(new Uint8Array(4096).fill(1)));
|
||||
throws(() => C.getPublicKey(Array(32).fill(1)));
|
||||
});
|
||||
should('.verify() should verify random signatures', () =>
|
||||
fc.assert(
|
||||
@ -559,13 +562,27 @@ for (const name in CURVES) {
|
||||
throws(() => C.sign(''));
|
||||
});
|
||||
|
||||
should('.verify() should not verify signature with wrong hash', () => {
|
||||
const MSG = '01'.repeat(32);
|
||||
const PRIV_KEY = 0x2n;
|
||||
const WRONG_MSG = '11'.repeat(32);
|
||||
const signature = C.sign(MSG, PRIV_KEY);
|
||||
const publicKey = C.getPublicKey(PRIV_KEY);
|
||||
deepStrictEqual(C.verify(signature, WRONG_MSG, publicKey), false);
|
||||
describe('verify()', () => {
|
||||
should('true for proper signatures', () => {
|
||||
const msg = '01'.repeat(32);
|
||||
const priv = C.utils.randomPrivateKey();
|
||||
const sig = C.sign(msg, priv);
|
||||
const pub = C.getPublicKey(priv);
|
||||
deepStrictEqual(C.verify(sig, msg, pub), true);
|
||||
});
|
||||
should('false for wrong messages', () => {
|
||||
const msg = '01'.repeat(32);
|
||||
const priv = C.utils.randomPrivateKey();
|
||||
const sig = C.sign(msg, priv);
|
||||
const pub = C.getPublicKey(priv);
|
||||
deepStrictEqual(C.verify(sig, '11'.repeat(32), pub), false);
|
||||
});
|
||||
should('false for wrong keys', () => {
|
||||
const msg = '01'.repeat(32);
|
||||
const priv = C.utils.randomPrivateKey();
|
||||
const sig = C.sign(msg, priv);
|
||||
deepStrictEqual(C.verify(sig, msg, C.getPublicKey(C.utils.randomPrivateKey())), false);
|
||||
});
|
||||
});
|
||||
// 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?
|
||||
@ -618,10 +635,10 @@ should('secp224k1 sqrt bug', () => {
|
||||
23621584063597419797792593680131996961517196803742576047493035507225n
|
||||
);
|
||||
deepStrictEqual(
|
||||
Fp.negate(sqrtMinus1),
|
||||
Fp.neg(sqrtMinus1),
|
||||
3338362603553219996874421406887633712040719456283732096017030791656n
|
||||
);
|
||||
deepStrictEqual(Fp.square(sqrtMinus1), Fp.create(-1n));
|
||||
deepStrictEqual(Fp.sqr(sqrtMinus1), Fp.create(-1n));
|
||||
});
|
||||
|
||||
// ESM is broken.
|
||||
|
@ -71,8 +71,8 @@ describe('bls12-381 Fp2', () => {
|
||||
fc.property(FC_BIGINT_2, FC_BIGINT_2, (num1, num2) => {
|
||||
const a = Fp2.fromBigTuple([num1[0], num1[1]]);
|
||||
const b = Fp2.fromBigTuple([num2[0], num2[1]]);
|
||||
deepStrictEqual(Fp2.equals(a, b), num1[0] === num2[0] && num1[1] === num2[1]);
|
||||
deepStrictEqual(Fp2.equals(b, a), num1[0] === num2[0] && num1[1] === num2[1]);
|
||||
deepStrictEqual(Fp2.eql(a, b), num1[0] === num2[0] && num1[1] === num2[1]);
|
||||
deepStrictEqual(Fp2.eql(b, a), num1[0] === num2[0] && num1[1] === num2[1]);
|
||||
})
|
||||
);
|
||||
});
|
||||
@ -103,7 +103,7 @@ describe('bls12-381 Fp2', () => {
|
||||
]);
|
||||
a = Fp2.frobeniusMap(a, 0);
|
||||
deepStrictEqual(
|
||||
Fp2.equals(
|
||||
Fp2.eql(
|
||||
a,
|
||||
Fp2.fromBigTuple([
|
||||
0x00f8d295b2ded9dcccc649c4b9532bf3b966ce3bc2108b138b1a52e0a90f59ed11e59ea221a3b6d22d0078036923ffc7n,
|
||||
@ -114,7 +114,7 @@ describe('bls12-381 Fp2', () => {
|
||||
);
|
||||
a = Fp2.frobeniusMap(a, 1);
|
||||
deepStrictEqual(
|
||||
Fp2.equals(
|
||||
Fp2.eql(
|
||||
a,
|
||||
Fp2.fromBigTuple([
|
||||
0x00f8d295b2ded9dcccc649c4b9532bf3b966ce3bc2108b138b1a52e0a90f59ed11e59ea221a3b6d22d0078036923ffc7n,
|
||||
@ -125,7 +125,7 @@ describe('bls12-381 Fp2', () => {
|
||||
);
|
||||
a = Fp2.frobeniusMap(a, 1);
|
||||
deepStrictEqual(
|
||||
Fp2.equals(
|
||||
Fp2.eql(
|
||||
a,
|
||||
Fp2.fromBigTuple([
|
||||
0x00f8d295b2ded9dcccc649c4b9532bf3b966ce3bc2108b138b1a52e0a90f59ed11e59ea221a3b6d22d0078036923ffc7n,
|
||||
@ -136,7 +136,7 @@ describe('bls12-381 Fp2', () => {
|
||||
);
|
||||
a = Fp2.frobeniusMap(a, 2);
|
||||
deepStrictEqual(
|
||||
Fp2.equals(
|
||||
Fp2.eql(
|
||||
a,
|
||||
Fp2.fromBigTuple([
|
||||
0x00f8d295b2ded9dcccc649c4b9532bf3b966ce3bc2108b138b1a52e0a90f59ed11e59ea221a3b6d22d0078036923ffc7n,
|
||||
|
@ -79,6 +79,7 @@ describe('ed25519', () => {
|
||||
);
|
||||
});
|
||||
const privKey = to32Bytes('a665a45920422f9d417e4867ef');
|
||||
const wrongPriv = to32Bytes('a675a45920422f9d417e4867ef');
|
||||
const msg = hexToBytes('874f9960c5d2b7a9b5fad383e1ba44719ebb743a');
|
||||
const wrongMsg = hexToBytes('589d8c7f1da0a24bc07b7381ad48b1cfc211af1c');
|
||||
describe('basic methods', () => {
|
||||
@ -87,16 +88,6 @@ describe('ed25519', () => {
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), true);
|
||||
});
|
||||
should('not verify signature with wrong public key', () => {
|
||||
const publicKey = ed.getPublicKey(12n);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), false);
|
||||
});
|
||||
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);
|
||||
});
|
||||
});
|
||||
describe('sync methods', () => {
|
||||
should('sign and verify', () => {
|
||||
@ -105,7 +96,7 @@ describe('ed25519', () => {
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), true);
|
||||
});
|
||||
should('not verify signature with wrong public key', () => {
|
||||
const publicKey = ed.getPublicKey(12n);
|
||||
const publicKey = ed.getPublicKey(wrongPriv);
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), false);
|
||||
});
|
||||
@ -649,7 +640,7 @@ describe('ed25519', () => {
|
||||
should('X25519 base point', () => {
|
||||
const { y } = ed25519.ExtendedPoint.BASE;
|
||||
const { Fp } = ed25519.CURVE;
|
||||
const u = Fp.create((y + 1n) * Fp.invert(1n - y));
|
||||
const u = Fp.create((y + 1n) * Fp.inv(1n - y));
|
||||
deepStrictEqual(hex(numberToBytesLE(u, 32)), x25519.Gu);
|
||||
});
|
||||
|
||||
|
@ -316,14 +316,16 @@ describe('ed448', () => {
|
||||
},
|
||||
];
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
describe('RFC8032', () => {
|
||||
for (let i = 0; i < VECTORS_RFC8032.length; i++) {
|
||||
const v = VECTORS_RFC8032[i];
|
||||
should(`${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('not accept >57byte private keys', () => {
|
||||
const invalidPriv =
|
||||
@ -383,7 +385,7 @@ describe('ed448', () => {
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), true);
|
||||
});
|
||||
should('not verify signature with wrong public key', () => {
|
||||
const publicKey = ed.getPublicKey(12n);
|
||||
const publicKey = ed.getPublicKey(ed.utils.randomPrivateKey());
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), false);
|
||||
});
|
||||
@ -400,7 +402,7 @@ describe('ed448', () => {
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), true);
|
||||
});
|
||||
should('not verify signature with wrong public key', () => {
|
||||
const publicKey = ed.getPublicKey(12n);
|
||||
const publicKey = ed.getPublicKey(ed.utils.randomPrivateKey());
|
||||
const signature = ed.sign(msg, privKey);
|
||||
deepStrictEqual(ed.verify(signature, msg, publicKey), false);
|
||||
});
|
||||
@ -437,14 +439,14 @@ describe('ed448', () => {
|
||||
}
|
||||
});
|
||||
|
||||
{
|
||||
describe('wycheproof', () => {
|
||||
for (let g = 0; g < ed448vectors.testGroups.length; g++) {
|
||||
const group = ed448vectors.testGroups[g];
|
||||
const key = group.key;
|
||||
should(`Wycheproof/ED448(${g}, public)`, () => {
|
||||
should(`ED448(${g}, public)`, () => {
|
||||
deepStrictEqual(hex(ed.getPublicKey(key.sk)), key.pk);
|
||||
});
|
||||
should(`Wycheproof/ED448`, () => {
|
||||
should(`ED448`, () => {
|
||||
for (let i = 0; i < group.tests.length; i++) {
|
||||
const v = group.tests[i];
|
||||
const index = `${g}/${i} ${v.comment}`;
|
||||
@ -463,7 +465,7 @@ describe('ed448', () => {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// ECDH
|
||||
const rfc7748Mul = [
|
||||
@ -482,12 +484,14 @@ describe('ed448', () => {
|
||||
'884a02576239ff7a2f2f63b2db6a9ff37047ac13568e1e30fe63c4a7ad1b3ee3a5700df34321d62077e63633c575c1c954514e99da7c179d',
|
||||
},
|
||||
];
|
||||
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);
|
||||
});
|
||||
}
|
||||
describe('RFC7748', () => {
|
||||
for (let i = 0; i < rfc7748Mul.length; i++) {
|
||||
const v = rfc7748Mul[i];
|
||||
should(`scalarMult (${i})`, () => {
|
||||
deepStrictEqual(hex(x448.scalarMult(v.scalar, v.u)), v.outputU);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const rfc7748Iter = [
|
||||
{
|
||||
@ -528,9 +532,9 @@ describe('ed448', () => {
|
||||
deepStrictEqual(hex(x448.scalarMult(bobPrivate, alicePublic)), shared);
|
||||
});
|
||||
|
||||
{
|
||||
describe('wycheproof', () => {
|
||||
const group = x448vectors.testGroups[0];
|
||||
should(`Wycheproof/X448`, () => {
|
||||
should(`X448`, () => {
|
||||
for (let i = 0; i < group.tests.length; i++) {
|
||||
const v = group.tests[i];
|
||||
const index = `(${i}, ${v.result}) ${v.comment}`;
|
||||
@ -556,7 +560,7 @@ describe('ed448', () => {
|
||||
} else throw new Error('unknown test result');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// should('X448: should convert base point to montgomery using fromPoint', () => {
|
||||
// deepStrictEqual(
|
||||
|
@ -11,164 +11,11 @@ import { default as ecdsa } from './wycheproof/ecdsa_test.json' assert { type: '
|
||||
import { default as ecdh } from './wycheproof/ecdh_test.json' assert { type: 'json' };
|
||||
import { default as rfc6979 } from './fixtures/rfc6979.json' assert { type: 'json' };
|
||||
|
||||
const hex = bytesToHex;
|
||||
|
||||
// prettier-ignore
|
||||
const NIST = {
|
||||
secp192r1, P192,
|
||||
secp224r1, P224,
|
||||
secp256r1, P256,
|
||||
secp384r1, P384,
|
||||
secp521r1, P521,
|
||||
secp256k1,
|
||||
};
|
||||
|
||||
should('Curve Fields', () => {
|
||||
const vectors = {
|
||||
secp192r1: 0xfffffffffffffffffffffffffffffffeffffffffffffffffn,
|
||||
secp224r1: 0xffffffffffffffffffffffffffffffff000000000000000000000001n,
|
||||
secp256r1: 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffffn,
|
||||
secp256k1: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fn,
|
||||
secp384r1:
|
||||
0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffffn,
|
||||
secp521r1:
|
||||
0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn,
|
||||
};
|
||||
for (const n in vectors) deepStrictEqual(NIST[n].CURVE.Fp.ORDER, vectors[n]);
|
||||
});
|
||||
|
||||
should('wychenproof ECDSA vectors', () => {
|
||||
for (const group of ecdsa.testGroups) {
|
||||
// Tested in secp256k1.test.js
|
||||
if (group.key.curve === 'secp256k1') continue;
|
||||
let CURVE = NIST[group.key.curve];
|
||||
if (!CURVE) continue;
|
||||
if (group.key.curve === 'secp224r1' && group.sha !== 'SHA-224') {
|
||||
if (group.sha === 'SHA-256') CURVE = CURVE.create(sha256);
|
||||
}
|
||||
const pubKey = CURVE.ProjectivePoint.fromHex(group.key.uncompressed);
|
||||
deepStrictEqual(pubKey.x, BigInt(`0x${group.key.wx}`));
|
||||
deepStrictEqual(pubKey.y, BigInt(`0x${group.key.wy}`));
|
||||
for (const test of group.tests) {
|
||||
if (['Hash weaker than DL-group'].includes(test.comment)) {
|
||||
continue;
|
||||
}
|
||||
const m = CURVE.CURVE.hash(hexToBytes(test.msg));
|
||||
if (test.result === 'valid' || test.result === 'acceptable') {
|
||||
try {
|
||||
CURVE.Signature.fromDER(test.sig);
|
||||
} catch (e) {
|
||||
// Some test has invalid signature which we don't accept
|
||||
if (e.message.includes('Invalid signature: incorrect length')) continue;
|
||||
throw e;
|
||||
}
|
||||
const verified = CURVE.verify(test.sig, m, pubKey.toHex());
|
||||
deepStrictEqual(verified, true, 'valid');
|
||||
} else if (test.result === 'invalid') {
|
||||
let failed = false;
|
||||
try {
|
||||
failed = !CURVE.verify(test.sig, m, pubKey.toHex());
|
||||
} catch (error) {
|
||||
failed = true;
|
||||
}
|
||||
deepStrictEqual(failed, true, 'invalid');
|
||||
} else throw new Error('unknown test result');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
should('wychenproof ECDH vectors', () => {
|
||||
for (const group of ecdh.testGroups) {
|
||||
// // Tested in secp256k1.test.js
|
||||
// if (group.key.curve === 'secp256k1') continue;
|
||||
// We don't have SHA-224
|
||||
const CURVE = NIST[group.curve];
|
||||
if (!CURVE) continue;
|
||||
for (const test of group.tests) {
|
||||
if (test.result === 'valid' || test.result === 'acceptable') {
|
||||
try {
|
||||
const pub = CURVE.ProjectivePoint.fromHex(test.public);
|
||||
} catch (e) {
|
||||
if (e.message.includes('Point.fromHex: received invalid point.')) continue;
|
||||
throw e;
|
||||
}
|
||||
const shared = CURVE.getSharedSecret(test.private, test.public);
|
||||
deepStrictEqual(shared, test.shared, 'valid');
|
||||
} else if (test.result === 'invalid') {
|
||||
let failed = false;
|
||||
try {
|
||||
CURVE.getSharedSecret(test.private, test.public);
|
||||
} catch (error) {
|
||||
failed = true;
|
||||
}
|
||||
deepStrictEqual(failed, true, 'invalid');
|
||||
} else throw new Error('unknown test result');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
import { default as ecdh_secp224r1_test } from './wycheproof/ecdh_secp224r1_test.json' assert { type: 'json' };
|
||||
import { default as ecdh_secp256r1_test } from './wycheproof/ecdh_secp256r1_test.json' assert { type: 'json' };
|
||||
import { default as ecdh_secp256k1_test } from './wycheproof/ecdh_secp256k1_test.json' assert { type: 'json' };
|
||||
import { default as ecdh_secp384r1_test } from './wycheproof/ecdh_secp384r1_test.json' assert { type: 'json' };
|
||||
import { default as ecdh_secp521r1_test } from './wycheproof/ecdh_secp521r1_test.json' assert { type: 'json' };
|
||||
|
||||
// More per curve tests
|
||||
const WYCHEPROOF_ECDH = {
|
||||
P224: {
|
||||
curve: P224,
|
||||
tests: [ecdh_secp224r1_test],
|
||||
},
|
||||
P256: {
|
||||
curve: P256,
|
||||
tests: [ecdh_secp256r1_test],
|
||||
},
|
||||
secp256k1: {
|
||||
curve: secp256k1,
|
||||
tests: [ecdh_secp256k1_test],
|
||||
},
|
||||
P384: {
|
||||
curve: P384,
|
||||
tests: [ecdh_secp384r1_test],
|
||||
},
|
||||
P521: {
|
||||
curve: P521,
|
||||
tests: [ecdh_secp521r1_test],
|
||||
},
|
||||
};
|
||||
|
||||
for (const name in WYCHEPROOF_ECDH) {
|
||||
const { curve, tests } = WYCHEPROOF_ECDH[name];
|
||||
for (let i = 0; i < tests.length; i++) {
|
||||
const test = tests[i];
|
||||
for (let j = 0; j < test.testGroups.length; j++) {
|
||||
const group = test.testGroups[j];
|
||||
should(`Wycheproof/ECDH ${name} (${i}/${j})`, () => {
|
||||
for (const test of group.tests) {
|
||||
if (test.result === 'valid' || test.result === 'acceptable') {
|
||||
try {
|
||||
const pub = curve.ProjectivePoint.fromHex(test.public);
|
||||
} catch (e) {
|
||||
if (e.message.includes('Point.fromHex: received invalid point.')) continue;
|
||||
throw e;
|
||||
}
|
||||
const shared = curve.getSharedSecret(test.private, test.public);
|
||||
deepStrictEqual(hex(shared), test.shared, 'valid');
|
||||
} else if (test.result === 'invalid') {
|
||||
let failed = false;
|
||||
try {
|
||||
curve.getSharedSecret(test.private, test.public);
|
||||
} catch (error) {
|
||||
failed = true;
|
||||
}
|
||||
deepStrictEqual(failed, true, 'invalid');
|
||||
} else throw new Error('unknown test result');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tests with custom hashes
|
||||
import { default as secp224r1_sha224_test } from './wycheproof/ecdsa_secp224r1_sha224_test.json' assert { type: 'json' };
|
||||
import { default as secp224r1_sha256_test } from './wycheproof/ecdsa_secp224r1_sha256_test.json' assert { type: 'json' };
|
||||
@ -199,6 +46,121 @@ import { sha3_224, sha3_256, sha3_384, sha3_512 } from '@noble/hashes/sha3';
|
||||
import { sha512, sha384 } from '@noble/hashes/sha512';
|
||||
import { sha224, sha256 } from '@noble/hashes/sha256';
|
||||
|
||||
const hex = bytesToHex;
|
||||
|
||||
// prettier-ignore
|
||||
const NIST = {
|
||||
secp192r1, P192,
|
||||
secp224r1, P224,
|
||||
secp256r1, P256,
|
||||
secp384r1, P384,
|
||||
secp521r1, P521,
|
||||
secp256k1,
|
||||
};
|
||||
|
||||
describe('NIST curves', () => {});
|
||||
should('fields', () => {
|
||||
const vectors = {
|
||||
secp192r1: 0xfffffffffffffffffffffffffffffffeffffffffffffffffn,
|
||||
secp224r1: 0xffffffffffffffffffffffffffffffff000000000000000000000001n,
|
||||
secp256r1: 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffffn,
|
||||
secp256k1: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fn,
|
||||
secp384r1:
|
||||
0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffffn,
|
||||
secp521r1:
|
||||
0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn,
|
||||
};
|
||||
for (const n in vectors) deepStrictEqual(NIST[n].CURVE.Fp.ORDER, vectors[n]);
|
||||
});
|
||||
|
||||
describe('wycheproof ECDH', () => {
|
||||
for (const group of ecdh.testGroups) {
|
||||
// // Tested in secp256k1.test.js
|
||||
// if (group.key.curve === 'secp256k1') continue;
|
||||
// We don't have SHA-224
|
||||
const CURVE = NIST[group.curve];
|
||||
if (!CURVE) continue;
|
||||
should(group.curve, () => {
|
||||
for (const test of group.tests) {
|
||||
if (test.result === 'valid' || test.result === 'acceptable') {
|
||||
try {
|
||||
const pub = CURVE.ProjectivePoint.fromHex(test.public);
|
||||
} catch (e) {
|
||||
if (e.message.includes('Point.fromHex: received invalid point.')) continue;
|
||||
throw e;
|
||||
}
|
||||
const shared = CURVE.getSharedSecret(test.private, test.public);
|
||||
deepStrictEqual(shared, test.shared, 'valid');
|
||||
} else if (test.result === 'invalid') {
|
||||
let failed = false;
|
||||
try {
|
||||
CURVE.getSharedSecret(test.private, test.public);
|
||||
} catch (error) {
|
||||
failed = true;
|
||||
}
|
||||
deepStrictEqual(failed, true, 'invalid');
|
||||
} else throw new Error('unknown test result');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// More per curve tests
|
||||
const WYCHEPROOF_ECDH = {
|
||||
P224: {
|
||||
curve: P224,
|
||||
tests: [ecdh_secp224r1_test],
|
||||
},
|
||||
P256: {
|
||||
curve: P256,
|
||||
tests: [ecdh_secp256r1_test],
|
||||
},
|
||||
secp256k1: {
|
||||
curve: secp256k1,
|
||||
tests: [ecdh_secp256k1_test],
|
||||
},
|
||||
P384: {
|
||||
curve: P384,
|
||||
tests: [ecdh_secp384r1_test],
|
||||
},
|
||||
P521: {
|
||||
curve: P521,
|
||||
tests: [ecdh_secp521r1_test],
|
||||
},
|
||||
};
|
||||
|
||||
for (const name in WYCHEPROOF_ECDH) {
|
||||
const { curve, tests } = WYCHEPROOF_ECDH[name];
|
||||
for (let i = 0; i < tests.length; i++) {
|
||||
const test = tests[i];
|
||||
for (let j = 0; j < test.testGroups.length; j++) {
|
||||
const group = test.testGroups[j];
|
||||
should(`additional ${name} (${i}/${j})`, () => {
|
||||
for (const test of group.tests) {
|
||||
if (test.result === 'valid' || test.result === 'acceptable') {
|
||||
try {
|
||||
const pub = curve.ProjectivePoint.fromHex(test.public);
|
||||
} catch (e) {
|
||||
if (e.message.includes('Point.fromHex: received invalid point.')) continue;
|
||||
throw e;
|
||||
}
|
||||
const shared = curve.getSharedSecret(test.private, test.public);
|
||||
deepStrictEqual(hex(shared), test.shared, 'valid');
|
||||
} else if (test.result === 'invalid') {
|
||||
let failed = false;
|
||||
try {
|
||||
curve.getSharedSecret(test.private, test.public);
|
||||
} catch (error) {
|
||||
failed = true;
|
||||
}
|
||||
deepStrictEqual(failed, true, 'invalid');
|
||||
} else throw new Error('unknown test result');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const WYCHEPROOF_ECDSA = {
|
||||
P224: {
|
||||
curve: P224,
|
||||
@ -344,42 +306,85 @@ 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(`${name}/${hName}`, () => {
|
||||
for (let i = 0; i < tests.length; i++) {
|
||||
const groups = tests[i].testGroups;
|
||||
for (let j = 0; j < groups.length; j++) {
|
||||
const group = groups[j];
|
||||
runWycheproof(name, CURVE, group, `${i}/${j}`);
|
||||
}
|
||||
describe('wycheproof ECDSA', () => {
|
||||
should('generic', () => {
|
||||
for (const group of ecdsa.testGroups) {
|
||||
// Tested in secp256k1.test.js
|
||||
if (group.key.curve === 'secp256k1') continue;
|
||||
let CURVE = NIST[group.key.curve];
|
||||
if (!CURVE) continue;
|
||||
if (group.key.curve === 'secp224r1' && group.sha !== 'SHA-224') {
|
||||
if (group.sha === 'SHA-256') CURVE = CURVE.create(sha256);
|
||||
}
|
||||
const pubKey = CURVE.ProjectivePoint.fromHex(group.key.uncompressed);
|
||||
deepStrictEqual(pubKey.x, BigInt(`0x${group.key.wx}`));
|
||||
deepStrictEqual(pubKey.y, BigInt(`0x${group.key.wy}`));
|
||||
for (const test of group.tests) {
|
||||
if (['Hash weaker than DL-group'].includes(test.comment)) {
|
||||
continue;
|
||||
}
|
||||
});
|
||||
const m = CURVE.CURVE.hash(hexToBytes(test.msg));
|
||||
if (test.result === 'valid' || test.result === 'acceptable') {
|
||||
try {
|
||||
CURVE.Signature.fromDER(test.sig);
|
||||
} catch (e) {
|
||||
// Some test has invalid signature which we don't accept
|
||||
if (e.message.includes('Invalid signature: incorrect length')) continue;
|
||||
throw e;
|
||||
}
|
||||
const verified = CURVE.verify(test.sig, m, pubKey.toHex());
|
||||
deepStrictEqual(verified, true, 'valid');
|
||||
} else if (test.result === 'invalid') {
|
||||
let failed = false;
|
||||
try {
|
||||
failed = !CURVE.verify(test.sig, m, pubKey.toHex());
|
||||
} catch (error) {
|
||||
failed = true;
|
||||
}
|
||||
deepStrictEqual(failed, true, 'invalid');
|
||||
} else throw new Error('unknown test result');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
for (const name in WYCHEPROOF_ECDSA) {
|
||||
const { curve, hashes } = WYCHEPROOF_ECDSA[name];
|
||||
describe(name, () => {
|
||||
for (const hName in hashes) {
|
||||
const { hash, tests } = hashes[hName];
|
||||
const CURVE = curve.create(hash);
|
||||
should(`${name}/${hName}`, () => {
|
||||
for (let i = 0; i < tests.length; i++) {
|
||||
const groups = tests[i].testGroups;
|
||||
for (let j = 0; j < groups.length; j++) {
|
||||
const group = groups[j];
|
||||
runWycheproof(name, CURVE, group, `${i}/${j}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const hexToBigint = (hex) => BigInt(`0x${hex}`);
|
||||
should('RFC6979', () => {
|
||||
describe('RFC6979', () => {
|
||||
for (const v of rfc6979) {
|
||||
const curve = NIST[v.curve];
|
||||
deepStrictEqual(curve.CURVE.n, hexToBigint(v.q));
|
||||
const pubKey = curve.getPublicKey(v.private);
|
||||
const pubPoint = curve.ProjectivePoint.fromHex(pubKey);
|
||||
deepStrictEqual(pubPoint.x, hexToBigint(v.Ux));
|
||||
deepStrictEqual(pubPoint.y, hexToBigint(v.Uy));
|
||||
for (const c of v.cases) {
|
||||
const h = curve.CURVE.hash(c.message);
|
||||
const sigObj = curve.sign(h, v.private);
|
||||
deepStrictEqual(sigObj.r, hexToBigint(c.r), 'R');
|
||||
deepStrictEqual(sigObj.s, hexToBigint(c.s), 'S');
|
||||
deepStrictEqual(curve.verify(sigObj.toDERRawBytes(), h, pubKey), true, 'verify(1)');
|
||||
deepStrictEqual(curve.verify(sigObj, h, pubKey), true, 'verify(2)');
|
||||
}
|
||||
should(v.curve, () => {
|
||||
const curve = NIST[v.curve];
|
||||
deepStrictEqual(curve.CURVE.n, hexToBigint(v.q));
|
||||
const pubKey = curve.getPublicKey(v.private);
|
||||
const pubPoint = curve.ProjectivePoint.fromHex(pubKey);
|
||||
deepStrictEqual(pubPoint.x, hexToBigint(v.Ux));
|
||||
deepStrictEqual(pubPoint.y, hexToBigint(v.Uy));
|
||||
for (const c of v.cases) {
|
||||
const h = curve.CURVE.hash(c.message);
|
||||
const sigObj = curve.sign(h, v.private);
|
||||
deepStrictEqual(sigObj.r, hexToBigint(c.r), 'R');
|
||||
deepStrictEqual(sigObj.s, hexToBigint(c.s), 'S');
|
||||
deepStrictEqual(curve.verify(sigObj.toDERRawBytes(), h, pubKey), true, 'verify(1)');
|
||||
deepStrictEqual(curve.verify(sigObj, h, pubKey), true, 'verify(2)');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -279,8 +279,8 @@ describe('secp256k1', () => {
|
||||
});
|
||||
should(' not verify signature with wrong public key', () => {
|
||||
const MSG = '01'.repeat(32);
|
||||
const PRIV_KEY = 0x2n;
|
||||
const WRONG_PRIV_KEY = 0x22n;
|
||||
const PRIV_KEY = '01'.repeat(32);
|
||||
const WRONG_PRIV_KEY = '02'.repeat(32);
|
||||
const signature = secp.sign(MSG, PRIV_KEY);
|
||||
const publicKey = Point.fromPrivateKey(WRONG_PRIV_KEY).toHex();
|
||||
deepStrictEqual(publicKey.length, 66);
|
||||
@ -469,7 +469,7 @@ describe('secp256k1', () => {
|
||||
},
|
||||
|
||||
privateNegate: (privateKey) => {
|
||||
return numberToBytesBE(Fn.negate(normal(privateKey)), 32);
|
||||
return numberToBytesBE(Fn.neg(normal(privateKey)), 32);
|
||||
},
|
||||
|
||||
pointAddScalar: (p, tweak, isCompressed) => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { deepStrictEqual, throws } from 'assert';
|
||||
import { should } from 'micro-should';
|
||||
import { describe, should } from 'micro-should';
|
||||
import * as starknet from '../../lib/esm/stark.js';
|
||||
import * as fs from 'fs';
|
||||
|
||||
@ -64,10 +64,12 @@ function poseidonTest(name, parsed) {
|
||||
});
|
||||
}
|
||||
|
||||
poseidonTest('poseidon3', parsed.poseidon3);
|
||||
poseidonTest('poseidon4', parsed.poseidon4);
|
||||
poseidonTest('poseidon5', parsed.poseidon5);
|
||||
poseidonTest('poseidon9', parsed.poseidon9);
|
||||
describe('poseidon txt vectors', () => {
|
||||
poseidonTest('poseidon3', parsed.poseidon3);
|
||||
poseidonTest('poseidon4', parsed.poseidon4);
|
||||
poseidonTest('poseidon5', parsed.poseidon5);
|
||||
poseidonTest('poseidon9', parsed.poseidon9);
|
||||
});
|
||||
|
||||
should('Poseidon examples', () => {
|
||||
const p3 = mapPoseidon(parsed.poseidon3);
|
||||
|
Loading…
Reference in New Issue
Block a user