diff --git a/curve-definitions/benchmark/index.js b/curve-definitions/benchmark/index.js index 7cdfab6..b9dbe48 100644 --- a/curve-definitions/benchmark/index.js +++ b/curve-definitions/benchmark/index.js @@ -30,19 +30,12 @@ old_secp.utils.hmacSha256Sync = (key, ...msgs) => .update(concatBytes(...msgs)) .digest(); import * as noble_ed25519 from '@noble/ed25519'; - -secp256k1.utils.precompute(8); // Not enabled by default? -ed25519.utils.precompute(8); -ed448.utils.precompute(8); -P256.utils.precompute(8); -P384.utils.precompute(8); -P521.utils.precompute(8); - noble_ed25519.utils.sha512Sync = (...m) => sha512(concatBytes(...m)); -old_secp.utils.precompute(8); -noble_ed25519.utils.precompute(8); -const wrapBuf = (arrayBuffer) => new Uint8Array(arrayBuffer); +for (let item of [secp256k1, ed25519, ed448, P256, P384, P521, old_secp, noble_ed25519]) { + item.utils.precompute(8); +} + const ONLY_NOBLE = process.argv[2] === 'noble'; function generateData(namespace) { @@ -73,17 +66,23 @@ export const CURVES = { secp256k1_old: ({ msg, priv }) => old_secp.signSync(msg, priv), secp256k1: ({ msg, priv }) => secp256k1.sign(msg, priv), }, - getSharedSecret: { - samples: 1000, - secp256k1_old: ({ pub, priv }) => old_secp.getSharedSecret(priv, pub), - secp256k1: ({ pub, priv }) => secp256k1.getSharedSecret(priv, pub), - }, verify: { samples: 1000, secp256k1_old: ({ sig, msg, pub }) => { return old_secp.verify((new old_secp.Signature(sig.r, sig.s)), msg, pub); }, secp256k1: ({ sig, msg, pub }) => secp256k1.verify(sig, msg, pub) + }, + getSharedSecret: { + samples: 1000, + secp256k1_old: ({ pub, priv }) => old_secp.getSharedSecret(priv, pub), + secp256k1: ({ pub, priv }) => secp256k1.getSharedSecret(priv, pub), + }, + recoverPublicKey: { + samples: 1000, + secp256k1_old: ({ sig, msg }) => + old_secp.recoverPublicKey(msg, (new old_secp.Signature(sig.r, sig.s)), sig.recovery), + secp256k1: ({ sig, msg }) => sig.recoverPublicKey(msg) } }, ed25519: { diff --git a/curve-definitions/test/ed25519.test.js b/curve-definitions/test/ed25519.test.js index e0e1da9..7fd0563 100644 --- a/curve-definitions/test/ed25519.test.js +++ b/curve-definitions/test/ed25519.test.js @@ -508,13 +508,14 @@ should('RFC7748 getSharedKey', () => { { const group = x25519vectors.testGroups[0]; - for (let i = 0; i < group.tests.length; i++) { - const v = group.tests[i]; - should(`Wycheproof/X25519(${i}, ${v.result}) ${v.comment}`, () => { + should(`Wycheproof/X25519`, () => { + for (let i = 0; i < group.tests.length; i++) { + const v = group.tests[i]; + const comment = `(${i}, ${v.result}) ${v.comment}`; if (v.result === 'valid' || v.result === 'acceptable') { try { const shared = hex(x25519.scalarMult(v.public, v.private)); - deepStrictEqual(shared, v.shared, 'valid'); + deepStrictEqual(shared, v.shared, comment); } catch (e) { // We are more strict if (e.message.includes('Expected valid scalar')) return; @@ -528,38 +529,35 @@ should('RFC7748 getSharedKey', () => { } catch (error) { failed = true; } - deepStrictEqual(failed, true, 'invalid'); + deepStrictEqual(failed, true, comment); } else throw new Error('unknown test result'); - }); - } + } + }); } -{ +should(`Wycheproof/ED25519`, () => { for (let g = 0; g < ed25519vectors.testGroups.length; g++) { const group = ed25519vectors.testGroups[g]; const key = group.key; - should(`Wycheproof/ED25519(${g}, public)`, () => { - deepStrictEqual(hex(ed.getPublicKey(key.sk)), key.pk); - }); + deepStrictEqual(hex(ed.getPublicKey(key.sk)), key.pk, `(${g}, public)`); for (let i = 0; i < group.tests.length; i++) { const v = group.tests[i]; - should(`Wycheproof/ED25519(${g}/${i}, ${v.result}): ${v.comment}`, () => { - if (v.result === 'valid' || v.result === 'acceptable') { - deepStrictEqual(hex(ed.sign(v.msg, key.sk)), v.sig); - deepStrictEqual(ed.verify(v.sig, v.msg, key.pk), true); - } else if (v.result === 'invalid') { - let failed = false; - try { - failed = !ed.verify(v.sig, v.msg, key.pk); - } catch (error) { - failed = true; - } - deepStrictEqual(failed, true, 'invalid'); - } else throw new Error('unknown test result'); - }); + const comment = `(${g}/${i}, ${v.result}): ${v.comment}`; + if (v.result === 'valid' || v.result === 'acceptable') { + deepStrictEqual(hex(ed.sign(v.msg, key.sk)), v.sig, comment); + deepStrictEqual(ed.verify(v.sig, v.msg, key.pk), true, comment); + } else if (v.result === 'invalid') { + let failed = false; + try { + failed = !ed.verify(v.sig, v.msg, key.pk); + } catch (error) { + failed = true; + } + deepStrictEqual(failed, true, comment); + } else throw new Error('unknown test result'); } } -} +}); should('Property test issue #1', () => { const message = new Uint8Array([12, 12, 12]); diff --git a/curve-definitions/test/ed448.test.js b/curve-definitions/test/ed448.test.js index d0c4fad..fdd851a 100644 --- a/curve-definitions/test/ed448.test.js +++ b/curve-definitions/test/ed448.test.js @@ -439,12 +439,13 @@ should('input immutability: sign/verify are immutable', () => { should(`Wycheproof/ED448(${g}, public)`, () => { deepStrictEqual(hex(ed.getPublicKey(key.sk)), key.pk); }); - for (let i = 0; i < group.tests.length; i++) { - const v = group.tests[i]; - should(`Wycheproof/ED448(${g}/${i}, ${v.result}): ${v.comment}`, () => { + should(`Wycheproof/ED448`, () => { + for (let i = 0; i < group.tests.length; i++) { + const v = group.tests[i]; + const index = `${g}/${i} ${v.comment}`; if (v.result === 'valid' || v.result === 'acceptable') { - deepStrictEqual(hex(ed.sign(v.msg, key.sk)), v.sig); - deepStrictEqual(ed.verify(v.sig, v.msg, key.pk), true); + deepStrictEqual(hex(ed.sign(v.msg, key.sk)), v.sig, index); + deepStrictEqual(ed.verify(v.sig, v.msg, key.pk), true, index); } else if (v.result === 'invalid') { let failed = false; try { @@ -452,10 +453,10 @@ should('input immutability: sign/verify are immutable', () => { } catch (error) { failed = true; } - deepStrictEqual(failed, true, 'invalid'); + deepStrictEqual(failed, true, index); } else throw new Error('unknown test result'); - }); - } + } + }); } } @@ -524,13 +525,14 @@ should('RFC7748 getSharedKey', () => { { const group = x448vectors.testGroups[0]; - for (let i = 0; i < group.tests.length; i++) { - const v = group.tests[i]; - should(`Wycheproof/X448(${i}, ${v.result}) ${v.comment}`, () => { + should(`Wycheproof/X448`, () => { + for (let i = 0; i < group.tests.length; i++) { + const v = group.tests[i]; + const index = `(${i}, ${v.result}) ${v.comment}`; if (v.result === 'valid' || v.result === 'acceptable') { try { const shared = hex(x448.scalarMult(v.public, v.private)); - deepStrictEqual(shared, v.shared, 'valid'); + deepStrictEqual(shared, v.shared, index); } catch (e) { // We are more strict if (e.message.includes('Expected valid scalar')) return; @@ -545,10 +547,10 @@ should('RFC7748 getSharedKey', () => { } catch (error) { failed = true; } - deepStrictEqual(failed, true, 'invalid'); + deepStrictEqual(failed, true, index); } else throw new Error('unknown test result'); - }); - } + } + }); } // should('X448: should convert base point to montgomery using fromPoint', () => { diff --git a/curve-definitions/test/nist.test.js b/curve-definitions/test/nist.test.js index 9fd57db..620a191 100644 --- a/curve-definitions/test/nist.test.js +++ b/curve-definitions/test/nist.test.js @@ -308,49 +308,55 @@ const WYCHEPROOF_ECDSA = { }, }; +function runWycheproof(name, CURVE, group, index) { + const pubKey = CURVE.Point.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) { + const m = CURVE.CURVE.hash(hexToBytes(test.msg)); + + if (test.result === 'valid' || test.result === 'acceptable') { + try { + CURVE.Signature.fromDER(test.sig); + } catch (e) { + // Some tests 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); + if (name === 'secp256k1') { + // lowS: true for secp256k1 + deepStrictEqual(verified, !CURVE.Signature.fromDER(test.sig).hasHighS(), `${index}: valid`); + } else { + deepStrictEqual(verified, true, `${index}: valid`); + } + + } else if (test.result === 'invalid') { + let failed = false; + try { + failed = !CURVE.verify(test.sig, m, pubKey); + } catch (error) { + failed = true; + } + deepStrictEqual(failed, true, `${index}: invalid`); + } else throw new Error('unknown test result'); + } +} + for (const name in WYCHEPROOF_ECDSA) { const { curve, hashes } = WYCHEPROOF_ECDSA[name]; for (const hName in hashes) { const { hash, tests } = hashes[hName]; const CURVE = curve.create(hash); - 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/WYCHEPROOF_ECDSA ${name}/${hName} (${i}/${j})`, () => { - const pubKey = CURVE.Point.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) { - const m = CURVE.CURVE.hash(hexToBytes(test.msg)); - if (test.result === 'valid' || test.result === 'acceptable') { - try { - CURVE.Signature.fromDER(test.sig); - } catch (e) { - // Some tests 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); - if (name === 'secp256k1') { - // lowS: true for secp256k1 - deepStrictEqual(verified, !CURVE.Signature.fromDER(test.sig).hasHighS()); - } else { - deepStrictEqual(verified, true, 'valid'); - } - } else if (test.result === 'invalid') { - let failed = false; - try { - failed = !CURVE.verify(test.sig, m, pubKey); - } catch (error) { - failed = true; - } - deepStrictEqual(failed, true, 'invalid'); - } else throw new Error('unknown test result'); - } - }); + should(`Wycheproof/WYCHEPROOF_ECDSA ${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}`); + } } - } + }); } }