modular, weierstrass, bls: use new mapHashToField
This commit is contained in:
parent
2ce3b825f8
commit
1545230ee5
@ -13,9 +13,6 @@ Audited & minimal JS implementation of elliptic curve cryptography.
|
||||
for encoding or hashing an arbitrary string to an elliptic curve point
|
||||
- 🧜♂️ Poseidon ZK-friendly hash
|
||||
|
||||
Check out [Upgrading](#upgrading) if you've previously used single-feature noble
|
||||
packages. See [Resources](#resources) for articles and real-world software that uses curves.
|
||||
|
||||
### This library belongs to _noble_ crypto
|
||||
|
||||
> **noble-crypto** — high-security, easily auditable set of contained cryptographic libraries and tools.
|
||||
@ -40,7 +37,6 @@ For [Deno](https://deno.land), ensure to use [npm specifier](https://deno.land/m
|
||||
For React Native, you may need a [polyfill for crypto.getRandomValues](https://github.com/LinusU/react-native-get-random-values).
|
||||
If you don't like NPM, a standalone [noble-curves.js](https://github.com/paulmillr/noble-curves/releases) is also available.
|
||||
|
||||
- [Usage](#usage)
|
||||
- [Implementations](#implementations)
|
||||
- [ECDSA signature scheme](#ecdsa-signature-scheme)
|
||||
- [ECDSA public key recovery & extra entropy](#ecdsa-public-key-recovery--extra-entropy)
|
||||
|
@ -12,7 +12,7 @@
|
||||
* Some projects may prefer to swap this relation, it is not supported for now.
|
||||
*/
|
||||
import { AffinePoint } from './curve.js';
|
||||
import { IField, hashToPrivateScalar } from './modular.js';
|
||||
import { IField, getMinHashLength, mapHashToField } from './modular.js';
|
||||
import { Hex, PrivKey, CHash, bitLen, bitGet, ensureBytes } from './utils.js';
|
||||
import * as htf from './hash-to-curve.js';
|
||||
import {
|
||||
@ -189,10 +189,8 @@ export function bls<Fp2, Fp6, Fp12>(
|
||||
|
||||
const utils = {
|
||||
randomPrivateKey: (): Uint8Array => {
|
||||
const bytesTaken = groupLen + Math.ceil(groupLen / 2); // e.g. 48b for 32b field
|
||||
const rand = CURVE.randomBytes(bytesTaken);
|
||||
const num = hashToPrivateScalar(rand, Fr.ORDER);
|
||||
return Fr.toBytes(num);
|
||||
const length = getMinHashLength(Fr.ORDER);
|
||||
return mapHashToField(CURVE.randomBytes(length), Fr.ORDER);
|
||||
},
|
||||
calcPairingPrecomputes,
|
||||
};
|
||||
|
@ -409,16 +409,9 @@ export function FpSqrtEven<T>(Fp: IField<T>, elm: T) {
|
||||
|
||||
/**
|
||||
* "Constant-time" private key generation utility.
|
||||
* Can take (n + 8) or more bytes of uniform input e.g. from CSPRNG or KDF
|
||||
* and convert them into private scalar, with the modulo bias being negligible.
|
||||
* Needs at least 40 bytes of input for 32-byte private key.
|
||||
* https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
|
||||
* FIPS 186-5, A.2 https://csrc.nist.gov/publications/detail/fips/186/5/final
|
||||
* hash-to-curve, https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-hashing-to-a-finite-field
|
||||
* @param hash hash output from SHA3 or a similar function
|
||||
* @param groupOrder size of subgroup - (e.g. secp256k1.CURVE.n)
|
||||
* @param isLE interpret hash bytes as LE num
|
||||
* @returns valid private scalar
|
||||
* Same as mapKeyToField, but accepts less bytes (40 instead of 48 for 32-byte field).
|
||||
* Which makes it slightly more biased, less secure.
|
||||
* @deprecated use mapKeyToField instead
|
||||
*/
|
||||
export function hashToPrivateScalar(
|
||||
hash: string | Uint8Array,
|
||||
@ -428,11 +421,43 @@ export function hashToPrivateScalar(
|
||||
hash = ensureBytes('privateHash', hash);
|
||||
const hashLen = hash.length;
|
||||
const minLen = nLength(groupOrder).nByteLength + 8; // 8b (64 bits) gives 2^-64 bias
|
||||
// Small numbers aren't supported: need to understand their security / bias story first.
|
||||
// Huge numbers aren't supported for security: it's easier to detect timings of their ops in JS.
|
||||
if (minLen < 24 || hashLen < minLen || hashLen > 1024)
|
||||
throw new Error(`expected ${minLen}-1024 bytes of input, got ${hashLen}`);
|
||||
const num = isLE ? bytesToNumberLE(hash) : bytesToNumberBE(hash);
|
||||
// `mod(x, 11)` can sometimes produce 0. `mod(x, 10) + 1` is the same, but no 0
|
||||
return mod(num, groupOrder - _1n) + _1n;
|
||||
}
|
||||
|
||||
export function getFieldBytesLength(fieldOrder: bigint): number {
|
||||
return nLength(fieldOrder).nByteLength;
|
||||
}
|
||||
|
||||
export function getMinHashLength(fieldOrder: bigint): number {
|
||||
const length = getFieldBytesLength(fieldOrder);
|
||||
return length + Math.ceil(length / 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* "Constant-time" private key generation utility.
|
||||
* Can take (n + n/2) or more bytes of uniform input e.g. from CSPRNG or KDF
|
||||
* and convert them into private scalar, with the modulo bias being negligible.
|
||||
* Needs at least 48 bytes of input for 32-byte private key.
|
||||
* https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
|
||||
* FIPS 186-5, A.2 https://csrc.nist.gov/publications/detail/fips/186/5/final
|
||||
* hash-to-curve, https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-hashing-to-a-finite-field
|
||||
* @param hash hash output from SHA3 or a similar function
|
||||
* @param groupOrder size of subgroup - (e.g. secp256k1.CURVE.n)
|
||||
* @param isLE interpret hash bytes as LE num
|
||||
* @returns valid private scalar
|
||||
*/
|
||||
export function mapHashToField(key: Uint8Array, fieldOrder: bigint, isLE = false): Uint8Array {
|
||||
const len = key.length;
|
||||
const fieldLen = getFieldBytesLength(fieldOrder);
|
||||
const minLen = getMinHashLength(fieldOrder);
|
||||
// No small numbers: need to understand bias story. No huge numbers: easier to detect JS timings.
|
||||
if (len < 16 || len < minLen || len > 1024)
|
||||
throw new Error(`expected ${minLen}-1024 bytes of input, got ${len}`);
|
||||
const num = isLE ? bytesToNumberBE(key) : bytesToNumberLE(key);
|
||||
// `mod(x, 11)` can sometimes produce 0. `mod(x, 10) + 1` is the same, but no 0
|
||||
const reduced = mod(num, fieldOrder - _1n) + _1n;
|
||||
return isLE ? numberToBytesLE(reduced, fieldLen) : numberToBytesBE(reduced, fieldLen)
|
||||
}
|
||||
|
@ -849,11 +849,8 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
||||
* (groupLen + ceil(groupLen / 2)) with modulo bias being negligible.
|
||||
*/
|
||||
randomPrivateKey: (): Uint8Array => {
|
||||
const groupLen = CURVE.nByteLength;
|
||||
const bytesTaken = groupLen + Math.ceil(groupLen / 2); // e.g. 48b for 32b field
|
||||
const rand = CURVE.randomBytes(bytesTaken);
|
||||
const num = mod.hashToPrivateScalar(rand, CURVE_ORDER);
|
||||
return ut.numberToBytesBE(num, groupLen);
|
||||
const length = mod.getMinHashLength(CURVE.n);
|
||||
return mod.mapHashToField(CURVE.randomBytes(length), CURVE.n);
|
||||
},
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user