@noble/curves
Version:
Audited & minimal JS implementation of elliptic curve cryptography
239 lines • 10 kB
TypeScript
/**
* hash-to-curve from RFC 9380.
* Hashes arbitrary-length byte strings to a list of one or more elements of a finite field F.
* https://www.rfc-editor.org/rfc/rfc9380
* @module
*/
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
import type { CHash, TArg, TRet } from '../utils.ts';
import type { AffinePoint, PC_ANY, PC_F, PC_P } from './curve.ts';
import { type IField } from './modular.ts';
/** ASCII domain-separation tag or raw bytes. */
export type AsciiOrBytes = string | Uint8Array;
type H2CDefaults = {
DST: AsciiOrBytes;
expand: 'xmd' | 'xof';
hash: CHash;
p: bigint;
m: number;
k: number;
encodeDST?: AsciiOrBytes;
};
/**
* * `DST` is a domain separation tag, defined in section 2.2.5
* * `p` characteristic of F, where F is a finite field of characteristic p and order q = p^m
* * `m` is extension degree (1 for prime fields)
* * `k` is the target security target in bits (e.g. 128), from section 5.1
* * `expand` is `xmd` (SHA2, SHA3, BLAKE) or `xof` (SHAKE, BLAKE-XOF)
* * `hash` conforming to `utils.CHash` interface, with `outputLen` / `blockLen` props
*/
export type H2COpts = {
/** Domain separation tag. */
DST: AsciiOrBytes;
/** Expander family used by RFC 9380. */
expand: 'xmd' | 'xof';
/** Hash or XOF implementation used by the expander. */
hash: CHash;
/** Base-field characteristic. */
p: bigint;
/** Extension degree (`1` for prime fields). */
m: number;
/** Target security level in bits. */
k: number;
};
/** Hash-only subset of RFC 9380 options used by per-call overrides. */
export type H2CHashOpts = {
/** Expander family used by RFC 9380. */
expand: 'xmd' | 'xof';
/** Hash or XOF implementation used by the expander. */
hash: CHash;
};
/**
* Map one hash-to-field output tuple onto affine curve coordinates.
* Implementations receive the validated scalar tuple by reference for performance and MUST treat it
* as read-only. Callers that need scratch space should copy before mutating.
* @param scalar - Field-element tuple produced by `hash_to_field`.
* @returns Affine point before subgroup clearing.
*/
export type MapToCurve<T> = (scalar: bigint[]) => AffinePoint<T>;
/** Per-call override for the domain-separation tag. */
export type H2CDSTOpts = {
/** Domain-separation tag override. */
DST: AsciiOrBytes;
};
/** Base hash-to-curve helpers shared by `hashToCurve` and `encodeToCurve`. */
export type H2CHasherBase<PC extends PC_ANY> = {
/**
* Hash arbitrary bytes to one curve point.
* @param msg - Input message bytes.
* @param options - Optional domain-separation override. See {@link H2CDSTOpts}.
* @returns Curve point after hash-to-curve.
*/
hashToCurve(msg: TArg<Uint8Array>, options?: TArg<H2CDSTOpts>): PC_P<PC>;
/**
* Hash arbitrary bytes to one scalar.
* @param msg - Input message bytes.
* @param options - Optional domain-separation override. See {@link H2CDSTOpts}.
* @returns Scalar reduced into the target field.
*/
hashToScalar(msg: TArg<Uint8Array>, options?: TArg<H2CDSTOpts>): bigint;
/**
* Derive one curve point from non-uniform bytes without the random-oracle
* guarantees of `hashToCurve`.
* Accepts the same arguments as `hashToCurve`, but runs the encode-to-curve
* path instead of the random-oracle construction.
*/
deriveToCurve?(msg: TArg<Uint8Array>, options?: TArg<H2CDSTOpts>): PC_P<PC>;
/** Point constructor for the target curve. */
Point: PC;
};
/**
* RFC 9380 methods, with cofactor clearing. See {@link https://www.rfc-editor.org/rfc/rfc9380#section-3 | RFC 9380 section 3}.
*
* * hashToCurve: `map(hash(input))`, encodes RANDOM bytes to curve (WITH hashing)
* * encodeToCurve: `map(hash(input))`, encodes NON-UNIFORM bytes to curve (WITH hashing)
* * mapToCurve: `map(scalars)`, encodes NON-UNIFORM scalars to curve (NO hashing)
*/
export type H2CHasher<PC extends PC_ANY> = H2CHasherBase<PC> & {
/**
* Encode non-uniform bytes to one curve point.
* @param msg - Input message bytes.
* @param options - Optional domain-separation override. See {@link H2CDSTOpts}.
* @returns Curve point after encode-to-curve.
*/
encodeToCurve(msg: TArg<Uint8Array>, options?: TArg<H2CDSTOpts>): PC_P<PC>;
/** Deterministic map from `hash_to_field` tuples into affine coordinates. */
mapToCurve: MapToCurve<PC_F<PC>>;
/** Default RFC 9380 options captured by this hasher bundle. */
defaults: H2CDefaults;
};
/**
* Produces a uniformly random byte string using a cryptographic hash
* function H that outputs b bits.
* See {@link https://www.rfc-editor.org/rfc/rfc9380#section-5.3.1 | RFC 9380 section 5.3.1}.
* @param msg - Input message.
* @param DST - Domain separation tag. This helper normalizes DST, rejects empty DSTs, and
* oversize-hashes DST when needed.
* @param lenInBytes - Output length.
* @param H - Hash function.
* @returns Uniform byte string.
* @throws If the message, DST, hash, or output length is invalid. {@link Error}
* @example
* Expand one message into uniform bytes with the XMD construction.
*
* ```ts
* import { expand_message_xmd } from '@noble/curves/abstract/hash-to-curve.js';
* import { sha256 } from '@noble/hashes/sha2.js';
* const uniform = expand_message_xmd(new TextEncoder().encode('hello noble'), 'DST', 32, sha256);
* ```
*/
export declare function expand_message_xmd(msg: TArg<Uint8Array>, DST: TArg<AsciiOrBytes>, lenInBytes: number, H: TArg<CHash>): TRet<Uint8Array>;
/**
* Produces a uniformly random byte string using an extendable-output function (XOF) H.
* 1. The collision resistance of H MUST be at least k bits.
* 2. H MUST be an XOF that has been proved indifferentiable from
* a random oracle under a reasonable cryptographic assumption.
* See {@link https://www.rfc-editor.org/rfc/rfc9380#section-5.3.2 | RFC 9380 section 5.3.2}.
* @param msg - Input message.
* @param DST - Domain separation tag. This helper normalizes DST, rejects empty DSTs, and
* oversize-hashes DST when needed.
* @param lenInBytes - Output length.
* @param k - Target security level.
* @param H - XOF hash function.
* @returns Uniform byte string.
* @throws If the message, DST, XOF, or output length is invalid. {@link Error}
* @example
* Expand one message into uniform bytes with the XOF construction.
*
* ```ts
* import { expand_message_xof } from '@noble/curves/abstract/hash-to-curve.js';
* import { shake256 } from '@noble/hashes/sha3.js';
* const uniform = expand_message_xof(
* new TextEncoder().encode('hello noble'),
* 'DST',
* 32,
* 128,
* shake256
* );
* ```
*/
export declare function expand_message_xof(msg: TArg<Uint8Array>, DST: TArg<AsciiOrBytes>, lenInBytes: number, k: number, H: TArg<CHash>): TRet<Uint8Array>;
/**
* Hashes arbitrary-length byte strings to a list of one or more elements of a finite field F.
* See {@link https://www.rfc-editor.org/rfc/rfc9380#section-5.2 | RFC 9380 section 5.2}.
* @param msg - Input message bytes.
* @param count - Number of field elements to derive. Must be `>= 1`.
* @param options - RFC 9380 options. See {@link H2COpts}. `m` must be `>= 1`.
* @returns `[u_0, ..., u_(count - 1)]`, a list of field elements.
* @throws If the expander choice or RFC 9380 options are invalid. {@link Error}
* @example
* Hash one message into field elements before mapping it onto a curve.
*
* ```ts
* import { hash_to_field } from '@noble/curves/abstract/hash-to-curve.js';
* import { sha256 } from '@noble/hashes/sha2.js';
* const scalars = hash_to_field(new TextEncoder().encode('hello noble'), 2, {
* DST: 'DST',
* p: 17n,
* m: 1,
* k: 128,
* expand: 'xmd',
* hash: sha256,
* });
* ```
*/
export declare function hash_to_field(msg: TArg<Uint8Array>, count: number, options: TArg<H2COpts>): bigint[][];
type XY<T> = (x: T, y: T) => {
x: T;
y: T;
};
type XYRatio<T> = [T[], T[], T[], T[]];
/**
* @param field - Field implementation.
* @param map - Isogeny coefficients.
* @returns Isogeny mapping helper.
* @example
* Build one rational isogeny map, then apply it to affine x/y coordinates.
*
* ```ts
* import { isogenyMap } from '@noble/curves/abstract/hash-to-curve.js';
* import { Field } from '@noble/curves/abstract/modular.js';
* const Fp = Field(17n);
* const iso = isogenyMap(Fp, [[0n, 1n], [1n], [1n], [1n]]);
* const point = iso(3n, 5n);
* ```
*/
export declare function isogenyMap<T, F extends IField<T>>(field: F, map: XYRatio<T>): XY<T>;
export declare const _DST_scalar: "HashToScalar-";
/**
* Creates hash-to-curve methods from EC Point and mapToCurve function. See {@link H2CHasher}.
* @param Point - Point constructor.
* @param mapToCurve - Map-to-curve function.
* @param defaults - Default hash-to-curve options. This object is frozen in place and reused as
* the shared defaults bundle for the returned helpers.
* @returns Hash-to-curve helper namespace.
* @throws If the map-to-curve callback or default hash-to-curve options are invalid. {@link Error}
* @example
* Bundle hash-to-curve, hash-to-scalar, and encode-to-curve helpers for one curve.
*
* ```ts
* import { createHasher } from '@noble/curves/abstract/hash-to-curve.js';
* import { p256 } from '@noble/curves/nist.js';
* import { sha256 } from '@noble/hashes/sha2.js';
* const hasher = createHasher(p256.Point, () => p256.Point.BASE.toAffine(), {
* DST: 'P256_XMD:SHA-256_SSWU_RO_',
* encodeDST: 'P256_XMD:SHA-256_SSWU_NU_',
* p: p256.Point.Fp.ORDER,
* m: 1,
* k: 128,
* expand: 'xmd',
* hash: sha256,
* });
* const point = hasher.encodeToCurve(new TextEncoder().encode('hello noble'));
* ```
*/
export declare function createHasher<PC extends PC_ANY>(Point: PC, mapToCurve: MapToCurve<PC_F<PC>>, defaults: TArg<H2COpts & {
encodeDST?: AsciiOrBytes;
}>): H2CHasher<PC>;
export {};
//# sourceMappingURL=hash-to-curve.d.ts.map