forked from tornado-packages/noble-curves
hash-to-curve, weierstrass, bls, ed: upgrade h2c comments to rfc 9380
This commit is contained in:
parent
e7ac5e85d3
commit
eb8e7ec964
33
README.md
33
README.md
@ -9,8 +9,7 @@ Audited & minimal JS implementation of elliptic curve cryptography.
|
|||||||
- ➰ Short Weierstrass, Edwards, Montgomery curves
|
- ➰ Short Weierstrass, Edwards, Montgomery curves
|
||||||
- ✍️ ECDSA, EdDSA, Schnorr, BLS signature schemes, ECDH key agreement
|
- ✍️ ECDSA, EdDSA, Schnorr, BLS signature schemes, ECDH key agreement
|
||||||
- 🔖 SUF-CMA and SBS (non-repudiation) for ed25519, ed448 and others
|
- 🔖 SUF-CMA and SBS (non-repudiation) for ed25519, ed448 and others
|
||||||
- #️⃣ Hash-to-curve
|
- #️⃣ hash-to-curve for encoding or hashing an arbitrary string to an elliptic curve point
|
||||||
for encoding or hashing an arbitrary string to an elliptic curve point
|
|
||||||
- 🧜♂️ Poseidon ZK-friendly hash
|
- 🧜♂️ Poseidon ZK-friendly hash
|
||||||
|
|
||||||
### This library belongs to _noble_ crypto
|
### This library belongs to _noble_ crypto
|
||||||
@ -676,7 +675,7 @@ utils: {
|
|||||||
|
|
||||||
### abstract/hash-to-curve: Hashing strings to curve points
|
### abstract/hash-to-curve: Hashing strings to curve points
|
||||||
|
|
||||||
The module allows to hash arbitrary strings to elliptic curve points. Implements [hash-to-curve v16](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16).
|
The module allows to hash arbitrary strings to elliptic curve points. Implements [RFC 9380](https://www.rfc-editor.org/rfc/rfc9380).
|
||||||
|
|
||||||
Every curve has exported `hashToCurve` and `encodeToCurve` methods. You should always prefer `hashToCurve` for security:
|
Every curve has exported `hashToCurve` and `encodeToCurve` methods. You should always prefer `hashToCurve` for security:
|
||||||
|
|
||||||
@ -692,19 +691,17 @@ bls12_381.G1.hashToCurve(randomBytes(), { DST: 'another' });
|
|||||||
bls12_381.G2.hashToCurve(randomBytes(), { DST: 'custom' });
|
bls12_381.G2.hashToCurve(randomBytes(), { DST: 'custom' });
|
||||||
```
|
```
|
||||||
|
|
||||||
If you need low-level methods from spec:
|
Low-level methods from the spec:
|
||||||
|
|
||||||
`expand_message_xmd` [(spec)](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.4.1) produces a uniformly random byte string using a cryptographic hash function H that outputs b bits.
|
|
||||||
|
|
||||||
Hash must conform to `CHash` interface (see [weierstrass section](#abstractweierstrass-short-weierstrass-curve)).
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
|
// produces a uniformly random byte string using a cryptographic hash function H that outputs b bits.
|
||||||
function expand_message_xmd(
|
function expand_message_xmd(
|
||||||
msg: Uint8Array,
|
msg: Uint8Array,
|
||||||
DST: Uint8Array,
|
DST: Uint8Array,
|
||||||
lenInBytes: number,
|
lenInBytes: number,
|
||||||
H: CHash
|
H: CHash // For CHash see abstract/weierstrass docs section
|
||||||
): Uint8Array;
|
): Uint8Array;
|
||||||
|
// produces a uniformly random byte string using an extendable-output function (XOF) H.
|
||||||
function expand_message_xof(
|
function expand_message_xof(
|
||||||
msg: Uint8Array,
|
msg: Uint8Array,
|
||||||
DST: Uint8Array,
|
DST: Uint8Array,
|
||||||
@ -712,13 +709,9 @@ function expand_message_xof(
|
|||||||
k: number,
|
k: number,
|
||||||
H: CHash
|
H: CHash
|
||||||
): Uint8Array;
|
): Uint8Array;
|
||||||
```
|
// Hashes arbitrary-length byte strings to a list of one or more elements of a finite field F
|
||||||
|
function hash_to_field(msg: Uint8Array, count: number, options: Opts): bigint[][];
|
||||||
|
|
||||||
`hash_to_field(msg, count, options)`
|
|
||||||
[(spec)](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3)
|
|
||||||
hashes arbitrary-length byte strings to a list of one or more elements of a finite field F.
|
|
||||||
|
|
||||||
```ts
|
|
||||||
/**
|
/**
|
||||||
* * `DST` is a domain separation tag, defined in section 2.2.5
|
* * `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
|
* * `p` characteristic of F, where F is a finite field of characteristic p and order q = p^m
|
||||||
@ -736,16 +729,6 @@ type Opts = {
|
|||||||
expand?: 'xmd' | 'xof';
|
expand?: 'xmd' | 'xof';
|
||||||
hash: CHash;
|
hash: CHash;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Hashes arbitrary-length byte strings to a list of one or more elements of a finite field F
|
|
||||||
* https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3
|
|
||||||
* @param msg a byte string containing the message to hash
|
|
||||||
* @param count the number of elements of F to output
|
|
||||||
* @param options `{DST: string, p: bigint, m: number, k: number, expand: 'xmd' | 'xof', hash: H}`, see above
|
|
||||||
* @returns [u_0, ..., u_(count - 1)], a list of field elements.
|
|
||||||
*/
|
|
||||||
function hash_to_field(msg: Uint8Array, count: number, options: Opts): bigint[][];
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### abstract/poseidon: Poseidon hash
|
### abstract/poseidon: Poseidon hash
|
||||||
|
@ -59,7 +59,7 @@ function isNum(item: unknown): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Produces a uniformly random byte string using a cryptographic hash function H that outputs b bits
|
// Produces a uniformly random byte string using a cryptographic hash function H that outputs b bits
|
||||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.4.1
|
// https://www.rfc-editor.org/rfc/rfc9380#section-5.3.1
|
||||||
export function expand_message_xmd(
|
export function expand_message_xmd(
|
||||||
msg: Uint8Array,
|
msg: Uint8Array,
|
||||||
DST: Uint8Array,
|
DST: Uint8Array,
|
||||||
@ -69,7 +69,7 @@ export function expand_message_xmd(
|
|||||||
isBytes(msg);
|
isBytes(msg);
|
||||||
isBytes(DST);
|
isBytes(DST);
|
||||||
isNum(lenInBytes);
|
isNum(lenInBytes);
|
||||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-5.3.3
|
// https://www.rfc-editor.org/rfc/rfc9380#section-5.3.3
|
||||||
if (DST.length > 255) DST = H(concatBytes(utf8ToBytes('H2C-OVERSIZE-DST-'), DST));
|
if (DST.length > 255) DST = H(concatBytes(utf8ToBytes('H2C-OVERSIZE-DST-'), DST));
|
||||||
const { outputLen: b_in_bytes, blockLen: r_in_bytes } = H;
|
const { outputLen: b_in_bytes, blockLen: r_in_bytes } = H;
|
||||||
const ell = Math.ceil(lenInBytes / b_in_bytes);
|
const ell = Math.ceil(lenInBytes / b_in_bytes);
|
||||||
@ -88,6 +88,11 @@ export function expand_message_xmd(
|
|||||||
return pseudo_random_bytes.slice(0, lenInBytes);
|
return pseudo_random_bytes.slice(0, lenInBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
// https://www.rfc-editor.org/rfc/rfc9380#section-5.3.2
|
||||||
export function expand_message_xof(
|
export function expand_message_xof(
|
||||||
msg: Uint8Array,
|
msg: Uint8Array,
|
||||||
DST: Uint8Array,
|
DST: Uint8Array,
|
||||||
@ -98,7 +103,7 @@ export function expand_message_xof(
|
|||||||
isBytes(msg);
|
isBytes(msg);
|
||||||
isBytes(DST);
|
isBytes(DST);
|
||||||
isNum(lenInBytes);
|
isNum(lenInBytes);
|
||||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-5.3.3
|
// https://www.rfc-editor.org/rfc/rfc9380#section-5.3.3
|
||||||
// DST = H('H2C-OVERSIZE-DST-' || a_very_long_DST, Math.ceil((lenInBytes * k) / 8));
|
// DST = H('H2C-OVERSIZE-DST-' || a_very_long_DST, Math.ceil((lenInBytes * k) / 8));
|
||||||
if (DST.length > 255) {
|
if (DST.length > 255) {
|
||||||
const dkLen = Math.ceil((2 * k) / 8);
|
const dkLen = Math.ceil((2 * k) / 8);
|
||||||
@ -119,7 +124,7 @@ export function expand_message_xof(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Hashes arbitrary-length byte strings to a list of one or more elements of a finite field F
|
* Hashes arbitrary-length byte strings to a list of one or more elements of a finite field F
|
||||||
* https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3
|
* https://www.rfc-editor.org/rfc/rfc9380#section-5.2
|
||||||
* @param msg a byte string containing the message to hash
|
* @param msg a byte string containing the message to hash
|
||||||
* @param count the number of elements of F to output
|
* @param count the number of elements of F to output
|
||||||
* @param options `{DST: string, p: bigint, m: number, k: number, expand: 'xmd' | 'xof', hash: H}`, see above
|
* @param options `{DST: string, p: bigint, m: number, k: number, expand: 'xmd' | 'xof', hash: H}`, see above
|
||||||
@ -201,8 +206,8 @@ export function createHasher<T>(
|
|||||||
) {
|
) {
|
||||||
if (typeof mapToCurve !== 'function') throw new Error('mapToCurve() must be defined');
|
if (typeof mapToCurve !== 'function') throw new Error('mapToCurve() must be defined');
|
||||||
return {
|
return {
|
||||||
// Encodes byte string to elliptic curve
|
// Encodes byte string to elliptic curve.
|
||||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-3
|
// hash_to_curve from https://www.rfc-editor.org/rfc/rfc9380#section-3
|
||||||
hashToCurve(msg: Uint8Array, options?: htfBasicOpts) {
|
hashToCurve(msg: Uint8Array, options?: htfBasicOpts) {
|
||||||
const u = hash_to_field(msg, 2, { ...def, DST: def.DST, ...options } as Opts);
|
const u = hash_to_field(msg, 2, { ...def, DST: def.DST, ...options } as Opts);
|
||||||
const u0 = Point.fromAffine(mapToCurve(u[0]));
|
const u0 = Point.fromAffine(mapToCurve(u[0]));
|
||||||
@ -212,7 +217,8 @@ export function createHasher<T>(
|
|||||||
return P;
|
return P;
|
||||||
},
|
},
|
||||||
|
|
||||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-3
|
// Encodes byte string to elliptic curve.
|
||||||
|
// encode_to_curve from https://www.rfc-editor.org/rfc/rfc9380#section-3
|
||||||
encodeToCurve(msg: Uint8Array, options?: htfBasicOpts) {
|
encodeToCurve(msg: Uint8Array, options?: htfBasicOpts) {
|
||||||
const u = hash_to_field(msg, 1, { ...def, DST: def.encodeDST, ...options } as Opts);
|
const u = hash_to_field(msg, 1, { ...def, DST: def.encodeDST, ...options } as Opts);
|
||||||
const P = Point.fromAffine(mapToCurve(u[0])).clearCofactor();
|
const P = Point.fromAffine(mapToCurve(u[0])).clearCofactor();
|
||||||
|
@ -1171,7 +1171,8 @@ export function SWUFpSqrtRatio<T>(Fp: mod.IField<T>, Z: T) {
|
|||||||
return sqrtRatio;
|
return sqrtRatio;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* From draft-irtf-cfrg-hash-to-curve-16
|
* Simplified Shallue-van de Woestijne-Ulas Method
|
||||||
|
* https://www.rfc-editor.org/rfc/rfc9380#section-6.6.2
|
||||||
*/
|
*/
|
||||||
export function mapToCurveSimpleSWU<T>(
|
export function mapToCurveSimpleSWU<T>(
|
||||||
Fp: mod.IField<T>,
|
Fp: mod.IField<T>,
|
||||||
|
@ -8,8 +8,8 @@
|
|||||||
// The library uses G1 for public keys and G2 for signatures. Support for G1 signatures is planned.
|
// The library uses G1 for public keys and G2 for signatures. Support for G1 signatures is planned.
|
||||||
// Compatible with Algorand, Chia, Dfinity, Ethereum, FIL, Zcash. Matches specs
|
// Compatible with Algorand, Chia, Dfinity, Ethereum, FIL, Zcash. Matches specs
|
||||||
// [pairing-curves-11](https://tools.ietf.org/html/draft-irtf-cfrg-pairing-friendly-curves-11),
|
// [pairing-curves-11](https://tools.ietf.org/html/draft-irtf-cfrg-pairing-friendly-curves-11),
|
||||||
// [bls-sigs-04](https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-04),
|
// [bls-sigs-04](https:/cfrg-hash-to/tools.ietf.org/html/draft-irtf-cfrg-bls-signature-04),
|
||||||
// [hash-to-curve-12](https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-12).
|
// [hash-to-curve-12](https://tools.ietf.org/html/draft-irtf--curve-12).
|
||||||
//
|
//
|
||||||
// ### Summary
|
// ### Summary
|
||||||
// 1. BLS Relies on Bilinear Pairing (expensive)
|
// 1. BLS Relies on Bilinear Pairing (expensive)
|
||||||
@ -177,7 +177,7 @@ const Fp2: mod.IField<Fp2> & Fp2Utils = {
|
|||||||
if (im1 > im2 || (im1 === im2 && re1 > re2)) return x1;
|
if (im1 > im2 || (im1 === im2 && re1 > re2)) return x1;
|
||||||
return x2;
|
return x2;
|
||||||
},
|
},
|
||||||
// Same as sgn0_fp2 in draft-irtf-cfrg-hash-to-curve-16
|
// Same as sgn0_m_eq_2 in RFC 9380
|
||||||
isOdd: (x: Fp2) => {
|
isOdd: (x: Fp2) => {
|
||||||
const { re: x0, im: x1 } = Fp2.reim(x);
|
const { re: x0, im: x1 } = Fp2.reim(x);
|
||||||
const sign_0 = x0 % _2n;
|
const sign_0 = x0 % _2n;
|
||||||
@ -780,8 +780,7 @@ const FP12_FROBENIUS_COEFFICIENTS = [
|
|||||||
|
|
||||||
// HashToCurve
|
// HashToCurve
|
||||||
|
|
||||||
// 3-isogeny map from E' to E
|
// 3-isogeny map from E' to E https://www.rfc-editor.org/rfc/rfc9380#appendix-E.3
|
||||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-E.3
|
|
||||||
const isogenyMapG2 = isogenyMap(
|
const isogenyMapG2 = isogenyMap(
|
||||||
Fp2,
|
Fp2,
|
||||||
[
|
[
|
||||||
@ -985,7 +984,7 @@ function G2psi2(c: ProjConstructor<Fp2>, P: ProjPointType<Fp2>) {
|
|||||||
//
|
//
|
||||||
// Parameter definitions are in section 5.3 of the spec unless otherwise noted.
|
// Parameter definitions are in section 5.3 of the spec unless otherwise noted.
|
||||||
// Parameter values come from section 8.8.2 of the spec.
|
// Parameter values come from section 8.8.2 of the spec.
|
||||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-8.8.2
|
// https://www.rfc-editor.org/rfc/rfc9380#section-8.8.2
|
||||||
//
|
//
|
||||||
// Base field F is GF(p^m)
|
// Base field F is GF(p^m)
|
||||||
// p = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab
|
// p = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab
|
||||||
@ -1040,7 +1039,7 @@ function signatureG2ToRawBytes(point: ProjPointType<Fp2>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// To verify curve parameters, see pairing-friendly-curves spec:
|
// To verify curve parameters, see pairing-friendly-curves spec:
|
||||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-09
|
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-11
|
||||||
// Basic math is done over finite fields over p.
|
// Basic math is done over finite fields over p.
|
||||||
// More complicated math is done over polynominal extension fields.
|
// More complicated math is done over polynominal extension fields.
|
||||||
// To simplify calculations in Fp12, we construct extension tower:
|
// To simplify calculations in Fp12, we construct extension tower:
|
||||||
|
@ -478,8 +478,7 @@ export const RistrettoPoint = /* @__PURE__ */ (() => {
|
|||||||
return RistPoint;
|
return RistPoint;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
// https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/14/
|
// Hashing to ristretto255. https://www.rfc-editor.org/rfc/rfc9380#appendix-B
|
||||||
// Appendix B. Hashing to ristretto255
|
|
||||||
export const hashToRistretto255 = (msg: Uint8Array, options: htfBasicOpts) => {
|
export const hashToRistretto255 = (msg: Uint8Array, options: htfBasicOpts) => {
|
||||||
const d = options.DST;
|
const d = options.DST;
|
||||||
const DST = typeof d === 'string' ? utf8ToBytes(d) : d;
|
const DST = typeof d === 'string' ? utf8ToBytes(d) : d;
|
||||||
|
@ -69,7 +69,7 @@ function adjustScalarBytes(bytes: Uint8Array): Uint8Array {
|
|||||||
// Uses algo from RFC8032 5.1.3.
|
// Uses algo from RFC8032 5.1.3.
|
||||||
function uvRatio(u: bigint, v: bigint): { isValid: boolean; value: bigint } {
|
function uvRatio(u: bigint, v: bigint): { isValid: boolean; value: bigint } {
|
||||||
const P = ed448P;
|
const P = ed448P;
|
||||||
// https://datatracker.ietf.org/doc/html/rfc8032#section-5.2.3
|
// https://www.rfc-editor.org/rfc/rfc8032#section-5.2.3
|
||||||
// To compute the square root of (u/v), the first step is to compute the
|
// To compute the square root of (u/v), the first step is to compute the
|
||||||
// candidate root x = (u/v)^((p+1)/4). This can be done using the
|
// candidate root x = (u/v)^((p+1)/4). This can be done using the
|
||||||
// following trick, to use a single modular powering for both the
|
// following trick, to use a single modular powering for both the
|
||||||
@ -454,8 +454,7 @@ export const DecafPoint = /* @__PURE__ */ (() => {
|
|||||||
return DcfPoint;
|
return DcfPoint;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
// https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/16/
|
// Hashing to decaf448. https://www.rfc-editor.org/rfc/rfc9380#appendix-C
|
||||||
// Appendix C. Hashing to decaf448
|
|
||||||
export const hashToDecaf448 = (msg: Uint8Array, options: htfBasicOpts) => {
|
export const hashToDecaf448 = (msg: Uint8Array, options: htfBasicOpts) => {
|
||||||
const d = options.DST;
|
const d = options.DST;
|
||||||
const DST = typeof d === 'string' ? utf8ToBytes(d) : d;
|
const DST = typeof d === 'string' ? utf8ToBytes(d) : d;
|
||||||
|
Loading…
Reference in New Issue
Block a user