tests of ed25519, ed448: improve
This commit is contained in:
parent
18eabfd3be
commit
37ebe6c40f
@ -1 +1,2 @@
|
|||||||
|
export { numberToBytesLE } from '../esm/abstract/utils.js';
|
||||||
export { ed25519, ED25519_TORSION_SUBGROUP } from '../esm/ed25519.js';
|
export { ed25519, ED25519_TORSION_SUBGROUP } from '../esm/ed25519.js';
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { deepStrictEqual, strictEqual, throws } from 'assert';
|
import { deepStrictEqual, strictEqual, throws } from 'assert';
|
||||||
import { readFileSync } from 'fs';
|
import { readFileSync } from 'fs';
|
||||||
import { hexToBytes, bytesToHex, randomBytes } from '@noble/hashes/utils';
|
import { bytesToHex, concatBytes, hexToBytes, randomBytes } from '@noble/hashes/utils';
|
||||||
import * as fc from 'fast-check';
|
import * as fc from 'fast-check';
|
||||||
import { describe, should } from 'micro-should';
|
import { describe, should } from 'micro-should';
|
||||||
import { ed25519, ED25519_TORSION_SUBGROUP } from './ed25519.helpers.js';
|
import { ed25519, ED25519_TORSION_SUBGROUP, numberToBytesLE } from './ed25519.helpers.js';
|
||||||
import { default as ed25519vectors } from './wycheproof/eddsa_test.json' assert { type: 'json' };
|
import { default as ed25519vectors } from './wycheproof/eddsa_test.json' assert { type: 'json' };
|
||||||
import { default as zip215 } from './ed25519/zip215.json' assert { type: 'json' };
|
import { default as zip215 } from './ed25519/zip215.json' assert { type: 'json' };
|
||||||
|
|
||||||
@ -346,7 +346,7 @@ describe('ed25519', () => {
|
|||||||
// );
|
// );
|
||||||
// });
|
// });
|
||||||
|
|
||||||
should(`Wycheproof/ED25519`, () => {
|
should(`wycheproof/ED25519`, () => {
|
||||||
for (let g = 0; g < ed25519vectors.testGroups.length; g++) {
|
for (let g = 0; g < ed25519vectors.testGroups.length; g++) {
|
||||||
const group = ed25519vectors.testGroups[g];
|
const group = ed25519vectors.testGroups[g];
|
||||||
const key = group.key;
|
const key = group.key;
|
||||||
@ -370,7 +370,7 @@ describe('ed25519', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
should('Property test issue #1', () => {
|
should('not mutate inputs', () => {
|
||||||
const message = new Uint8Array([12, 12, 12]);
|
const message = new Uint8Array([12, 12, 12]);
|
||||||
const signature = ed.sign(message, to32Bytes(1n));
|
const signature = ed.sign(message, to32Bytes(1n));
|
||||||
const publicKey = ed.getPublicKey(to32Bytes(1n)); // <- was 1n
|
const publicKey = ed.getPublicKey(to32Bytes(1n)); // <- was 1n
|
||||||
@ -387,15 +387,35 @@ describe('ed25519', () => {
|
|||||||
strictEqual(cleared.isTorsionFree(), true, `cleared must be torsionFree: ${hex}`);
|
strictEqual(cleared.isTorsionFree(), true, `cleared must be torsionFree: ${hex}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
should('ed25519 bug', () => {
|
should('not verify when sig.s >= CURVE.n', () => {
|
||||||
const t = 81718630521762619991978402609047527194981150691135404693881672112315521837062n;
|
const privateKey = ed25519.utils.randomPrivateKey();
|
||||||
const point = ed25519.ExtendedPoint.fromAffine({ x: t, y: t });
|
const message = Uint8Array.from([0xab, 0xbc, 0xcd, 0xde]);
|
||||||
throws(() => point.assertValidity());
|
const publicKey = ed25519.getPublicKey(privateKey);
|
||||||
// Otherwise (without assertValidity):
|
const signature = ed25519.sign(message, privateKey);
|
||||||
// const point2 = point.double();
|
|
||||||
// point2.toAffine(); // crash!
|
const R = signature.slice(0, 32);
|
||||||
|
let s = signature.slice(32, 64);
|
||||||
|
|
||||||
|
s = bytesToHex(s.slice().reverse());
|
||||||
|
s = BigInt('0x' + s);
|
||||||
|
s = s + ed25519.CURVE.n;
|
||||||
|
s = numberToBytesLE(s, 32);
|
||||||
|
|
||||||
|
const sig_invalid = concatBytes(R, s);
|
||||||
|
throws(() => {
|
||||||
|
ed25519.verify(sig_invalid, message, publicKey);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
should('not accept point without z, t', () => {
|
||||||
|
const t = 81718630521762619991978402609047527194981150691135404693881672112315521837062n;
|
||||||
|
const point = ed25519.ExtendedPoint.fromAffine({ x: t, y: t });
|
||||||
|
throws(() => point.assertValidity());
|
||||||
|
// Otherwise (without assertValidity):
|
||||||
|
// const point2 = point.double();
|
||||||
|
// point2.toAffine(); // crash!
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// ESM is broken.
|
// ESM is broken.
|
||||||
|
@ -2,7 +2,7 @@ import { deepStrictEqual, throws } from 'assert';
|
|||||||
import { describe, should } from 'micro-should';
|
import { describe, should } from 'micro-should';
|
||||||
import * as fc from 'fast-check';
|
import * as fc from 'fast-check';
|
||||||
import { ed448, ed448ph, x448 } from '../esm/ed448.js';
|
import { ed448, ed448ph, x448 } from '../esm/ed448.js';
|
||||||
import { hexToBytes, bytesToHex, randomBytes } from '@noble/hashes/utils';
|
import { bytesToHex, concatBytes, hexToBytes, randomBytes } from '@noble/hashes/utils';
|
||||||
import { numberToBytesLE } from '../esm/abstract/utils.js';
|
import { numberToBytesLE } from '../esm/abstract/utils.js';
|
||||||
import { default as ed448vectors } from './wycheproof/ed448_test.json' assert { type: 'json' };
|
import { default as ed448vectors } from './wycheproof/ed448_test.json' assert { type: 'json' };
|
||||||
import { default as x448vectors } from './wycheproof/x448_test.json' assert { type: 'json' };
|
import { default as x448vectors } from './wycheproof/x448_test.json' assert { type: 'json' };
|
||||||
@ -467,101 +467,6 @@ describe('ed448', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// ECDH
|
|
||||||
const rfc7748Mul = [
|
|
||||||
{
|
|
||||||
scalar:
|
|
||||||
'3d262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3',
|
|
||||||
u: '06fce640fa3487bfda5f6cf2d5263f8aad88334cbd07437f020f08f9814dc031ddbdc38c19c6da2583fa5429db94ada18aa7a7fb4ef8a086',
|
|
||||||
outputU:
|
|
||||||
'ce3e4ff95a60dc6697da1db1d85e6afbdf79b50a2412d7546d5f239fe14fbaadeb445fc66a01b0779d98223961111e21766282f73dd96b6f',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scalar:
|
|
||||||
'203d494428b8399352665ddca42f9de8fef600908e0d461cb021f8c538345dd77c3e4806e25f46d3315c44e0a5b4371282dd2c8d5be3095f',
|
|
||||||
u: '0fbcc2f993cd56d3305b0b7d9e55d4c1a8fb5dbb52f8e9a1e9b6201b165d015894e56c4d3570bee52fe205e28a78b91cdfbde71ce8d157db',
|
|
||||||
outputU:
|
|
||||||
'884a02576239ff7a2f2f63b2db6a9ff37047ac13568e1e30fe63c4a7ad1b3ee3a5700df34321d62077e63633c575c1c954514e99da7c179d',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
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 = [
|
|
||||||
{
|
|
||||||
scalar:
|
|
||||||
'3f482c8a9f19b01e6c46ee9711d9dc14fd4bf67af30765c2ae2b846a4d23a8cd0db897086239492caf350b51f833868b9bc2b3bca9cf4113',
|
|
||||||
iters: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scalar:
|
|
||||||
'aa3b4749d55b9daf1e5b00288826c467274ce3ebbdd5c17b975e09d4af6c67cf10d087202db88286e2b79fceea3ec353ef54faa26e219f38',
|
|
||||||
iters: 1000,
|
|
||||||
},
|
|
||||||
// { scalar: '077f453681caca3693198420bbe515cae0002472519b3e67661a7e89cab94695c8f4bcd66e61b9b9c946da8d524de3d69bd9d9d66b997e37', iters: 1000000 },
|
|
||||||
];
|
|
||||||
for (let i = 0; i < rfc7748Iter.length; i++) {
|
|
||||||
const { scalar, iters } = rfc7748Iter[i];
|
|
||||||
should(`RFC7748: scalarMult iteration (${i})`, () => {
|
|
||||||
let k = x448.GuBytes;
|
|
||||||
for (let i = 0, u = k; i < iters; i++) [k, u] = [x448.scalarMult(k, u), k];
|
|
||||||
deepStrictEqual(hex(k), scalar);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
should('RFC7748 getSharedKey', () => {
|
|
||||||
const alicePrivate =
|
|
||||||
'9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b';
|
|
||||||
const alicePublic =
|
|
||||||
'9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0';
|
|
||||||
const bobPrivate =
|
|
||||||
'1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d';
|
|
||||||
const bobPublic =
|
|
||||||
'3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b43027d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609';
|
|
||||||
const shared =
|
|
||||||
'07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d';
|
|
||||||
deepStrictEqual(alicePublic, hex(x448.getPublicKey(alicePrivate)));
|
|
||||||
deepStrictEqual(bobPublic, hex(x448.getPublicKey(bobPrivate)));
|
|
||||||
deepStrictEqual(hex(x448.scalarMult(alicePrivate, bobPublic)), shared);
|
|
||||||
deepStrictEqual(hex(x448.scalarMult(bobPrivate, alicePublic)), shared);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('wycheproof', () => {
|
|
||||||
const group = x448vectors.testGroups[0];
|
|
||||||
should(`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.private, v.public));
|
|
||||||
deepStrictEqual(shared, v.shared, index);
|
|
||||||
} catch (e) {
|
|
||||||
// We are more strict
|
|
||||||
if (e.message.includes('Expected valid scalar')) return;
|
|
||||||
if (e.message.includes('Invalid private or public key received')) return;
|
|
||||||
if (e.message.includes('Expected 56 bytes')) return;
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
} else if (v.result === 'invalid') {
|
|
||||||
let failed = false;
|
|
||||||
try {
|
|
||||||
x448.scalarMult(v.private, v.public);
|
|
||||||
} catch (error) {
|
|
||||||
failed = true;
|
|
||||||
}
|
|
||||||
deepStrictEqual(failed, true, index);
|
|
||||||
} else throw new Error('unknown test result');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// should('X448: should convert base point to montgomery using fromPoint', () => {
|
// should('X448: should convert base point to montgomery using fromPoint', () => {
|
||||||
// deepStrictEqual(
|
// deepStrictEqual(
|
||||||
// hex(ed.montgomeryCurve.UfromPoint(Point.BASE)),
|
// hex(ed.montgomeryCurve.UfromPoint(Point.BASE)),
|
||||||
@ -584,87 +489,204 @@ describe('ed448', () => {
|
|||||||
// }
|
// }
|
||||||
// });
|
// });
|
||||||
|
|
||||||
const VECTORS_RFC8032_CTX = [
|
describe('ed448ctx', () => {
|
||||||
{
|
const VECTORS_RFC8032_CTX = [
|
||||||
secretKey:
|
{
|
||||||
'c4eab05d357007c632f3dbb48489924d552b08fe0c353a0d4a1f00acda2c463afbea67c5e8d2877c5e3bc397a659949ef8021e954e0a12274e',
|
secretKey:
|
||||||
publicKey:
|
'c4eab05d357007c632f3dbb48489924d552b08fe0c353a0d4a1f00acda2c463afbea67c5e8d2877c5e3bc397a659949ef8021e954e0a12274e',
|
||||||
'43ba28f430cdff456ae531545f7ecd0ac834a55d9358c0372bfa0c6c6798c0866aea01eb00742802b8438ea4cb82169c235160627b4c3a9480',
|
publicKey:
|
||||||
message: '03',
|
'43ba28f430cdff456ae531545f7ecd0ac834a55d9358c0372bfa0c6c6798c0866aea01eb00742802b8438ea4cb82169c235160627b4c3a9480',
|
||||||
context: '666f6f',
|
message: '03',
|
||||||
signature:
|
context: '666f6f',
|
||||||
'd4f8f6131770dd46f40867d6fd5d5055' +
|
signature:
|
||||||
'de43541f8c5e35abbcd001b32a89f7d2' +
|
'd4f8f6131770dd46f40867d6fd5d5055' +
|
||||||
'151f7647f11d8ca2ae279fb842d60721' +
|
'de43541f8c5e35abbcd001b32a89f7d2' +
|
||||||
'7fce6e042f6815ea000c85741de5c8da' +
|
'151f7647f11d8ca2ae279fb842d60721' +
|
||||||
'1144a6a1aba7f96de42505d7a7298524' +
|
'7fce6e042f6815ea000c85741de5c8da' +
|
||||||
'fda538fccbbb754f578c1cad10d54d0d' +
|
'1144a6a1aba7f96de42505d7a7298524' +
|
||||||
'5428407e85dcbc98a49155c13764e66c' +
|
'fda538fccbbb754f578c1cad10d54d0d' +
|
||||||
'3c00',
|
'5428407e85dcbc98a49155c13764e66c' +
|
||||||
},
|
'3c00',
|
||||||
];
|
},
|
||||||
|
];
|
||||||
|
for (let i = 0; i < VECTORS_RFC8032_CTX.length; i++) {
|
||||||
|
const v = VECTORS_RFC8032_CTX[i];
|
||||||
|
should(`${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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
for (let i = 0; i < VECTORS_RFC8032_CTX.length; i++) {
|
describe('ed448ph', () => {
|
||||||
const v = VECTORS_RFC8032_CTX[i];
|
const VECTORS_RFC8032_PH = [
|
||||||
should(`RFC8032ctx/${i}`, () => {
|
{
|
||||||
deepStrictEqual(hex(ed.getPublicKey(v.secretKey)), v.publicKey);
|
secretKey:
|
||||||
deepStrictEqual(hex(ed.sign(v.message, v.secretKey, v.context)), v.signature);
|
'833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42ef7822e0d5104127dc05d6dbefde69e3ab2cec7c867c6e2c49',
|
||||||
deepStrictEqual(ed.verify(v.signature, v.message, v.publicKey, v.context), true);
|
publicKey:
|
||||||
|
'259b71c19f83ef77a7abd26524cbdb3161b590a48f7d17de3ee0ba9c52beb743c09428a131d6b1b57303d90d8132c276d5ed3d5d01c0f53880',
|
||||||
|
message: '616263',
|
||||||
|
signature:
|
||||||
|
'822f6901f7480f3d5f562c592994d969' +
|
||||||
|
'3602875614483256505600bbc281ae38' +
|
||||||
|
'1f54d6bce2ea911574932f52a4e6cadd' +
|
||||||
|
'78769375ec3ffd1b801a0d9b3f4030cd' +
|
||||||
|
'433964b6457ea39476511214f97469b5' +
|
||||||
|
'7dd32dbc560a9a94d00bff07620464a3' +
|
||||||
|
'ad203df7dc7ce360c3cd3696d9d9fab9' +
|
||||||
|
'0f00',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
secretKey:
|
||||||
|
'833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42ef7822e0d5104127dc05d6dbefde69e3ab2cec7c867c6e2c49',
|
||||||
|
publicKey:
|
||||||
|
'259b71c19f83ef77a7abd26524cbdb3161b590a48f7d17de3ee0ba9c52beb743c09428a131d6b1b57303d90d8132c276d5ed3d5d01c0f53880',
|
||||||
|
message: '616263',
|
||||||
|
context: '666f6f',
|
||||||
|
signature:
|
||||||
|
'c32299d46ec8ff02b54540982814dce9' +
|
||||||
|
'a05812f81962b649d528095916a2aa48' +
|
||||||
|
'1065b1580423ef927ecf0af5888f90da' +
|
||||||
|
'0f6a9a85ad5dc3f280d91224ba9911a3' +
|
||||||
|
'653d00e484e2ce232521481c8658df30' +
|
||||||
|
'4bb7745a73514cdb9bf3e15784ab7128' +
|
||||||
|
'4f8d0704a608c54a6b62d97beb511d13' +
|
||||||
|
'2100',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
for (let i = 0; i < VECTORS_RFC8032_PH.length; i++) {
|
||||||
|
const v = VECTORS_RFC8032_PH[i];
|
||||||
|
should(`${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('not verify when sig.s >= CURVE.n', () => {
|
||||||
|
const privateKey = ed448.utils.randomPrivateKey();
|
||||||
|
const message = Uint8Array.from([0xab, 0xbc, 0xcd, 0xde]);
|
||||||
|
const publicKey = ed448.getPublicKey(privateKey);
|
||||||
|
const signature = ed448.sign(message, privateKey);
|
||||||
|
|
||||||
|
const R = signature.slice(0, 56);
|
||||||
|
let s = signature.slice(56, 112);
|
||||||
|
|
||||||
|
s = bytesToHex(s.slice().reverse());
|
||||||
|
s = BigInt('0x' + s);
|
||||||
|
s = s + ed448.CURVE.n;
|
||||||
|
s = numberToBytesLE(s, 56);
|
||||||
|
|
||||||
|
const sig_invalid = concatBytes(R, s);
|
||||||
|
throws(() => {
|
||||||
|
ed448.verify(sig_invalid, message, publicKey);
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
|
|
||||||
const VECTORS_RFC8032_PH = [
|
describe('RFC7748 X448 ECDH', () => {
|
||||||
{
|
// ECDH
|
||||||
secretKey:
|
const rfc7748Mul = [
|
||||||
'833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42ef7822e0d5104127dc05d6dbefde69e3ab2cec7c867c6e2c49',
|
{
|
||||||
publicKey:
|
scalar:
|
||||||
'259b71c19f83ef77a7abd26524cbdb3161b590a48f7d17de3ee0ba9c52beb743c09428a131d6b1b57303d90d8132c276d5ed3d5d01c0f53880',
|
'3d262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3',
|
||||||
message: '616263',
|
u: '06fce640fa3487bfda5f6cf2d5263f8aad88334cbd07437f020f08f9814dc031ddbdc38c19c6da2583fa5429db94ada18aa7a7fb4ef8a086',
|
||||||
signature:
|
outputU:
|
||||||
'822f6901f7480f3d5f562c592994d969' +
|
'ce3e4ff95a60dc6697da1db1d85e6afbdf79b50a2412d7546d5f239fe14fbaadeb445fc66a01b0779d98223961111e21766282f73dd96b6f',
|
||||||
'3602875614483256505600bbc281ae38' +
|
},
|
||||||
'1f54d6bce2ea911574932f52a4e6cadd' +
|
{
|
||||||
'78769375ec3ffd1b801a0d9b3f4030cd' +
|
scalar:
|
||||||
'433964b6457ea39476511214f97469b5' +
|
'203d494428b8399352665ddca42f9de8fef600908e0d461cb021f8c538345dd77c3e4806e25f46d3315c44e0a5b4371282dd2c8d5be3095f',
|
||||||
'7dd32dbc560a9a94d00bff07620464a3' +
|
u: '0fbcc2f993cd56d3305b0b7d9e55d4c1a8fb5dbb52f8e9a1e9b6201b165d015894e56c4d3570bee52fe205e28a78b91cdfbde71ce8d157db',
|
||||||
'ad203df7dc7ce360c3cd3696d9d9fab9' +
|
outputU:
|
||||||
'0f00',
|
'884a02576239ff7a2f2f63b2db6a9ff37047ac13568e1e30fe63c4a7ad1b3ee3a5700df34321d62077e63633c575c1c954514e99da7c179d',
|
||||||
},
|
},
|
||||||
{
|
];
|
||||||
secretKey:
|
for (let i = 0; i < rfc7748Mul.length; i++) {
|
||||||
'833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42ef7822e0d5104127dc05d6dbefde69e3ab2cec7c867c6e2c49',
|
const v = rfc7748Mul[i];
|
||||||
publicKey:
|
should(`scalarMult (${i})`, () => {
|
||||||
'259b71c19f83ef77a7abd26524cbdb3161b590a48f7d17de3ee0ba9c52beb743c09428a131d6b1b57303d90d8132c276d5ed3d5d01c0f53880',
|
deepStrictEqual(hex(x448.scalarMult(v.scalar, v.u)), v.outputU);
|
||||||
message: '616263',
|
});
|
||||||
context: '666f6f',
|
}
|
||||||
signature:
|
|
||||||
'c32299d46ec8ff02b54540982814dce9' +
|
|
||||||
'a05812f81962b649d528095916a2aa48' +
|
|
||||||
'1065b1580423ef927ecf0af5888f90da' +
|
|
||||||
'0f6a9a85ad5dc3f280d91224ba9911a3' +
|
|
||||||
'653d00e484e2ce232521481c8658df30' +
|
|
||||||
'4bb7745a73514cdb9bf3e15784ab7128' +
|
|
||||||
'4f8d0704a608c54a6b62d97beb511d13' +
|
|
||||||
'2100',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
for (let i = 0; i < VECTORS_RFC8032_PH.length; i++) {
|
const rfc7748Iter = [
|
||||||
const v = VECTORS_RFC8032_PH[i];
|
{
|
||||||
should(`RFC8032ph/${i}`, () => {
|
scalar:
|
||||||
deepStrictEqual(hex(ed448ph.getPublicKey(v.secretKey)), v.publicKey);
|
'3f482c8a9f19b01e6c46ee9711d9dc14fd4bf67af30765c2ae2b846a4d23a8cd0db897086239492caf350b51f833868b9bc2b3bca9cf4113',
|
||||||
deepStrictEqual(hex(ed448ph.sign(v.message, v.secretKey, v.context)), v.signature);
|
iters: 1,
|
||||||
deepStrictEqual(ed448ph.verify(v.signature, v.message, v.publicKey, v.context), true);
|
},
|
||||||
|
{
|
||||||
|
scalar:
|
||||||
|
'aa3b4749d55b9daf1e5b00288826c467274ce3ebbdd5c17b975e09d4af6c67cf10d087202db88286e2b79fceea3ec353ef54faa26e219f38',
|
||||||
|
iters: 1000,
|
||||||
|
},
|
||||||
|
// { scalar: '077f453681caca3693198420bbe515cae0002472519b3e67661a7e89cab94695c8f4bcd66e61b9b9c946da8d524de3d69bd9d9d66b997e37', iters: 1000000 },
|
||||||
|
];
|
||||||
|
for (let i = 0; i < rfc7748Iter.length; i++) {
|
||||||
|
const { scalar, iters } = rfc7748Iter[i];
|
||||||
|
should(`scalarMult iterated ${iters}x`, () => {
|
||||||
|
let k = x448.GuBytes;
|
||||||
|
for (let i = 0, u = k; i < iters; i++) [k, u] = [x448.scalarMult(k, u), k];
|
||||||
|
deepStrictEqual(hex(k), scalar);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
should('getSharedKey', () => {
|
||||||
|
const alicePrivate =
|
||||||
|
'9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b';
|
||||||
|
const alicePublic =
|
||||||
|
'9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0';
|
||||||
|
const bobPrivate =
|
||||||
|
'1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d';
|
||||||
|
const bobPublic =
|
||||||
|
'3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b43027d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609';
|
||||||
|
const shared =
|
||||||
|
'07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d';
|
||||||
|
deepStrictEqual(alicePublic, hex(x448.getPublicKey(alicePrivate)));
|
||||||
|
deepStrictEqual(bobPublic, hex(x448.getPublicKey(bobPrivate)));
|
||||||
|
deepStrictEqual(hex(x448.scalarMult(alicePrivate, bobPublic)), shared);
|
||||||
|
deepStrictEqual(hex(x448.scalarMult(bobPrivate, alicePublic)), shared);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
should('X448 base point', () => {
|
describe('wycheproof', () => {
|
||||||
const { x, y } = Point.BASE;
|
const group = x448vectors.testGroups[0];
|
||||||
const { Fp } = ed448.CURVE;
|
should(`X448`, () => {
|
||||||
// const invX = Fp.invert(x * x); // x²
|
for (let i = 0; i < group.tests.length; i++) {
|
||||||
const u = Fp.div(Fp.create(y * y), Fp.create(x * x)); // (y²/x²)
|
const v = group.tests[i];
|
||||||
// const u = Fp.create(y * y * invX);
|
const index = `(${i}, ${v.result}) ${v.comment}`;
|
||||||
deepStrictEqual(numberToBytesLE(u, 56), x448.GuBytes);
|
if (v.result === 'valid' || v.result === 'acceptable') {
|
||||||
|
try {
|
||||||
|
const shared = hex(x448.scalarMult(v.private, v.public));
|
||||||
|
deepStrictEqual(shared, v.shared, index);
|
||||||
|
} catch (e) {
|
||||||
|
// We are more strict
|
||||||
|
if (e.message.includes('Expected valid scalar')) return;
|
||||||
|
if (e.message.includes('Invalid private or public key received')) return;
|
||||||
|
if (e.message.includes('Expected 56 bytes')) return;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} else if (v.result === 'invalid') {
|
||||||
|
let failed = false;
|
||||||
|
try {
|
||||||
|
x448.scalarMult(v.private, v.public);
|
||||||
|
} catch (error) {
|
||||||
|
failed = true;
|
||||||
|
}
|
||||||
|
deepStrictEqual(failed, true, index);
|
||||||
|
} else throw new Error('unknown test result');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
should('have proper base point', () => {
|
||||||
|
const { x, y } = 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(numberToBytesLE(u, 56), x448.GuBytes);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user