UNPKG

@noble/curves

Version:

Audited & minimal JS implementation of elliptic curve cryptography

411 lines 17.6 kB
/** * BLS != BLS. * The file implements BLS (Boneh-Lynn-Shacham) signatures. * Used in both BLS (Barreto-Lynn-Scott) and BN (Barreto-Naehrig) * families of pairing-friendly curves. * Consists of two curves: G1 and G2: * - G1 is a subgroup of (x, y) E(Fq) over y² = x³ + 4. * - G2 is a subgroup of ((x₁, x₂+i), (y₁, y₂+i)) E(Fq²) over y² = x³ + 4(1 + i) where i is √-1 * - Gt, created by bilinear (ate) pairing e(G1, G2), consists of p-th roots of unity in * Fq^k where k is embedding degree. Only degree 12 is currently supported, 24 is not. * Pairing is used to aggregate and verify signatures. * There are two modes of operation: * - Long signatures: X-byte keys + 2X-byte sigs (G1 keys + G2 sigs). * - Short signatures: 2X-byte keys + X-byte sigs (G2 keys + G1 sigs). * @module **/ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ import { type TArg, type TRet } from '../utils.ts'; import { type CurveLengths } from './curve.ts'; import { type H2CHasher, type H2COpts, type MapToCurve } from './hash-to-curve.ts'; import { type IField } from './modular.ts'; import type { Fp12, Fp12Bls, Fp2, Fp2Bls, Fp6Bls } from './tower.ts'; import { type WeierstrassPoint, type WeierstrassPointCons } from './weierstrass.ts'; type Fp = bigint; /** * Twist convention used by the pairing formulas for a concrete curve family. * BLS12-381 uses a multiplicative twist, while BN254 uses a divisive one. */ export type BlsTwistType = 'multiplicative' | 'divisive'; /** * Codec exposed as `curve.shortSignatures.Signature`. * Use it to parse or serialize G1 signatures in short-signature mode. * In this mode, public keys live in G2. */ export type BlsShortSignatureCoder<Fp> = { /** * Parse a compressed signature from raw bytes. * @param bytes - Compressed signature bytes. * @returns Parsed signature point. */ fromBytes(bytes: TArg<Uint8Array>): WeierstrassPoint<Fp>; /** * Parse a compressed signature from a hex string. * @param hex - Compressed signature hex string. * @returns Parsed signature point. */ fromHex(hex: string): WeierstrassPoint<Fp>; /** * Encode a signature point into compressed bytes. * @param point - Signature point. * @returns Compressed signature bytes. */ toBytes(point: WeierstrassPoint<Fp>): TRet<Uint8Array>; /** * Encode a signature point into a hex string. * @param point - Signature point. * @returns Compressed signature hex. */ toHex(point: WeierstrassPoint<Fp>): string; }; /** * Codec exposed as `curve.longSignatures.Signature`. * Use it to parse or serialize G2 signatures in long-signature mode. * In this mode, public keys live in G1. */ export type BlsLongSignatureCoder<Fp> = { /** * Parse a compressed signature from raw bytes. * @param bytes - Compressed signature bytes. * @returns Parsed signature point. */ fromBytes(bytes: TArg<Uint8Array>): WeierstrassPoint<Fp>; /** * Parse a compressed signature from a hex string. * @param hex - Compressed signature hex string. * @returns Parsed signature point. */ fromHex(hex: string): WeierstrassPoint<Fp>; /** * Encode a signature point into compressed bytes. * @param point - Signature point. * @returns Compressed signature bytes. */ toBytes(point: WeierstrassPoint<Fp>): TRet<Uint8Array>; /** * Encode a signature point into a hex string. * @param point - Signature point. * @returns Compressed signature hex. */ toHex(point: WeierstrassPoint<Fp>): string; }; /** Tower fields needed by pairing code, hash-to-curve, and subgroup arithmetic. */ export type BlsFields = { /** Base field of G1 coordinates. */ Fp: IField<Fp>; /** Scalar field used for secret scalars and subgroup order arithmetic. */ Fr: IField<bigint>; /** Quadratic extension field used by G2. */ Fp2: Fp2Bls; /** Sextic extension field used inside pairing arithmetic. */ Fp6: Fp6Bls; /** Degree-12 extension field that contains the GT target group. */ Fp12: Fp12Bls; }; /** * Callback used by pairing post-processing hooks to add one more G2 point to the Miller-loop state. * @param Rx - Current projective X coordinate. * @param Ry - Current projective Y coordinate. * @param Rz - Current projective Z coordinate. * @param Qx - G2 affine x coordinate. * @param Qy - G2 affine y coordinate. * @returns Updated projective accumulator coordinates. */ export type BlsPostPrecomputePointAddFn = (Rx: Fp2, Ry: Fp2, Rz: Fp2, Qx: Fp2, Qy: Fp2) => { Rx: Fp2; Ry: Fp2; Rz: Fp2; }; /** * Hook for curve-specific pairing cleanup after the Miller loop precomputes are built. * @param Rx - Current projective X coordinate. * @param Ry - Current projective Y coordinate. * @param Rz - Current projective Z coordinate. * @param Qx - G2 affine x coordinate. * @param Qy - G2 affine y coordinate. * @param pointAdd - Callback used to fold one more point into the accumulator. */ export type BlsPostPrecomputeFn = (Rx: Fp2, Ry: Fp2, Rz: Fp2, Qx: Fp2, Qy: Fp2, pointAdd: BlsPostPrecomputePointAddFn) => void; /** Low-level pairing helpers shared by BLS curve bundles. */ export type BlsPairing = { /** Byte lengths for keys and signatures exposed by this pairing family. */ lengths: CurveLengths; /** Scalar field used by the pairing and signing helpers. */ Fr: IField<bigint>; /** Target field used for the GT result of pairings. */ Fp12: Fp12Bls; /** * Build Miller-loop precomputes for one G2 point. * @param p - G2 point to precompute. * @returns Pairing precompute table. */ calcPairingPrecomputes: (p: WeierstrassPoint<Fp2>) => Precompute; /** * Evaluate a batch of Miller loops from precomputed line coefficients. * @param pairs - Precomputed Miller-loop inputs. * @returns Accumulated GT value before or after final exponentiation. */ millerLoopBatch: (pairs: [Precompute, Fp, Fp][]) => Fp12; /** * Pair one G1 point with one G2 point. * @param P - G1 point. * @param Q - G2 point. * @param withFinalExponent - Whether to apply the final exponentiation step. * @returns GT pairing result. * @throws If either point is the point at infinity. {@link Error} */ pairing: (P: WeierstrassPoint<Fp>, Q: WeierstrassPoint<Fp2>, withFinalExponent?: boolean) => Fp12; /** * Pair many G1/G2 pairs in one batch. * @param pairs - Point pairs to accumulate. * @param withFinalExponent - Whether to apply the final exponentiation step. * @returns GT pairing result. Empty input returns the multiplicative identity in GT. */ pairingBatch: (pairs: { g1: WeierstrassPoint<Fp>; g2: WeierstrassPoint<Fp2>; }[], withFinalExponent?: boolean) => Fp12; /** * Generate a random secret key for this pairing family. * @param seed - Optional seed material. * @returns Secret key bytes. */ randomSecretKey: (seed?: TArg<Uint8Array>) => TRet<Uint8Array>; }; /** * Parameters that define the Miller-loop shape and twist handling * for a concrete pairing family. */ export type BlsPairingParams = { /** Signed loop parameter used by the Miller loop. */ ateLoopSize: bigint; /** Whether the signed Miller-loop parameter is negative. */ xNegative: boolean; /** * Twist convention used by the pairing formulas. * BLS12-381 is multiplicative; BN254 is divisive. */ twistType: BlsTwistType; /** * Optional RNG override used by helper constructors. * Receives the requested byte length and returns random bytes. */ randomBytes?: (len?: number) => TRet<Uint8Array>; /** * Optional hook for curve-specific untwisting after precomputation. * Used by BN254 after the Miller loop. */ postPrecompute?: BlsPostPrecomputeFn; }; /** Hash-to-curve settings shared by the G1 and G2 hashers inside a BLS curve bundle. */ export type BlsHasherParams = { /** * Optional map-to-curve override for G1. * Receives the hash-to-field tuple and returns one affine G1 point. */ mapToG1?: MapToCurve<Fp>; /** * Optional map-to-curve override for G2. * Receives the hash-to-field tuple and returns one affine G2 point. */ mapToG2?: MapToCurve<Fp2>; /** Shared baseline hash-to-curve options. */ hasherOpts: H2COpts; /** G1-specific hash-to-curve options merged on top of `hasherOpts`. */ hasherOptsG1: H2COpts; /** G2-specific hash-to-curve options merged on top of `hasherOpts`. */ hasherOptsG2: H2COpts; }; type PrecomputeSingle = [Fp2, Fp2, Fp2][]; type Precompute = PrecomputeSingle[]; /** * BLS consists of two curves: G1 and G2: * - G1 is a subgroup of (x, y) E(Fq) over y² = x³ + 4. * - G2 is a subgroup of ((x₁, x₂+i), (y₁, y₂+i)) E(Fq²) over y² = x³ + 4(1 + i) where i is √-1 */ export interface BlsCurvePair { /** Byte lengths for keys and signatures exposed by this curve family. */ lengths: CurveLengths; /** * Shared Miller-loop batch evaluator. * @param pairs - Precomputed Miller-loop inputs. * @returns Accumulated GT value. */ millerLoopBatch: BlsPairing['millerLoopBatch']; /** * Pair one G1 point with one G2 point. * @param P - G1 point. * @param Q - G2 point. * @param withFinalExponent - Whether to apply the final exponentiation step. * @returns GT pairing result. * @throws If either point is the point at infinity. {@link Error} */ pairing: BlsPairing['pairing']; /** * Pair many G1/G2 pairs in one batch. * @param pairs - Point pairs to accumulate. * @param withFinalExponent - Whether to apply the final exponentiation step. * @returns GT pairing result. Empty input returns the multiplicative identity in GT. */ pairingBatch: BlsPairing['pairingBatch']; /** G1 point constructor for the base field subgroup. */ G1: { Point: WeierstrassPointCons<Fp>; }; /** G2 point constructor for the twist subgroup. */ G2: { Point: WeierstrassPointCons<Fp2>; }; /** Tower fields exposed by the pairing implementation. */ fields: { Fp: IField<Fp>; Fp2: Fp2Bls; Fp6: Fp6Bls; Fp12: Fp12Bls; Fr: IField<bigint>; }; /** Utility helpers shared by hashers and signers. */ utils: { randomSecretKey: (seed?: TArg<Uint8Array>) => TRet<Uint8Array>; calcPairingPrecomputes: BlsPairing['calcPairingPrecomputes']; }; /** Public pairing parameters exposed for introspection. */ params: { ateLoopSize: bigint; twistType: BlsTwistType; }; } /** BLS curve bundle extended with hash-to-curve helpers for G1 and G2. */ export interface BlsCurvePairWithHashers extends BlsCurvePair { /** G1 hasher bundle with RFC 9380 helpers. */ G1: H2CHasher<WeierstrassPointCons<Fp>>; /** G2 hasher bundle with RFC 9380 helpers. */ G2: H2CHasher<WeierstrassPointCons<Fp2>>; } /** BLS curve bundle extended with both hashers and signature helpers. */ export interface BlsCurvePairWithSignatures extends BlsCurvePairWithHashers { /** Long-signature mode: G1 public keys and G2 signatures. */ longSignatures: BlsSigs<bigint, Fp2>; /** Short-signature mode: G2 public keys and G1 signatures. */ shortSignatures: BlsSigs<Fp2, bigint>; } type BLSInput = TArg<Uint8Array>; /** BLS signer helpers for one signature mode. */ export interface BlsSigs<P, S> { /** Byte lengths for secret keys, public keys, and signatures. */ lengths: CurveLengths; /** * Generate a secret/public key pair for this signature mode. * @param seed - Optional seed material. * @returns Secret and public key pair. */ keygen(seed?: TArg<Uint8Array>): { secretKey: TRet<Uint8Array>; publicKey: WeierstrassPoint<P>; }; /** * Derive the public key from a secret key. * @param secretKey - Secret key bytes. * @returns Public-key point. */ getPublicKey(secretKey: TArg<Uint8Array>): WeierstrassPoint<P>; /** * Sign a message already hashed onto the signature subgroup. * @param hashedMessage - Message mapped to the signature subgroup. * @param secretKey - Secret key bytes. * @returns Signature point. */ sign(hashedMessage: WeierstrassPoint<S>, secretKey: TArg<Uint8Array>): WeierstrassPoint<S>; /** * Verify one signature against one public key and hashed message. * @param signature - Signature point or encoded signature. * @param message - Hashed message point. * @param publicKey - Public-key point or encoded key. * @returns Whether the signature is valid. */ verify(signature: WeierstrassPoint<S> | BLSInput, message: WeierstrassPoint<S>, publicKey: WeierstrassPoint<P> | BLSInput): boolean; /** * Verify one aggregated signature against many `(message, publicKey)` pairs. * @param signature - Aggregated signature. * @param items - Message/public-key pairs. * @returns Whether the aggregated signature is valid. Same-message aggregate verification still * requires proof of possession or another rogue-key defense from the caller. */ verifyBatch: (signature: WeierstrassPoint<S> | BLSInput, items: { message: WeierstrassPoint<S>; publicKey: WeierstrassPoint<P> | BLSInput; }[]) => boolean; /** * Add many public keys into one aggregate point. * @param publicKeys - Public keys to aggregate. * @returns Aggregated public-key point. This is raw point addition and does not add proof of * possession or rogue-key protection on its own. */ aggregatePublicKeys(publicKeys: (WeierstrassPoint<P> | BLSInput)[]): WeierstrassPoint<P>; /** * Add many signatures into one aggregate point. * @param signatures - Signatures to aggregate. * @returns Aggregated signature point. This is raw point addition and does not change the proof * of possession requirements of the aggregate-verification scheme. */ aggregateSignatures(signatures: (WeierstrassPoint<S> | BLSInput)[]): WeierstrassPoint<S>; /** * Hash an arbitrary message onto the signature subgroup. * @param message - Message bytes. * @param DST - Optional domain separation tag. * @returns Curve point on the signature subgroup. */ hash(message: TArg<Uint8Array>, DST?: TArg<string | Uint8Array>): WeierstrassPoint<S>; /** Signature codec for this mode. */ Signature: BlsLongSignatureCoder<S>; } type BlsSignatureCoders = Partial<{ LongSignature: BlsLongSignatureCoder<Fp2>; ShortSignature: BlsShortSignatureCoder<Fp>; }>; /** * @param fields - Tower field implementations. * @param G1_Point - G1 point constructor. * @param G2_Point - G2 point constructor. * @param params - Pairing parameters. See {@link BlsPairingParams}. * @returns Pairing-only BLS helpers. The returned pairing surface rejects infinity inputs, while * empty `pairingBatch(...)` calls return the multiplicative identity in GT. This keeps the * low-level pairing API fail-closed for BLS-style callers, where identity points usually signal * broken hash / wiring instead of an intentionally neutral pairing term. This also eagerly * precomputes the G1 base-point table as a performance side effect. * @throws If the pairing parameters or underlying curve helpers are inconsistent. {@link Error} * @example * ```ts * import { blsBasic } from '@noble/curves/abstract/bls.js'; * import { bn254 } from '@noble/curves/bn254.js'; * // Pair a G1 point with a G2 point without the higher-level signer helpers. * const gt = bn254.pairing(bn254.G1.Point.BASE, bn254.G2.Point.BASE); * ``` */ export declare function blsBasic(fields: TArg<BlsFields>, G1_Point: WeierstrassPointCons<Fp>, G2_Point: WeierstrassPointCons<Fp2>, params: TArg<BlsPairingParams>): BlsCurvePair; /** * @param fields - Tower field implementations. * @param G1_Point - G1 point constructor. * @param G2_Point - G2 point constructor. * @param params - Pairing parameters. See {@link BlsPairingParams}. * @param hasherParams - Hash-to-curve configuration. See {@link BlsHasherParams}. * @param signatureCoders - Signature codecs. * @returns BLS helpers with signers. The inherited pairing surface still rejects infinity inputs, * and empty `pairingBatch(...)` calls still return the multiplicative identity in GT. Aggregate * verification still requires proof of possession or another rogue-key defense from the caller. * @throws If the pairing, hashing, or signature helpers are configured inconsistently. {@link Error} * @example * ```ts * import { bls } from '@noble/curves/abstract/bls.js'; * import { bls12_381 } from '@noble/curves/bls12-381.js'; * const sigs = bls12_381.longSignatures; * // Use the full BLS helper set when you need hashing, keygen, signing, and verification. * const { secretKey, publicKey } = sigs.keygen(); * const msg = sigs.hash(new TextEncoder().encode('hello noble')); * const sig = sigs.sign(msg, secretKey); * const isValid = sigs.verify(sig, msg, publicKey); * ``` */ export declare function bls(fields: TArg<BlsFields>, G1_Point: WeierstrassPointCons<Fp>, G2_Point: WeierstrassPointCons<Fp2>, params: TArg<BlsPairingParams>, hasherParams: TArg<BlsHasherParams>, signatureCoders: BlsSignatureCoders): BlsCurvePairWithSignatures; export {}; //# sourceMappingURL=bls.d.ts.map