From 0fb78b709787b732efefe4c02f589ca39864299f Mon Sep 17 00:00:00 2001 From: Paul Miller Date: Thu, 26 Jan 2023 03:14:21 +0000 Subject: [PATCH] Rename group to curve. More refactoring --- package.json | 8 +- src/abstract/bls.ts | 2 +- src/abstract/{group.ts => curve.ts} | 34 ++ src/abstract/edwards.ts | 48 ++- src/abstract/hash-to-curve.ts | 19 +- src/abstract/modular.ts | 50 ++- src/abstract/montgomery.ts | 5 +- src/abstract/poseidon.ts | 1 + src/abstract/utils.ts | 77 ---- src/abstract/weierstrass.ts | 100 +++-- src/bn.ts | 2 +- test/bls12-381.test.js | 581 +--------------------------- test/hash-to-curve.test.js | 1 - 13 files changed, 190 insertions(+), 738 deletions(-) rename src/abstract/{group.ts => curve.ts} (75%) diff --git a/package.json b/package.json index 77a5b0c..0a914a6 100644 --- a/package.json +++ b/package.json @@ -73,10 +73,10 @@ "import": "./lib/esm/abstract/hash-to-curve.js", "default": "./lib/abstract/hash-to-curve.js" }, - "./abstract/group": { - "types": "./lib/abstract/group.d.ts", - "import": "./lib/esm/abstract/group.js", - "default": "./lib/abstract/group.js" + "./abstract/curve": { + "types": "./lib/abstract/curve.d.ts", + "import": "./lib/esm/abstract/curve.js", + "default": "./lib/abstract/curve.js" }, "./abstract/utils": { "types": "./lib/abstract/utils.d.ts", diff --git a/src/abstract/bls.ts b/src/abstract/bls.ts index 2ca93ca..607a566 100644 --- a/src/abstract/bls.ts +++ b/src/abstract/bls.ts @@ -193,7 +193,7 @@ export function bls( ) => htf.hash_to_field(msg, count, { ...CURVE.htfDefaults, ...options }), expandMessageXMD: (msg: Uint8Array, DST: Uint8Array, lenInBytes: number, H = CURVE.hash) => htf.expand_message_xmd(msg, DST, lenInBytes, H), - hashToPrivateKey: (hash: Hex): Uint8Array => Fr.toBytes(ut.hashToPrivateScalar(hash, CURVE.r)), + hashToPrivateKey: (hash: Hex): Uint8Array => Fr.toBytes(mod.hashToPrivateScalar(hash, CURVE.r)), randomBytes: (bytesLength: number = groupLen): Uint8Array => CURVE.randomBytes(bytesLength), randomPrivateKey: (): Uint8Array => utils.hashToPrivateKey(utils.randomBytes(groupLen + 8)), }; diff --git a/src/abstract/group.ts b/src/abstract/curve.ts similarity index 75% rename from src/abstract/group.ts rename to src/abstract/curve.ts index d07b2d5..2b15bbb 100644 --- a/src/abstract/group.ts +++ b/src/abstract/curve.ts @@ -1,5 +1,6 @@ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ // Abelian group utilities +import { Field, validateField, nLength } from './modular.js'; const _0n = BigInt(0); const _1n = BigInt(1); @@ -144,3 +145,36 @@ export function wNAF>(c: GroupConstructor, bits: number) { }, }; } + +// Generic BasicCurve interface: works even for polynomial fields (BLS): P, n, h would be ok. +// Though generator can be different (Fp2 / Fp6 for BLS). +export type BasicCurve = { + Fp: Field; // Field over which we'll do calculations (Fp) + n: bigint; // Curve order, total count of valid points in the field + nBitLength?: number; // bit length of curve order + nByteLength?: number; // byte length of curve order + h: bigint; // cofactor. we can assign default=1, but users will just ignore it w/o validation + hEff?: bigint; // Number to multiply to clear cofactor + Gx: T; // base point X coordinate + Gy: T; // base point Y coordinate + wrapPrivateKey?: boolean; // bls12-381 requires mod(n) instead of rejecting keys >= n + allowInfinityPoint?: boolean; // bls12-381 requires it. ZERO point is valid, but invalid pubkey +}; + +export function validateBasicCurveOpts(curve: BasicCurve & T) { + validateField(curve.Fp); + for (const i of ['n', 'h'] as const) { + const val = curve[i]; + if (typeof val !== 'bigint') throw new Error(`Invalid curve param ${i}=${val} (${typeof val})`); + } + if (!curve.Fp.isValid(curve.Gx)) throw new Error('Invalid generator X coordinate Fp element'); + if (!curve.Fp.isValid(curve.Gy)) throw new Error('Invalid generator Y coordinate Fp element'); + + for (const i of ['nBitLength', 'nByteLength'] as const) { + const val = curve[i]; + if (val === undefined) continue; // Optional + if (!Number.isSafeInteger(val)) throw new Error(`Invalid param ${i}=${val} (${typeof val})`); + } + // Set defaults + return Object.freeze({ ...nLength(curve.n, curve.nBitLength), ...curve } as const); +} diff --git a/src/abstract/edwards.ts b/src/abstract/edwards.ts index 0f6831e..3adba37 100644 --- a/src/abstract/edwards.ts +++ b/src/abstract/edwards.ts @@ -1,9 +1,16 @@ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ // Twisted Edwards curve. The formula is: ax² + y² = 1 + dx²y² -import * as mod from './modular.js'; -import * as ut from './utils.js'; -import { ensureBytes, Hex } from './utils.js'; -import { Group, GroupConstructor, wNAF } from './group.js'; +import { mod } from './modular.js'; +import { + bytesToHex, + bytesToNumberLE, + concatBytes, + ensureBytes, + FHash, + Hex, + numberToBytesLE, +} from './utils.js'; +import { Group, GroupConstructor, wNAF, BasicCurve, validateBasicCurveOpts } from './curve.js'; // Be friendly to bad ECMAScript parsers by not using bigint literals like 123n const _0n = BigInt(0); @@ -12,20 +19,20 @@ const _2n = BigInt(2); const _8n = BigInt(8); // Edwards curves must declare params a & d. -export type CurveType = ut.BasicCurve & { +export type CurveType = BasicCurve & { a: bigint; // curve param a d: bigint; // curve param d - hash: ut.FHash; // Hashing + hash: FHash; // Hashing randomBytes: (bytesLength?: number) => Uint8Array; // CSPRNG adjustScalarBytes?: (bytes: Uint8Array) => Uint8Array; // clears bits to get valid field elemtn domain?: (data: Uint8Array, ctx: Uint8Array, phflag: boolean) => Uint8Array; // Used for hashing uvRatio?: (u: bigint, v: bigint) => { isValid: boolean; value: bigint }; // Ratio √(u/v) - preHash?: ut.FHash; // RFC 8032 pre-hashing of messages to sign() / verify() + preHash?: FHash; // RFC 8032 pre-hashing of messages to sign() / verify() mapToCurve?: (scalar: bigint[]) => AffinePoint; // for hash-to-curve standard }; function validateOpts(curve: CurveType) { - const opts = ut.validateOpts(curve); + const opts = validateBasicCurveOpts(curve); if (typeof opts.hash !== 'function') throw new Error('Invalid hash function'); for (const i of ['a', 'd'] as const) { const val = opts[i]; @@ -329,7 +336,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn { const normed = hex.slice(); // copy again, we'll manipulate it const lastByte = hex[len - 1]; // select last byte normed[len - 1] = lastByte & ~0x80; // clear last bit - const y = ut.bytesToNumberLE(normed); + const y = bytesToNumberLE(normed); if (y === _0n) { // y=0 is allowed } else { @@ -355,20 +362,23 @@ export function twistedEdwards(curveDef: CurveType): CurveFn { } toRawBytes(): Uint8Array { const { x, y } = this.toAffine(); - const bytes = ut.numberToBytesLE(y, Fp.BYTES); // each y has 2 x values (x, -y) + const bytes = numberToBytesLE(y, Fp.BYTES); // each y has 2 x values (x, -y) bytes[bytes.length - 1] |= x & _1n ? 0x80 : 0; // when compressing, it's enough to store y return bytes; // and use the last byte to encode sign of x } toHex(): string { - return ut.bytesToHex(this.toRawBytes()); // Same as toRawBytes, but returns string. + return bytesToHex(this.toRawBytes()); // Same as toRawBytes, but returns string. } } const { BASE: G, ZERO: I } = Point; const wnaf = wNAF(Point, nByteLength * 8); + function modN(a: bigint) { + return mod(a, CURVE_ORDER); + } // Little-endian SHA512 with modulo n - function modnLE(hash: Uint8Array): bigint { - return mod.mod(ut.bytesToNumberLE(hash), CURVE_ORDER); + function modN_LE(hash: Uint8Array): bigint { + return modN(bytesToNumberLE(hash)); } function isHex(item: Hex, err: string) { if (typeof item !== 'string' && !(item instanceof Uint8Array)) @@ -384,7 +394,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn { const hashed = ensureBytes(cHash(ensureBytes(key, len)), 2 * len); const head = adjustScalarBytes(hashed.slice(0, len)); // clear first half bits, produce FE const prefix = hashed.slice(len, 2 * len); // second half is called key prefix (5.1.6) - const scalar = modnLE(head); // The actual private scalar + const scalar = modN_LE(head); // The actual private scalar const point = G.multiply(scalar); // Point on Edwards curve aka public key const pointBytes = point.toRawBytes(); // Uint8Array representation return { head, prefix, scalar, point, pointBytes }; @@ -397,8 +407,8 @@ export function twistedEdwards(curveDef: CurveType): CurveFn { // int('LE', SHA512(dom2(F, C) || msgs)) mod N function hashDomainToScalar(context: Hex = new Uint8Array(), ...msgs: Uint8Array[]) { - const msg = ut.concatBytes(...msgs); - return modnLE(cHash(domain(msg, ensureBytes(context), !!preHash))); + const msg = concatBytes(...msgs); + return modN_LE(cHash(domain(msg, ensureBytes(context), !!preHash))); } /** Signs message with privateKey. RFC8032 5.1.6 */ @@ -410,9 +420,9 @@ export function twistedEdwards(curveDef: CurveType): CurveFn { const r = hashDomainToScalar(context, prefix, msg); // r = dom2(F, C) || prefix || PH(M) const R = G.multiply(r).toRawBytes(); // R = rG const k = hashDomainToScalar(context, R, pointBytes, msg); // R || A || PH(M) - const s = mod.mod(r + k * scalar, CURVE_ORDER); // S = (r + k * s) mod L + const s = modN(r + k * scalar); // S = (r + k * s) mod L assertGE0(s); // 0 <= s < l - const res = ut.concatBytes(R, ut.numberToBytesLE(s, Fp.BYTES)); + const res = concatBytes(R, numberToBytesLE(s, Fp.BYTES)); return ensureBytes(res, nByteLength * 2); // 64-byte signature } @@ -425,7 +435,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn { if (preHash) msg = preHash(msg); // for ed25519ph, etc const A = Point.fromHex(publicKey, false); // Check for s bounds, hex validity const R = Point.fromHex(sig.slice(0, len), false); // 0 <= R < 2^256: ZIP215 R can be >= P - const s = ut.bytesToNumberLE(sig.slice(len, 2 * len)); // 0 <= s < l + const s = bytesToNumberLE(sig.slice(len, 2 * len)); // 0 <= s < l const SB = G.multiplyUnsafe(s); const k = hashDomainToScalar(context, R.toRawBytes(), A.toRawBytes(), msg); const RkA = R.add(A.multiplyUnsafe(k)); diff --git a/src/abstract/hash-to-curve.ts b/src/abstract/hash-to-curve.ts index 1e67865..0f0f4ad 100644 --- a/src/abstract/hash-to-curve.ts +++ b/src/abstract/hash-to-curve.ts @@ -1,7 +1,7 @@ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ import * as ut from './utils.js'; import * as mod from './modular.js'; -import type { Group, GroupConstructor } from './group.js'; +import type { Group, GroupConstructor } from './curve.js'; export type Opts = { // DST: a domain separation tag @@ -38,13 +38,16 @@ export function validateOpts(opts: Opts) { throw new Error('Invalid htf/hash function'); } -// UTF8 to ui8a -// TODO: looks broken, ASCII only, why not TextEncoder/TextDecoder? it is in hashes anyway -export function stringToBytes(str: string) { - // return new TextEncoder().encode(str); - const bytes = new Uint8Array(str.length); - for (let i = 0; i < str.length; i++) bytes[i] = str.charCodeAt(i); - return bytes; +// Global symbols in both browsers and Node.js since v11 +// See https://github.com/microsoft/TypeScript/issues/31535 +declare const TextEncoder: any; +declare const TextDecoder: any; + +export function stringToBytes(str: string): Uint8Array { + if (typeof str !== 'string') { + throw new TypeError(`utf8ToBytes expected string, got ${typeof str}`); + } + return new TextEncoder().encode(str); } // Octet Stream to Integer (bytesToNumberBE) diff --git a/src/abstract/modular.ts b/src/abstract/modular.ts index 7f73dd9..0060edb 100644 --- a/src/abstract/modular.ts +++ b/src/abstract/modular.ts @@ -1,7 +1,13 @@ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ -// TODO: remove circular imports -import * as utils from './utils.js'; // Utilities for modular arithmetics and finite fields +import { + bitMask, + numberToBytesBE, + numberToBytesLE, + bytesToNumberBE, + bytesToNumberLE, + ensureBytes, +} from './utils.js'; // prettier-ignore const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3); // prettier-ignore @@ -306,6 +312,14 @@ export function FpIsSquare(f: Field) { }; } +// CURVE.n lengths +export function nLength(n: bigint, nBitLength?: number) { + // Bit size, byte size of CURVE.n + const _nBitLength = nBitLength !== undefined ? nBitLength : n.toString(2).length; + const nByteLength = Math.ceil(_nBitLength / 8); + return { nBitLength: _nBitLength, nByteLength }; +} + // NOTE: very fragile, always bench. Major performance points: // - NonNormalized ops // - Object.freeze @@ -318,14 +332,14 @@ export function Fp( redef: Partial> = {} ): Readonly { if (ORDER <= _0n) throw new Error(`Expected Fp ORDER > 0, got ${ORDER}`); - const { nBitLength: BITS, nByteLength: BYTES } = utils.nLength(ORDER, bitLen); + const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, bitLen); if (BYTES > 2048) throw new Error('Field lengths over 2048 bytes are not supported'); const sqrtP = FpSqrt(ORDER); const f: Readonly = Object.freeze({ ORDER, BITS, BYTES, - MASK: utils.bitMask(BITS), + MASK: bitMask(BITS), ZERO: _0n, ONE: _1n, create: (num) => mod(num, ORDER), @@ -358,12 +372,11 @@ export function Fp( // TODO: do we really need constant cmov? // We don't have const-time bigints anyway, so probably will be not very useful cmov: (a, b, c) => (c ? b : a), - toBytes: (num) => - isLE ? utils.numberToBytesLE(num, BYTES) : utils.numberToBytesBE(num, BYTES), + toBytes: (num) => (isLE ? numberToBytesLE(num, BYTES) : numberToBytesBE(num, BYTES)), fromBytes: (bytes) => { if (bytes.length !== BYTES) throw new Error(`Fp.fromBytes: expected ${BYTES}, got ${bytes.length}`); - return isLE ? utils.bytesToNumberLE(bytes) : utils.bytesToNumberBE(bytes); + return isLE ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes); }, } as FpField); return Object.freeze(f); @@ -380,3 +393,26 @@ export function FpSqrtEven(Fp: Field, elm: T) { const root = Fp.sqrt(elm); return Fp.isOdd(root) ? Fp.neg(root) : root; } + +/** + * FIPS 186 B.4.1-compliant "constant-time" private key generation utility. + * Can take (n+8) or more bytes of uniform input e.g. from CSPRNG or KDF + * and convert them into private scalar, with the modulo bias being neglible. + * Needs at least 40 bytes of input for 32-byte private key. + * https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/ + * @param hash hash output from SHA3 or a similar function + * @returns valid private scalar + */ +export function hashToPrivateScalar( + hash: string | Uint8Array, + groupOrder: bigint, + isLE = false +): bigint { + hash = ensureBytes(hash); + const hashLen = hash.length; + const minLen = nLength(groupOrder).nByteLength + 8; + if (minLen < 24 || hashLen < minLen || hashLen > 1024) + throw new Error(`hashToPrivateScalar: expected ${minLen}-1024 bytes of input, got ${hashLen}`); + const num = isLE ? bytesToNumberLE(hash) : bytesToNumberBE(hash); + return mod(num, groupOrder - _1n) + _1n; +} diff --git a/src/abstract/montgomery.ts b/src/abstract/montgomery.ts index 6138fdd..999192f 100644 --- a/src/abstract/montgomery.ts +++ b/src/abstract/montgomery.ts @@ -1,6 +1,6 @@ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ import * as mod from './modular.js'; -import { ensureBytes, numberToBytesLE, bytesToNumberLE, isPositiveInt } from './utils.js'; +import { ensureBytes, numberToBytesLE, bytesToNumberLE } from './utils.js'; const _0n = BigInt(0); const _1n = BigInt(1); @@ -33,7 +33,7 @@ function validateOpts(curve: CurveType) { } for (const i of ['montgomeryBits', 'nByteLength'] as const) { if (curve[i] === undefined) continue; // Optional - if (!isPositiveInt(curve[i])) + if (!Number.isSafeInteger(curve[i])) throw new Error(`Invalid curve param ${i}=${curve[i]} (${typeof curve[i]})`); } for (const fn of ['adjustScalarBytes', 'domain', 'powPminus2'] as const) { @@ -46,7 +46,6 @@ function validateOpts(curve: CurveType) { throw new Error(`Invalid curve param ${i}=${curve[i]} (${typeof curve[i]})`); } // Set defaults - // ...nLength(curve.n, curve.nBitLength), return Object.freeze({ ...curve } as const); } diff --git a/src/abstract/poseidon.ts b/src/abstract/poseidon.ts index fc8b66e..c170d94 100644 --- a/src/abstract/poseidon.ts +++ b/src/abstract/poseidon.ts @@ -1,3 +1,4 @@ +/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ // Poseidon Hash (https://eprint.iacr.org/2019/458.pdf) // Website: https://www.poseidon-hash.info diff --git a/src/abstract/utils.ts b/src/abstract/utils.ts index 751e56e..4101193 100644 --- a/src/abstract/utils.ts +++ b/src/abstract/utils.ts @@ -1,11 +1,9 @@ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ -import * as mod from './modular.js'; const _0n = BigInt(0); const _1n = BigInt(1); const _2n = BigInt(2); const str = (a: any): a is string => typeof a === 'string'; -export const big = (a: any): a is bigint => typeof a === 'bigint'; const u8a = (a: any): a is Uint8Array => a instanceof Uint8Array; // We accept hex strings besides Uint8Array for simplicity @@ -20,54 +18,6 @@ export type CHash = { }; export type FHash = (message: Uint8Array | string) => Uint8Array; -// NOTE: these are generic, even if curve is on some polynominal field (bls), it will still have P/n/h -// But generator can be different (Fp2/Fp6 for bls?) -export type BasicCurve = { - // Field over which we'll do calculations (Fp) - Fp: mod.Field; - // Curve order, total count of valid points in the field - n: bigint; - // Bit/byte length of curve order - nBitLength?: number; - nByteLength?: number; - // Cofactor - // NOTE: we can assign default value of 1, but then users will just ignore it, without validating with spec - // Has not use for now, but nice to have in API - h: bigint; - hEff?: bigint; // Number to multiply to clear cofactor - // Base point (x, y) aka generator point - Gx: T; - Gy: T; - // Wrap private key by curve order (% CURVE.n instead of throwing error) - wrapPrivateKey?: boolean; - // Point at infinity is perfectly valid point, but not valid public key. - // Disabled by default because of compatibility reasons with @noble/secp256k1 - allowInfinityPoint?: boolean; -}; - -// Bans floats and integers above 2^53-1 -export function isPositiveInt(num: any): num is number { - return typeof num === 'number' && Number.isSafeInteger(num) && num > 0; -} - -export function validateOpts(curve: BasicCurve & T) { - mod.validateField(curve.Fp); - for (const i of ['n', 'h'] as const) { - const val = curve[i]; - if (!big(val)) throw new Error(`Invalid curve param ${i}=${val} (${typeof val})`); - } - if (!curve.Fp.isValid(curve.Gx)) throw new Error('Invalid generator X coordinate Fp element'); - if (!curve.Fp.isValid(curve.Gy)) throw new Error('Invalid generator Y coordinate Fp element'); - - for (const i of ['nBitLength', 'nByteLength'] as const) { - const val = curve[i]; - if (val === undefined) continue; // Optional - if (!isPositiveInt(val)) throw new Error(`Invalid curve param ${i}=${val} (${typeof val})`); - } - // Set defaults - return Object.freeze({ ...nLength(curve.n, curve.nBitLength), ...curve } as const); -} - const hexes = Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0')); export function bytesToHex(bytes: Uint8Array): string { if (!u8a(bytes)) throw new Error('Expected Uint8Array'); @@ -147,33 +97,6 @@ export function concatBytes(...arrays: Uint8Array[]): Uint8Array { return result; } -// CURVE.n lengths -export function nLength(n: bigint, nBitLength?: number) { - // Bit size, byte size of CURVE.n - const _nBitLength = nBitLength !== undefined ? nBitLength : n.toString(2).length; - const nByteLength = Math.ceil(_nBitLength / 8); - return { nBitLength: _nBitLength, nByteLength }; -} - -/** - * FIPS 186 B.4.1-compliant "constant-time" private key generation utility. - * Can take (n+8) or more bytes of uniform input e.g. from CSPRNG or KDF - * and convert them into private scalar, with the modulo bias being neglible. - * Needs at least 40 bytes of input for 32-byte private key. - * https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/ - * @param hash hash output from SHA3 or a similar function - * @returns valid private scalar - */ -export function hashToPrivateScalar(hash: Hex, groupOrder: bigint, isLE = false): bigint { - hash = ensureBytes(hash); - const hashLen = hash.length; - const minLen = nLength(groupOrder).nByteLength + 8; - if (minLen < 24 || hashLen < minLen || hashLen > 1024) - throw new Error(`hashToPrivateScalar: expected ${minLen}-1024 bytes of input, got ${hashLen}`); - const num = isLE ? bytesToNumberLE(hash) : bytesToNumberBE(hash); - return mod.mod(num, groupOrder - _1n) + _1n; -} - export function equalBytes(b1: Uint8Array, b2: Uint8Array) { // We don't care about timing attacks here if (b1.length !== b2.length) return false; diff --git a/src/abstract/weierstrass.ts b/src/abstract/weierstrass.ts index 75b5eff..12b8444 100644 --- a/src/abstract/weierstrass.ts +++ b/src/abstract/weierstrass.ts @@ -1,16 +1,34 @@ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ // Short Weierstrass curve. The formula is: y² = x³ + ax + b import * as mod from './modular.js'; -import * as ut from './utils.js'; -import { Hex, PrivKey } from './utils.js'; -import { Group, GroupConstructor, wNAF } from './group.js'; +// import * as ut from './utils.js'; +import { + Hex, + PrivKey, + bytesToHex, + bytesToNumberBE, + ensureBytes, + hexToBytes, + concatBytes, + bitMask, + numberToBytesBE, + CHash, + numberToHexUnpadded, +} from './utils.js'; +import { + Group, + GroupConstructor, + wNAF, + BasicCurve as CBasicCurve, + validateBasicCurveOpts, +} from './curve.js'; type HmacFnSync = (key: Uint8Array, ...messages: Uint8Array[]) => Uint8Array; type EndomorphismOpts = { beta: bigint; splitScalar: (k: bigint) => { k1neg: boolean; k1: bigint; k2neg: boolean; k2: bigint }; }; -export type BasicCurve = ut.BasicCurve & { +export type BasicCurve = CBasicCurve & { // Params: a, b a: T; b: T; @@ -44,7 +62,7 @@ const DER = { }, parseInt(data: Uint8Array): { data: bigint; left: Uint8Array } { if (data.length < 2 || data[0] !== 0x02) { - throw new DERError(`Invalid signature integer tag: ${ut.bytesToHex(data)}`); + throw new DERError(`Invalid signature integer tag: ${bytesToHex(data)}`); } const len = data[1]; const res = data.subarray(2, len + 2); @@ -55,11 +73,11 @@ const DER = { if (res[0] === 0x00 && res[1] <= 0x7f) { throw new DERError('Invalid signature integer: trailing length'); } - return { data: ut.bytesToNumberBE(res), left: data.subarray(len + 2) }; + return { data: bytesToNumberBE(res), left: data.subarray(len + 2) }; }, parseSig(data: Uint8Array): { r: bigint; s: bigint } { if (data.length < 2 || data[0] != 0x30) { - throw new DERError(`Invalid signature tag: ${ut.bytesToHex(data)}`); + throw new DERError(`Invalid signature tag: ${bytesToHex(data)}`); } if (data[1] !== data.length - 2) { throw new DERError('Invalid signature: incorrect length'); @@ -67,9 +85,7 @@ const DER = { const { data: r, left: sBytes } = DER.parseInt(data.subarray(2)); const { data: s, left: rBytesLeft } = DER.parseInt(sBytes); if (rBytesLeft.length) { - throw new DERError( - `Invalid signature: left bytes after parsing: ${ut.bytesToHex(rBytesLeft)}` - ); + throw new DERError(`Invalid signature: left bytes after parsing: ${bytesToHex(rBytesLeft)}`); } return { r, s }; }, @@ -138,7 +154,7 @@ export type CurvePointsType = BasicCurve & { }; function validatePointOpts(curve: CurvePointsType) { - const opts = ut.validateOpts(curve); + const opts = validateBasicCurveOpts(curve); const Fp = opts.Fp; for (const i of ['a', 'b'] as const) { if (!Fp.isValid(curve[i])) @@ -216,10 +232,10 @@ export function weierstrassPoints(opts: CurvePointsType) { } else if (typeof key === 'string') { if (key.length !== 2 * groupLen) throw new Error(`must be ${groupLen} bytes`); // Validates individual octets - num = ut.hexToNumber(key); + num = bytesToNumberBE(ensureBytes(key)); } else if (key instanceof Uint8Array) { if (key.length !== groupLen) throw new Error(`must be ${groupLen} bytes`); - num = ut.bytesToNumberBE(key); + num = bytesToNumberBE(key); } else { throw new Error('private key must be bytes, hex or bigint, not ' + typeof key); } @@ -281,7 +297,7 @@ export function weierstrassPoints(opts: CurvePointsType) { * @param hex short/long ECDSA hex */ static fromHex(hex: Hex): ProjectivePoint { - const P = ProjectivePoint.fromAffine(CURVE.fromBytes(ut.ensureBytes(hex))); + const P = ProjectivePoint.fromAffine(CURVE.fromBytes(ensureBytes(hex))); P.assertValidity(); return P; } @@ -565,7 +581,7 @@ export function weierstrassPoints(opts: CurvePointsType) { } toHex(isCompressed = true): string { - return ut.bytesToHex(this.toRawBytes(isCompressed)); + return bytesToHex(this.toRawBytes(isCompressed)); } } const _bits = CURVE.nBitLength; @@ -608,7 +624,7 @@ export type CurveType = BasicCurve & { // Default options lowS?: boolean; // Hashes - hash: ut.CHash; // Because we need outputLen for DRBG + hash: CHash; // Because we need outputLen for DRBG hmac: HmacFnSync; randomBytes: (bytesLength?: number) => Uint8Array; // truncateHash?: (hash: Uint8Array, truncateOnly?: boolean) => Uint8Array; @@ -617,8 +633,8 @@ export type CurveType = BasicCurve & { }; function validateOpts(curve: CurveType) { - const opts = ut.validateOpts(curve); - if (typeof opts.hash !== 'function' || !ut.isPositiveInt(opts.hash.outputLen)) + const opts = validateBasicCurveOpts(curve); + if (typeof opts.hash !== 'function' || !Number.isSafeInteger(opts.hash.outputLen)) throw new Error('Invalid hash function'); if (typeof opts.hmac !== 'function') throw new Error('Invalid hmac function'); if (typeof opts.randomBytes !== 'function') throw new Error('Invalid randomBytes function'); @@ -683,7 +699,7 @@ function hmacDrbg( out.push(sl); len += v.length; } - return ut.concatBytes(...out); + return concatBytes(...out); }; const genUntil = (seed: Uint8Array, pred: Pred): T => { reset(); @@ -716,7 +732,7 @@ export function weierstrass(curveDef: CurveType): CurveFn { toBytes(c, point, isCompressed: boolean): Uint8Array { const a = point.toAffine(); const x = Fp.toBytes(a.x); - const cat = ut.concatBytes; + const cat = concatBytes; if (isCompressed) { // TODO: hasEvenY return cat(Uint8Array.from([point.hasEvenY() ? 0x02 : 0x03]), x); @@ -730,7 +746,7 @@ export function weierstrass(curveDef: CurveType): CurveFn { const tail = bytes.subarray(1); // this.assertValidity() is done inside of fromHex if (len === compressedLen && (head === 0x02 || head === 0x03)) { - const x = ut.bytesToNumberBE(tail); + const x = bytesToNumberBE(tail); if (!isValidFieldElement(x)) throw new Error('Point is not on curve'); const y2 = weierstrassEquation(x); // y² = x³ + ax + b let y = Fp.sqrt(y2); // y = y² ^ (p+1)/4 @@ -751,7 +767,7 @@ export function weierstrass(curveDef: CurveType): CurveFn { }, }); const numToNByteStr = (num: bigint): string => - ut.bytesToHex(ut.numberToBytesBE(num, CURVE.nByteLength)); + bytesToHex(numberToBytesBE(num, CURVE.nByteLength)); function isBiggerThanHalfOrder(number: bigint) { const HALF = CURVE_ORDER >> _1n; @@ -762,7 +778,7 @@ export function weierstrass(curveDef: CurveType): CurveFn { return isBiggerThanHalfOrder(s) ? mod.mod(-s, CURVE_ORDER) : s; } // slice bytes num - const slcNum = (b: Uint8Array, from: number, to: number) => ut.bytesToNumberBE(b.slice(from, to)); + const slcNum = (b: Uint8Array, from: number, to: number) => bytesToNumberBE(b.slice(from, to)); /** * ECDSA signature with its (r, s) properties. Supports DER & compact representations. @@ -775,7 +791,7 @@ export function weierstrass(curveDef: CurveType): CurveFn { // pair (bytes of r, bytes of s) static fromCompact(hex: Hex) { const gl = CURVE.nByteLength; - hex = ut.ensureBytes(hex, gl * 2); + hex = ensureBytes(hex, gl * 2); return new Signature(slcNum(hex, 0, gl), slcNum(hex, gl, 2 * gl)); } @@ -785,7 +801,7 @@ export function weierstrass(curveDef: CurveType): CurveFn { const arr = hex instanceof Uint8Array; if (typeof hex !== 'string' && !arr) throw new Error(`Signature.fromDER: Expected string or Uint8Array`); - const { r, s } = DER.parseSig(arr ? hex : ut.hexToBytes(hex)); + const { r, s } = DER.parseSig(ensureBytes(hex)); return new Signature(r, s); } @@ -802,7 +818,7 @@ export function weierstrass(curveDef: CurveType): CurveFn { recoverPublicKey(msgHash: Hex): typeof Point.BASE { const { n: N } = CURVE; // ECDSA public key recovery secg.org/sec1-v2.pdf 4.1.6 const { r, s, recovery: rec } = this; - const h = bits2int_modN(ut.ensureBytes(msgHash)); // Truncate hash + const h = bits2int_modN(ensureBytes(msgHash)); // Truncate hash if (rec == null || ![0, 1, 2, 3].includes(rec)) throw new Error('recovery id invalid'); const radj = rec === 2 || rec === 3 ? r + N : r; if (radj >= Fp.ORDER) throw new Error('recovery id 2 or 3 invalid'); @@ -831,10 +847,10 @@ export function weierstrass(curveDef: CurveType): CurveFn { // DER-encoded toDERRawBytes() { - return ut.hexToBytes(this.toDERHex()); + return hexToBytes(this.toDERHex()); } toDERHex() { - const { numberToHexUnpadded: toHex } = ut; + const toHex = numberToHexUnpadded; const sHex = DER.slice(toHex(this.s)); const rHex = DER.slice(toHex(this.r)); const sHexL = sHex.length / 2; @@ -847,9 +863,15 @@ export function weierstrass(curveDef: CurveType): CurveFn { // padded bytes of r, then padded bytes of s toCompactRawBytes() { - return ut.hexToBytes(this.toCompactHex()); + // const l = CURVE.nByteLength; + // const a = new Uint8Array(2 * l); + // a.set(numberToBytesBE(this.r, l), 0); + // a.set(numberToBytesBE(this.s, l), l); + // return a; + return hexToBytes(this.toCompactHex()); } toCompactHex() { + // return bytesToHex(this.toCompactRawBytes()); return numToNByteStr(this.r) + numToNByteStr(this.s); } } @@ -869,7 +891,7 @@ export function weierstrass(curveDef: CurveType): CurveFn { * Converts some bytes to a valid private key. Needs at least (nBitLength+64) bytes. */ hashToPrivateKey: (hash: Hex): Uint8Array => - ut.numberToBytesBE(ut.hashToPrivateScalar(hash, CURVE_ORDER), CURVE.nByteLength), + numberToBytesBE(mod.hashToPrivateScalar(hash, CURVE_ORDER), CURVE.nByteLength), /** * Produces cryptographically secure private key from random of size (nBitLength+64) @@ -941,7 +963,7 @@ export function weierstrass(curveDef: CurveType): CurveFn { // For curves with nBitLength % 8 !== 0: bits2octets(bits2octets(m)) !== bits2octets(m) // for some cases, since bytes.length * 8 is not actual bitLength. const delta = bytes.length * 8 - CURVE.nBitLength; // truncate to nBitLength leftmost bits - const num = ut.bytesToNumberBE(bytes); // check for == u8 done here + const num = bytesToNumberBE(bytes); // check for == u8 done here return delta > 0 ? num >> BigInt(delta) : num; }; const bits2int_modN = @@ -950,13 +972,13 @@ export function weierstrass(curveDef: CurveType): CurveFn { return mod.mod(bits2int(bytes), CURVE_ORDER); // can't use bytesToNumberBE here }; // NOTE: pads output with zero as per spec - const ORDER_MASK = ut.bitMask(CURVE.nBitLength); + const ORDER_MASK = bitMask(CURVE.nBitLength); function int2octets(num: bigint): Uint8Array { if (typeof num !== 'bigint') throw new Error('Expected bigint'); if (!(_0n <= num && num < ORDER_MASK)) throw new Error(`Expected number < 2^${CURVE.nBitLength}`); // works with order, can have different size than numToField! - return ut.numberToBytesBE(num, CURVE.nByteLength); + return numberToBytesBE(num, CURVE.nByteLength); } // Steps A, D of RFC6979 3.2 // Creates RFC6979 seed; converts msg/privKey to numbers. @@ -969,7 +991,7 @@ export function weierstrass(curveDef: CurveType): CurveFn { // Ban legacy options throw new Error('sign() legacy options not supported'); let { lowS, prehash, extraEntropy: ent } = opts; // generates low-s sigs by default - if (prehash) msgHash = CURVE.hash(ut.ensureBytes(msgHash)); + if (prehash) msgHash = CURVE.hash(ensureBytes(msgHash)); 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 @@ -977,8 +999,8 @@ export function weierstrass(curveDef: CurveType): CurveFn { // custom truncation for stark. For other curves it is essentially same as calling bits2int + mod // However, we cannot later call bits2octets (which is truncateHash + int2octets), since nested bits2int is broken // for curves where nBitLength % 8 !== 0, so we unwrap it here as int2octets call. - // const bits2octets = (bits)=>int2octets(ut.bytesToNumberBE(truncateHash(bits))) - const h1int = bits2int_modN(ut.ensureBytes(msgHash)); + // const bits2octets = (bits)=>int2octets(bytesToNumberBE(truncateHash(bits))) + const h1int = bits2int_modN(ensureBytes(msgHash)); const h1octets = int2octets(h1int); const d = normalizePrivateKey(privateKey); @@ -987,14 +1009,14 @@ export function weierstrass(curveDef: CurveType): CurveFn { if (ent != null) { // RFC6979 3.6: additional k' (optional) if (ent === true) ent = CURVE.randomBytes(Fp.BYTES); - const e = ut.ensureBytes(ent); + const e = ensureBytes(ent); if (e.length !== Fp.BYTES) throw new Error(`sign: Expected ${Fp.BYTES} bytes of extra data`); seedArgs.push(e); } // seed is constructed from private key and message // Step D // V, 0x00 are done in HmacDRBG constructor. - const seed = ut.concatBytes(...seedArgs); + const seed = concatBytes(...seedArgs); const m = h1int; // NOTE: no need to call bits2int second time here, it is inside truncateHash! // Converts signature params into point w r/s, checks result for validity. function k2sig(kBytes: Uint8Array): Signature | undefined { @@ -1080,7 +1102,7 @@ export function weierstrass(curveDef: CurveType): CurveFn { _sig = Signature.fromCompact(signature as Hex); } } - msgHash = ut.ensureBytes(msgHash); + msgHash = ensureBytes(msgHash); P = Point.fromHex(publicKey); } catch (error) { return false; diff --git a/src/bn.ts b/src/bn.ts index 935e52c..09272ff 100644 --- a/src/bn.ts +++ b/src/bn.ts @@ -1,6 +1,6 @@ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ -import { weierstrass } from './abstract/weierstrass.js'; import { sha256 } from '@noble/hashes/sha256'; +import { weierstrass } from './abstract/weierstrass.js'; import { getHash } from './_shortw_utils.js'; import { Fp } from './abstract/modular.js'; /** diff --git a/test/bls12-381.test.js b/test/bls12-381.test.js index 86f220c..dca52ff 100644 --- a/test/bls12-381.test.js +++ b/test/bls12-381.test.js @@ -6,7 +6,7 @@ import * as fc from 'fast-check'; import { readFileSync } from 'fs'; import zkVectors from './bls12-381/zkcrypto/converted.json' assert { type: 'json' }; import pairingVectors from './bls12-381/go_pairing_vectors/pairing.json' assert { type: 'json' }; -import { wNAF } from '../lib/esm/abstract/group.js'; +import { wNAF } from '../lib/esm/abstract/curve.js'; const bls = bls12_381; const { Fp2 } = bls; const G1Point = bls.G1.ProjectivePoint; @@ -970,352 +970,6 @@ describe('pairing', () => { }); // hashToCurve describe('hash-to-curve', () => { - const DST = 'QUUX-V01-CS02-with-expander-SHA256-128'; - const VECTORS = [ - { - msg: '', - len: 0x20, - expected: '68a985b87eb6b46952128911f2a4412bbc302a9d759667f87f7a21d803f07235', - }, - { - msg: 'abc', - len: 0x20, - expected: 'd8ccab23b5985ccea865c6c97b6e5b8350e794e603b4b97902f53a8a0d605615', - }, - { - msg: 'abcdef0123456789', - len: 0x20, - expected: 'eff31487c770a893cfb36f912fbfcbff40d5661771ca4b2cb4eafe524333f5c1', - }, - { - msg: - 'q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq' + - 'qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq', - len: 0x20, - expected: 'b23a1d2b4d97b2ef7785562a7e8bac7eed54ed6e97e29aa51bfe3f12ddad1ff9', - }, - { - msg: - 'a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', - len: 0x20, - expected: '4623227bcc01293b8c130bf771da8c298dede7383243dc0993d2d94823958c4c', - }, - { - msg: '', - len: 0x80, - expected: - 'af84c27ccfd45d41914fdff5df25293e221afc53d8ad2ac0' + - '6d5e3e29485dadbee0d121587713a3e0dd4d5e69e93eb7cd4f5df4' + - 'cd103e188cf60cb02edc3edf18eda8576c412b18ffb658e3dd6ec8' + - '49469b979d444cf7b26911a08e63cf31f9dcc541708d3491184472' + - 'c2c29bb749d4286b004ceb5ee6b9a7fa5b646c993f0ced', - }, - { - msg: 'abc', - len: 0x80, - expected: - 'abba86a6129e366fc877aab32fc4ffc70120d8996c88aee2' + - 'fe4b32d6c7b6437a647e6c3163d40b76a73cf6a5674ef1d890f95b' + - '664ee0afa5359a5c4e07985635bbecbac65d747d3d2da7ec2b8221' + - 'b17b0ca9dc8a1ac1c07ea6a1e60583e2cb00058e77b7b72a298425' + - 'cd1b941ad4ec65e8afc50303a22c0f99b0509b4c895f40', - }, - { - msg: 'abcdef0123456789', - len: 0x80, - expected: - 'ef904a29bffc4cf9ee82832451c946ac3c8f8058ae97d8d6' + - '29831a74c6572bd9ebd0df635cd1f208e2038e760c4994984ce73f' + - '0d55ea9f22af83ba4734569d4bc95e18350f740c07eef653cbb9f8' + - '7910d833751825f0ebefa1abe5420bb52be14cf489b37fe1a72f7d' + - 'e2d10be453b2c9d9eb20c7e3f6edc5a60629178d9478df', - }, - { - msg: - 'q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq' + - 'qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq', - len: 0x80, - expected: - '80be107d0884f0d881bb460322f0443d38bd222db8bd0b0a' + - '5312a6fedb49c1bbd88fd75d8b9a09486c60123dfa1d73c1cc3169' + - '761b17476d3c6b7cbbd727acd0e2c942f4dd96ae3da5de368d26b3' + - '2286e32de7e5a8cb2949f866a0b80c58116b29fa7fabb3ea7d520e' + - 'e603e0c25bcaf0b9a5e92ec6a1fe4e0391d1cdbce8c68a', - }, - { - msg: - 'a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', - len: 0x80, - expected: - '546aff5444b5b79aa6148bd81728704c32decb73a3ba76e9' + - 'e75885cad9def1d06d6792f8a7d12794e90efed817d96920d72889' + - '6a4510864370c207f99bd4a608ea121700ef01ed879745ee3e4cee' + - 'f777eda6d9e5e38b90c86ea6fb0b36504ba4a45d22e86f6db5dd43' + - 'd98a294bebb9125d5b794e9d2a81181066eb954966a487', - }, - ]; - for (let i = 0; i < VECTORS.length; i++) { - const t = VECTORS[i]; - should(`hash_to_field/expand_message_xmd(SHA-256) (${i})`, () => { - const p = bls.utils.expandMessageXMD( - bls.utils.stringToBytes(t.msg), - bls.utils.stringToBytes(DST), - t.len - ); - deepStrictEqual(bls.utils.bytesToHex(p), t.expected); - }); - } - const LONG_DST = - 'QUUX-V01-CS02-with-expander-SHA256-128-long-DST-111111' + - '111111111111111111111111111111111111111111111111111111' + - '111111111111111111111111111111111111111111111111111111' + - '111111111111111111111111111111111111111111111111111111' + - '1111111111111111111111111111111111111111'; - const VECTORS_BIG = [ - { - msg: '', - len: 0x20, - expected: 'e8dc0c8b686b7ef2074086fbdd2f30e3f8bfbd3bdf177f73f04b97ce618a3ed3', - }, - { - msg: 'abc', - len: 0x20, - expected: '52dbf4f36cf560fca57dedec2ad924ee9c266341d8f3d6afe5171733b16bbb12', - }, - { - msg: 'abcdef0123456789', - len: 0x20, - expected: '35387dcf22618f3728e6c686490f8b431f76550b0b2c61cbc1ce7001536f4521', - }, - { - msg: - 'q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq' + - 'qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq', - len: 0x20, - expected: '01b637612bb18e840028be900a833a74414140dde0c4754c198532c3a0ba42bc', - }, - { - msg: - 'a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', - len: 0x20, - expected: '20cce7033cabc5460743180be6fa8aac5a103f56d481cf369a8accc0c374431b', - }, - { - msg: '', - len: 0x80, - expected: - '14604d85432c68b757e485c8894db3117992fc57e0e136f7' + - '1ad987f789a0abc287c47876978e2388a02af86b1e8d1342e5ce4f' + - '7aaa07a87321e691f6fba7e0072eecc1218aebb89fb14a0662322d' + - '5edbd873f0eb35260145cd4e64f748c5dfe60567e126604bcab1a3' + - 'ee2dc0778102ae8a5cfd1429ebc0fa6bf1a53c36f55dfc', - }, - { - msg: 'abc', - len: 0x80, - expected: - '1a30a5e36fbdb87077552b9d18b9f0aee16e80181d5b951d' + - '0471d55b66684914aef87dbb3626eaabf5ded8cd0686567e503853' + - 'e5c84c259ba0efc37f71c839da2129fe81afdaec7fbdc0ccd4c794' + - '727a17c0d20ff0ea55e1389d6982d1241cb8d165762dbc39fb0cee' + - '4474d2cbbd468a835ae5b2f20e4f959f56ab24cd6fe267', - }, - { - msg: 'abcdef0123456789', - len: 0x80, - expected: - 'd2ecef3635d2397f34a9f86438d772db19ffe9924e28a1ca' + - 'f6f1c8f15603d4028f40891044e5c7e39ebb9b31339979ff33a424' + - '9206f67d4a1e7c765410bcd249ad78d407e303675918f20f26ce6d' + - '7027ed3774512ef5b00d816e51bfcc96c3539601fa48ef1c07e494' + - 'bdc37054ba96ecb9dbd666417e3de289d4f424f502a982', - }, - { - msg: - 'q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq' + - 'qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq', - len: 0x80, - expected: - 'ed6e8c036df90111410431431a232d41a32c86e296c05d42' + - '6e5f44e75b9a50d335b2412bc6c91e0a6dc131de09c43110d9180d' + - '0a70f0d6289cb4e43b05f7ee5e9b3f42a1fad0f31bac6a625b3b5c' + - '50e3a83316783b649e5ecc9d3b1d9471cb5024b7ccf40d41d1751a' + - '04ca0356548bc6e703fca02ab521b505e8e45600508d32', - }, - { - msg: - 'a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', - len: 0x80, - expected: - '78b53f2413f3c688f07732c10e5ced29a17c6a16f717179f' + - 'fbe38d92d6c9ec296502eb9889af83a1928cd162e845b0d3c5424e' + - '83280fed3d10cffb2f8431f14e7a23f4c68819d40617589e4c4116' + - '9d0b56e0e3535be1fd71fbb08bb70c5b5ffed953d6c14bf7618b35' + - 'fc1f4c4b30538236b4b08c9fbf90462447a8ada60be495', - }, - ]; - for (let i = 0; i < VECTORS_BIG.length; i++) { - const t = VECTORS_BIG[i]; - should(`hash_to_field/expand_message_xmd(SHA-256) (long DST) (${i})`, () => { - const p = bls.utils.expandMessageXMD( - bls.utils.stringToBytes(t.msg), - bls.utils.stringToBytes(LONG_DST), - t.len - ); - deepStrictEqual(bls.utils.bytesToHex(p), t.expected); - }); - } - const DST_512 = 'QUUX-V01-CS02-with-expander-SHA512-256'; - const VECTORS_SHA512 = [ - { - msg: '', - len: 0x20, - expected: '6b9a7312411d92f921c6f68ca0b6380730a1a4d982c507211a90964c394179ba', - }, - { - msg: 'abc', - len: 0x20, - expected: '0da749f12fbe5483eb066a5f595055679b976e93abe9be6f0f6318bce7aca8dc', - }, - { - msg: 'abcdef0123456789', - len: 0x20, - expected: '087e45a86e2939ee8b91100af1583c4938e0f5fc6c9db4b107b83346bc967f58', - }, - { - msg: - 'q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq' + - 'qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq', - len: 0x20, - expected: '7336234ee9983902440f6bc35b348352013becd88938d2afec44311caf8356b3', - }, - { - msg: - 'a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', - len: 0x20, - expected: '57b5f7e766d5be68a6bfe1768e3c2b7f1228b3e4b3134956dd73a59b954c66f4', - }, - { - msg: '', - len: 0x80, - expected: - '41b037d1734a5f8df225dd8c7de38f851efdb45c372887be' + - '655212d07251b921b052b62eaed99b46f72f2ef4cc96bfaf254ebb' + - 'bec091e1a3b9e4fb5e5b619d2e0c5414800a1d882b62bb5cd1778f' + - '098b8eb6cb399d5d9d18f5d5842cf5d13d7eb00a7cff859b605da6' + - '78b318bd0e65ebff70bec88c753b159a805d2c89c55961', - }, - { - msg: 'abc', - len: 0x80, - expected: - '7f1dddd13c08b543f2e2037b14cefb255b44c83cc397c178' + - '6d975653e36a6b11bdd7732d8b38adb4a0edc26a0cef4bb4521713' + - '5456e58fbca1703cd6032cb1347ee720b87972d63fbf232587043e' + - 'd2901bce7f22610c0419751c065922b488431851041310ad659e4b' + - '23520e1772ab29dcdeb2002222a363f0c2b1c972b3efe1', - }, - { - msg: 'abcdef0123456789', - len: 0x80, - expected: - '3f721f208e6199fe903545abc26c837ce59ac6fa45733f1b' + - 'aaf0222f8b7acb0424814fcb5eecf6c1d38f06e9d0a6ccfbf85ae6' + - '12ab8735dfdf9ce84c372a77c8f9e1c1e952c3a61b7567dd069301' + - '6af51d2745822663d0c2367e3f4f0bed827feecc2aaf98c949b5ed' + - '0d35c3f1023d64ad1407924288d366ea159f46287e61ac', - }, - { - msg: - 'q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq' + - 'qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq', - len: 0x80, - expected: - 'b799b045a58c8d2b4334cf54b78260b45eec544f9f2fb5bd' + - '12fb603eaee70db7317bf807c406e26373922b7b8920fa29142703' + - 'dd52bdf280084fb7ef69da78afdf80b3586395b433dc66cde048a2' + - '58e476a561e9deba7060af40adf30c64249ca7ddea79806ee5beb9' + - 'a1422949471d267b21bc88e688e4014087a0b592b695ed', - }, - { - msg: - 'a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', - len: 0x80, - expected: - '05b0bfef265dcee87654372777b7c44177e2ae4c13a27f10' + - '3340d9cd11c86cb2426ffcad5bd964080c2aee97f03be1ca18e30a' + - '1f14e27bc11ebbd650f305269cc9fb1db08bf90bfc79b42a952b46' + - 'daf810359e7bc36452684784a64952c343c52e5124cd1f71d474d5' + - '197fefc571a92929c9084ffe1112cf5eea5192ebff330b', - }, - ]; - for (let i = 0; i < VECTORS_SHA512.length; i++) { - const t = VECTORS_SHA512[i]; - should(`hash_to_field/expand_message_xmd(SHA-256) (long DST) (${i})`, () => { - const p = bls.utils.expandMessageXMD( - bls.utils.stringToBytes(t.msg), - bls.utils.stringToBytes(DST_512), - t.len, - sha512 - ); - deepStrictEqual(bls.utils.bytesToHex(p), t.expected); - }); - } - // Point G1 const VECTORS_G1 = [ { @@ -1354,107 +1008,7 @@ describe('hash-to-curve', () => { deepStrictEqual(p.toHex(false), t.expected); }); } - const VECTORS_G1_RO = [ - { - msg: bls.utils.stringToBytes(''), - expected: - '052926add2207b76ca4fa57a8734416c8dc95e24501772c814278700eed6d1e4e8cf62d9c09db0fac349612b759e79a1' + - '08ba738453bfed09cb546dbb0783dbb3a5f1f566ed67bb6be0e8c67e2e81a4cc68ee29813bb7994998f3eae0c9c6a265', - }, - { - msg: bls.utils.stringToBytes('abc'), - expected: - '03567bc5ef9c690c2ab2ecdf6a96ef1c139cc0b2f284dca0a9a7943388a49a3aee664ba5379a7655d3c68900be2f6903' + - '0b9c15f3fe6e5cf4211f346271d7b01c8f3b28be689c8429c85b67af215533311f0b8dfaaa154fa6b88176c229f2885d', - }, - { - msg: bls.utils.stringToBytes('abcdef0123456789'), - expected: - '11e0b079dea29a68f0383ee94fed1b940995272407e3bb916bbf268c263ddd57a6a27200a784cbc248e84f357ce82d98' + - '03a87ae2caf14e8ee52e51fa2ed8eefe80f02457004ba4d486d6aa1f517c0889501dc7413753f9599b099ebcbbd2d709', - }, - { - msg: bls.utils.stringToBytes( - 'q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq' + - 'qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq' - ), - expected: - '15f68eaa693b95ccb85215dc65fa81038d69629f70aeee0d0f677cf22285e7bf58d7cb86eefe8f2e9bc3f8cb84fac488' + - '1807a1d50c29f430b8cafc4f8638dfeeadf51211e1602a5f184443076715f91bb90a48ba1e370edce6ae1062f5e6dd38', - }, - { - msg: bls.utils.stringToBytes( - 'a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' - ), - expected: - '082aabae8b7dedb0e78aeb619ad3bfd9277a2f77ba7fad20ef6aabdc6c31d19ba5a6d12283553294c1825c4b3ca2dcfe' + - '05b84ae5a942248eea39e1d91030458c40153f3b654ab7872d779ad1e942856a20c438e8d99bc8abfbf74729ce1f7ac8', - }, - ]; - for (let i = 0; i < VECTORS_G1_RO.length; i++) { - const t = VECTORS_G1_RO[i]; - should(`hashToCurve/G1 (BLS12381G1_XMD:SHA-256_SSWU_RO_) (${i})`, () => { - const p = bls.hashToCurve.G1.hashToCurve(t.msg, { - DST: 'QUUX-V01-CS02-with-BLS12381G1_XMD:SHA-256_SSWU_RO_', - }); - deepStrictEqual(p.toHex(false), t.expected); - }); - } - const VECTORS_G1_NU = [ - { - msg: bls.utils.stringToBytes(''), - expected: - '184bb665c37ff561a89ec2122dd343f20e0f4cbcaec84e3c3052ea81d1834e192c426074b02ed3dca4e7676ce4ce48ba' + - '04407b8d35af4dacc809927071fc0405218f1401a6d15af775810e4e460064bcc9468beeba82fdc751be70476c888bf3', - }, - { - msg: bls.utils.stringToBytes('abc'), - expected: - '009769f3ab59bfd551d53a5f846b9984c59b97d6842b20a2c565baa167945e3d026a3755b6345df8ec7e6acb6868ae6d' + - '1532c00cf61aa3d0ce3e5aa20c3b531a2abd2c770a790a2613818303c6b830ffc0ecf6c357af3317b9575c567f11cd2c', - }, - { - msg: bls.utils.stringToBytes('abcdef0123456789'), - expected: - '1974dbb8e6b5d20b84df7e625e2fbfecb2cdb5f77d5eae5fb2955e5ce7313cae8364bc2fff520a6c25619739c6bdcb6a' + - '15f9897e11c6441eaa676de141c8d83c37aab8667173cbe1dfd6de74d11861b961dccebcd9d289ac633455dfcc7013a3', - }, - { - msg: bls.utils.stringToBytes( - 'q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq' + - 'qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq' - ), - expected: - '0a7a047c4a8397b3446450642c2ac64d7239b61872c9ae7a59707a8f4f950f101e766afe58223b3bff3a19a7f754027c' + - '1383aebba1e4327ccff7cf9912bda0dbc77de048b71ef8c8a81111d71dc33c5e3aa6edee9cf6f5fe525d50cc50b77cc9', - }, - { - msg: bls.utils.stringToBytes( - 'a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' - ), - expected: - '0e7a16a975904f131682edbb03d9560d3e48214c9986bd50417a77108d13dc957500edf96462a3d01e62dc6cd468ef11' + - '0ae89e677711d05c30a48d6d75e76ca9fb70fe06c6dd6ff988683d89ccde29ac7d46c53bb97a59b1901abf1db66052db', - }, - ]; - for (let i = 0; i < VECTORS_G1_NU.length; i++) { - const t = VECTORS_G1_NU[i]; - should(`hashToCurve/G1 (BLS12381G1_XMD:SHA-256_SSWU_NU_) (${i})`, () => { - const p = bls.hashToCurve.G1.encodeToCurve(t.msg, { - DST: 'QUUX-V01-CS02-with-BLS12381G1_XMD:SHA-256_SSWU_NU_', - }); - deepStrictEqual(p.toHex(false), t.expected); - }); - } + const VECTORS_ENCODE_G1 = [ { msg: bls.utils.stringToBytes(''), @@ -1538,136 +1092,7 @@ describe('hash-to-curve', () => { deepStrictEqual(p.toHex(false), t.expected); }); } - const VECTORS_G2_RO = [ - { - msg: bls.utils.stringToBytes(''), - expected: - '05cb8437535e20ecffaef7752baddf98034139c38452458baeefab379ba13dff5bf5dd71b72418717047f5b0f37da03d' + - '0141ebfbdca40eb85b87142e130ab689c673cf60f1a3e98d69335266f30d9b8d4ac44c1038e9dcdd5393faf5c41fb78a' + - '12424ac32561493f3fe3c260708a12b7c620e7be00099a974e259ddc7d1f6395c3c811cdd19f1e8dbf3e9ecfdcbab8d6' + - '0503921d7f6a12805e72940b963c0cf3471c7b2a524950ca195d11062ee75ec076daf2d4bc358c4b190c0c98064fdd92', - }, - { - msg: bls.utils.stringToBytes('abc'), - expected: - '139cddbccdc5e91b9623efd38c49f81a6f83f175e80b06fc374de9eb4b41dfe4ca3a230ed250fbe3a2acf73a41177fd8' + - '02c2d18e033b960562aae3cab37a27ce00d80ccd5ba4b7fe0e7a210245129dbec7780ccc7954725f4168aff2787776e6' + - '00aa65dae3c8d732d10ecd2c50f8a1baf3001578f71c694e03866e9f3d49ac1e1ce70dd94a733534f106d4cec0eddd16' + - '1787327b68159716a37440985269cf584bcb1e621d3a7202be6ea05c4cfe244aeb197642555a0645fb87bf7466b2ba48', - }, - { - msg: bls.utils.stringToBytes('abcdef0123456789'), - expected: - '190d119345b94fbd15497bcba94ecf7db2cbfd1e1fe7da034d26cbba169fb3968288b3fafb265f9ebd380512a71c3f2c' + - '121982811d2491fde9ba7ed31ef9ca474f0e1501297f68c298e9f4c0028add35aea8bb83d53c08cfc007c1e005723cd0' + - '0bb5e7572275c567462d91807de765611490205a941a5a6af3b1691bfe596c31225d3aabdf15faff860cb4ef17c7c3be' + - '05571a0f8d3c08d094576981f4a3b8eda0a8e771fcdcc8ecceaf1356a6acf17574518acb506e435b639353c2e14827c8', - }, - { - msg: bls.utils.stringToBytes( - 'q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq' + - 'qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq' - ), - expected: - '0934aba516a52d8ae479939a91998299c76d39cc0c035cd18813bec433f587e2d7a4fef038260eef0cef4d02aae3eb91' + - '19a84dd7248a1066f737cc34502ee5555bd3c19f2ecdb3c7d9e24dc65d4e25e50d83f0f77105e955d78f4762d33c17da' + - '09bcccfa036b4847c9950780733633f13619994394c23ff0b32fa6b795844f4a0673e20282d07bc69641cee04f5e5662' + - '14f81cd421617428bc3b9fe25afbb751d934a00493524bc4e065635b0555084dd54679df1536101b2c979c0152d09192', - }, - { - msg: bls.utils.stringToBytes( - 'a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' - ), - expected: - '11fca2ff525572795a801eed17eb12785887c7b63fb77a42be46ce4a34131d71f7a73e95fee3f812aea3de78b4d01569' + - '01a6ba2f9a11fa5598b2d8ace0fbe0a0eacb65deceb476fbbcb64fd24557c2f4b18ecfc5663e54ae16a84f5ab7f62534' + - '03a47f8e6d1763ba0cad63d6114c0accbef65707825a511b251a660a9b3994249ae4e63fac38b23da0c398689ee2ab52' + - '0b6798718c8aed24bc19cb27f866f1c9effcdbf92397ad6448b5c9db90d2b9da6cbabf48adc1adf59a1a28344e79d57e', - }, - ]; - for (let i = 0; i < VECTORS_G2_RO.length; i++) { - const t = VECTORS_G2_RO[i]; - should(`hashToCurve/G2 (BLS12381G2_XMD:SHA-256_SSWU_RO_) (${i})`, () => { - const p = bls.hashToCurve.G2.hashToCurve(t.msg, { - DST: 'QUUX-V01-CS02-with-BLS12381G2_XMD:SHA-256_SSWU_RO_', - }); - deepStrictEqual(p.toHex(false), t.expected); - }); - } - const VECTORS_G2_NU = [ - { - msg: bls.utils.stringToBytes(''), - expected: - '126b855e9e69b1f691f816e48ac6977664d24d99f8724868a184186469ddfd4617367e94527d4b74fc86413483afb35b' + - '00e7f4568a82b4b7dc1f14c6aaa055edf51502319c723c4dc2688c7fe5944c213f510328082396515734b6612c4e7bb7' + - '1498aadcf7ae2b345243e281ae076df6de84455d766ab6fcdaad71fab60abb2e8b980a440043cd305db09d283c895e3d' + - '0caead0fd7b6176c01436833c79d305c78be307da5f6af6c133c47311def6ff1e0babf57a0fb5539fce7ee12407b0a42', - }, - { - msg: bls.utils.stringToBytes('abc'), - expected: - '0296238ea82c6d4adb3c838ee3cb2346049c90b96d602d7bb1b469b905c9228be25c627bffee872def773d5b2a2eb57d' + - '108ed59fd9fae381abfd1d6bce2fd2fa220990f0f837fa30e0f27914ed6e1454db0d1ee957b219f61da6ff8be0d6441f' + - '153606c417e59fb331b7ae6bce4fbf7c5190c33ce9402b5ebe2b70e44fca614f3f1382a3625ed5493843d0b0a652fc3f' + - '033f90f6057aadacae7963b0a0b379dd46750c1c94a6357c99b65f63b79e321ff50fe3053330911c56b6ceea08fee656', - }, - { - msg: bls.utils.stringToBytes('abcdef0123456789'), - expected: - '0da75be60fb6aa0e9e3143e40c42796edf15685cafe0279afd2a67c3dff1c82341f17effd402e4f1af240ea90f4b659b' + - '038af300ef34c7759a6caaa4e69363cafeed218a1f207e93b2c70d91a1263d375d6730bd6b6509dcac3ba5b567e85bf3' + - '0492f4fed741b073e5a82580f7c663f9b79e036b70ab3e51162359cec4e77c78086fe879b65ca7a47d34374c8315ac5e' + - '19b148cbdf163cf0894f29660d2e7bfb2b68e37d54cc83fd4e6e62c020eaa48709302ef8e746736c0e19342cc1ce3df4', - }, - { - msg: bls.utils.stringToBytes( - 'q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq' + - 'qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq' - ), - expected: - '12c8c05c1d5fc7bfa847f4d7d81e294e66b9a78bc9953990c358945e1f042eedafce608b67fdd3ab0cb2e6e263b9b1ad' + - '0c5ae723be00e6c3f0efe184fdc0702b64588fe77dda152ab13099a3bacd3876767fa7bbad6d6fd90b3642e902b208f9' + - '11c624c56dbe154d759d021eec60fab3d8b852395a89de497e48504366feedd4662d023af447d66926a28076813dd646' + - '04e77ddb3ede41b5ec4396b7421dd916efc68a358a0d7425bddd253547f2fb4830522358491827265dfc5bcc1928a569', - }, - { - msg: bls.utils.stringToBytes( - 'a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' - ), - expected: - '1565c2f625032d232f13121d3cfb476f45275c303a037faa255f9da62000c2c864ea881e2bcddd111edc4a3c0da3e88d' + - '0ea4e7c33d43e17cc516a72f76437c4bf81d8f4eac69ac355d3bf9b71b8138d55dc10fd458be115afa798b55dac34be1' + - '0f8991d2a1ad662e7b6f58ab787947f1fa607fce12dde171bc17903b012091b657e15333e11701edcf5b63ba2a561247' + - '043b6f5fe4e52c839148dc66f2b3751e69a0f6ebb3d056d6465d50d4108543ecd956e10fa1640dfd9bc0030cc2558d28', - }, - ]; - for (let i = 0; i < VECTORS_G2_NU.length; i++) { - const t = VECTORS_G2_NU[i]; - should(`hashToCurve/G2 (BLS12381G2_XMD:SHA-256_SSWU_NU_) (${i})`, () => { - const p = bls.hashToCurve.G2.encodeToCurve(t.msg, { - DST: 'QUUX-V01-CS02-with-BLS12381G2_XMD:SHA-256_SSWU_NU_', - }); - deepStrictEqual(p.toHex(false), t.expected); - }); - } + const VECTORS_ENCODE_G2 = [ { msg: bls.utils.stringToBytes(''), diff --git a/test/hash-to-curve.test.js b/test/hash-to-curve.test.js index d7771b6..bd82950 100644 --- a/test/hash-to-curve.test.js +++ b/test/hash-to-curve.test.js @@ -140,7 +140,6 @@ function testCurve(curve, ro, nu) { testCurve(secp256r1, p256_ro, p256_nu); testCurve(secp384r1, p384_ro, p384_nu); testCurve(secp521r1, p521_ro, p521_nu); -// TODO: remove same tests from bls12 testCurve(bls12_381.hashToCurve.G1, g1_ro, g1_nu); testCurve(bls12_381.hashToCurve.G2, g2_ro, g2_nu); testCurve(secp256k1, secp256k1_ro, secp256k1_nu);