forked from tornado-packages/noble-curves
weierstrass, montgomery, secp: add comments
This commit is contained in:
parent
26ebb5dcce
commit
e1cb8549e8
@ -4,8 +4,8 @@
|
|||||||
|
|
||||||
| Version | Supported |
|
| Version | Supported |
|
||||||
| ------- | ------------------ |
|
| ------- | ------------------ |
|
||||||
| >=0.5.0 | :white_check_mark: |
|
| >=1.0.0 | :white_check_mark: |
|
||||||
| <0.5.0 | :x: |
|
| <1.0.0 | :x: |
|
||||||
|
|
||||||
## Reporting a Vulnerability
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
@ -73,6 +73,7 @@ export function montgomery(curveDef: CurveType): CurveFn {
|
|||||||
return [x_2, x_3];
|
return [x_2, x_3];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Accepts 0 as well
|
||||||
function assertFieldElement(n: bigint): bigint {
|
function assertFieldElement(n: bigint): bigint {
|
||||||
if (typeof n === 'bigint' && _0n <= n && n < P) return n;
|
if (typeof n === 'bigint' && _0n <= n && n < P) return n;
|
||||||
throw new Error('Expected valid scalar 0 < scalar < CURVE.P');
|
throw new Error('Expected valid scalar 0 < scalar < CURVE.P');
|
||||||
|
@ -642,7 +642,6 @@ export type CurveFn = {
|
|||||||
utils: {
|
utils: {
|
||||||
normPrivateKeyToScalar: (key: PrivKey) => bigint;
|
normPrivateKeyToScalar: (key: PrivKey) => bigint;
|
||||||
isValidPrivateKey(privateKey: PrivKey): boolean;
|
isValidPrivateKey(privateKey: PrivKey): boolean;
|
||||||
hashToPrivateKey: (hash: Hex) => Uint8Array;
|
|
||||||
randomPrivateKey: () => Uint8Array;
|
randomPrivateKey: () => Uint8Array;
|
||||||
precompute: (windowSize?: number, point?: ProjPointType<bigint>) => ProjPointType<bigint>;
|
precompute: (windowSize?: number, point?: ProjPointType<bigint>) => ProjPointType<bigint>;
|
||||||
};
|
};
|
||||||
@ -677,7 +676,6 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
const x = Fp.toBytes(a.x);
|
const x = Fp.toBytes(a.x);
|
||||||
const cat = ut.concatBytes;
|
const cat = ut.concatBytes;
|
||||||
if (isCompressed) {
|
if (isCompressed) {
|
||||||
// TODO: hasEvenY
|
|
||||||
return cat(Uint8Array.from([point.hasEvenY() ? 0x02 : 0x03]), x);
|
return cat(Uint8Array.from([point.hasEvenY() ? 0x02 : 0x03]), x);
|
||||||
} else {
|
} else {
|
||||||
return cat(Uint8Array.from([0x04]), x, Fp.toBytes(a.y));
|
return cat(Uint8Array.from([0x04]), x, Fp.toBytes(a.y));
|
||||||
@ -809,17 +807,15 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
},
|
},
|
||||||
normPrivateKeyToScalar: normalizePrivateKey,
|
normPrivateKeyToScalar: normalizePrivateKey,
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts some bytes to a valid private key. Needs at least (nBitLength+64) bytes.
|
|
||||||
*/
|
|
||||||
hashToPrivateKey: (hash: Hex): Uint8Array =>
|
|
||||||
ut.numberToBytesBE(mod.hashToPrivateScalar(hash, CURVE_ORDER), CURVE.nByteLength),
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Produces cryptographically secure private key from random of size (nBitLength+64)
|
* Produces cryptographically secure private key from random of size (nBitLength+64)
|
||||||
* as per FIPS 186 B.4.1 with modulo bias being neglible.
|
* as per FIPS 186 B.4.1 with modulo bias being neglible.
|
||||||
*/
|
*/
|
||||||
randomPrivateKey: (): Uint8Array => utils.hashToPrivateKey(CURVE.randomBytes(Fp.BYTES + 8)),
|
randomPrivateKey: (): Uint8Array => {
|
||||||
|
const rand = CURVE.randomBytes(Fp.BYTES + 8);
|
||||||
|
const num = mod.hashToPrivateScalar(rand, CURVE_ORDER);
|
||||||
|
return ut.numberToBytesBE(num, CURVE.nByteLength);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 1. Returns cached point which you can use to pass to `getSharedSecret` or `#multiply` by it.
|
* 1. Returns cached point which you can use to pass to `getSharedSecret` or `#multiply` by it.
|
||||||
@ -862,7 +858,8 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
/**
|
/**
|
||||||
* ECDH (Elliptic Curve Diffie Hellman).
|
* ECDH (Elliptic Curve Diffie Hellman).
|
||||||
* Computes shared public key from private key and public key.
|
* Computes shared public key from private key and public key.
|
||||||
* Checks: 1) private key validity 2) shared key is on-curve
|
* Checks: 1) private key validity 2) shared key is on-curve.
|
||||||
|
* Does NOT hash the result.
|
||||||
* @param privateA private key
|
* @param privateA private key
|
||||||
* @param publicB different public key
|
* @param publicB different public key
|
||||||
* @param isCompressed whether to return compact (default), or full key
|
* @param isCompressed whether to return compact (default), or full key
|
||||||
@ -895,10 +892,12 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|||||||
};
|
};
|
||||||
// NOTE: pads output with zero as per spec
|
// NOTE: pads output with zero as per spec
|
||||||
const ORDER_MASK = ut.bitMask(CURVE.nBitLength);
|
const ORDER_MASK = ut.bitMask(CURVE.nBitLength);
|
||||||
|
/**
|
||||||
|
* Converts to bytes. Checks if num in `[0..ORDER_MASK-1]` e.g.: `[0..2^256-1]`.
|
||||||
|
*/
|
||||||
function int2octets(num: bigint): Uint8Array {
|
function int2octets(num: bigint): Uint8Array {
|
||||||
if (typeof num !== 'bigint') throw new Error('bigint expected');
|
if (typeof num !== 'bigint') throw new Error('bigint expected');
|
||||||
if (!(_0n <= num && num < ORDER_MASK))
|
if (!(_0n <= num && num < ORDER_MASK))
|
||||||
// n in [0..ORDER_MASK-1]
|
|
||||||
throw new Error(`bigint expected < 2^${CURVE.nBitLength}`);
|
throw new Error(`bigint expected < 2^${CURVE.nBitLength}`);
|
||||||
// works with order, can have different size than numToField!
|
// works with order, can have different size than numToField!
|
||||||
return ut.numberToBytesBE(num, CURVE.nByteLength);
|
return ut.numberToBytesBE(num, CURVE.nByteLength);
|
||||||
|
@ -107,6 +107,7 @@ function taggedHash(tag: string, ...messages: Uint8Array[]): Uint8Array {
|
|||||||
return sha256(concatBytes(tagP, ...messages));
|
return sha256(concatBytes(tagP, ...messages));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ECDSA compact points are 33-byte. Schnorr is 32: we strip first byte 0x02 or 0x03
|
||||||
const pointToBytes = (point: PointType<bigint>) => point.toRawBytes(true).slice(1);
|
const pointToBytes = (point: PointType<bigint>) => point.toRawBytes(true).slice(1);
|
||||||
const numTo32b = (n: bigint) => numberToBytesBE(n, 32);
|
const numTo32b = (n: bigint) => numberToBytesBE(n, 32);
|
||||||
const modP = (x: bigint) => mod(x, secp256k1P);
|
const modP = (x: bigint) => mod(x, secp256k1P);
|
||||||
@ -114,12 +115,17 @@ const modN = (x: bigint) => mod(x, secp256k1N);
|
|||||||
const Point = secp256k1.ProjectivePoint;
|
const Point = secp256k1.ProjectivePoint;
|
||||||
const GmulAdd = (Q: PointType<bigint>, a: bigint, b: bigint) =>
|
const GmulAdd = (Q: PointType<bigint>, a: bigint, b: bigint) =>
|
||||||
Point.BASE.multiplyAndAddUnsafe(Q, a, b);
|
Point.BASE.multiplyAndAddUnsafe(Q, a, b);
|
||||||
|
// Calculate point, scalar and bytes
|
||||||
function schnorrGetExtPubKey(priv: PrivKey) {
|
function schnorrGetExtPubKey(priv: PrivKey) {
|
||||||
const d = secp256k1.utils.normPrivateKeyToScalar(priv);
|
const d = secp256k1.utils.normPrivateKeyToScalar(priv); // same method executed in fromPrivateKey
|
||||||
const point = Point.fromPrivateKey(d); // P = d'⋅G; 0 < d' < n check is done inside
|
const point = Point.fromPrivateKey(d); // P = d'⋅G; 0 < d' < n check is done inside
|
||||||
const scalar = point.hasEvenY() ? d : modN(-d); // d = d' if has_even_y(P), otherwise d = n-d'
|
const scalar = point.hasEvenY() ? d : modN(-d); // d = d' if has_even_y(P), otherwise d = n-d'
|
||||||
return { point, scalar, bytes: pointToBytes(point) };
|
return { point, scalar, bytes: pointToBytes(point) };
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* lift_x from BIP340. Convert 32-byte x coordinate to elliptic curve point.
|
||||||
|
* @returns valid point checked for being on-curve
|
||||||
|
*/
|
||||||
function lift_x(x: bigint): PointType<bigint> {
|
function lift_x(x: bigint): PointType<bigint> {
|
||||||
if (!fe(x)) throw new Error('bad x: need 0 < x < p'); // Fail if x ≥ p.
|
if (!fe(x)) throw new Error('bad x: need 0 < x < p'); // Fail if x ≥ p.
|
||||||
const xx = modP(x * x);
|
const xx = modP(x * x);
|
||||||
@ -130,6 +136,9 @@ function lift_x(x: bigint): PointType<bigint> {
|
|||||||
p.assertValidity();
|
p.assertValidity();
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Create tagged hash, convert it to bigint, reduce modulo-n.
|
||||||
|
*/
|
||||||
function challenge(...args: Uint8Array[]): bigint {
|
function challenge(...args: Uint8Array[]): bigint {
|
||||||
return modN(bytesToNumberBE(taggedHash('BIP0340/challenge', ...args)));
|
return modN(bytesToNumberBE(taggedHash('BIP0340/challenge', ...args)));
|
||||||
}
|
}
|
||||||
@ -169,6 +178,7 @@ function schnorrSign(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifies Schnorr signature.
|
* Verifies Schnorr signature.
|
||||||
|
* Will swallow errors & return false except for initial type validation of arguments.
|
||||||
*/
|
*/
|
||||||
function schnorrVerify(signature: Hex, message: Hex, publicKey: Hex): boolean {
|
function schnorrVerify(signature: Hex, message: Hex, publicKey: Hex): boolean {
|
||||||
const sig = ensureBytes('signature', signature, 64);
|
const sig = ensureBytes('signature', signature, 64);
|
||||||
|
Loading…
Reference in New Issue
Block a user