@noble/curves
Advanced tools
Comparing version 0.7.2 to 0.7.3
@@ -5,5 +5,12 @@ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ | ||
import { CHash } from './utils.js'; | ||
/** | ||
* * `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 declare type Opts = { | ||
DST: string; | ||
encodeDST: string; | ||
DST: string | Uint8Array; | ||
p: bigint; | ||
@@ -22,3 +29,3 @@ m: number; | ||
* @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}` | ||
* @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. | ||
@@ -44,3 +51,5 @@ */ | ||
}; | ||
export declare function createHasher<T>(Point: H2CPointConstructor<T>, mapToCurve: MapToCurve<T>, def: Opts): { | ||
export declare function createHasher<T>(Point: H2CPointConstructor<T>, mapToCurve: MapToCurve<T>, def: Opts & { | ||
encodeDST?: string; | ||
}): { | ||
hashToCurve(msg: Uint8Array, options?: htfBasicOpts): H2CPoint<T>; | ||
@@ -47,0 +56,0 @@ encodeToCurve(msg: Uint8Array, options?: htfBasicOpts): H2CPoint<T>; |
@@ -6,12 +6,12 @@ "use strict"; | ||
const utils_js_1 = require("./utils.js"); | ||
// Octet Stream to Integer (bytesToNumberBE) | ||
function os2ip(bytes) { | ||
let result = 0n; | ||
for (let i = 0; i < bytes.length; i++) { | ||
result <<= 8n; | ||
result += BigInt(bytes[i]); | ||
} | ||
return result; | ||
function validateDST(dst) { | ||
if (dst instanceof Uint8Array) | ||
return dst; | ||
if (typeof dst === 'string') | ||
return (0, utils_js_1.utf8ToBytes)(dst); | ||
throw new Error('DST must be Uint8Array or string'); | ||
} | ||
// Integer to Octet Stream | ||
// Octet Stream to Integer. "spec" implementation of os2ip is 2.5x slower vs bytesToNumberBE. | ||
const os2ip = utils_js_1.bytesToNumberBE; | ||
// Integer to Octet Stream (numberToBytesBE) | ||
function i2osp(value, length) { | ||
@@ -52,4 +52,3 @@ if (value < 0 || value >= 1 << (8 * length)) { | ||
DST = H((0, utils_js_1.concatBytes)((0, utils_js_1.utf8ToBytes)('H2C-OVERSIZE-DST-'), DST)); | ||
const b_in_bytes = H.outputLen; | ||
const r_in_bytes = H.blockLen; | ||
const { outputLen: b_in_bytes, blockLen: r_in_bytes } = H; | ||
const ell = Math.ceil(lenInBytes / b_in_bytes); | ||
@@ -60,3 +59,3 @@ if (ell > 255) | ||
const Z_pad = i2osp(0, r_in_bytes); | ||
const l_i_b_str = i2osp(lenInBytes, 2); | ||
const l_i_b_str = i2osp(lenInBytes, 2); // len_in_bytes_str | ||
const b = new Array(ell); | ||
@@ -99,3 +98,3 @@ const b_0 = H((0, utils_js_1.concatBytes)(Z_pad, msg, l_i_b_str, i2osp(0, 1), DST_prime)); | ||
* @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}` | ||
* @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. | ||
@@ -107,13 +106,19 @@ */ | ||
isNum(count); | ||
if (typeof _DST !== 'string') | ||
throw new Error('DST must be valid'); | ||
const DST = validateDST(_DST); | ||
const log2p = p.toString(2).length; | ||
const L = Math.ceil((log2p + k) / 8); // section 5.1 of ietf draft link above | ||
const len_in_bytes = count * m * L; | ||
const DST = (0, utils_js_1.utf8ToBytes)(_DST); | ||
const pseudo_random_bytes = expand === 'xmd' | ||
? expand_message_xmd(msg, DST, len_in_bytes, hash) | ||
: expand === 'xof' | ||
? expand_message_xof(msg, DST, len_in_bytes, k, hash) | ||
: msg; | ||
let prb; // pseudo_random_bytes | ||
if (expand === 'xmd') { | ||
prb = expand_message_xmd(msg, DST, len_in_bytes, hash); | ||
} | ||
else if (expand === 'xof') { | ||
prb = expand_message_xof(msg, DST, len_in_bytes, k, hash); | ||
} | ||
else if (expand === undefined) { | ||
prb = msg; | ||
} | ||
else { | ||
throw new Error('expand must be "xmd", "xof" or undefined'); | ||
} | ||
const u = new Array(count); | ||
@@ -124,3 +129,3 @@ for (let i = 0; i < count; i++) { | ||
const elm_offset = L * (j + i * m); | ||
const tv = pseudo_random_bytes.subarray(elm_offset, elm_offset + L); | ||
const tv = prb.subarray(elm_offset, elm_offset + L); | ||
e[j] = (0, modular_js_1.mod)(os2ip(tv), p); | ||
@@ -152,6 +157,4 @@ } | ||
}); | ||
if (def.expand !== 'xmd' && def.expand !== 'xof' && def.expand !== undefined) | ||
throw new Error('Invalid htf/expand'); | ||
if (typeof mapToCurve !== 'function') | ||
throw new Error('hashToCurve: mapToCurve() has not been defined'); | ||
throw new Error('mapToCurve() must be defined'); | ||
return { | ||
@@ -158,0 +161,0 @@ // Encodes byte string to elliptic curve |
import { mod } from './modular.js'; | ||
import { concatBytes, utf8ToBytes, validateObject } from './utils.js'; | ||
// Octet Stream to Integer (bytesToNumberBE) | ||
function os2ip(bytes) { | ||
let result = 0n; | ||
for (let i = 0; i < bytes.length; i++) { | ||
result <<= 8n; | ||
result += BigInt(bytes[i]); | ||
} | ||
return result; | ||
import { bytesToNumberBE, concatBytes, utf8ToBytes, validateObject } from './utils.js'; | ||
function validateDST(dst) { | ||
if (dst instanceof Uint8Array) | ||
return dst; | ||
if (typeof dst === 'string') | ||
return utf8ToBytes(dst); | ||
throw new Error('DST must be Uint8Array or string'); | ||
} | ||
// Integer to Octet Stream | ||
// Octet Stream to Integer. "spec" implementation of os2ip is 2.5x slower vs bytesToNumberBE. | ||
const os2ip = bytesToNumberBE; | ||
// Integer to Octet Stream (numberToBytesBE) | ||
function i2osp(value, length) { | ||
@@ -48,4 +48,3 @@ if (value < 0 || value >= 1 << (8 * length)) { | ||
DST = H(concatBytes(utf8ToBytes('H2C-OVERSIZE-DST-'), DST)); | ||
const b_in_bytes = H.outputLen; | ||
const r_in_bytes = H.blockLen; | ||
const { outputLen: b_in_bytes, blockLen: r_in_bytes } = H; | ||
const ell = Math.ceil(lenInBytes / b_in_bytes); | ||
@@ -56,3 +55,3 @@ if (ell > 255) | ||
const Z_pad = i2osp(0, r_in_bytes); | ||
const l_i_b_str = i2osp(lenInBytes, 2); | ||
const l_i_b_str = i2osp(lenInBytes, 2); // len_in_bytes_str | ||
const b = new Array(ell); | ||
@@ -93,3 +92,3 @@ const b_0 = H(concatBytes(Z_pad, msg, l_i_b_str, i2osp(0, 1), DST_prime)); | ||
* @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}` | ||
* @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. | ||
@@ -101,13 +100,19 @@ */ | ||
isNum(count); | ||
if (typeof _DST !== 'string') | ||
throw new Error('DST must be valid'); | ||
const DST = validateDST(_DST); | ||
const log2p = p.toString(2).length; | ||
const L = Math.ceil((log2p + k) / 8); // section 5.1 of ietf draft link above | ||
const len_in_bytes = count * m * L; | ||
const DST = utf8ToBytes(_DST); | ||
const pseudo_random_bytes = expand === 'xmd' | ||
? expand_message_xmd(msg, DST, len_in_bytes, hash) | ||
: expand === 'xof' | ||
? expand_message_xof(msg, DST, len_in_bytes, k, hash) | ||
: msg; | ||
let prb; // pseudo_random_bytes | ||
if (expand === 'xmd') { | ||
prb = expand_message_xmd(msg, DST, len_in_bytes, hash); | ||
} | ||
else if (expand === 'xof') { | ||
prb = expand_message_xof(msg, DST, len_in_bytes, k, hash); | ||
} | ||
else if (expand === undefined) { | ||
prb = msg; | ||
} | ||
else { | ||
throw new Error('expand must be "xmd", "xof" or undefined'); | ||
} | ||
const u = new Array(count); | ||
@@ -118,3 +123,3 @@ for (let i = 0; i < count; i++) { | ||
const elm_offset = L * (j + i * m); | ||
const tv = pseudo_random_bytes.subarray(elm_offset, elm_offset + L); | ||
const tv = prb.subarray(elm_offset, elm_offset + L); | ||
e[j] = mod(os2ip(tv), p); | ||
@@ -144,6 +149,4 @@ } | ||
}); | ||
if (def.expand !== 'xmd' && def.expand !== 'xof' && def.expand !== undefined) | ||
throw new Error('Invalid htf/expand'); | ||
if (typeof mapToCurve !== 'function') | ||
throw new Error('hashToCurve: mapToCurve() has not been defined'); | ||
throw new Error('mapToCurve() must be defined'); | ||
return { | ||
@@ -150,0 +153,0 @@ // Encodes byte string to elliptic curve |
{ | ||
"name": "@noble/curves", | ||
"version": "0.7.2", | ||
"version": "0.7.3", | ||
"description": "Minimal, auditable JS implementation of elliptic curve cryptography", | ||
@@ -5,0 +5,0 @@ "files": [ |
@@ -8,3 +8,3 @@ # noble-curves | ||
- ECDSA, EdDSA, Schnorr, BLS signature schemes, ECDH key agreement | ||
- #️⃣ [hash to curve](https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/) | ||
- #️⃣ [hash to curve](#abstracthash-to-curve-hashing-strings-to-curve-points) | ||
for encoding or hashing an arbitrary string to an elliptic curve point | ||
@@ -474,3 +474,3 @@ - 🧜♂️ [Poseidon](https://www.poseidon-hash.info) ZK-friendly hash | ||
The module allows to hash arbitrary strings to elliptic curve points. Implements [hash-to-curve v11](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11). | ||
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). | ||
@@ -486,3 +486,2 @@ Every curve has exported `hashToCurve` and `encodeToCurve` methods: | ||
import { bls12_381 } from '@noble/curves/bls12-381'; | ||
@@ -497,2 +496,4 @@ bls12_381.G1.hashToCurve(randomBytes(), { DST: 'another' }); | ||
Hash must conform to `CHash` interface (see [weierstrass section](#abstractweierstrass-short-weierstrass-curve)). | ||
```ts | ||
@@ -516,9 +517,14 @@ function expand_message_xmd( | ||
hashes arbitrary-length byte strings to a list of one or more elements of a finite field F. | ||
_ `msg` a byte string containing the message to hash | ||
_ `count` the number of elements of F to output | ||
_ `options` `{DST: string, p: bigint, m: number, k: number, expand: 'xmd' | 'xof', hash: H}` | ||
_ Returns `[u_0, ..., u_(count - 1)]`, a list of field elements. | ||
- `msg` a byte string containing the message to hash | ||
- `count` the number of elements of F to output | ||
- `options` `{DST: string, p: bigint, m: number, k: number, expand: 'xmd' | 'xof', hash: H}`. | ||
- `p` is field prime, m=field extension (1 for prime fields) | ||
- `k` is security target in bits (e.g. 128). | ||
- `expand` should be `xmd` for SHA2, SHA3, BLAKE; `xof` for SHAKE, BLAKE-XOF | ||
- `hash` conforming to `utils.CHash` interface, with `outputLen` / `blockLen` props | ||
- Returns `[u_0, ..., u_(count - 1)]`, a list of field elements. | ||
```ts | ||
function hash_to_field(msg: Uint8Array, count: number, options: htfOpts): bigint[][]; | ||
function hash_to_field(msg: Uint8Array, count: number, options: Opts): bigint[][]; | ||
``` | ||
@@ -594,3 +600,2 @@ | ||
### abstract/utils: General utilities | ||
@@ -701,2 +706,12 @@ | ||
aggregateSignatures/128 x 3 ops/sec @ 332ms/opp | ||
hash-to-curve | ||
hash_to_field x 850,340 ops/sec @ 1μs/op | ||
hashToCurve | ||
├─secp256k1 x 1,850 ops/sec @ 540μs/op | ||
├─P256 x 3,352 ops/sec @ 298μs/op | ||
├─P384 x 1,367 ops/sec @ 731μs/op | ||
├─P521 x 691 ops/sec @ 1ms/op | ||
├─ed25519 x 2,492 ops/sec @ 401μs/op | ||
└─ed448 x 1,045 ops/sec @ 956μs/op | ||
``` | ||
@@ -703,0 +718,0 @@ |
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ | ||
import type { Group, GroupConstructor, AffinePoint } from './curve.js'; | ||
import { mod, Field } from './modular.js'; | ||
import { CHash, concatBytes, utf8ToBytes, validateObject } from './utils.js'; | ||
import { bytesToNumberBE, CHash, concatBytes, utf8ToBytes, validateObject } from './utils.js'; | ||
/** | ||
* * `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 Opts = { | ||
DST: string; // DST: a domain separation tag, defined in section 2.2.5 | ||
encodeDST: string; | ||
p: bigint; // characteristic of F, where F is a finite field of characteristic p and order q = p^m | ||
m: number; // extension degree of F, m >= 1 | ||
k: number; // k: the target security level for the suite in bits, defined in section 5.1 | ||
expand?: 'xmd' | 'xof'; // use a message that has already been processed by expand_message_xmd | ||
// Hash functions for: expand_message_xmd is appropriate for use with a | ||
// wide range of hash functions, including SHA-2, SHA-3, BLAKE2, and others. | ||
// BBS+ uses blake2: https://github.com/hyperledger/aries-framework-go/issues/2247 | ||
// TODO: verify that hash is shake if expand==='xof' via types | ||
DST: string | Uint8Array; | ||
p: bigint; | ||
m: number; | ||
k: number; | ||
expand?: 'xmd' | 'xof'; | ||
hash: CHash; | ||
}; | ||
// Octet Stream to Integer (bytesToNumberBE) | ||
function os2ip(bytes: Uint8Array): bigint { | ||
let result = 0n; | ||
for (let i = 0; i < bytes.length; i++) { | ||
result <<= 8n; | ||
result += BigInt(bytes[i]); | ||
} | ||
return result; | ||
function validateDST(dst: string | Uint8Array): Uint8Array { | ||
if (dst instanceof Uint8Array) return dst; | ||
if (typeof dst === 'string') return utf8ToBytes(dst); | ||
throw new Error('DST must be Uint8Array or string'); | ||
} | ||
// Integer to Octet Stream | ||
// Octet Stream to Integer. "spec" implementation of os2ip is 2.5x slower vs bytesToNumberBE. | ||
const os2ip = bytesToNumberBE; | ||
// Integer to Octet Stream (numberToBytesBE) | ||
function i2osp(value: number, length: number): Uint8Array { | ||
@@ -71,4 +73,3 @@ if (value < 0 || value >= 1 << (8 * length)) { | ||
if (DST.length > 255) DST = H(concatBytes(utf8ToBytes('H2C-OVERSIZE-DST-'), DST)); | ||
const b_in_bytes = H.outputLen; | ||
const r_in_bytes = H.blockLen; | ||
const { outputLen: b_in_bytes, blockLen: r_in_bytes } = H; | ||
const ell = Math.ceil(lenInBytes / b_in_bytes); | ||
@@ -78,3 +79,3 @@ if (ell > 255) throw new Error('Invalid xmd length'); | ||
const Z_pad = i2osp(0, r_in_bytes); | ||
const l_i_b_str = i2osp(lenInBytes, 2); | ||
const l_i_b_str = i2osp(lenInBytes, 2); // len_in_bytes_str | ||
const b = new Array<Uint8Array>(ell); | ||
@@ -125,3 +126,3 @@ const b_0 = H(concatBytes(Z_pad, msg, l_i_b_str, i2osp(0, 1), DST_prime)); | ||
* @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}` | ||
* @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. | ||
@@ -133,13 +134,16 @@ */ | ||
isNum(count); | ||
if (typeof _DST !== 'string') throw new Error('DST must be valid'); | ||
const DST = validateDST(_DST); | ||
const log2p = p.toString(2).length; | ||
const L = Math.ceil((log2p + k) / 8); // section 5.1 of ietf draft link above | ||
const len_in_bytes = count * m * L; | ||
const DST = utf8ToBytes(_DST); | ||
const pseudo_random_bytes = | ||
expand === 'xmd' | ||
? expand_message_xmd(msg, DST, len_in_bytes, hash) | ||
: expand === 'xof' | ||
? expand_message_xof(msg, DST, len_in_bytes, k, hash) | ||
: msg; | ||
let prb; // pseudo_random_bytes | ||
if (expand === 'xmd') { | ||
prb = expand_message_xmd(msg, DST, len_in_bytes, hash); | ||
} else if (expand === 'xof') { | ||
prb = expand_message_xof(msg, DST, len_in_bytes, k, hash); | ||
} else if (expand === undefined) { | ||
prb = msg; | ||
} else { | ||
throw new Error('expand must be "xmd", "xof" or undefined'); | ||
} | ||
const u = new Array(count); | ||
@@ -150,3 +154,3 @@ for (let i = 0; i < count; i++) { | ||
const elm_offset = L * (j + i * m); | ||
const tv = pseudo_random_bytes.subarray(elm_offset, elm_offset + L); | ||
const tv = prb.subarray(elm_offset, elm_offset + L); | ||
e[j] = mod(os2ip(tv), p); | ||
@@ -192,3 +196,3 @@ } | ||
mapToCurve: MapToCurve<T>, | ||
def: Opts | ||
def: Opts & { encodeDST?: string } | ||
) { | ||
@@ -202,6 +206,3 @@ validateObject(def, { | ||
}); | ||
if (def.expand !== 'xmd' && def.expand !== 'xof' && def.expand !== undefined) | ||
throw new Error('Invalid htf/expand'); | ||
if (typeof mapToCurve !== 'function') | ||
throw new Error('hashToCurve: mapToCurve() has not been defined'); | ||
if (typeof mapToCurve !== 'function') throw new Error('mapToCurve() must be defined'); | ||
return { | ||
@@ -208,0 +209,0 @@ // Encodes byte string to elliptic curve |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1308163
18004
770