forked from tornado-packages/noble-curves
weierstrass: prehash option in sign/verify. Remove _normalizePublicKey
This commit is contained in:
parent
849dc38f3c
commit
5fc38fc0e7
@ -85,7 +85,8 @@ const DER = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type Entropy = Hex | true;
|
type Entropy = Hex | true;
|
||||||
export type SignOpts = { lowS?: boolean; extraEntropy?: Entropy };
|
export type SignOpts = { lowS?: boolean; extraEntropy?: Entropy; prehash?: boolean };
|
||||||
|
export type VerOpts = { lowS?: boolean; prehash?: boolean };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ### Design rationale for types
|
* ### Design rationale for types
|
||||||
@ -214,8 +215,7 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
|
|||||||
return typeof num === 'bigint' && _0n < num && num < CURVE.n;
|
return typeof num === 'bigint' && _0n < num && num < CURVE.n;
|
||||||
}
|
}
|
||||||
function assertGE(num: bigint) {
|
function assertGE(num: bigint) {
|
||||||
if (!isWithinCurveOrder(num))
|
if (!isWithinCurveOrder(num)) throw new Error('Expected valid bigint: 0 < bigint < curve.n');
|
||||||
throw new TypeError('Expected valid bigint: 0 < bigint < curve.n');
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Validates if a private key is valid and converts it to bigint form.
|
* Validates if a private key is valid and converts it to bigint form.
|
||||||
@ -240,7 +240,7 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
|
|||||||
if (key.length !== groupLen) throw new Error(`Private key must be ${groupLen} bytes`);
|
if (key.length !== groupLen) throw new Error(`Private key must be ${groupLen} bytes`);
|
||||||
num = ut.bytesToNumberBE(key);
|
num = ut.bytesToNumberBE(key);
|
||||||
} else {
|
} else {
|
||||||
throw new TypeError('Private key was invalid');
|
throw new Error('Private key was invalid');
|
||||||
}
|
}
|
||||||
// Useful for curves with cofactor != 1
|
// Useful for curves with cofactor != 1
|
||||||
if (wrapPrivateKey) num = mod.mod(num, order);
|
if (wrapPrivateKey) num = mod.mod(num, order);
|
||||||
@ -588,7 +588,7 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
|
|||||||
const wnaf = wNAF(ProjectivePoint, CURVE.endo ? Math.ceil(_bits / 2) : _bits);
|
const wnaf = wNAF(ProjectivePoint, CURVE.endo ? Math.ceil(_bits / 2) : _bits);
|
||||||
|
|
||||||
function assertPrjPoint(other: unknown) {
|
function assertPrjPoint(other: unknown) {
|
||||||
if (!(other instanceof ProjectivePoint)) throw new TypeError('ProjectivePoint expected');
|
if (!(other instanceof ProjectivePoint)) throw new Error('ProjectivePoint expected');
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
ProjectivePoint: ProjectivePoint as ProjectiveConstructor<T>,
|
ProjectivePoint: ProjectivePoint as ProjectiveConstructor<T>,
|
||||||
@ -648,24 +648,15 @@ function validateOpts(curve: CurveType) {
|
|||||||
export type CurveFn = {
|
export type CurveFn = {
|
||||||
CURVE: ReturnType<typeof validateOpts>;
|
CURVE: ReturnType<typeof validateOpts>;
|
||||||
getPublicKey: (privateKey: PrivKey, isCompressed?: boolean) => Uint8Array;
|
getPublicKey: (privateKey: PrivKey, isCompressed?: boolean) => Uint8Array;
|
||||||
getSharedSecret: (privateA: PrivKey, publicB: PubKey, isCompressed?: boolean) => Uint8Array;
|
getSharedSecret: (privateA: PrivKey, publicB: Hex, isCompressed?: boolean) => Uint8Array;
|
||||||
sign: (msgHash: Hex, privKey: PrivKey, opts?: SignOpts) => SignatureType;
|
sign: (msgHash: Hex, privKey: PrivKey, opts?: SignOpts) => SignatureType;
|
||||||
signUnhashed: (msg: Uint8Array, privKey: PrivKey, opts?: SignOpts) => SignatureType;
|
verify: (signature: Hex | SignatureType, msgHash: Hex, publicKey: Hex, opts?: VerOpts) => boolean;
|
||||||
verify: (
|
|
||||||
signature: Hex | SignatureType,
|
|
||||||
msgHash: Hex,
|
|
||||||
publicKey: PubKey,
|
|
||||||
opts?: {
|
|
||||||
lowS?: boolean;
|
|
||||||
}
|
|
||||||
) => boolean;
|
|
||||||
ProjectivePoint: ProjectiveConstructor<bigint>;
|
ProjectivePoint: ProjectiveConstructor<bigint>;
|
||||||
Signature: SignatureConstructor;
|
Signature: SignatureConstructor;
|
||||||
utils: {
|
utils: {
|
||||||
_bigintToBytes: (num: bigint) => Uint8Array;
|
_bigintToBytes: (num: bigint) => Uint8Array;
|
||||||
_bigintToString: (num: bigint) => string;
|
_bigintToString: (num: bigint) => string;
|
||||||
_normalizePrivateKey: (key: PrivKey) => bigint;
|
_normalizePrivateKey: (key: PrivKey) => bigint;
|
||||||
_normalizePublicKey: (publicKey: PubKey) => ProjectivePointType<bigint>;
|
|
||||||
_isWithinCurveOrder: (num: bigint) => boolean;
|
_isWithinCurveOrder: (num: bigint) => boolean;
|
||||||
_isValidFieldElement: (num: bigint) => boolean;
|
_isValidFieldElement: (num: bigint) => boolean;
|
||||||
_weierstrassEquation: (x: bigint) => bigint;
|
_weierstrassEquation: (x: bigint) => bigint;
|
||||||
@ -793,19 +784,6 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
}
|
}
|
||||||
const numToFieldStr = (num: bigint): string => bytesToHex(numToField(num));
|
const numToFieldStr = (num: bigint): string => bytesToHex(numToField(num));
|
||||||
|
|
||||||
/**
|
|
||||||
* Normalizes hex, bytes, Point to Point. Checks for curve equation.
|
|
||||||
*/
|
|
||||||
function normalizePublicKey(publicKey: PubKey): ProjectivePointType<bigint> {
|
|
||||||
if (publicKey instanceof Point) {
|
|
||||||
publicKey.assertValidity();
|
|
||||||
return publicKey;
|
|
||||||
} else if (publicKey instanceof Uint8Array || typeof publicKey === 'string') {
|
|
||||||
return Point.fromHex(publicKey);
|
|
||||||
// This can happen because PointType can be instance of different class
|
|
||||||
} else throw new Error(`Unknown type of public key: ${publicKey}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isBiggerThanHalfOrder(number: bigint) {
|
function isBiggerThanHalfOrder(number: bigint) {
|
||||||
const HALF = CURVE_ORDER >> _1n;
|
const HALF = CURVE_ORDER >> _1n;
|
||||||
return number > HALF;
|
return number > HALF;
|
||||||
@ -837,7 +815,7 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
static fromDER(hex: Hex) {
|
static fromDER(hex: Hex) {
|
||||||
const arr = hex instanceof Uint8Array;
|
const arr = hex instanceof Uint8Array;
|
||||||
if (typeof hex !== 'string' && !arr)
|
if (typeof hex !== 'string' && !arr)
|
||||||
throw new TypeError(`Signature.fromDER: Expected string or Uint8Array`);
|
throw new Error(`Signature.fromDER: Expected string or Uint8Array`);
|
||||||
const { r, s } = DER.parseSig(arr ? hex : ut.hexToBytes(hex));
|
const { r, s } = DER.parseSig(arr ? hex : ut.hexToBytes(hex));
|
||||||
return new Signature(r, s);
|
return new Signature(r, s);
|
||||||
}
|
}
|
||||||
@ -852,35 +830,19 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
return new Signature(this.r, this.s, recovery);
|
return new Signature(this.r, this.s, recovery);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Recovers public key from signature with recovery bit. Throws on invalid hash.
|
|
||||||
* https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm#Public_key_recovery
|
|
||||||
* It's also possible to recover key without bit: try all 4 bit values and check for sig match.
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
* recover(r, s, h) where
|
|
||||||
* u1 = hs^-1 mod n
|
|
||||||
* u2 = sr^-1 mod n
|
|
||||||
* Q = u1⋅G + u2⋅R
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @param msgHash message hash
|
|
||||||
* @returns Point corresponding to public key
|
|
||||||
*/
|
|
||||||
recoverPublicKey(msgHash: Hex): typeof Point.BASE {
|
recoverPublicKey(msgHash: Hex): typeof Point.BASE {
|
||||||
const { n: N } = CURVE;
|
const { n: N } = CURVE; // ECDSA public key recovery secg.org/sec1-v2.pdf 4.1.6
|
||||||
const { r, s, recovery: rec } = this;
|
const { r, s, recovery: rec } = this;
|
||||||
const h = bits2int_modN(ut.ensureBytes(msgHash));
|
const h = bits2int_modN(ut.ensureBytes(msgHash)); // Truncate hash
|
||||||
if (rec == null || ![0, 1, 2, 3].includes(rec)) throw new Error('recovery id invalid');
|
if (rec == null || ![0, 1, 2, 3].includes(rec)) throw new Error('recovery id invalid');
|
||||||
const radj = rec === 2 || rec === 3 ? r + N : r;
|
const radj = rec === 2 || rec === 3 ? r + N : r;
|
||||||
if (radj >= Fp.ORDER) throw new Error('recovery id 2 or 3 currently invalid');
|
if (radj >= Fp.ORDER) throw new Error('recovery id 2 or 3 invalid');
|
||||||
const prefix = (rec & 1) === 0 ? '02' : '03';
|
const prefix = (rec & 1) === 0 ? '02' : '03';
|
||||||
const R = Point.fromHex(prefix + numToFieldStr(radj));
|
const R = Point.fromHex(prefix + numToFieldStr(radj));
|
||||||
const ir = mod.invert(radj, N); // r^-1
|
const ir = mod.invert(radj, N); // r^-1
|
||||||
const u1 = mod.mod(-h * ir, N); // -hr^-1
|
const u1 = mod.mod(-h * ir, N); // -hr^-1
|
||||||
const u2 = mod.mod(s * ir, N); // sr^-1
|
const u2 = mod.mod(s * ir, N); // sr^-1
|
||||||
// (sr^-1)R-(hr^-1)G = -(hr^-1)G + (sr^-1)
|
const Q = Point.BASE.multiplyAndAddUnsafe(R, u1, u2); // (sr^-1)R-(hr^-1)G = -(hr^-1)G + (sr^-1)
|
||||||
const Q = Point.BASE.multiplyAndAddUnsafe(R, u1, u2);
|
|
||||||
if (!Q) throw new Error('point at infinify'); // unsafe is fine: no priv data leaked
|
if (!Q) throw new Error('point at infinify'); // unsafe is fine: no priv data leaked
|
||||||
Q.assertValidity();
|
Q.assertValidity();
|
||||||
return Q;
|
return Q;
|
||||||
@ -938,7 +900,6 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
_bigintToBytes: numToField,
|
_bigintToBytes: numToField,
|
||||||
_bigintToString: numToFieldStr,
|
_bigintToString: numToFieldStr,
|
||||||
_normalizePrivateKey: normalizePrivateKey,
|
_normalizePrivateKey: normalizePrivateKey,
|
||||||
_normalizePublicKey: normalizePublicKey,
|
|
||||||
_isWithinCurveOrder: isWithinCurveOrder,
|
_isWithinCurveOrder: isWithinCurveOrder,
|
||||||
_isValidFieldElement: isValidFieldElement,
|
_isValidFieldElement: isValidFieldElement,
|
||||||
_weierstrassEquation: weierstrassEquation,
|
_weierstrassEquation: weierstrassEquation,
|
||||||
@ -1002,11 +963,10 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
* @param isCompressed whether to return compact (default), or full key
|
* @param isCompressed whether to return compact (default), or full key
|
||||||
* @returns shared public key
|
* @returns shared public key
|
||||||
*/
|
*/
|
||||||
function getSharedSecret(privateA: PrivKey, publicB: PubKey, isCompressed = true): Uint8Array {
|
function getSharedSecret(privateA: PrivKey, publicB: Hex, isCompressed = true): Uint8Array {
|
||||||
if (isProbPub(privateA)) throw new TypeError('getSharedSecret: first arg must be private key');
|
if (isProbPub(privateA)) throw new Error('first arg must be private key');
|
||||||
if (!isProbPub(publicB)) throw new TypeError('getSharedSecret: second arg must be public key');
|
if (!isProbPub(publicB)) throw new Error('second arg must be public key');
|
||||||
const b = normalizePublicKey(publicB);
|
const b = Point.fromHex(publicB); // check for being on-curve
|
||||||
b.assertValidity();
|
|
||||||
return b.multiply(normalizePrivateKey(privateA)).toRawBytes(isCompressed);
|
return b.multiply(normalizePrivateKey(privateA)).toRawBytes(isCompressed);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1047,7 +1007,8 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
if (['recovered', 'canonical'].some((k) => k in opts))
|
if (['recovered', 'canonical'].some((k) => k in opts))
|
||||||
// Ban legacy options
|
// Ban legacy options
|
||||||
throw new Error('sign() legacy options not supported');
|
throw new Error('sign() legacy options not supported');
|
||||||
let { lowS } = opts; // generates low-s sigs by default
|
let { lowS, prehash, extraEntropy: ent } = opts; // generates low-s sigs by default
|
||||||
|
if (prehash) msgHash = CURVE.hash(ut.ensureBytes(msgHash));
|
||||||
if (lowS == null) lowS = true; // RFC6979 3.2: we skip step A, because
|
if (lowS == null) lowS = true; // RFC6979 3.2: we skip step A, because
|
||||||
// Step A is ignored, since we already provide hash instead of msg
|
// Step A is ignored, since we already provide hash instead of msg
|
||||||
|
|
||||||
@ -1062,8 +1023,8 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
const d = normalizePrivateKey(privateKey);
|
const d = normalizePrivateKey(privateKey);
|
||||||
// K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) || k')
|
// K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) || k')
|
||||||
const seedArgs = [int2octets(d), h1octets];
|
const seedArgs = [int2octets(d), h1octets];
|
||||||
let ent = opts.extraEntropy; // RFC6979 3.6: additional k' (optional)
|
|
||||||
if (ent != null) {
|
if (ent != null) {
|
||||||
|
// RFC6979 3.6: additional k' (optional)
|
||||||
if (ent === true) ent = CURVE.randomBytes(Fp.BYTES);
|
if (ent === true) ent = CURVE.randomBytes(Fp.BYTES);
|
||||||
const e = ut.ensureBytes(ent);
|
const e = ut.ensureBytes(ent);
|
||||||
if (e.length !== Fp.BYTES) throw new Error(`sign: Expected ${Fp.BYTES} bytes of extra data`);
|
if (e.length !== Fp.BYTES) throw new Error(`sign: Expected ${Fp.BYTES} bytes of extra data`);
|
||||||
@ -1100,7 +1061,8 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
}
|
}
|
||||||
return { seed, k2sig };
|
return { seed, k2sig };
|
||||||
}
|
}
|
||||||
const defaultSigOpts: SignOpts = { lowS: CURVE.lowS };
|
const defaultSigOpts: SignOpts = { lowS: CURVE.lowS, prehash: false };
|
||||||
|
const defaultVerOpts: VerOpts = { lowS: CURVE.lowS, prehash: false };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signs message hash (not message: you need to hash it by yourself).
|
* Signs message hash (not message: you need to hash it by yourself).
|
||||||
@ -1119,13 +1081,6 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
return genUntil(seed, k2sig); // Steps B, C, D, E, F, G
|
return genUntil(seed, k2sig); // Steps B, C, D, E, F, G
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Signs a message (not message hash).
|
|
||||||
*/
|
|
||||||
function signUnhashed(msg: Uint8Array, privKey: PrivKey, opts = defaultSigOpts): Signature {
|
|
||||||
return sign(CURVE.hash(ut.ensureBytes(msg)), privKey, opts);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable precomputes. Slows down first publicKey computation by 20ms.
|
// Enable precomputes. Slows down first publicKey computation by 20ms.
|
||||||
Point.BASE._setWindowSize(8);
|
Point.BASE._setWindowSize(8);
|
||||||
// utils.precompute(8, ProjectivePoint.BASE)
|
// utils.precompute(8, ProjectivePoint.BASE)
|
||||||
@ -1146,10 +1101,12 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
function verify(
|
function verify(
|
||||||
signature: Hex | SignatureType,
|
signature: Hex | SignatureType,
|
||||||
msgHash: Hex,
|
msgHash: Hex,
|
||||||
publicKey: PubKey,
|
publicKey: Hex,
|
||||||
opts: { lowS?: boolean } = { lowS: CURVE.lowS }
|
opts = defaultVerOpts
|
||||||
): boolean {
|
): boolean {
|
||||||
|
let P: ProjectivePointType<bigint>;
|
||||||
let _sig: Signature | undefined = undefined;
|
let _sig: Signature | undefined = undefined;
|
||||||
|
if (publicKey instanceof Point) throw new Error('publicKey must be hex');
|
||||||
try {
|
try {
|
||||||
if (signature instanceof Signature) {
|
if (signature instanceof Signature) {
|
||||||
signature.assertValidity();
|
signature.assertValidity();
|
||||||
@ -1165,28 +1122,21 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
msgHash = ut.ensureBytes(msgHash);
|
msgHash = ut.ensureBytes(msgHash);
|
||||||
|
P = Point.fromHex(publicKey);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (opts.lowS && _sig.hasHighS()) return false;
|
if (opts.lowS && _sig.hasHighS()) return false;
|
||||||
let P;
|
if (opts.prehash) msgHash = CURVE.hash(msgHash);
|
||||||
try {
|
const { n: N } = CURVE;
|
||||||
P = normalizePublicKey(publicKey);
|
|
||||||
} catch (error) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const { n } = CURVE;
|
|
||||||
const { r, s } = _sig;
|
const { r, s } = _sig;
|
||||||
|
|
||||||
const h = bits2int_modN(msgHash); // Cannot use fields methods, since it is group element
|
const h = bits2int_modN(msgHash); // Cannot use fields methods, since it is group element
|
||||||
const sinv = mod.invert(s, n); // s^-1
|
const is = mod.invert(s, N); // s^-1
|
||||||
// R = u1⋅G - u2⋅P
|
const u1 = mod.mod(h * is, N); // u1 = hs^-1 mod n
|
||||||
const u1 = mod.mod(h * sinv, n);
|
const u2 = mod.mod(r * is, N); // u2 = rs^-1 mod n
|
||||||
const u2 = mod.mod(r * sinv, n);
|
const R = Point.BASE.multiplyAndAddUnsafe(P, u1, u2)?.toAffine(); // R = u1⋅G + u2⋅P
|
||||||
|
|
||||||
const R = Point.BASE.multiplyAndAddUnsafe(P, u1, u2)?.toAffine();
|
|
||||||
if (!R) return false;
|
if (!R) return false;
|
||||||
const v = mod.mod(R.x, n);
|
const v = mod.mod(R.x, N);
|
||||||
return v === r;
|
return v === r;
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@ -1194,7 +1144,6 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
getPublicKey,
|
getPublicKey,
|
||||||
getSharedSecret,
|
getSharedSecret,
|
||||||
sign,
|
sign,
|
||||||
signUnhashed,
|
|
||||||
verify,
|
verify,
|
||||||
// Point,
|
// Point,
|
||||||
ProjectivePoint: Point,
|
ProjectivePoint: Point,
|
||||||
|
@ -230,9 +230,7 @@ class SchnorrSignature {
|
|||||||
const bytes = ensureBytes(hex);
|
const bytes = ensureBytes(hex);
|
||||||
const len = 32; // group length
|
const len = 32; // group length
|
||||||
if (bytes.length !== 2 * len)
|
if (bytes.length !== 2 * len)
|
||||||
throw new Error(
|
throw new Error(`SchnorrSignature.fromHex: expected ${2 * len} bytes, not ${bytes.length}`);
|
||||||
`SchnorrSignature.fromHex: expected ${2 * len} bytes, not ${bytes.length}`
|
|
||||||
);
|
|
||||||
const r = bytesToNumberBE(bytes.subarray(0, len));
|
const r = bytesToNumberBE(bytes.subarray(0, len));
|
||||||
const s = bytesToNumberBE(bytes.subarray(len, 2 * len));
|
const s = bytesToNumberBE(bytes.subarray(len, 2 * len));
|
||||||
return new SchnorrSignature(r, s);
|
return new SchnorrSignature(r, s);
|
||||||
@ -301,7 +299,7 @@ function schnorrVerify(signature: Hex, message: Hex, publicKey: Hex): boolean {
|
|||||||
// Finalize
|
// Finalize
|
||||||
// R = s⋅G - e⋅P
|
// R = s⋅G - e⋅P
|
||||||
// -eP == (n-e)P
|
// -eP == (n-e)P
|
||||||
const R = secp256k1.ProjectivePoint.BASE.mulAddQUnsafe(
|
const R = secp256k1.ProjectivePoint.BASE.multiplyAndAddUnsafe(
|
||||||
P,
|
P,
|
||||||
normalizePrivateKey(s),
|
normalizePrivateKey(s),
|
||||||
mod(-e, secp256k1.CURVE.n)
|
mod(-e, secp256k1.CURVE.n)
|
||||||
|
@ -62,12 +62,12 @@ should('wychenproof ECDSA vectors', () => {
|
|||||||
if (e.message.includes('Invalid signature: incorrect length')) continue;
|
if (e.message.includes('Invalid signature: incorrect length')) continue;
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
const verified = CURVE.verify(test.sig, m, pubKey);
|
const verified = CURVE.verify(test.sig, m, pubKey.toHex());
|
||||||
deepStrictEqual(verified, true, 'valid');
|
deepStrictEqual(verified, true, 'valid');
|
||||||
} else if (test.result === 'invalid') {
|
} else if (test.result === 'invalid') {
|
||||||
let failed = false;
|
let failed = false;
|
||||||
try {
|
try {
|
||||||
failed = !CURVE.verify(test.sig, m, pubKey);
|
failed = !CURVE.verify(test.sig, m, pubKey.toHex());
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
failed = true;
|
failed = true;
|
||||||
}
|
}
|
||||||
@ -312,28 +312,30 @@ function runWycheproof(name, CURVE, group, index) {
|
|||||||
const pubKey = CURVE.ProjectivePoint.fromHex(group.key.uncompressed);
|
const pubKey = CURVE.ProjectivePoint.fromHex(group.key.uncompressed);
|
||||||
deepStrictEqual(pubKey.x, BigInt(`0x${group.key.wx}`));
|
deepStrictEqual(pubKey.x, BigInt(`0x${group.key.wx}`));
|
||||||
deepStrictEqual(pubKey.y, BigInt(`0x${group.key.wy}`));
|
deepStrictEqual(pubKey.y, BigInt(`0x${group.key.wy}`));
|
||||||
|
const pubR = pubKey.toRawBytes();
|
||||||
for (const test of group.tests) {
|
for (const test of group.tests) {
|
||||||
const m = CURVE.CURVE.hash(hexToBytes(test.msg));
|
const m = CURVE.CURVE.hash(hexToBytes(test.msg));
|
||||||
|
const { sig } = test;
|
||||||
|
|
||||||
if (test.result === 'valid' || test.result === 'acceptable') {
|
if (test.result === 'valid' || test.result === 'acceptable') {
|
||||||
try {
|
try {
|
||||||
CURVE.Signature.fromDER(test.sig);
|
CURVE.Signature.fromDER(sig);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Some tests has invalid signature which we don't accept
|
// Some tests has invalid signature which we don't accept
|
||||||
if (e.message.includes('Invalid signature: incorrect length')) continue;
|
if (e.message.includes('Invalid signature: incorrect length')) continue;
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
const verified = CURVE.verify(test.sig, m, pubKey);
|
const verified = CURVE.verify(sig, m, pubR);
|
||||||
if (name === 'secp256k1') {
|
if (name === 'secp256k1') {
|
||||||
// lowS: true for secp256k1
|
// lowS: true for secp256k1
|
||||||
deepStrictEqual(verified, !CURVE.Signature.fromDER(test.sig).hasHighS(), `${index}: valid`);
|
deepStrictEqual(verified, !CURVE.Signature.fromDER(sig).hasHighS(), `${index}: valid`);
|
||||||
} else {
|
} else {
|
||||||
deepStrictEqual(verified, true, `${index}: valid`);
|
deepStrictEqual(verified, true, `${index}: valid`);
|
||||||
}
|
}
|
||||||
} else if (test.result === 'invalid') {
|
} else if (test.result === 'invalid') {
|
||||||
let failed = false;
|
let failed = false;
|
||||||
try {
|
try {
|
||||||
failed = !CURVE.verify(test.sig, m, pubKey);
|
failed = !CURVE.verify(sig, m, pubR);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
failed = true;
|
failed = true;
|
||||||
}
|
}
|
||||||
|
@ -314,7 +314,7 @@ describe('secp256k1', () => {
|
|||||||
const r = 1n;
|
const r = 1n;
|
||||||
const s = 115792089237316195423570985008687907852837564279074904382605163141518162728904n;
|
const s = 115792089237316195423570985008687907852837564279074904382605163141518162728904n;
|
||||||
|
|
||||||
const pub = new Point(x, y, 1n);
|
const pub = new Point(x, y, 1n).toRawBytes();
|
||||||
const signature = new secp.Signature(2n, 2n);
|
const signature = new secp.Signature(2n, 2n);
|
||||||
signature.r = r;
|
signature.r = r;
|
||||||
signature.s = s;
|
signature.s = s;
|
||||||
@ -329,7 +329,7 @@ describe('secp256k1', () => {
|
|||||||
const y = 32670510020758816978083085130507043184471273380659243275938904335757337482424n;
|
const y = 32670510020758816978083085130507043184471273380659243275938904335757337482424n;
|
||||||
const r = 104546003225722045112039007203142344920046999340768276760147352389092131869133n;
|
const r = 104546003225722045112039007203142344920046999340768276760147352389092131869133n;
|
||||||
const s = 96900796730960181123786672629079577025401317267213807243199432755332205217369n;
|
const s = 96900796730960181123786672629079577025401317267213807243199432755332205217369n;
|
||||||
const pub = new Point(x, y, 1n);
|
const pub = new Point(x, y, 1n).toRawBytes();
|
||||||
const sig = new secp.Signature(r, s);
|
const sig = new secp.Signature(r, s);
|
||||||
deepStrictEqual(secp.verify(sig, msg, pub), false);
|
deepStrictEqual(secp.verify(sig, msg, pub), false);
|
||||||
});
|
});
|
||||||
@ -339,7 +339,7 @@ describe('secp256k1', () => {
|
|||||||
const y = 17482644437196207387910659778872952193236850502325156318830589868678978890912n;
|
const y = 17482644437196207387910659778872952193236850502325156318830589868678978890912n;
|
||||||
const r = 432420386565659656852420866390673177323n;
|
const r = 432420386565659656852420866390673177323n;
|
||||||
const s = 115792089237316195423570985008687907852837564279074904382605163141518161494334n;
|
const s = 115792089237316195423570985008687907852837564279074904382605163141518161494334n;
|
||||||
const pub = new Point(x, y, 1n);
|
const pub = new Point(x, y, 1n).toRawBytes();
|
||||||
const sig = new secp.Signature(r, s);
|
const sig = new secp.Signature(r, s);
|
||||||
deepStrictEqual(secp.verify(sig, msg, pub, { strict: false }), true);
|
deepStrictEqual(secp.verify(sig, msg, pub, { strict: false }), true);
|
||||||
});
|
});
|
||||||
@ -527,9 +527,10 @@ describe('secp256k1', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
should('wychenproof vectors', () => {
|
should('wycheproof vectors', () => {
|
||||||
for (let group of wp.testGroups) {
|
for (let group of wp.testGroups) {
|
||||||
const pubKey = Point.fromHex(group.key.uncompressed);
|
// const pubKey = Point.fromHex().toRawBytes();
|
||||||
|
const pubKey = group.key.uncompressed;
|
||||||
for (let test of group.tests) {
|
for (let test of group.tests) {
|
||||||
const m = secp.CURVE.hash(hexToBytes(test.msg));
|
const m = secp.CURVE.hash(hexToBytes(test.msg));
|
||||||
if (test.result === 'valid' || test.result === 'acceptable') {
|
if (test.result === 'valid' || test.result === 'acceptable') {
|
||||||
|
Loading…
Reference in New Issue
Block a user