Audited & minimal JS implementation of elliptic curve cryptography
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Low-level building blocks for implementing custom elliptic curves, including field arithmetic, point operations, signature schemes, and hash-to-curve functionality.
Abstract implementation for short Weierstrass curves (y² = x³ + ax + b) with ECDSA signatures.
import { weierstrass, ecdsa, ecdh, weierstrassPoints } from "@noble/curves/abstract/weierstrass";
/**
* Creates a Weierstrass curve implementation from curve parameters
* @param c - Curve configuration including field, curve parameters, and options
* @returns Complete curve implementation with signing, verification, and point operations
*/
function weierstrass(c: CurveType): CurveFn;
/**
* Creates ECDSA signature implementation for a curve
* @param Point - Point constructor from curve implementation
* @param Hash - Hash function (must have blockLen and outputLen properties)
* @param opts - ECDSA options including lowS canonicalization
* @returns ECDSA interface with sign, verify, and key operations
*/
function ecdsa(
Point: WeierstrassPointCons<bigint>,
Hash: CHash,
opts?: ECDSAOpts
): ECDSA;
/**
* Creates ECDH key exchange implementation
* @param Point - Point constructor from curve implementation
* @param opts - ECDH options
* @returns ECDH interface with getSharedSecret
*/
function ecdh(Point: WeierstrassPointCons<bigint>, opts?: ECDHOpts): ECDH;
/**
* Creates point operations for Weierstrass curves
* @param c - Curve points configuration
* @returns Point constructor and utilities
*/
function weierstrassPoints<T>(c: CurvePointsTypeWithLength<T>): CurvePointsRes<T>;
/**
* Simplified SWU map-to-curve implementation
* @param Fp - Base field
* @param opts - SWU parameters (A, B, Z)
* @returns Function that maps field element to curve point
*/
function mapToCurveSimpleSWU<T>(
Fp: IField<T>,
opts: { A: T; B: T; Z: T }
): (u: T) => AffinePoint<T>;
/**
* Square root ratio for SWU mapping
* @param Fp - Base field
* @param Z - SWU parameter Z
* @returns Function computing sqrt(u/v) or indication if not square
*/
function SWUFpSqrtRatio<T>(
Fp: IField<T>,
Z: T
): (u: T, v: T) => { isValid: boolean; value: T };interface CurveType {
p: bigint; // Base field modulus
n: bigint; // Curve order (number of points)
a: bigint; // Curve parameter a
b: bigint; // Curve parameter b
Gx: bigint; // Generator point x coordinate
Gy: bigint; // Generator point y coordinate
h?: bigint; // Cofactor (default 1)
Fp?: IField<bigint>; // Base field implementation
lowS?: boolean; // Canonical signature requirement
endo?: EndomorphismOpts; // GLV endomorphism for faster scalar multiplication
}
interface WeierstrassPoint<T> {
x: T;
y: T;
z: T; // Projective coordinate
add(other: WeierstrassPoint<T>): WeierstrassPoint<T>;
subtract(other: WeierstrassPoint<T>): WeierstrassPoint<T>;
multiply(scalar: bigint): WeierstrassPoint<T>;
multiplyUnsafe(scalar: bigint): WeierstrassPoint<T>;
negate(): WeierstrassPoint<T>;
double(): WeierstrassPoint<T>;
toAffine(): AffinePoint<T>;
toRawBytes(isCompressed?: boolean): Uint8Array;
toHex(isCompressed?: boolean): string;
equals(other: WeierstrassPoint<T>): boolean;
assertValidity(): void;
}
interface ECDSA {
sign(message: Hex, privateKey: PrivKey, opts?: ECDSASignOpts): ECDSASignature;
verify(signature: ECDSASignature, message: Hex, publicKey: Hex, opts?: ECDSAVerifyOpts): boolean;
getPublicKey(privateKey: PrivKey, isCompressed?: boolean): Uint8Array;
}
interface ECDH {
getSharedSecret(privateKeyA: PrivKey, publicKeyB: Hex, isCompressed?: boolean): Uint8Array;
}
interface ECDSASignature {
r: bigint;
s: bigint;
recovery?: number;
toCompactRawBytes(): Uint8Array;
toDERRawBytes(): Uint8Array;
toCompactHex(): string;
toDERHex(): string;
normalizeS(): ECDSASignature;
recoverPublicKey(message: Hex): WeierstrassPoint<bigint>;
}Abstract implementation for twisted Edwards curves (ax² + y² = 1 + dx²y²) with EdDSA signatures.
import { twistedEdwards, edwards, eddsa } from "@noble/curves/abstract/edwards";
/**
* Creates a twisted Edwards curve implementation from curve parameters
* @param c - Curve configuration including field, curve parameters, and hash function
* @returns Complete curve implementation with signing, verification, and point operations
*/
function twistedEdwards(c: CurveTypeWithLength): CurveFn;
/**
* Creates Edwards curve point operations
* @param params - Edwards curve parameters (a, d, etc.)
* @param extraOpts - Additional options like hash function and precomputation
* @returns Edwards point constructor
*/
function edwards(params: EdwardsOpts, extraOpts?: EdwardsExtraOpts): EdwardsPointCons;
/**
* Creates EdDSA signature implementation for Edwards curves
* @param Point - Edwards point constructor
* @param cHash - Hash function for EdDSA
* @param eddsaOpts - EdDSA-specific options
* @returns EdDSA interface with sign, verify, and key operations
*/
function eddsa(
Point: EdwardsPointCons,
cHash: FHash,
eddsaOpts?: EdDSAOpts
): EdDSA;interface CurveTypeWithLength {
p: bigint; // Base field modulus
n: bigint; // Curve order
a: bigint; // Curve parameter a
d: bigint; // Curve parameter d
Gx: bigint; // Generator point x coordinate
Gy: bigint; // Generator point y coordinate
h?: bigint; // Cofactor
hash: CHash; // Hash function for signatures
nByteLength?: number; // Byte length of scalar field
nBitLength?: number; // Bit length of scalar field
}
interface EdwardsPoint {
x: bigint;
y: bigint;
z: bigint;
t: bigint; // Extended coordinate t = xy/z
add(other: EdwardsPoint): EdwardsPoint;
subtract(other: EdwardsPoint): EdwardsPoint;
multiply(scalar: bigint): EdwardsPoint;
multiplyUnsafe(scalar: bigint): EdwardsPoint;
negate(): EdwardsPoint;
double(): EdwardsPoint;
toAffine(): AffinePoint<bigint>;
toRawBytes(): Uint8Array;
toHex(): string;
equals(other: EdwardsPoint): boolean;
assertValidity(): void;
}
interface EdDSA {
sign(message: Hex, privateKey: PrivKey, context?: Hex): Uint8Array;
verify(signature: Hex, message: Hex, publicKey: Hex, context?: Hex): boolean;
getPublicKey(privateKey: PrivKey): Uint8Array;
}
interface EdwardsOpts {
p: bigint; // Base field modulus
a: bigint; // Curve parameter a
d: bigint; // Curve parameter d
n: bigint; // Curve order
Gx: bigint; // Generator x coordinate
Gy: bigint; // Generator y coordinate
h?: bigint; // Cofactor
adjustScalarBytes?: (bytes: Uint8Array) => Uint8Array; // Scalar clamping function
}Field arithmetic operations and finite field implementations.
import {
Field, mod, pow, pow2, invert, tonelliShanks, FpSqrt,
FpPow, FpInvertBatch, FpDiv, hashToPrivateScalar, mapHashToField
} from "@noble/curves/abstract/modular";
/**
* Creates a finite field implementation
* @param ORDER - Field modulus (prime number)
* @param opts - Field options including sqrt implementation
* @returns Field implementation with arithmetic operations
*/
function Field(
ORDER: bigint,
opts?: {
sqrt?: (n: bigint) => bigint;
isLE?: boolean;
}
): IField<bigint>;
/**
* Modular reduction: a mod b
* @param a - Number to reduce
* @param b - Modulus
* @returns a mod b, always positive
*/
function mod(a: bigint, b: bigint): bigint;
/**
* Modular exponentiation: num^power mod modulo
* @param num - Base
* @param power - Exponent
* @param modulo - Modulus
* @returns num^power mod modulo
*/
function pow(num: bigint, power: bigint, modulo: bigint): bigint;
/**
* Optimized modular exponentiation with precomputed powers
* @param x - Base
* @param power - Exponent
* @param modulo - Modulus
* @returns x^power mod modulo
*/
function pow2(x: bigint, power: bigint, modulo: bigint): bigint;
/**
* Modular multiplicative inverse using extended Euclidean algorithm
* @param number - Number to invert
* @param modulo - Modulus (must be prime)
* @returns number^(-1) mod modulo
*/
function invert(number: bigint, modulo: bigint): bigint;
/**
* Creates Tonelli-Shanks square root implementation
* @param P - Prime modulus
* @returns Function to compute square roots in field
*/
function tonelliShanks(P: bigint): <T>(Fp: IField<T>, n: T) => T;
/**
* Creates square root implementation for finite fields
* @param P - Prime modulus
* @returns Square root function
*/
function FpSqrt(P: bigint): <T>(Fp: IField<T>, n: T) => T;
/**
* Batch modular inversion using Montgomery's trick
* @param Fp - Field implementation
* @param nums - Array of field elements to invert
* @param passZero - Whether to pass zero elements unchanged
* @returns Array of inverted elements
*/
function FpInvertBatch<T>(Fp: IField<T>, nums: T[], passZero?: boolean): T[];
/**
* Hash arbitrary data to private scalar
* @param hash - Hash bytes
* @param groupOrder - Curve order
* @param isLE - Whether hash is little-endian
* @returns Private scalar in range [1, groupOrder-1]
*/
function hashToPrivateScalar(
hash: Uint8Array,
groupOrder: bigint,
isLE?: boolean
): bigint;
/**
* Map hash output to field element
* @param key - Hash bytes
* @param fieldOrder - Field modulus
* @param isLE - Whether to use little-endian interpretation
* @returns Field element
*/
function mapHashToField(key: Uint8Array, fieldOrder: bigint, isLE?: boolean): Uint8Array;interface IField<T> {
ORDER: bigint; // Field modulus
ZERO: T; // Additive identity
ONE: T; // Multiplicative identity
BYTES: number; // Byte length of field elements
BITS: number; // Bit length of field elements
MASK: bigint; // Bit mask for field elements
// Arithmetic operations
create(num: T): T;
add(a: T, b: T): T;
sub(a: T, b: T): T;
mul(a: T, b: T): T;
div(a: T, b: T): T;
pow(a: T, b: bigint): T;
inv(a: T): T;
neg(a: T): T;
sqr(a: T): T;
sqrt(a: T): T;
// Comparison and validation
eql(a: T, b: T): boolean;
isZero(a: T): boolean;
isOne(a: T): boolean;
isValid(a: T): boolean;
// Serialization
toBytes(a: T): Uint8Array;
fromBytes(bytes: Uint8Array): T;
}
interface NLength {
nByteLength: number;
nBitLength: number;
}Standardized methods for hashing arbitrary data to elliptic curve points.
import {
createHasher, expand_message_xmd, expand_message_xof,
hash_to_field, isogenyMap
} from "@noble/curves/abstract/hash-to-curve";
/**
* Creates hash-to-curve hasher following RFC 9380
* @param Point - Curve point constructor
* @param mapToCurve - Map-to-curve function
* @param opts - Hash-to-curve options including DST and hash function
* @returns Hash-to-curve hasher with hashToCurve and encodeToCurve methods
*/
function createHasher<T>(
Point: H2CPointConstructor<T>,
mapToCurve: MapToCurve<T>,
opts: {
DST: string; // Domain separation tag
encodeDST?: string; // Encode domain separation tag
p: bigint; // Field modulus
m: number; // Field extension degree
k: number; // Security parameter
expand?: string; // Expand function ('xmd' or 'xof')
hash: CHash; // Hash function
}
): H2CHasher<T>;
/**
* Expand message using XMD (eXpand Message Domain)
* @param msg - Message to expand
* @param DST - Domain separation tag
* @param lenInBytes - Target length in bytes
* @param H - Hash function
* @returns Expanded message
*/
function expand_message_xmd(
msg: Uint8Array,
DST: Uint8Array,
lenInBytes: number,
H: CHash
): Uint8Array;
/**
* Expand message using XOF (eXtendable Output Function)
* @param msg - Message to expand
* @param DST - Domain separation tag
* @param lenInBytes - Target length in bytes
* @param k - Security parameter
* @param H - XOF function
* @returns Expanded message
*/
function expand_message_xof(
msg: Uint8Array,
DST: Uint8Array,
lenInBytes: number,
k: number,
H: any
): Uint8Array;
/**
* Hash message to field elements
* @param msg - Message bytes
* @param count - Number of field elements to produce
* @param options - Hash-to-field options
* @returns Array of field element arrays
*/
function hash_to_field(
msg: Uint8Array,
count: number,
options: {
DST: string;
p: bigint;
m: number;
k: number;
expand?: string;
hash: CHash;
}
): bigint[][];
/**
* Creates isogeny map for hash-to-curve
* @param field - Base field
* @param map - Isogeny rational map coefficients [xNum, xDen, yNum, yDen]
* @returns Isogeny mapping function
*/
function isogenyMap<T, F extends IField<T>>(
field: F,
map: [T[], T[], T[], T[]]
): (x: T, y: T) => { x: T; y: T };interface H2CHasher<T> {
hashToCurve(msg: Uint8Array, options?: { DST?: string }): H2CPoint<T>;
encodeToCurve(msg: Uint8Array, options?: { DST?: string }): H2CPoint<T>;
}
interface H2CPoint<T> {
toAffine(): AffinePoint<T>;
add(other: H2CPoint<T>): H2CPoint<T>;
multiply(scalar: bigint): H2CPoint<T>;
equals(other: H2CPoint<T>): boolean;
}
type MapToCurve<T> = (scalar: bigint[]) => AffinePoint<T>;
type H2CMethod<T> = (msg: Uint8Array, options?: { DST?: string }) => H2CPoint<T>;
interface AffinePoint<T> {
x: T;
y: T;
}import { bls } from "@noble/curves/abstract/bls";
/**
* Creates BLS signature implementation for pairing-friendly curves
* @param CURVE - BLS curve configuration with G1, G2, GT, and pairing
* @returns BLS signature interface with aggregation support
*/
function bls<T>(CURVE: BLSOpts<T>): BLSCurveFn;
interface BLSCurveFn {
sign(message: Hex, privateKey: PrivKey): Uint8Array;
verify(signature: Hex, message: Hex, publicKey: Hex): boolean;
aggregatePublicKeys(publicKeys: Hex[]): Uint8Array;
aggregateSignatures(signatures: Hex[]): Uint8Array;
verifyBatch(signature: Hex, messages: Hex[], publicKeys: Hex[]): boolean;
getPublicKey(privateKey: PrivKey): Uint8Array;
}import { montgomery } from "@noble/curves/abstract/montgomery";
/**
* Creates Montgomery curve implementation for key exchange
* @param opts - Montgomery curve parameters
* @returns Montgomery curve with key exchange operations
*/
function montgomery(opts: MontgomeryOpts): MontgomeryCurveFn;
interface MontgomeryCurveFn {
getPublicKey(privateKey: PrivKey): Uint8Array;
getSharedSecret(privateKey: PrivKey, publicKey: Hex): Uint8Array;
utils: {
randomPrivateKey(): Uint8Array;
};
}Extension field operations for pairing-friendly curves, enabling efficient computation over Fp2, Fp6, and Fp12.
import { tower12 } from "@noble/curves/abstract/tower";
/**
* Creates tower field operations for BLS-style pairing curves
* @param opts - Tower field configuration including base field and extension parameters
* @returns Field operations for Fp2, Fp6, and Fp12 extensions
*/
function tower12(opts: Tower12Opts): {
Fp2: Fp2Bls;
Fp6: Fp6Bls;
Fp12: Fp12Bls;
psiFrobenius(x: Fp2): Fp2;
};
type Fp2 = { c0: bigint; c1: bigint };
type Fp6 = { c0: Fp2; c1: Fp2; c2: Fp2 };
type Fp12 = { c0: Fp6; c1: Fp6 };Algebraic hash function designed for zero-knowledge proof systems with efficient circuit representation.
import { poseidon, poseidonSponge } from "@noble/curves/abstract/poseidon";
/**
* Creates Poseidon hash function
* @param opts - Poseidon configuration including field size, rounds, and constants
* @returns Poseidon hash function instance
*/
function poseidon(opts: PoseidonOpts): PoseidonFn;
/**
* Creates Poseidon sponge construction for variable-length input
* @param opts - Sponge configuration parameters
* @returns Factory function for Poseidon sponge instances
*/
function poseidonSponge(opts: PoseidonSpongeOpts): () => PoseidonSponge;
interface PoseidonFn {
(inputs: bigint[]): bigint;
m: number;
roundConstants: bigint[][];
}Polynomial operations and number-theoretic transforms for efficient computation in cryptographic protocols, including FFT/NTT, polynomial arithmetic, and roots of unity generation.
import { FFT, poly, rootsOfUnity } from "@noble/curves/abstract/fft";
/**
* Creates FFT/NTT operations for polynomial arithmetic
* @param roots - Roots of unity for the transformation
* @param opts - FFT configuration options including field operations
* @returns FFT transformation methods for direct and inverse transforms
*/
function FFT<T>(roots: RootsOfUnity, opts: FFTOpts<T, bigint>): FFTMethods<T>;
/**
* Creates comprehensive polynomial operations over a field
* @param field - Field operations for polynomial coefficients
* @param roots - Roots of unity for FFT-based operations
* @param create - Function to create polynomial instances
* @param fft - Optional pre-computed FFT methods
* @param length - Default polynomial length
* @returns Complete polynomial arithmetic suite
*/
function poly<T, P extends Polynomial<T>>(
field: IField<T>,
roots: RootsOfUnity,
create?: CreatePolyFn<P, T>,
fft?: FFTMethods<T>,
length?: number
): PolyFn<P, T>;
/**
* Generates roots of unity for FFT operations
* @param field - Field operations (must have primitive root)
* @param generator - Optional primitive root generator
* @returns Cached roots of unity and bit-reversal permutation utilities
*/
function rootsOfUnity(field: IField<bigint>, generator?: bigint): RootsOfUnity;
// Core FFT interfaces
interface FFTMethods<T> {
/** Forward FFT: time domain to frequency domain */
direct<P extends Polynomial<T>>(values: P, brpInput?: boolean, brpOutput?: boolean): P;
/** Inverse FFT: frequency domain to time domain */
inverse<P extends Polynomial<T>>(values: P, brpInput?: boolean, brpOutput?: boolean): P;
}
interface RootsOfUnity {
/** Get roots of unity for given bit size */
roots(bits: number): bigint[];
/** Get bit-reversal permutation indices */
brp(bits: number): bigint[];
/** Get inverse roots of unity */
inverse(bits: number): bigint[];
/** Get primitive root for given bit size */
omega(bits: number): bigint;
/** Clear cached values */
clear(): void;
}
// Polynomial operations
interface PolyFn<P extends Polynomial<T>, T> {
/** Create zero polynomial */
ZERO: P;
/** Create polynomial from coefficients */
fromCoeffs(coeffs: T[]): P;
/** Create polynomial from evaluations */
fromEvals(evals: T[]): P;
/** Add two polynomials */
add(a: P, b: P): P;
/** Subtract two polynomials */
sub(a: P, b: P): P;
/** Multiply two polynomials (FFT-accelerated) */
mul(a: P, b: P): P;
/** Multiply polynomial by scalar */
scale(a: P, scalar: T): P;
/** Compute polynomial division with quotient and remainder */
divmod(a: P, b: P): { quotient: P; remainder: P };
/** Evaluate polynomial at point */
eval(poly: P, point: T): T;
/** Multi-point evaluation */
evalMany(poly: P, points: T[]): T[];
/** Polynomial interpolation from points */
interpolate(points: Array<{ x: T; y: T }>): P;
/** Convert between coefficient and evaluation representations */
toCoeffs(poly: P): T[];
toEvals(poly: P): T[];
/** FFT-based operations */
fft: FFTMethods<T>;
}
// Configuration types
interface FFTOpts<T, F> {
/** Field for polynomial coefficients */
field: IField<F>;
/** Function to create polynomial from array */
create: CreatePolyFn<Polynomial<T>, T>;
/** Optional custom multiplication for performance */
mul?: (a: T, b: F) => T;
/** Optional custom addition for performance */
add?: (a: T, b: T) => T;
/** Optional custom zero element */
zero?: () => T;
}
interface Polynomial<T> extends MutableArrayLike<T> {
[index: number]: T;
length: number;
slice(start?: number, end?: number): this;
}
interface MutableArrayLike<T> {
[index: number]: T;
length: number;
}
type CreatePolyFn<P, T> = (values: T[]) => P;FFT Usage Examples:
import { FFT, poly, rootsOfUnity } from "@noble/curves/abstract/fft";
import { Field } from "@noble/curves/abstract/modular";
// Create field for polynomial coefficients
const Fp = Field(2n ** 255n - 19n); // Ed25519 field
// Generate roots of unity for FFT
const roots = rootsOfUnity(Fp);
// Create FFT operations
const fft = FFT(roots, {
field: Fp,
create: (values) => new Uint8Array(values.map(v => Number(v))),
});
// Create polynomial operations with FFT acceleration
const polynomial = poly(Fp, roots, (coeffs) => new BigUint64Array(coeffs));
// Polynomial arithmetic
const p1 = polynomial.fromCoeffs([1n, 2n, 3n]); // 3x² + 2x + 1
const p2 = polynomial.fromCoeffs([4n, 5n]); // 5x + 4
const sum = polynomial.add(p1, p2); // 3x² + 7x + 5
const product = polynomial.mul(p1, p2); // FFT-accelerated multiplication
// Evaluation and interpolation
const result = polynomial.eval(p1, 10n); // Evaluate at x = 10
const points = [
{ x: 1n, y: 6n },
{ x: 2n, y: 17n },
{ x: 3n, y: 34n }
];
const interpolated = polynomial.interpolate(points);Use Cases:
RFC 9497 implementation of Oblivious Pseudorandom Functions supporting OPRF, VOPRF, and POPRF modes for privacy-preserving protocols.
import { createORPF } from "@noble/curves/abstract/oprf";
/**
* Creates OPRF implementation for a specific curve and hash function
* @param opts - OPRF configuration including curve, hash, and domain separation
* @returns Complete OPRF suite with three protocol variants
*/
function createORPF<P extends CurvePoint<any, P>>(opts: OPRFOpts<P>): OPRF;
/**
* OPRF suite providing three protocol variants
*/
interface OPRF {
readonly name: string; // Ciphersuite identifier
// Base OPRF mode (mode 0x00) - simple, non-verifiable
readonly oprf: {
generateKeyPair(): OPRFKeys;
deriveKeyPair(seed: Bytes, keyInfo: Bytes): OPRFKeys;
blind(input: Bytes, rng?: RNG): OPRFBlind;
blindEvaluate(secretKey: ScalarBytes, blinded: PointBytes): PointBytes;
finalize(input: Bytes, blind: ScalarBytes, evaluated: PointBytes): Bytes;
};
// Verifiable OPRF mode (mode 0x01) - includes proofs
readonly voprf: {
generateKeyPair(): OPRFKeys;
deriveKeyPair(seed: Bytes, keyInfo: Bytes): OPRFKeys;
blind(input: Bytes, rng?: RNG): OPRFBlind;
blindEvaluate(secretKey: ScalarBytes, publicKey: PointBytes, blinded: PointBytes, rng?: RNG): OPRFBlindEval;
blindEvaluateBatch(secretKey: ScalarBytes, publicKey: PointBytes, blinded: PointBytes[], rng?: RNG): OPRFBlindEvalBatch;
finalize(input: Bytes, blind: ScalarBytes, evaluated: PointBytes, blinded: PointBytes, publicKey: PointBytes, proof: Bytes): Bytes;
finalizeBatch(items: OPRFFinalizeItem[], publicKey: PointBytes, proof: Bytes): Bytes[];
};
// Partially Oblivious PRF mode (mode 0x02) - includes domain separation
readonly poprf: (info: Bytes) => {
generateKeyPair(): OPRFKeys;
deriveKeyPair(seed: Bytes, keyInfo: Bytes): OPRFKeys;
blind(input: Bytes, publicKey: PointBytes, rng?: RNG): OPRFBlind & { tweakedKey: PointBytes };
blindEvaluate(secretKey: ScalarBytes, blinded: PointBytes, rng?: RNG): OPRFBlindEval;
blindEvaluateBatch(secretKey: ScalarBytes, blinded: PointBytes[], rng: RNG): OPRFBlindEvalBatch;
finalize(input: Bytes, blind: ScalarBytes, evaluated: PointBytes, blinded: PointBytes, proof: Bytes, tweakedKey: PointBytes): Bytes;
finalizeBatch(items: OPRFFinalizeItem[], proof: Bytes, tweakedKey: PointBytes): Bytes[];
};
}
// OPRF configuration
interface OPRFOpts<P extends CurvePoint<any, P>> {
name: string; // Ciphersuite name
Point: CurvePointCons<P>; // Curve point constructor
hash: (msg: Bytes) => Bytes; // Hash function
hashToScalar: (msg: Uint8Array, options: htfBasicOpts) => bigint; // Hash-to-scalar
hashToGroup: ((msg: Uint8Array, options: htfBasicOpts) => P) | H2CMethod<P>; // Hash-to-curve
}
// OPRF data types
interface OPRFKeys {
secretKey: ScalarBytes;
publicKey: PointBytes;
}
interface OPRFBlind {
blind: Uint8Array; // Secret blinding scalar
blinded: Uint8Array; // Blinded group element to send to server
}
interface OPRFBlindEval {
evaluated: PointBytes; // Server's evaluation result
proof: Bytes; // DLEQ proof of correct evaluation
}
interface OPRFBlindEvalBatch {
evaluated: PointBytes[]; // Batch evaluation results
proof: Bytes; // Single proof for entire batch
}
interface OPRFFinalizeItem {
input: Bytes;
blind: ScalarBytes;
evaluated: PointBytes;
blinded: PointBytes;
}
type PointBytes = Uint8Array;
type ScalarBytes = Uint8Array;
type Bytes = Uint8Array;
type RNG = typeof randomBytes;OPRF Protocol Flow:
import { createORPF } from "@noble/curves/abstract/oprf";
import { ristretto255 } from "@noble/curves/ed25519";
import { sha512 } from "@noble/hashes/sha512";
// Create OPRF suite for Ristretto255 + SHA-512
const oprf = createORPF({
name: "ristretto255-SHA512",
Point: ristretto255.Point,
hash: sha512,
hashToScalar: ristretto255.hashToScalar,
hashToGroup: ristretto255.hashToCurve
});
// Server: Generate key pair
const serverKeys = oprf.voprf.generateKeyPair();
// Client: Blind input
const input = new TextEncoder().encode("secret-input");
const { blind, blinded } = oprf.voprf.blind(input);
// Server: Evaluate blinded input with proof
const { evaluated, proof } = oprf.voprf.blindEvaluate(
serverKeys.secretKey,
serverKeys.publicKey,
blinded
);
// Client: Finalize to get OPRF output
const output = oprf.voprf.finalize(
input,
blind,
evaluated,
blinded,
serverKeys.publicKey,
proof
);Use Cases:
Core abstractions and interfaces for elliptic curve implementations, providing foundational types and multi-scalar multiplication.
import { Group, GroupCons, CurvePoint, pippenger } from "@noble/curves/abstract/curve";
// Base group interface for algebraic structures
interface Group<T extends Group<T>> {
double(): T;
negate(): T;
add(other: T): T;
subtract(other: T): T;
equals(other: T): boolean;
multiply(scalar: bigint): T;
}
// Group constructor interface
interface GroupCons<T extends Group<T>> {
ZERO: T;
BASE: T;
fromBytes(bytes: Uint8Array): T;
fromHex(hex: string): T;
}
// Curve point interface extending Group
interface CurvePoint<U, T extends CurvePoint<U, T> = CurvePoint<U, any>> extends Group<T> {
readonly Fp: IField<U>;
readonly Fn: IField<bigint>;
x: U;
y: U;
is0(): boolean;
toBytes(isCompressed?: boolean): Uint8Array;
toHex(isCompressed?: boolean): string;
toRawBytes(isCompressed?: boolean): Uint8Array;
assertValidity(): void;
}
/**
* Multi-scalar multiplication using Pippenger's algorithm
* @param Point - Group constructor
* @param Fn - Scalar field
* @param points - Array of points to multiply
* @param scalars - Array of scalars for multiplication
* @returns Result of sum(points[i] * scalars[i])
*/
function pippenger<T extends Group<T>>(
Point: GroupCons<T>,
Fn: IField<bigint>,
points: T[],
scalars: bigint[]
): T;