weierstrass: rename normalizePrivateKey to allowedPrivateKeyLengths
This commit is contained in:
parent
fcd422d246
commit
f39fb80c52
@ -24,11 +24,9 @@ export type BasicCurve<T> = AbstractCurve<T> & {
|
||||
b: T;
|
||||
|
||||
// Optional params
|
||||
normalizePrivateKey?: (key: PrivKey) => PrivKey; // called before privkey validation. used w p521
|
||||
// Whether to execute modular division on a private key, useful for bls curves with cofactor > 1
|
||||
allowedPrivateKeyLengths?: readonly number[]; // for P521
|
||||
wrapPrivateKey?: boolean; // bls12-381 requires mod(n) instead of rejecting keys >= n
|
||||
// Endomorphism options for Koblitz curves
|
||||
endo?: EndomorphismOpts;
|
||||
endo?: EndomorphismOpts; // Endomorphism options for Koblitz curves
|
||||
// When a cofactor != 1, there can be an effective methods to:
|
||||
// 1. Determine whether a point is torsion-free
|
||||
isTorsionFree?: (c: ProjConstructor<T>, point: ProjPointType<T>) => boolean;
|
||||
@ -101,6 +99,14 @@ function validatePointOpts<T>(curve: CurvePointsType<T>) {
|
||||
if (!Fp.isValid(curve[i]))
|
||||
throw new Error(`Invalid curve param ${i}=${opts[i]} (${typeof opts[i]})`);
|
||||
}
|
||||
for (const i of ['allowedPrivateKeyLengths'] as const) {
|
||||
if (curve[i] === undefined) continue; // Optional
|
||||
if (!Array.isArray(curve[i])) throw new Error(`Invalid ${i} array`);
|
||||
}
|
||||
for (const i of ['wrapPrivateKey'] as const) {
|
||||
if (curve[i] === undefined) continue; // Optional
|
||||
if (typeof curve[i] !== 'boolean') throw new Error(`Invalid ${i} boolean`);
|
||||
}
|
||||
for (const i of ['isTorsionFree', 'clearCofactor'] as const) {
|
||||
if (curve[i] === undefined) continue; // Optional
|
||||
if (typeof curve[i] !== 'function') throw new Error(`Invalid ${i} function`);
|
||||
@ -209,8 +215,13 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
|
||||
// Validates if priv key is valid and converts it to bigint.
|
||||
// Supports options CURVE.normalizePrivateKey and CURVE.wrapPrivateKey.
|
||||
function normalizePrivateKey(key: PrivKey): bigint {
|
||||
const { normalizePrivateKey: custom, nByteLength, wrapPrivateKey, n } = CURVE;
|
||||
if (typeof custom === 'function') key = custom(key); // CURVE.normalizePrivateKey()
|
||||
const { allowedPrivateKeyLengths: lengths, nByteLength, wrapPrivateKey, n } = CURVE;
|
||||
if (lengths && typeof key !== 'bigint') {
|
||||
if (key instanceof Uint8Array) key = ut.bytesToHex(key);
|
||||
// Normalize to hex string, pad. E.g. P521 would norm 130-132 char hex to 132-char bytes
|
||||
if (typeof key !== 'string' || !lengths.includes(key.length)) throw new Error('Invalid key');
|
||||
key = key.padStart(nByteLength * 2, '0');
|
||||
}
|
||||
let num: bigint;
|
||||
try {
|
||||
num = typeof key === 'bigint' ? key : ut.bytesToNumberBE(ensureBytes(key, nByteLength));
|
||||
|
12
src/p521.ts
12
src/p521.ts
@ -1,7 +1,6 @@
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { createCurve } from './_shortw_utils.js';
|
||||
import { sha512 } from '@noble/hashes/sha512';
|
||||
import { bytesToHex, PrivKey } from './abstract/utils.js';
|
||||
import { Fp as Field } from './abstract/modular.js';
|
||||
import { mapToCurveSimpleSWU } from './abstract/weierstrass.js';
|
||||
import * as htf from './abstract/hash-to-curve.js';
|
||||
@ -38,16 +37,7 @@ export const P521 = createCurve({
|
||||
Gy: BigInt('0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650'),
|
||||
h: BigInt(1),
|
||||
lowS: false,
|
||||
// P521 keys could be 130, 131, 132 bytes. We normalize to 132 bytes.
|
||||
// Does not replace validation; invalid keys would still be rejected.
|
||||
normalizePrivateKey(key: PrivKey) {
|
||||
if (typeof key === 'bigint') return key;
|
||||
if (key instanceof Uint8Array) key = bytesToHex(key);
|
||||
if (typeof key !== 'string' || !([130, 131, 132].includes(key.length))) {
|
||||
throw new Error('Invalid key');
|
||||
}
|
||||
return key.padStart(66 * 2, '0'); // ensure it's always 132 bytes
|
||||
},
|
||||
allowedPrivateKeyLengths: [130, 131, 132] // P521 keys are variable-length. Normalize to 132b
|
||||
} as const, sha512);
|
||||
export const secp521r1 = P521;
|
||||
|
||||
|
@ -436,9 +436,16 @@ for (const name in CURVES) {
|
||||
throws(() => G[1][op](0n), '0n');
|
||||
G[1][op](G[2]);
|
||||
throws(() => G[1][op](CURVE_ORDER), 'CURVE_ORDER');
|
||||
throws(() => G[1][op](-123n), '-123n');
|
||||
throws(() => G[1][op](123), '123');
|
||||
throws(() => G[1][op](123.456), '123.456');
|
||||
throws(() => G[1][op](true), 'true');
|
||||
throws(() => G[1][op](false), 'false');
|
||||
throws(() => G[1][op](null), 'null');
|
||||
throws(() => G[1][op](undefined), 'undefined');
|
||||
throws(() => G[1][op]('1'), "'1'");
|
||||
throws(() => G[1][op]({ x: 1n, y: 1n }), '{ x: 1n, y: 1n }');
|
||||
throws(() => G[1][op]({ x: 1n, y: 1n, z: 1n }), '{ x: 1n, y: 1n, z: 1n }');
|
||||
throws(
|
||||
() => G[1][op]({ x: 1n, y: 1n, z: 1n, t: 1n }),
|
||||
'{ x: 1n, y: 1n, z: 1n, t: 1n }'
|
||||
@ -527,10 +534,13 @@ for (const name in CURVES) {
|
||||
should('.getPublicKey() type check', () => {
|
||||
throws(() => C.getPublicKey(0), '0');
|
||||
throws(() => C.getPublicKey(0n), '0n');
|
||||
throws(() => C.getPublicKey(false), 'false');
|
||||
throws(() => C.getPublicKey(-123n), '-123n');
|
||||
throws(() => C.getPublicKey(123), '123');
|
||||
throws(() => C.getPublicKey(123.456), '123.456');
|
||||
throws(() => C.getPublicKey(true), 'true');
|
||||
throws(() => C.getPublicKey(false), 'false');
|
||||
throws(() => C.getPublicKey(null), 'null');
|
||||
throws(() => C.getPublicKey(undefined), 'undefined');
|
||||
throws(() => C.getPublicKey(''), "''");
|
||||
// NOTE: passes because of disabled hex padding checks for starknet, maybe enable?
|
||||
// throws(() => C.getPublicKey('1'), "'1'");
|
||||
@ -560,25 +570,25 @@ for (const name in CURVES) {
|
||||
should('.sign() edge cases', () => {
|
||||
throws(() => C.sign());
|
||||
throws(() => C.sign(''));
|
||||
throws(() => C.sign('', ''));
|
||||
throws(() => C.sign(new Uint8Array(), new Uint8Array()));
|
||||
});
|
||||
|
||||
describe('verify()', () => {
|
||||
const msg = '01'.repeat(32);
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user