@noble/curves 1.6.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -22
- package/_shortw_utils.d.ts.map +1 -1
- package/abstract/bls.d.ts +7 -5
- package/abstract/bls.d.ts.map +1 -1
- package/abstract/bls.js +9 -9
- package/abstract/bls.js.map +1 -1
- package/abstract/curve.d.ts +29 -6
- package/abstract/curve.d.ts.map +1 -1
- package/abstract/curve.js +184 -41
- package/abstract/curve.js.map +1 -1
- package/abstract/edwards.d.ts +2 -0
- package/abstract/edwards.d.ts.map +1 -1
- package/abstract/edwards.js +20 -9
- package/abstract/edwards.js.map +1 -1
- package/abstract/hash-to-curve.d.ts.map +1 -1
- package/abstract/hash-to-curve.js +3 -4
- package/abstract/hash-to-curve.js.map +1 -1
- package/abstract/modular.d.ts.map +1 -1
- package/abstract/modular.js +32 -21
- package/abstract/modular.js.map +1 -1
- package/abstract/montgomery.d.ts.map +1 -1
- package/abstract/montgomery.js +5 -3
- package/abstract/montgomery.js.map +1 -1
- package/abstract/poseidon.d.ts.map +1 -1
- package/abstract/poseidon.js +22 -22
- package/abstract/poseidon.js.map +1 -1
- package/abstract/tower.d.ts +1 -0
- package/abstract/tower.d.ts.map +1 -1
- package/abstract/tower.js +6 -6
- package/abstract/tower.js.map +1 -1
- package/abstract/utils.d.ts.map +1 -1
- package/abstract/utils.js +21 -23
- package/abstract/utils.js.map +1 -1
- package/abstract/weierstrass.d.ts +1 -0
- package/abstract/weierstrass.d.ts.map +1 -1
- package/abstract/weierstrass.js +54 -36
- package/abstract/weierstrass.js.map +1 -1
- package/bls12-381.js +8 -8
- package/bn254.d.ts +2 -1
- package/bn254.d.ts.map +1 -1
- package/bn254.js +9 -7
- package/bn254.js.map +1 -1
- package/ed448.js +1 -1
- package/ed448.js.map +1 -1
- package/esm/_shortw_utils.d.ts.map +1 -1
- package/esm/abstract/bls.d.ts +7 -5
- package/esm/abstract/bls.d.ts.map +1 -1
- package/esm/abstract/bls.js +9 -9
- package/esm/abstract/bls.js.map +1 -1
- package/esm/abstract/curve.d.ts +29 -6
- package/esm/abstract/curve.d.ts.map +1 -1
- package/esm/abstract/curve.js +183 -41
- package/esm/abstract/curve.js.map +1 -1
- package/esm/abstract/edwards.d.ts +2 -0
- package/esm/abstract/edwards.d.ts.map +1 -1
- package/esm/abstract/edwards.js +20 -9
- package/esm/abstract/edwards.js.map +1 -1
- package/esm/abstract/hash-to-curve.d.ts.map +1 -1
- package/esm/abstract/hash-to-curve.js +3 -4
- package/esm/abstract/hash-to-curve.js.map +1 -1
- package/esm/abstract/modular.d.ts.map +1 -1
- package/esm/abstract/modular.js +32 -21
- package/esm/abstract/modular.js.map +1 -1
- package/esm/abstract/montgomery.d.ts.map +1 -1
- package/esm/abstract/montgomery.js +5 -3
- package/esm/abstract/montgomery.js.map +1 -1
- package/esm/abstract/poseidon.d.ts.map +1 -1
- package/esm/abstract/poseidon.js +22 -22
- package/esm/abstract/poseidon.js.map +1 -1
- package/esm/abstract/tower.d.ts +1 -0
- package/esm/abstract/tower.d.ts.map +1 -1
- package/esm/abstract/tower.js +6 -6
- package/esm/abstract/tower.js.map +1 -1
- package/esm/abstract/utils.d.ts.map +1 -1
- package/esm/abstract/utils.js +21 -23
- package/esm/abstract/utils.js.map +1 -1
- package/esm/abstract/weierstrass.d.ts +1 -0
- package/esm/abstract/weierstrass.d.ts.map +1 -1
- package/esm/abstract/weierstrass.js +54 -36
- package/esm/abstract/weierstrass.js.map +1 -1
- package/esm/bls12-381.js +8 -8
- package/esm/bn254.d.ts +2 -1
- package/esm/bn254.d.ts.map +1 -1
- package/esm/bn254.js +7 -6
- package/esm/bn254.js.map +1 -1
- package/esm/ed448.js +1 -1
- package/esm/ed448.js.map +1 -1
- package/esm/p256.d.ts.map +1 -1
- package/esm/p256.js +6 -6
- package/esm/p256.js.map +1 -1
- package/esm/p384.d.ts.map +1 -1
- package/esm/p384.js +6 -6
- package/esm/p384.js.map +1 -1
- package/esm/p521.d.ts.map +1 -1
- package/esm/p521.js +7 -7
- package/esm/p521.js.map +1 -1
- package/esm/secp256k1.d.ts.map +1 -1
- package/esm/secp256k1.js +8 -8
- package/esm/secp256k1.js.map +1 -1
- package/p256.d.ts.map +1 -1
- package/p256.js +6 -6
- package/p256.js.map +1 -1
- package/p384.d.ts.map +1 -1
- package/p384.js +6 -6
- package/p384.js.map +1 -1
- package/p521.d.ts.map +1 -1
- package/p521.js +7 -7
- package/p521.js.map +1 -1
- package/package.json +4 -3
- package/secp256k1.d.ts.map +1 -1
- package/secp256k1.js +8 -8
- package/secp256k1.js.map +1 -1
- package/src/abstract/bls.ts +25 -13
- package/src/abstract/curve.ts +188 -39
- package/src/abstract/edwards.ts +25 -10
- package/src/abstract/hash-to-curve.ts +2 -5
- package/src/abstract/modular.ts +29 -19
- package/src/abstract/montgomery.ts +5 -3
- package/src/abstract/poseidon.ts +20 -24
- package/src/abstract/tower.ts +7 -6
- package/src/abstract/utils.ts +18 -24
- package/src/abstract/weierstrass.ts +57 -35
- package/src/bls12-381.ts +9 -9
- package/src/bn254.ts +16 -7
- package/src/ed448.ts +1 -1
- package/src/p256.ts +6 -6
- package/src/p384.ts +6 -6
- package/src/p521.ts +7 -7
- package/src/secp256k1.ts +8 -8
package/src/abstract/modular.ts
CHANGED
|
@@ -10,11 +10,11 @@ import {
|
|
|
10
10
|
validateObject,
|
|
11
11
|
} from './utils.js';
|
|
12
12
|
// prettier-ignore
|
|
13
|
-
const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3);
|
|
13
|
+
const _0n = BigInt(0), _1n = BigInt(1), _2n = /* @__PURE__ */ BigInt(2), _3n = /* @__PURE__ */ BigInt(3);
|
|
14
14
|
// prettier-ignore
|
|
15
|
-
const _4n = BigInt(4), _5n = BigInt(5), _8n = BigInt(8);
|
|
15
|
+
const _4n = /* @__PURE__ */ BigInt(4), _5n = /* @__PURE__ */ BigInt(5), _8n = /* @__PURE__ */ BigInt(8);
|
|
16
16
|
// prettier-ignore
|
|
17
|
-
const _9n
|
|
17
|
+
const _9n =/* @__PURE__ */ BigInt(9), _16n = /* @__PURE__ */ BigInt(16);
|
|
18
18
|
|
|
19
19
|
// Calculates a modulo b
|
|
20
20
|
export function mod(a: bigint, b: bigint): bigint {
|
|
@@ -29,7 +29,8 @@ export function mod(a: bigint, b: bigint): bigint {
|
|
|
29
29
|
*/
|
|
30
30
|
// TODO: use field version && remove
|
|
31
31
|
export function pow(num: bigint, power: bigint, modulo: bigint): bigint {
|
|
32
|
-
if (
|
|
32
|
+
if (power < _0n) throw new Error('invalid exponent, negatives unsupported');
|
|
33
|
+
if (modulo <= _0n) throw new Error('invalid modulus');
|
|
33
34
|
if (modulo === _1n) return _0n;
|
|
34
35
|
let res = _1n;
|
|
35
36
|
while (power > _0n) {
|
|
@@ -52,9 +53,8 @@ export function pow2(x: bigint, power: bigint, modulo: bigint): bigint {
|
|
|
52
53
|
|
|
53
54
|
// Inverses number over modulo
|
|
54
55
|
export function invert(number: bigint, modulo: bigint): bigint {
|
|
55
|
-
if (number === _0n
|
|
56
|
-
|
|
57
|
-
}
|
|
56
|
+
if (number === _0n) throw new Error('invert: expected non-zero number');
|
|
57
|
+
if (modulo <= _0n) throw new Error('invert: expected positive modulus, got ' + modulo);
|
|
58
58
|
// Euclidean GCD https://brilliant.org/wiki/extended-euclidean-algorithm/
|
|
59
59
|
// Fermat's little theorem "CT-like" version inv(n) = n^(m-2) mod m is 30x slower.
|
|
60
60
|
let a = mod(number, modulo);
|
|
@@ -97,7 +97,10 @@ export function tonelliShanks(P: bigint) {
|
|
|
97
97
|
for (Q = P - _1n, S = 0; Q % _2n === _0n; Q /= _2n, S++);
|
|
98
98
|
|
|
99
99
|
// Step 2: Select a non-square z such that (z | p) ≡ -1 and set c ≡ zq
|
|
100
|
-
for (Z = _2n; Z < P && pow(Z, legendreC, P) !== P - _1n; Z++)
|
|
100
|
+
for (Z = _2n; Z < P && pow(Z, legendreC, P) !== P - _1n; Z++) {
|
|
101
|
+
// Crash instead of infinity loop, we cannot reasonable count until P.
|
|
102
|
+
if (Z > 1000) throw new Error('Cannot find square root: likely non-prime P');
|
|
103
|
+
}
|
|
101
104
|
|
|
102
105
|
// Fast-path
|
|
103
106
|
if (S === 1) {
|
|
@@ -273,7 +276,7 @@ export function validateField<T>(field: IField<T>) {
|
|
|
273
276
|
export function FpPow<T>(f: IField<T>, num: T, power: bigint): T {
|
|
274
277
|
// Should have same speed as pow for bigints
|
|
275
278
|
// TODO: benchmark!
|
|
276
|
-
if (power < _0n) throw new Error('
|
|
279
|
+
if (power < _0n) throw new Error('invalid exponent, negatives unsupported');
|
|
277
280
|
if (power === _0n) return f.ONE;
|
|
278
281
|
if (power === _1n) return num;
|
|
279
282
|
let p = f.ONE;
|
|
@@ -360,10 +363,10 @@ export function Field(
|
|
|
360
363
|
isLE = false,
|
|
361
364
|
redef: Partial<IField<bigint>> = {}
|
|
362
365
|
): Readonly<FpField> {
|
|
363
|
-
if (ORDER <= _0n) throw new Error(
|
|
366
|
+
if (ORDER <= _0n) throw new Error('invalid field: expected ORDER > 0, got ' + ORDER);
|
|
364
367
|
const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, bitLen);
|
|
365
|
-
if (BYTES > 2048) throw new Error('
|
|
366
|
-
|
|
368
|
+
if (BYTES > 2048) throw new Error('invalid field: expected ORDER of <= 2048 bytes');
|
|
369
|
+
let sqrtP: ReturnType<typeof FpSqrt>; // cached sqrtP
|
|
367
370
|
const f: Readonly<FpField> = Object.freeze({
|
|
368
371
|
ORDER,
|
|
369
372
|
BITS,
|
|
@@ -374,7 +377,7 @@ export function Field(
|
|
|
374
377
|
create: (num) => mod(num, ORDER),
|
|
375
378
|
isValid: (num) => {
|
|
376
379
|
if (typeof num !== 'bigint')
|
|
377
|
-
throw new Error(
|
|
380
|
+
throw new Error('invalid field element: expected bigint, got ' + typeof num);
|
|
378
381
|
return _0n <= num && num < ORDER; // 0 is valid element, but it's not invertible
|
|
379
382
|
},
|
|
380
383
|
is0: (num) => num === _0n,
|
|
@@ -396,7 +399,12 @@ export function Field(
|
|
|
396
399
|
mulN: (lhs, rhs) => lhs * rhs,
|
|
397
400
|
|
|
398
401
|
inv: (num) => invert(num, ORDER),
|
|
399
|
-
sqrt:
|
|
402
|
+
sqrt:
|
|
403
|
+
redef.sqrt ||
|
|
404
|
+
((n) => {
|
|
405
|
+
if (!sqrtP) sqrtP = FpSqrt(ORDER);
|
|
406
|
+
return sqrtP(f, n);
|
|
407
|
+
}),
|
|
400
408
|
invertBatch: (lst) => FpInvertBatch(f, lst),
|
|
401
409
|
// TODO: do we really need constant cmov?
|
|
402
410
|
// We don't have const-time bigints anyway, so probably will be not very useful
|
|
@@ -404,7 +412,7 @@ export function Field(
|
|
|
404
412
|
toBytes: (num) => (isLE ? numberToBytesLE(num, BYTES) : numberToBytesBE(num, BYTES)),
|
|
405
413
|
fromBytes: (bytes) => {
|
|
406
414
|
if (bytes.length !== BYTES)
|
|
407
|
-
throw new Error(
|
|
415
|
+
throw new Error('Field.fromBytes: expected ' + BYTES + ' bytes, got ' + bytes.length);
|
|
408
416
|
return isLE ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes);
|
|
409
417
|
},
|
|
410
418
|
} as FpField);
|
|
@@ -412,13 +420,13 @@ export function Field(
|
|
|
412
420
|
}
|
|
413
421
|
|
|
414
422
|
export function FpSqrtOdd<T>(Fp: IField<T>, elm: T) {
|
|
415
|
-
if (!Fp.isOdd) throw new Error(
|
|
423
|
+
if (!Fp.isOdd) throw new Error("Field doesn't have isOdd");
|
|
416
424
|
const root = Fp.sqrt(elm);
|
|
417
425
|
return Fp.isOdd(root) ? root : Fp.neg(root);
|
|
418
426
|
}
|
|
419
427
|
|
|
420
428
|
export function FpSqrtEven<T>(Fp: IField<T>, elm: T) {
|
|
421
|
-
if (!Fp.isOdd) throw new Error(
|
|
429
|
+
if (!Fp.isOdd) throw new Error("Field doesn't have isOdd");
|
|
422
430
|
const root = Fp.sqrt(elm);
|
|
423
431
|
return Fp.isOdd(root) ? Fp.neg(root) : root;
|
|
424
432
|
}
|
|
@@ -438,7 +446,9 @@ export function hashToPrivateScalar(
|
|
|
438
446
|
const hashLen = hash.length;
|
|
439
447
|
const minLen = nLength(groupOrder).nByteLength + 8;
|
|
440
448
|
if (minLen < 24 || hashLen < minLen || hashLen > 1024)
|
|
441
|
-
throw new Error(
|
|
449
|
+
throw new Error(
|
|
450
|
+
'hashToPrivateScalar: expected ' + minLen + '-1024 bytes of input, got ' + hashLen
|
|
451
|
+
);
|
|
442
452
|
const num = isLE ? bytesToNumberLE(hash) : bytesToNumberBE(hash);
|
|
443
453
|
return mod(num, groupOrder - _1n) + _1n;
|
|
444
454
|
}
|
|
@@ -486,7 +496,7 @@ export function mapHashToField(key: Uint8Array, fieldOrder: bigint, isLE = false
|
|
|
486
496
|
const minLen = getMinHashLength(fieldOrder);
|
|
487
497
|
// No small numbers: need to understand bias story. No huge numbers: easier to detect JS timings.
|
|
488
498
|
if (len < 16 || len < minLen || len > 1024)
|
|
489
|
-
throw new Error(
|
|
499
|
+
throw new Error('expected ' + minLen + '-1024 bytes of input, got ' + len);
|
|
490
500
|
const num = isLE ? bytesToNumberBE(key) : bytesToNumberLE(key);
|
|
491
501
|
// `mod(x, 11)` can sometimes produce 0. `mod(x, 10) + 1` is the same, but no 0
|
|
492
502
|
const reduced = mod(num, fieldOrder - _1n) + _1n;
|
|
@@ -158,8 +158,10 @@ export function montgomery(curveDef: CurveType): CurveFn {
|
|
|
158
158
|
function decodeScalar(n: Hex): bigint {
|
|
159
159
|
const bytes = ensureBytes('scalar', n);
|
|
160
160
|
const len = bytes.length;
|
|
161
|
-
if (len !== montgomeryBytes && len !== fieldLen)
|
|
162
|
-
|
|
161
|
+
if (len !== montgomeryBytes && len !== fieldLen) {
|
|
162
|
+
let valid = '' + montgomeryBytes + ' or ' + fieldLen;
|
|
163
|
+
throw new Error('invalid scalar, expected ' + valid + ' bytes, got ' + len);
|
|
164
|
+
}
|
|
163
165
|
return bytesToNumberLE(adjustScalarBytes(bytes));
|
|
164
166
|
}
|
|
165
167
|
function scalarMult(scalar: Hex, u: Hex): Uint8Array {
|
|
@@ -168,7 +170,7 @@ export function montgomery(curveDef: CurveType): CurveFn {
|
|
|
168
170
|
const pu = montgomeryLadder(pointU, _scalar);
|
|
169
171
|
// The result was not contributory
|
|
170
172
|
// https://cr.yp.to/ecdh.html#validate
|
|
171
|
-
if (pu === _0n) throw new Error('
|
|
173
|
+
if (pu === _0n) throw new Error('invalid private or public key received');
|
|
172
174
|
return encodeUCoordinate(pu);
|
|
173
175
|
}
|
|
174
176
|
// Computes public key from private. By doing scalar multiplication of base point.
|
package/src/abstract/poseidon.ts
CHANGED
|
@@ -21,40 +21,37 @@ export function validateOpts(opts: PoseidonOpts) {
|
|
|
21
21
|
validateField(Fp);
|
|
22
22
|
for (const i of ['t', 'roundsFull', 'roundsPartial'] as const) {
|
|
23
23
|
if (typeof opts[i] !== 'number' || !Number.isSafeInteger(opts[i]))
|
|
24
|
-
throw new Error(
|
|
24
|
+
throw new Error('invalid number ' + i);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
// MDS is TxT matrix
|
|
28
|
-
if (!Array.isArray(mds) || mds.length !== t) throw new Error('Poseidon:
|
|
28
|
+
if (!Array.isArray(mds) || mds.length !== t) throw new Error('Poseidon: invalid MDS matrix');
|
|
29
29
|
const _mds = mds.map((mdsRow) => {
|
|
30
30
|
if (!Array.isArray(mdsRow) || mdsRow.length !== t)
|
|
31
|
-
throw new Error(
|
|
31
|
+
throw new Error('invalid MDS matrix row: ' + mdsRow);
|
|
32
32
|
return mdsRow.map((i) => {
|
|
33
|
-
if (typeof i !== 'bigint') throw new Error(
|
|
33
|
+
if (typeof i !== 'bigint') throw new Error('invalid MDS matrix bigint: ' + i);
|
|
34
34
|
return Fp.create(i);
|
|
35
35
|
});
|
|
36
36
|
});
|
|
37
37
|
|
|
38
38
|
if (rev !== undefined && typeof rev !== 'boolean')
|
|
39
|
-
throw new Error(
|
|
39
|
+
throw new Error('invalid param reversePartialPowIdx=' + rev);
|
|
40
40
|
|
|
41
|
-
if (roundsFull
|
|
41
|
+
if (roundsFull & 1) throw new Error('roundsFull is not even' + roundsFull);
|
|
42
42
|
const rounds = roundsFull + roundsPartial;
|
|
43
43
|
|
|
44
44
|
if (!Array.isArray(rc) || rc.length !== rounds)
|
|
45
|
-
throw new Error('Poseidon:
|
|
45
|
+
throw new Error('Poseidon: invalid round constants');
|
|
46
46
|
const roundConstants = rc.map((rc) => {
|
|
47
|
-
if (!Array.isArray(rc) || rc.length !== t)
|
|
48
|
-
throw new Error(`Poseidon wrong round constants: ${rc}`);
|
|
47
|
+
if (!Array.isArray(rc) || rc.length !== t) throw new Error('invalid round constants');
|
|
49
48
|
return rc.map((i) => {
|
|
50
|
-
if (typeof i !== 'bigint' || !Fp.isValid(i))
|
|
51
|
-
throw new Error(`Poseidon wrong round constant=${i}`);
|
|
49
|
+
if (typeof i !== 'bigint' || !Fp.isValid(i)) throw new Error('invalid round constant');
|
|
52
50
|
return Fp.create(i);
|
|
53
51
|
});
|
|
54
52
|
});
|
|
55
53
|
|
|
56
|
-
if (!sboxPower || ![3, 5, 7].includes(sboxPower))
|
|
57
|
-
throw new Error(`Poseidon wrong sboxPower=${sboxPower}`);
|
|
54
|
+
if (!sboxPower || ![3, 5, 7].includes(sboxPower)) throw new Error('invalid sboxPower');
|
|
58
55
|
const _sboxPower = BigInt(sboxPower);
|
|
59
56
|
let sboxFn = (n: bigint) => FpPow(Fp, n, _sboxPower);
|
|
60
57
|
// Unwrapped sbox power for common cases (195->142μs)
|
|
@@ -65,8 +62,8 @@ export function validateOpts(opts: PoseidonOpts) {
|
|
|
65
62
|
}
|
|
66
63
|
|
|
67
64
|
export function splitConstants(rc: bigint[], t: number) {
|
|
68
|
-
if (typeof t !== 'number') throw new Error('poseidonSplitConstants:
|
|
69
|
-
if (!Array.isArray(rc) || rc.length % t) throw new Error('poseidonSplitConstants:
|
|
65
|
+
if (typeof t !== 'number') throw new Error('poseidonSplitConstants: invalid t');
|
|
66
|
+
if (!Array.isArray(rc) || rc.length % t) throw new Error('poseidonSplitConstants: invalid rc');
|
|
70
67
|
const res = [];
|
|
71
68
|
let tmp = [];
|
|
72
69
|
for (let i = 0; i < rc.length; i++) {
|
|
@@ -81,7 +78,7 @@ export function splitConstants(rc: bigint[], t: number) {
|
|
|
81
78
|
|
|
82
79
|
export function poseidon(opts: PoseidonOpts) {
|
|
83
80
|
const _opts = validateOpts(opts);
|
|
84
|
-
const { Fp, mds, roundConstants, rounds, roundsPartial, sboxFn, t } = _opts;
|
|
81
|
+
const { Fp, mds, roundConstants, rounds: totalRounds, roundsPartial, sboxFn, t } = _opts;
|
|
85
82
|
const halfRoundsFull = _opts.roundsFull / 2;
|
|
86
83
|
const partialIdx = _opts.reversePartialPowIdx ? t - 1 : 0;
|
|
87
84
|
const poseidonRound = (values: bigint[], isFull: boolean, idx: number) => {
|
|
@@ -95,21 +92,20 @@ export function poseidon(opts: PoseidonOpts) {
|
|
|
95
92
|
};
|
|
96
93
|
const poseidonHash = function poseidonHash(values: bigint[]) {
|
|
97
94
|
if (!Array.isArray(values) || values.length !== t)
|
|
98
|
-
throw new Error(
|
|
95
|
+
throw new Error('invalid values, expected array of bigints with length ' + t);
|
|
99
96
|
values = values.map((i) => {
|
|
100
|
-
if (typeof i !== 'bigint') throw new Error(
|
|
97
|
+
if (typeof i !== 'bigint') throw new Error('invalid bigint=' + i);
|
|
101
98
|
return Fp.create(i);
|
|
102
99
|
});
|
|
103
|
-
let
|
|
100
|
+
let lastRound = 0;
|
|
104
101
|
// Apply r_f/2 full rounds.
|
|
105
|
-
for (let i = 0; i < halfRoundsFull; i++) values = poseidonRound(values, true,
|
|
102
|
+
for (let i = 0; i < halfRoundsFull; i++) values = poseidonRound(values, true, lastRound++);
|
|
106
103
|
// Apply r_p partial rounds.
|
|
107
|
-
for (let i = 0; i < roundsPartial; i++) values = poseidonRound(values, false,
|
|
104
|
+
for (let i = 0; i < roundsPartial; i++) values = poseidonRound(values, false, lastRound++);
|
|
108
105
|
// Apply r_f/2 full rounds.
|
|
109
|
-
for (let i = 0; i < halfRoundsFull; i++) values = poseidonRound(values, true,
|
|
106
|
+
for (let i = 0; i < halfRoundsFull; i++) values = poseidonRound(values, true, lastRound++);
|
|
110
107
|
|
|
111
|
-
if (
|
|
112
|
-
throw new Error(`Poseidon: wrong number of rounds: last round=${round}, total=${rounds}`);
|
|
108
|
+
if (lastRound !== totalRounds) throw new Error('invalid number of rounds');
|
|
113
109
|
return values;
|
|
114
110
|
};
|
|
115
111
|
// For verification in tests
|
package/src/abstract/tower.ts
CHANGED
|
@@ -47,6 +47,7 @@ export type Fp12Bls = mod.IField<Fp12> & {
|
|
|
47
47
|
mul034(num: Fp12, o0: Fp2, o3: Fp2, o4: Fp2): Fp12;
|
|
48
48
|
conjugate(num: Fp12): Fp12;
|
|
49
49
|
finalExponentiate(num: Fp12): Fp12;
|
|
50
|
+
fromBigTwelve(num: BigintTwelve): Fp12;
|
|
50
51
|
};
|
|
51
52
|
|
|
52
53
|
function calcFrobeniusCoefficients<T>(
|
|
@@ -163,7 +164,7 @@ export function tower12(opts: Tower12Opts) {
|
|
|
163
164
|
frobeniusMap(num: Fp2, power: number): Fp2;
|
|
164
165
|
};
|
|
165
166
|
const Fp2fromBigTuple = (tuple: BigintTuple | bigint[]) => {
|
|
166
|
-
if (tuple.length !== 2) throw new Error('
|
|
167
|
+
if (tuple.length !== 2) throw new Error('invalid tuple');
|
|
167
168
|
const fps = tuple.map((n) => Fp.create(n)) as [Fp, Fp];
|
|
168
169
|
return { c0: fps[0], c1: fps[1] };
|
|
169
170
|
};
|
|
@@ -250,7 +251,7 @@ export function tower12(opts: Tower12Opts) {
|
|
|
250
251
|
},
|
|
251
252
|
// Bytes util
|
|
252
253
|
fromBytes(b: Uint8Array): Fp2 {
|
|
253
|
-
if (b.length !== Fp2.BYTES) throw new Error(
|
|
254
|
+
if (b.length !== Fp2.BYTES) throw new Error('fromBytes invalid length=' + b.length);
|
|
254
255
|
return { c0: Fp.fromBytes(b.subarray(0, Fp.BYTES)), c1: Fp.fromBytes(b.subarray(Fp.BYTES)) };
|
|
255
256
|
},
|
|
256
257
|
toBytes: ({ c0, c1 }) => concatBytes(Fp.toBytes(c0), Fp.toBytes(c1)),
|
|
@@ -378,7 +379,7 @@ export function tower12(opts: Tower12Opts) {
|
|
|
378
379
|
},
|
|
379
380
|
// Bytes utils
|
|
380
381
|
fromBytes: (b: Uint8Array): Fp6 => {
|
|
381
|
-
if (b.length !== Fp6.BYTES) throw new Error(
|
|
382
|
+
if (b.length !== Fp6.BYTES) throw new Error('fromBytes invalid length=' + b.length);
|
|
382
383
|
return {
|
|
383
384
|
c0: Fp2.fromBytes(b.subarray(0, Fp2.BYTES)),
|
|
384
385
|
c1: Fp2.fromBytes(b.subarray(Fp2.BYTES, 2 * Fp2.BYTES)),
|
|
@@ -393,7 +394,7 @@ export function tower12(opts: Tower12Opts) {
|
|
|
393
394
|
c2: Fp2.cmov(c2, r2, c),
|
|
394
395
|
}),
|
|
395
396
|
fromBigSix: (t: BigintSix): Fp6 => {
|
|
396
|
-
if (!Array.isArray(t) || t.length !== 6) throw new Error('
|
|
397
|
+
if (!Array.isArray(t) || t.length !== 6) throw new Error('invalid Fp6 usage');
|
|
397
398
|
return {
|
|
398
399
|
c0: Fp2.fromBigTuple(t.slice(0, 2)),
|
|
399
400
|
c1: Fp2.fromBigTuple(t.slice(2, 4)),
|
|
@@ -526,7 +527,7 @@ export function tower12(opts: Tower12Opts) {
|
|
|
526
527
|
|
|
527
528
|
// Bytes utils
|
|
528
529
|
fromBytes: (b: Uint8Array): Fp12 => {
|
|
529
|
-
if (b.length !== Fp12.BYTES) throw new Error(
|
|
530
|
+
if (b.length !== Fp12.BYTES) throw new Error('fromBytes invalid length=' + b.length);
|
|
530
531
|
return {
|
|
531
532
|
c0: Fp6.fromBytes(b.subarray(0, Fp6.BYTES)),
|
|
532
533
|
c1: Fp6.fromBytes(b.subarray(Fp6.BYTES)),
|
|
@@ -539,7 +540,7 @@ export function tower12(opts: Tower12Opts) {
|
|
|
539
540
|
}),
|
|
540
541
|
// Utils
|
|
541
542
|
// toString() {
|
|
542
|
-
// return
|
|
543
|
+
// return '' + 'Fp12(' + this.c0 + this.c1 + '* w');
|
|
543
544
|
// },
|
|
544
545
|
// fromTuple(c: [Fp6, Fp6]) {
|
|
545
546
|
// return new Fp12(...c);
|
package/src/abstract/utils.ts
CHANGED
|
@@ -17,10 +17,7 @@ export type CHash = {
|
|
|
17
17
|
export type FHash = (message: Uint8Array | string) => Uint8Array;
|
|
18
18
|
|
|
19
19
|
export function isBytes(a: unknown): a is Uint8Array {
|
|
20
|
-
return (
|
|
21
|
-
a instanceof Uint8Array ||
|
|
22
|
-
(a != null && typeof a === 'object' && a.constructor.name === 'Uint8Array')
|
|
23
|
-
);
|
|
20
|
+
return a instanceof Uint8Array || (ArrayBuffer.isView(a) && a.constructor.name === 'Uint8Array');
|
|
24
21
|
}
|
|
25
22
|
|
|
26
23
|
export function abytes(item: unknown): void {
|
|
@@ -28,8 +25,7 @@ export function abytes(item: unknown): void {
|
|
|
28
25
|
}
|
|
29
26
|
|
|
30
27
|
export function abool(title: string, value: boolean): void {
|
|
31
|
-
if (typeof value !== 'boolean')
|
|
32
|
-
throw new Error(`${title} must be valid boolean, got "${value}".`);
|
|
28
|
+
if (typeof value !== 'boolean') throw new Error(title + ' boolean expected, got ' + value);
|
|
33
29
|
}
|
|
34
30
|
|
|
35
31
|
// Array where index 0xf0 (240) is mapped to string 'f0'
|
|
@@ -51,21 +47,20 @@ export function bytesToHex(bytes: Uint8Array): string {
|
|
|
51
47
|
|
|
52
48
|
export function numberToHexUnpadded(num: number | bigint): string {
|
|
53
49
|
const hex = num.toString(16);
|
|
54
|
-
return hex.length & 1 ?
|
|
50
|
+
return hex.length & 1 ? '0' + hex : hex;
|
|
55
51
|
}
|
|
56
52
|
|
|
57
53
|
export function hexToNumber(hex: string): bigint {
|
|
58
54
|
if (typeof hex !== 'string') throw new Error('hex string expected, got ' + typeof hex);
|
|
59
|
-
// Big Endian
|
|
60
|
-
return BigInt(hex === '' ? '0' : `0x${hex}`);
|
|
55
|
+
return hex === '' ? _0n : BigInt('0x' + hex); // Big Endian
|
|
61
56
|
}
|
|
62
57
|
|
|
63
58
|
// We use optimized technique to convert hex string to byte array
|
|
64
|
-
const asciis = { _0: 48, _9: 57,
|
|
65
|
-
function asciiToBase16(
|
|
66
|
-
if (
|
|
67
|
-
if (
|
|
68
|
-
if (
|
|
59
|
+
const asciis = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 } as const;
|
|
60
|
+
function asciiToBase16(ch: number): number | undefined {
|
|
61
|
+
if (ch >= asciis._0 && ch <= asciis._9) return ch - asciis._0; // '2' => 50-48
|
|
62
|
+
if (ch >= asciis.A && ch <= asciis.F) return ch - (asciis.A - 10); // 'B' => 66-(65-10)
|
|
63
|
+
if (ch >= asciis.a && ch <= asciis.f) return ch - (asciis.a - 10); // 'b' => 98-(97-10)
|
|
69
64
|
return;
|
|
70
65
|
}
|
|
71
66
|
|
|
@@ -76,7 +71,7 @@ export function hexToBytes(hex: string): Uint8Array {
|
|
|
76
71
|
if (typeof hex !== 'string') throw new Error('hex string expected, got ' + typeof hex);
|
|
77
72
|
const hl = hex.length;
|
|
78
73
|
const al = hl / 2;
|
|
79
|
-
if (hl % 2) throw new Error('
|
|
74
|
+
if (hl % 2) throw new Error('hex string expected, got unpadded hex of length ' + hl);
|
|
80
75
|
const array = new Uint8Array(al);
|
|
81
76
|
for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {
|
|
82
77
|
const n1 = asciiToBase16(hex.charCodeAt(hi));
|
|
@@ -85,7 +80,7 @@ export function hexToBytes(hex: string): Uint8Array {
|
|
|
85
80
|
const char = hex[hi] + hex[hi + 1];
|
|
86
81
|
throw new Error('hex string expected, got non-hex character "' + char + '" at index ' + hi);
|
|
87
82
|
}
|
|
88
|
-
array[ai] = n1 * 16 + n2;
|
|
83
|
+
array[ai] = n1 * 16 + n2; // multiply first octet, e.g. 'a3' => 10*16+3 => 160 + 3 => 163
|
|
89
84
|
}
|
|
90
85
|
return array;
|
|
91
86
|
}
|
|
@@ -125,18 +120,18 @@ export function ensureBytes(title: string, hex: Hex, expectedLength?: number): U
|
|
|
125
120
|
try {
|
|
126
121
|
res = hexToBytes(hex);
|
|
127
122
|
} catch (e) {
|
|
128
|
-
throw new Error(
|
|
123
|
+
throw new Error(title + ' must be hex string or Uint8Array, cause: ' + e);
|
|
129
124
|
}
|
|
130
125
|
} else if (isBytes(hex)) {
|
|
131
126
|
// Uint8Array.from() instead of hash.slice() because node.js Buffer
|
|
132
127
|
// is instance of Uint8Array, and its slice() creates **mutable** copy
|
|
133
128
|
res = Uint8Array.from(hex);
|
|
134
129
|
} else {
|
|
135
|
-
throw new Error(
|
|
130
|
+
throw new Error(title + ' must be hex string or Uint8Array');
|
|
136
131
|
}
|
|
137
132
|
const len = res.length;
|
|
138
133
|
if (typeof expectedLength === 'number' && len !== expectedLength)
|
|
139
|
-
throw new Error(
|
|
134
|
+
throw new Error(title + ' of length ' + expectedLength + ' expected, got ' + len);
|
|
140
135
|
return res;
|
|
141
136
|
}
|
|
142
137
|
|
|
@@ -175,7 +170,7 @@ declare const TextEncoder: any;
|
|
|
175
170
|
* @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])
|
|
176
171
|
*/
|
|
177
172
|
export function utf8ToBytes(str: string): Uint8Array {
|
|
178
|
-
if (typeof str !== 'string') throw new Error(
|
|
173
|
+
if (typeof str !== 'string') throw new Error('string expected');
|
|
179
174
|
return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809
|
|
180
175
|
}
|
|
181
176
|
|
|
@@ -198,7 +193,7 @@ export function aInRange(title: string, n: bigint, min: bigint, max: bigint) {
|
|
|
198
193
|
// - b would commonly require subtraction: `inRange('x', x, 0n, P - 1n)`
|
|
199
194
|
// - our way is the cleanest: `inRange('x', x, 0n, P)
|
|
200
195
|
if (!inRange(n, min, max))
|
|
201
|
-
throw new Error(
|
|
196
|
+
throw new Error('expected valid ' + title + ': ' + min + ' <= n < ' + max + ', got ' + n);
|
|
202
197
|
}
|
|
203
198
|
|
|
204
199
|
// Bit operations
|
|
@@ -321,14 +316,13 @@ export function validateObject<T extends Record<string, any>>(
|
|
|
321
316
|
) {
|
|
322
317
|
const checkField = (fieldName: keyof T, type: Validator, isOptional: boolean) => {
|
|
323
318
|
const checkVal = validatorFns[type];
|
|
324
|
-
if (typeof checkVal !== 'function')
|
|
325
|
-
throw new Error(`Invalid validator "${type}", expected function`);
|
|
319
|
+
if (typeof checkVal !== 'function') throw new Error('invalid validator function');
|
|
326
320
|
|
|
327
321
|
const val = object[fieldName as keyof typeof object];
|
|
328
322
|
if (isOptional && val === undefined) return;
|
|
329
323
|
if (!checkVal(val, object)) {
|
|
330
324
|
throw new Error(
|
|
331
|
-
|
|
325
|
+
'param ' + String(fieldName) + ' is invalid. Expected ' + type + ', got ' + val
|
|
332
326
|
);
|
|
333
327
|
}
|
|
334
328
|
};
|