@noble/curves 0.5.2 → 0.6.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 +49 -5
- package/lib/_shortw_utils.d.ts +10 -21
- package/lib/abstract/bls.d.ts +39 -32
- package/lib/abstract/bls.js +74 -73
- package/lib/abstract/{group.d.ts → curve.d.ts} +31 -1
- package/lib/abstract/{group.js → curve.js} +39 -2
- package/lib/abstract/edwards.d.ts +30 -72
- package/lib/abstract/edwards.js +197 -375
- package/lib/abstract/hash-to-curve.d.ts +25 -6
- package/lib/abstract/hash-to-curve.js +40 -12
- package/lib/abstract/modular.d.ts +20 -7
- package/lib/abstract/modular.js +61 -35
- package/lib/abstract/montgomery.js +4 -5
- package/lib/abstract/poseidon.d.ts +29 -0
- package/lib/abstract/poseidon.js +115 -0
- package/lib/abstract/utils.d.ts +5 -36
- package/lib/abstract/utils.js +23 -71
- package/lib/abstract/weierstrass.d.ts +51 -74
- package/lib/abstract/weierstrass.js +455 -628
- package/lib/bls12-381.js +63 -58
- package/lib/bn.js +1 -1
- package/lib/ed25519.d.ts +7 -5
- package/lib/ed25519.js +82 -79
- package/lib/ed448.d.ts +3 -0
- package/lib/ed448.js +86 -83
- package/lib/esm/abstract/bls.js +75 -74
- package/lib/esm/abstract/{group.js → curve.js} +37 -1
- package/lib/esm/abstract/edwards.js +196 -374
- package/lib/esm/abstract/hash-to-curve.js +38 -11
- package/lib/esm/abstract/modular.js +58 -34
- package/lib/esm/abstract/montgomery.js +5 -6
- package/lib/esm/abstract/poseidon.js +109 -0
- package/lib/esm/abstract/utils.js +21 -66
- package/lib/esm/abstract/weierstrass.js +454 -627
- package/lib/esm/bls12-381.js +75 -70
- package/lib/esm/bn.js +1 -1
- package/lib/esm/ed25519.js +80 -78
- package/lib/esm/ed448.js +84 -82
- package/lib/esm/jubjub.js +1 -1
- package/lib/esm/p256.js +11 -9
- package/lib/esm/p384.js +11 -9
- package/lib/esm/p521.js +13 -12
- package/lib/esm/secp256k1.js +115 -151
- package/lib/esm/stark.js +104 -40
- package/lib/jubjub.d.ts +2 -2
- package/lib/jubjub.js +1 -1
- package/lib/p192.d.ts +20 -42
- package/lib/p224.d.ts +20 -42
- package/lib/p256.d.ts +23 -42
- package/lib/p256.js +13 -10
- package/lib/p384.d.ts +23 -42
- package/lib/p384.js +13 -10
- package/lib/p521.d.ts +23 -42
- package/lib/p521.js +15 -13
- package/lib/secp256k1.d.ts +25 -37
- package/lib/secp256k1.js +115 -151
- package/lib/stark.d.ts +36 -19
- package/lib/stark.js +107 -40
- package/package.json +13 -8
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
|
|
2
|
+
import type { Group, GroupConstructor, AffinePoint } from './curve.js';
|
|
3
|
+
import { Field } from './modular.js';
|
|
4
|
+
import { CHash, Hex } from './utils.js';
|
|
5
|
+
export declare type Opts = {
|
|
5
6
|
DST: string;
|
|
7
|
+
encodeDST: string;
|
|
6
8
|
p: bigint;
|
|
7
9
|
m: number;
|
|
8
10
|
k: number;
|
|
9
11
|
expand?: 'xmd' | 'xof';
|
|
10
12
|
hash: CHash;
|
|
11
13
|
};
|
|
12
|
-
export declare function
|
|
14
|
+
export declare function validateOpts(opts: Opts): void;
|
|
13
15
|
export declare function stringToBytes(str: string): Uint8Array;
|
|
14
16
|
export declare function expand_message_xmd(msg: Uint8Array, DST: Uint8Array, lenInBytes: number, H: CHash): Uint8Array;
|
|
15
17
|
export declare function expand_message_xof(msg: Uint8Array, DST: Uint8Array, lenInBytes: number, k: number, H: CHash): Uint8Array;
|
|
@@ -21,8 +23,25 @@ export declare function expand_message_xof(msg: Uint8Array, DST: Uint8Array, len
|
|
|
21
23
|
* @param options `{DST: string, p: bigint, m: number, k: number, expand: 'xmd' | 'xof', hash: H}`
|
|
22
24
|
* @returns [u_0, ..., u_(count - 1)], a list of field elements.
|
|
23
25
|
*/
|
|
24
|
-
export declare function hash_to_field(msg: Uint8Array, count: number, options:
|
|
25
|
-
export declare function isogenyMap<T, F extends
|
|
26
|
+
export declare function hash_to_field(msg: Uint8Array, count: number, options: Opts): bigint[][];
|
|
27
|
+
export declare function isogenyMap<T, F extends Field<T>>(field: F, map: [T[], T[], T[], T[]]): (x: T, y: T) => {
|
|
26
28
|
x: T;
|
|
27
29
|
y: T;
|
|
28
30
|
};
|
|
31
|
+
export interface H2CPoint<T> extends Group<H2CPoint<T>> {
|
|
32
|
+
add(rhs: H2CPoint<T>): H2CPoint<T>;
|
|
33
|
+
toAffine(iz?: bigint): AffinePoint<T>;
|
|
34
|
+
clearCofactor(): H2CPoint<T>;
|
|
35
|
+
assertValidity(): void;
|
|
36
|
+
}
|
|
37
|
+
export interface H2CPointConstructor<T> extends GroupConstructor<H2CPoint<T>> {
|
|
38
|
+
fromAffine(ap: AffinePoint<T>): H2CPoint<T>;
|
|
39
|
+
}
|
|
40
|
+
export declare type MapToCurve<T> = (scalar: bigint[]) => AffinePoint<T>;
|
|
41
|
+
export declare type htfBasicOpts = {
|
|
42
|
+
DST: string;
|
|
43
|
+
};
|
|
44
|
+
export declare function hashToCurve<T>(Point: H2CPointConstructor<T>, mapToCurve: MapToCurve<T>, def: Opts): {
|
|
45
|
+
hashToCurve(msg: Hex, options?: htfBasicOpts): H2CPoint<T>;
|
|
46
|
+
encodeToCurve(msg: Hex, options?: htfBasicOpts): H2CPoint<T>;
|
|
47
|
+
};
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isogenyMap = exports.hash_to_field = exports.expand_message_xof = exports.expand_message_xmd = exports.stringToBytes = exports.
|
|
4
|
-
|
|
3
|
+
exports.hashToCurve = exports.isogenyMap = exports.hash_to_field = exports.expand_message_xof = exports.expand_message_xmd = exports.stringToBytes = exports.validateOpts = void 0;
|
|
4
|
+
const modular_js_1 = require("./modular.js");
|
|
5
5
|
const utils_js_1 = require("./utils.js");
|
|
6
|
-
|
|
7
|
-
function validateHTFOpts(opts) {
|
|
6
|
+
function validateOpts(opts) {
|
|
8
7
|
if (typeof opts.DST !== 'string')
|
|
9
8
|
throw new Error('Invalid htf/DST');
|
|
10
9
|
if (typeof opts.p !== 'bigint')
|
|
@@ -18,14 +17,12 @@ function validateHTFOpts(opts) {
|
|
|
18
17
|
if (typeof opts.hash !== 'function' || !Number.isSafeInteger(opts.hash.outputLen))
|
|
19
18
|
throw new Error('Invalid htf/hash function');
|
|
20
19
|
}
|
|
21
|
-
exports.
|
|
22
|
-
// UTF8 to ui8a
|
|
23
|
-
// TODO: looks broken, ASCII only, why not TextEncoder/TextDecoder? it is in hashes anyway
|
|
20
|
+
exports.validateOpts = validateOpts;
|
|
24
21
|
function stringToBytes(str) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return
|
|
22
|
+
if (typeof str !== 'string') {
|
|
23
|
+
throw new TypeError(`utf8ToBytes expected string, got ${typeof str}`);
|
|
24
|
+
}
|
|
25
|
+
return new TextEncoder().encode(str);
|
|
29
26
|
}
|
|
30
27
|
exports.stringToBytes = stringToBytes;
|
|
31
28
|
// Octet Stream to Integer (bytesToNumberBE)
|
|
@@ -127,7 +124,7 @@ function hash_to_field(msg, count, options) {
|
|
|
127
124
|
for (let j = 0; j < options.m; j++) {
|
|
128
125
|
const elm_offset = L * (j + i * options.m);
|
|
129
126
|
const tv = pseudo_random_bytes.subarray(elm_offset, elm_offset + L);
|
|
130
|
-
e[j] =
|
|
127
|
+
e[j] = (0, modular_js_1.mod)(os2ip(tv), options.p);
|
|
131
128
|
}
|
|
132
129
|
u[i] = e;
|
|
133
130
|
}
|
|
@@ -145,3 +142,34 @@ function isogenyMap(field, map) {
|
|
|
145
142
|
};
|
|
146
143
|
}
|
|
147
144
|
exports.isogenyMap = isogenyMap;
|
|
145
|
+
function hashToCurve(Point, mapToCurve, def) {
|
|
146
|
+
validateOpts(def);
|
|
147
|
+
if (typeof mapToCurve !== 'function')
|
|
148
|
+
throw new Error('hashToCurve: mapToCurve() has not been defined');
|
|
149
|
+
return {
|
|
150
|
+
// Encodes byte string to elliptic curve
|
|
151
|
+
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-3
|
|
152
|
+
hashToCurve(msg, options) {
|
|
153
|
+
if (!mapToCurve)
|
|
154
|
+
throw new Error('CURVE.mapToCurve() has not been defined');
|
|
155
|
+
msg = (0, utils_js_1.ensureBytes)(msg);
|
|
156
|
+
const u = hash_to_field(msg, 2, { ...def, DST: def.DST, ...options });
|
|
157
|
+
const P = Point.fromAffine(mapToCurve(u[0]))
|
|
158
|
+
.add(Point.fromAffine(mapToCurve(u[1])))
|
|
159
|
+
.clearCofactor();
|
|
160
|
+
P.assertValidity();
|
|
161
|
+
return P;
|
|
162
|
+
},
|
|
163
|
+
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-3
|
|
164
|
+
encodeToCurve(msg, options) {
|
|
165
|
+
if (!mapToCurve)
|
|
166
|
+
throw new Error('CURVE.mapToCurve() has not been defined');
|
|
167
|
+
msg = (0, utils_js_1.ensureBytes)(msg);
|
|
168
|
+
const u = hash_to_field(msg, 1, { ...def, DST: def.encodeDST, ...options });
|
|
169
|
+
const P = Point.fromAffine(mapToCurve(u[0])).clearCofactor();
|
|
170
|
+
P.assertValidity();
|
|
171
|
+
return P;
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
exports.hashToCurve = hashToCurve;
|
|
@@ -20,12 +20,12 @@ export interface Field<T> {
|
|
|
20
20
|
ONE: T;
|
|
21
21
|
create: (num: T) => T;
|
|
22
22
|
isValid: (num: T) => boolean;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
is0: (num: T) => boolean;
|
|
24
|
+
neg(num: T): T;
|
|
25
|
+
inv(num: T): T;
|
|
26
26
|
sqrt(num: T): T;
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
sqr(num: T): T;
|
|
28
|
+
eql(lhs: T, rhs: T): boolean;
|
|
29
29
|
add(lhs: T, rhs: T): T;
|
|
30
30
|
sub(lhs: T, rhs: T): T;
|
|
31
31
|
mul(lhs: T, rhs: T | bigint): T;
|
|
@@ -34,9 +34,8 @@ export interface Field<T> {
|
|
|
34
34
|
addN(lhs: T, rhs: T): T;
|
|
35
35
|
subN(lhs: T, rhs: T): T;
|
|
36
36
|
mulN(lhs: T, rhs: T | bigint): T;
|
|
37
|
-
|
|
37
|
+
sqrN(num: T): T;
|
|
38
38
|
isOdd?(num: T): boolean;
|
|
39
|
-
legendre?(num: T): T;
|
|
40
39
|
pow(lhs: T, power: bigint): T;
|
|
41
40
|
invertBatch: (lst: T[]) => T[];
|
|
42
41
|
toBytes(num: T): Uint8Array;
|
|
@@ -48,8 +47,22 @@ export declare function FpPow<T>(f: Field<T>, num: T, power: bigint): T;
|
|
|
48
47
|
export declare function FpInvertBatch<T>(f: Field<T>, nums: T[]): T[];
|
|
49
48
|
export declare function FpDiv<T>(f: Field<T>, lhs: T, rhs: T | bigint): T;
|
|
50
49
|
export declare function FpIsSquare<T>(f: Field<T>): (x: T) => boolean;
|
|
50
|
+
export declare function nLength(n: bigint, nBitLength?: number): {
|
|
51
|
+
nBitLength: number;
|
|
52
|
+
nByteLength: number;
|
|
53
|
+
};
|
|
51
54
|
declare type FpField = Field<bigint> & Required<Pick<Field<bigint>, 'isOdd'>>;
|
|
52
55
|
export declare function Fp(ORDER: bigint, bitLen?: number, isLE?: boolean, redef?: Partial<Field<bigint>>): Readonly<FpField>;
|
|
53
56
|
export declare function FpSqrtOdd<T>(Fp: Field<T>, elm: T): T;
|
|
54
57
|
export declare function FpSqrtEven<T>(Fp: Field<T>, elm: T): T;
|
|
58
|
+
/**
|
|
59
|
+
* FIPS 186 B.4.1-compliant "constant-time" private key generation utility.
|
|
60
|
+
* Can take (n+8) or more bytes of uniform input e.g. from CSPRNG or KDF
|
|
61
|
+
* and convert them into private scalar, with the modulo bias being neglible.
|
|
62
|
+
* Needs at least 40 bytes of input for 32-byte private key.
|
|
63
|
+
* https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
|
|
64
|
+
* @param hash hash output from SHA3 or a similar function
|
|
65
|
+
* @returns valid private scalar
|
|
66
|
+
*/
|
|
67
|
+
export declare function hashToPrivateScalar(hash: string | Uint8Array, groupOrder: bigint, isLE?: boolean): bigint;
|
|
55
68
|
export {};
|
package/lib/abstract/modular.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.FpSqrtEven = exports.FpSqrtOdd = exports.Fp = exports.FpIsSquare = exports.FpDiv = exports.FpInvertBatch = exports.FpPow = exports.validateField = exports.isNegativeLE = exports.FpSqrt = exports.tonelliShanks = exports.invert = exports.pow2 = exports.pow = exports.mod = void 0;
|
|
3
|
+
exports.hashToPrivateScalar = exports.FpSqrtEven = exports.FpSqrtOdd = exports.Fp = exports.nLength = exports.FpIsSquare = exports.FpDiv = exports.FpInvertBatch = exports.FpPow = exports.validateField = exports.isNegativeLE = exports.FpSqrt = exports.tonelliShanks = exports.invert = exports.pow2 = exports.pow = exports.mod = void 0;
|
|
4
4
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
5
|
-
// TODO: remove circular imports
|
|
6
|
-
const utils = require("./utils.js");
|
|
7
5
|
// Utilities for modular arithmetics and finite fields
|
|
6
|
+
const utils_js_1 = require("./utils.js");
|
|
8
7
|
// prettier-ignore
|
|
9
8
|
const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3);
|
|
10
9
|
// prettier-ignore
|
|
@@ -98,7 +97,7 @@ function tonelliShanks(P) {
|
|
|
98
97
|
const p1div4 = (P + _1n) / _4n;
|
|
99
98
|
return function tonelliFast(Fp, n) {
|
|
100
99
|
const root = Fp.pow(n, p1div4);
|
|
101
|
-
if (!Fp.
|
|
100
|
+
if (!Fp.eql(Fp.sqr(root), n))
|
|
102
101
|
throw new Error('Cannot find square root');
|
|
103
102
|
return root;
|
|
104
103
|
};
|
|
@@ -107,26 +106,26 @@ function tonelliShanks(P) {
|
|
|
107
106
|
const Q1div2 = (Q + _1n) / _2n;
|
|
108
107
|
return function tonelliSlow(Fp, n) {
|
|
109
108
|
// Step 0: Check that n is indeed a square: (n | p) should not be ≡ -1
|
|
110
|
-
if (Fp.pow(n, legendreC) === Fp.
|
|
109
|
+
if (Fp.pow(n, legendreC) === Fp.neg(Fp.ONE))
|
|
111
110
|
throw new Error('Cannot find square root');
|
|
112
111
|
let r = S;
|
|
113
112
|
// TODO: will fail at Fp2/etc
|
|
114
113
|
let g = Fp.pow(Fp.mul(Fp.ONE, Z), Q); // will update both x and b
|
|
115
114
|
let x = Fp.pow(n, Q1div2); // first guess at the square root
|
|
116
115
|
let b = Fp.pow(n, Q); // first guess at the fudge factor
|
|
117
|
-
while (!Fp.
|
|
118
|
-
if (Fp.
|
|
116
|
+
while (!Fp.eql(b, Fp.ONE)) {
|
|
117
|
+
if (Fp.eql(b, Fp.ZERO))
|
|
119
118
|
return Fp.ZERO; // https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm (4. If t = 0, return r = 0)
|
|
120
119
|
// Find m such b^(2^m)==1
|
|
121
120
|
let m = 1;
|
|
122
|
-
for (let t2 = Fp.
|
|
123
|
-
if (Fp.
|
|
121
|
+
for (let t2 = Fp.sqr(b); m < r; m++) {
|
|
122
|
+
if (Fp.eql(t2, Fp.ONE))
|
|
124
123
|
break;
|
|
125
|
-
t2 = Fp.
|
|
124
|
+
t2 = Fp.sqr(t2); // t2 *= t2
|
|
126
125
|
}
|
|
127
126
|
// NOTE: r-m-1 can be bigger than 32, need to convert to bigint before shift, otherwise there will be overflow
|
|
128
127
|
const ge = Fp.pow(g, _1n << BigInt(r - m - 1)); // ge = 2^(r-m-1)
|
|
129
|
-
g = Fp.
|
|
128
|
+
g = Fp.sqr(ge); // g = ge * ge
|
|
130
129
|
x = Fp.mul(x, ge); // x *= ge
|
|
131
130
|
b = Fp.mul(b, g); // b *= g
|
|
132
131
|
r = m;
|
|
@@ -149,7 +148,7 @@ function FpSqrt(P) {
|
|
|
149
148
|
return function sqrt3mod4(Fp, n) {
|
|
150
149
|
const root = Fp.pow(n, p1div4);
|
|
151
150
|
// Throw if root**2 != n
|
|
152
|
-
if (!Fp.
|
|
151
|
+
if (!Fp.eql(Fp.sqr(root), n))
|
|
153
152
|
throw new Error('Cannot find square root');
|
|
154
153
|
return root;
|
|
155
154
|
};
|
|
@@ -163,7 +162,7 @@ function FpSqrt(P) {
|
|
|
163
162
|
const nv = Fp.mul(n, v);
|
|
164
163
|
const i = Fp.mul(Fp.mul(nv, _2n), v);
|
|
165
164
|
const root = Fp.mul(nv, Fp.sub(i, Fp.ONE));
|
|
166
|
-
if (!Fp.
|
|
165
|
+
if (!Fp.eql(Fp.sqr(root), n))
|
|
167
166
|
throw new Error('Cannot find square root');
|
|
168
167
|
return root;
|
|
169
168
|
};
|
|
@@ -199,9 +198,9 @@ const isNegativeLE = (num, modulo) => (mod(num, modulo) & _1n) === _1n;
|
|
|
199
198
|
exports.isNegativeLE = isNegativeLE;
|
|
200
199
|
// prettier-ignore
|
|
201
200
|
const FIELD_FIELDS = [
|
|
202
|
-
'create', 'isValid', '
|
|
203
|
-
'
|
|
204
|
-
'addN', 'subN', 'mulN', '
|
|
201
|
+
'create', 'isValid', 'is0', 'neg', 'inv', 'sqrt', 'sqr',
|
|
202
|
+
'eql', 'add', 'sub', 'mul', 'pow', 'div',
|
|
203
|
+
'addN', 'subN', 'mulN', 'sqrN'
|
|
205
204
|
];
|
|
206
205
|
function validateField(field) {
|
|
207
206
|
for (const i of ['ORDER', 'MASK']) {
|
|
@@ -233,7 +232,7 @@ function FpPow(f, num, power) {
|
|
|
233
232
|
while (power > _0n) {
|
|
234
233
|
if (power & _1n)
|
|
235
234
|
p = f.mul(p, d);
|
|
236
|
-
d = f.
|
|
235
|
+
d = f.sqr(d);
|
|
237
236
|
power >>= 1n;
|
|
238
237
|
}
|
|
239
238
|
return p;
|
|
@@ -243,16 +242,16 @@ function FpInvertBatch(f, nums) {
|
|
|
243
242
|
const tmp = new Array(nums.length);
|
|
244
243
|
// Walk from first to last, multiply them by each other MOD p
|
|
245
244
|
const lastMultiplied = nums.reduce((acc, num, i) => {
|
|
246
|
-
if (f.
|
|
245
|
+
if (f.is0(num))
|
|
247
246
|
return acc;
|
|
248
247
|
tmp[i] = acc;
|
|
249
248
|
return f.mul(acc, num);
|
|
250
249
|
}, f.ONE);
|
|
251
250
|
// Invert last element
|
|
252
|
-
const inverted = f.
|
|
251
|
+
const inverted = f.inv(lastMultiplied);
|
|
253
252
|
// Walk from last to first, multiply them by inverted each other MOD p
|
|
254
253
|
nums.reduceRight((acc, num, i) => {
|
|
255
|
-
if (f.
|
|
254
|
+
if (f.is0(num))
|
|
256
255
|
return acc;
|
|
257
256
|
tmp[i] = f.mul(acc, tmp[i]);
|
|
258
257
|
return f.mul(acc, num);
|
|
@@ -261,7 +260,7 @@ function FpInvertBatch(f, nums) {
|
|
|
261
260
|
}
|
|
262
261
|
exports.FpInvertBatch = FpInvertBatch;
|
|
263
262
|
function FpDiv(f, lhs, rhs) {
|
|
264
|
-
return f.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, f.ORDER) : f.
|
|
263
|
+
return f.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, f.ORDER) : f.inv(rhs));
|
|
265
264
|
}
|
|
266
265
|
exports.FpDiv = FpDiv;
|
|
267
266
|
// This function returns True whenever the value x is a square in the field F.
|
|
@@ -269,14 +268,22 @@ function FpIsSquare(f) {
|
|
|
269
268
|
const legendreConst = (f.ORDER - _1n) / _2n; // Integer arithmetic
|
|
270
269
|
return (x) => {
|
|
271
270
|
const p = f.pow(x, legendreConst);
|
|
272
|
-
return f.
|
|
271
|
+
return f.eql(p, f.ZERO) || f.eql(p, f.ONE);
|
|
273
272
|
};
|
|
274
273
|
}
|
|
275
274
|
exports.FpIsSquare = FpIsSquare;
|
|
275
|
+
// CURVE.n lengths
|
|
276
|
+
function nLength(n, nBitLength) {
|
|
277
|
+
// Bit size, byte size of CURVE.n
|
|
278
|
+
const _nBitLength = nBitLength !== undefined ? nBitLength : n.toString(2).length;
|
|
279
|
+
const nByteLength = Math.ceil(_nBitLength / 8);
|
|
280
|
+
return { nBitLength: _nBitLength, nByteLength };
|
|
281
|
+
}
|
|
282
|
+
exports.nLength = nLength;
|
|
276
283
|
function Fp(ORDER, bitLen, isLE = false, redef = {}) {
|
|
277
284
|
if (ORDER <= _0n)
|
|
278
285
|
throw new Error(`Expected Fp ORDER > 0, got ${ORDER}`);
|
|
279
|
-
const { nBitLength: BITS, nByteLength: BYTES } =
|
|
286
|
+
const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, bitLen);
|
|
280
287
|
if (BYTES > 2048)
|
|
281
288
|
throw new Error('Field lengths over 2048 bytes are not supported');
|
|
282
289
|
const sqrtP = FpSqrt(ORDER);
|
|
@@ -284,41 +291,41 @@ function Fp(ORDER, bitLen, isLE = false, redef = {}) {
|
|
|
284
291
|
ORDER,
|
|
285
292
|
BITS,
|
|
286
293
|
BYTES,
|
|
287
|
-
MASK:
|
|
294
|
+
MASK: (0, utils_js_1.bitMask)(BITS),
|
|
288
295
|
ZERO: _0n,
|
|
289
296
|
ONE: _1n,
|
|
290
297
|
create: (num) => mod(num, ORDER),
|
|
291
298
|
isValid: (num) => {
|
|
292
299
|
if (typeof num !== 'bigint')
|
|
293
300
|
throw new Error(`Invalid field element: expected bigint, got ${typeof num}`);
|
|
294
|
-
return _0n <= num && num < ORDER;
|
|
301
|
+
return _0n <= num && num < ORDER; // 0 is valid element, but it's not invertible
|
|
295
302
|
},
|
|
296
|
-
|
|
303
|
+
is0: (num) => num === _0n,
|
|
297
304
|
isOdd: (num) => (num & _1n) === _1n,
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
305
|
+
neg: (num) => mod(-num, ORDER),
|
|
306
|
+
eql: (lhs, rhs) => lhs === rhs,
|
|
307
|
+
sqr: (num) => mod(num * num, ORDER),
|
|
301
308
|
add: (lhs, rhs) => mod(lhs + rhs, ORDER),
|
|
302
309
|
sub: (lhs, rhs) => mod(lhs - rhs, ORDER),
|
|
303
310
|
mul: (lhs, rhs) => mod(lhs * rhs, ORDER),
|
|
304
311
|
pow: (num, power) => FpPow(f, num, power),
|
|
305
312
|
div: (lhs, rhs) => mod(lhs * invert(rhs, ORDER), ORDER),
|
|
306
313
|
// Same as above, but doesn't normalize
|
|
307
|
-
|
|
314
|
+
sqrN: (num) => num * num,
|
|
308
315
|
addN: (lhs, rhs) => lhs + rhs,
|
|
309
316
|
subN: (lhs, rhs) => lhs - rhs,
|
|
310
317
|
mulN: (lhs, rhs) => lhs * rhs,
|
|
311
|
-
|
|
318
|
+
inv: (num) => invert(num, ORDER),
|
|
312
319
|
sqrt: redef.sqrt || ((n) => sqrtP(f, n)),
|
|
313
320
|
invertBatch: (lst) => FpInvertBatch(f, lst),
|
|
314
321
|
// TODO: do we really need constant cmov?
|
|
315
322
|
// We don't have const-time bigints anyway, so probably will be not very useful
|
|
316
323
|
cmov: (a, b, c) => (c ? b : a),
|
|
317
|
-
toBytes: (num) => isLE ?
|
|
324
|
+
toBytes: (num) => (isLE ? (0, utils_js_1.numberToBytesLE)(num, BYTES) : (0, utils_js_1.numberToBytesBE)(num, BYTES)),
|
|
318
325
|
fromBytes: (bytes) => {
|
|
319
326
|
if (bytes.length !== BYTES)
|
|
320
327
|
throw new Error(`Fp.fromBytes: expected ${BYTES}, got ${bytes.length}`);
|
|
321
|
-
return isLE ?
|
|
328
|
+
return isLE ? (0, utils_js_1.bytesToNumberLE)(bytes) : (0, utils_js_1.bytesToNumberBE)(bytes);
|
|
322
329
|
},
|
|
323
330
|
});
|
|
324
331
|
return Object.freeze(f);
|
|
@@ -328,13 +335,32 @@ function FpSqrtOdd(Fp, elm) {
|
|
|
328
335
|
if (!Fp.isOdd)
|
|
329
336
|
throw new Error(`Field doesn't have isOdd`);
|
|
330
337
|
const root = Fp.sqrt(elm);
|
|
331
|
-
return Fp.isOdd(root) ? root : Fp.
|
|
338
|
+
return Fp.isOdd(root) ? root : Fp.neg(root);
|
|
332
339
|
}
|
|
333
340
|
exports.FpSqrtOdd = FpSqrtOdd;
|
|
334
341
|
function FpSqrtEven(Fp, elm) {
|
|
335
342
|
if (!Fp.isOdd)
|
|
336
343
|
throw new Error(`Field doesn't have isOdd`);
|
|
337
344
|
const root = Fp.sqrt(elm);
|
|
338
|
-
return Fp.isOdd(root) ? Fp.
|
|
345
|
+
return Fp.isOdd(root) ? Fp.neg(root) : root;
|
|
339
346
|
}
|
|
340
347
|
exports.FpSqrtEven = FpSqrtEven;
|
|
348
|
+
/**
|
|
349
|
+
* FIPS 186 B.4.1-compliant "constant-time" private key generation utility.
|
|
350
|
+
* Can take (n+8) or more bytes of uniform input e.g. from CSPRNG or KDF
|
|
351
|
+
* and convert them into private scalar, with the modulo bias being neglible.
|
|
352
|
+
* Needs at least 40 bytes of input for 32-byte private key.
|
|
353
|
+
* https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
|
|
354
|
+
* @param hash hash output from SHA3 or a similar function
|
|
355
|
+
* @returns valid private scalar
|
|
356
|
+
*/
|
|
357
|
+
function hashToPrivateScalar(hash, groupOrder, isLE = false) {
|
|
358
|
+
hash = (0, utils_js_1.ensureBytes)(hash);
|
|
359
|
+
const hashLen = hash.length;
|
|
360
|
+
const minLen = nLength(groupOrder).nByteLength + 8;
|
|
361
|
+
if (minLen < 24 || hashLen < minLen || hashLen > 1024)
|
|
362
|
+
throw new Error(`hashToPrivateScalar: expected ${minLen}-1024 bytes of input, got ${hashLen}`);
|
|
363
|
+
const num = isLE ? (0, utils_js_1.bytesToNumberLE)(hash) : (0, utils_js_1.bytesToNumberBE)(hash);
|
|
364
|
+
return mod(num, groupOrder - _1n) + _1n;
|
|
365
|
+
}
|
|
366
|
+
exports.hashToPrivateScalar = hashToPrivateScalar;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.montgomery = void 0;
|
|
4
4
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
5
|
-
const
|
|
5
|
+
const modular_js_1 = require("./modular.js");
|
|
6
6
|
const utils_js_1 = require("./utils.js");
|
|
7
7
|
const _0n = BigInt(0);
|
|
8
8
|
const _1n = BigInt(1);
|
|
@@ -14,7 +14,7 @@ function validateOpts(curve) {
|
|
|
14
14
|
for (const i of ['montgomeryBits', 'nByteLength']) {
|
|
15
15
|
if (curve[i] === undefined)
|
|
16
16
|
continue; // Optional
|
|
17
|
-
if (!
|
|
17
|
+
if (!Number.isSafeInteger(curve[i]))
|
|
18
18
|
throw new Error(`Invalid curve param ${i}=${curve[i]} (${typeof curve[i]})`);
|
|
19
19
|
}
|
|
20
20
|
for (const fn of ['adjustScalarBytes', 'domain', 'powPminus2']) {
|
|
@@ -30,7 +30,6 @@ function validateOpts(curve) {
|
|
|
30
30
|
throw new Error(`Invalid curve param ${i}=${curve[i]} (${typeof curve[i]})`);
|
|
31
31
|
}
|
|
32
32
|
// Set defaults
|
|
33
|
-
// ...nLength(curve.n, curve.nBitLength),
|
|
34
33
|
return Object.freeze({ ...curve });
|
|
35
34
|
}
|
|
36
35
|
// NOTE: not really montgomery curve, just bunch of very specific methods for X25519/X448 (RFC 7748, https://www.rfc-editor.org/rfc/rfc7748)
|
|
@@ -38,12 +37,12 @@ function validateOpts(curve) {
|
|
|
38
37
|
function montgomery(curveDef) {
|
|
39
38
|
const CURVE = validateOpts(curveDef);
|
|
40
39
|
const { P } = CURVE;
|
|
41
|
-
const modP = (a) =>
|
|
40
|
+
const modP = (a) => (0, modular_js_1.mod)(a, P);
|
|
42
41
|
const montgomeryBits = CURVE.montgomeryBits;
|
|
43
42
|
const montgomeryBytes = Math.ceil(montgomeryBits / 8);
|
|
44
43
|
const fieldLen = CURVE.nByteLength;
|
|
45
44
|
const adjustScalarBytes = CURVE.adjustScalarBytes || ((bytes) => bytes);
|
|
46
|
-
const powPminus2 = CURVE.powPminus2 || ((x) =>
|
|
45
|
+
const powPminus2 = CURVE.powPminus2 || ((x) => (0, modular_js_1.pow)(x, P - BigInt(2), P));
|
|
47
46
|
/**
|
|
48
47
|
* Checks for num to be in range:
|
|
49
48
|
* For strict == true: `0 < num < max`.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
|
+
import { Field } from './modular.js';
|
|
3
|
+
export declare type PoseidonOpts = {
|
|
4
|
+
Fp: Field<bigint>;
|
|
5
|
+
t: number;
|
|
6
|
+
roundsFull: number;
|
|
7
|
+
roundsPartial: number;
|
|
8
|
+
sboxPower?: number;
|
|
9
|
+
reversePartialPowIdx?: boolean;
|
|
10
|
+
mds: bigint[][];
|
|
11
|
+
roundConstants: bigint[][];
|
|
12
|
+
};
|
|
13
|
+
export declare function validateOpts(opts: PoseidonOpts): Readonly<{
|
|
14
|
+
rounds: number;
|
|
15
|
+
sboxFn: (n: bigint) => bigint;
|
|
16
|
+
roundConstants: bigint[][];
|
|
17
|
+
mds: bigint[][];
|
|
18
|
+
Fp: Field<bigint>;
|
|
19
|
+
t: number;
|
|
20
|
+
roundsFull: number;
|
|
21
|
+
roundsPartial: number;
|
|
22
|
+
sboxPower?: number | undefined;
|
|
23
|
+
reversePartialPowIdx?: boolean | undefined;
|
|
24
|
+
}>;
|
|
25
|
+
export declare function splitConstants(rc: bigint[], t: number): bigint[][];
|
|
26
|
+
export declare function poseidon(opts: PoseidonOpts): {
|
|
27
|
+
(values: bigint[]): bigint[];
|
|
28
|
+
roundConstants: bigint[][];
|
|
29
|
+
};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.poseidon = exports.splitConstants = exports.validateOpts = void 0;
|
|
4
|
+
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
5
|
+
// Poseidon Hash: https://eprint.iacr.org/2019/458.pdf, https://www.poseidon-hash.info
|
|
6
|
+
const modular_js_1 = require("./modular.js");
|
|
7
|
+
function validateOpts(opts) {
|
|
8
|
+
const { Fp } = opts;
|
|
9
|
+
(0, modular_js_1.validateField)(Fp);
|
|
10
|
+
for (const i of ['t', 'roundsFull', 'roundsPartial']) {
|
|
11
|
+
if (typeof opts[i] !== 'number' || !Number.isSafeInteger(opts[i]))
|
|
12
|
+
throw new Error(`Poseidon: invalid param ${i}=${opts[i]} (${typeof opts[i]})`);
|
|
13
|
+
}
|
|
14
|
+
if (opts.reversePartialPowIdx !== undefined && typeof opts.reversePartialPowIdx !== 'boolean')
|
|
15
|
+
throw new Error(`Poseidon: invalid param reversePartialPowIdx=${opts.reversePartialPowIdx}`);
|
|
16
|
+
// Default is 5, but by some reasons stark uses 3
|
|
17
|
+
let sboxPower = opts.sboxPower;
|
|
18
|
+
if (sboxPower === undefined)
|
|
19
|
+
sboxPower = 5;
|
|
20
|
+
if (typeof sboxPower !== 'number' || !Number.isSafeInteger(sboxPower))
|
|
21
|
+
throw new Error(`Poseidon wrong sboxPower=${sboxPower}`);
|
|
22
|
+
const _sboxPower = BigInt(sboxPower);
|
|
23
|
+
let sboxFn = (n) => (0, modular_js_1.FpPow)(Fp, n, _sboxPower);
|
|
24
|
+
// Unwrapped sbox power for common cases (195->142μs)
|
|
25
|
+
if (sboxPower === 3)
|
|
26
|
+
sboxFn = (n) => Fp.mul(Fp.sqrN(n), n);
|
|
27
|
+
else if (sboxPower === 5)
|
|
28
|
+
sboxFn = (n) => Fp.mul(Fp.sqrN(Fp.sqrN(n)), n);
|
|
29
|
+
if (opts.roundsFull % 2 !== 0)
|
|
30
|
+
throw new Error(`Poseidon roundsFull is not even: ${opts.roundsFull}`);
|
|
31
|
+
const rounds = opts.roundsFull + opts.roundsPartial;
|
|
32
|
+
if (!Array.isArray(opts.roundConstants) || opts.roundConstants.length !== rounds)
|
|
33
|
+
throw new Error('Poseidon: wrong round constants');
|
|
34
|
+
const roundConstants = opts.roundConstants.map((rc) => {
|
|
35
|
+
if (!Array.isArray(rc) || rc.length !== opts.t)
|
|
36
|
+
throw new Error(`Poseidon wrong round constants: ${rc}`);
|
|
37
|
+
return rc.map((i) => {
|
|
38
|
+
if (typeof i !== 'bigint' || !Fp.isValid(i))
|
|
39
|
+
throw new Error(`Poseidon wrong round constant=${i}`);
|
|
40
|
+
return Fp.create(i);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
// MDS is TxT matrix
|
|
44
|
+
if (!Array.isArray(opts.mds) || opts.mds.length !== opts.t)
|
|
45
|
+
throw new Error('Poseidon: wrong MDS matrix');
|
|
46
|
+
const mds = opts.mds.map((mdsRow) => {
|
|
47
|
+
if (!Array.isArray(mdsRow) || mdsRow.length !== opts.t)
|
|
48
|
+
throw new Error(`Poseidon MDS matrix row: ${mdsRow}`);
|
|
49
|
+
return mdsRow.map((i) => {
|
|
50
|
+
if (typeof i !== 'bigint')
|
|
51
|
+
throw new Error(`Poseidon MDS matrix value=${i}`);
|
|
52
|
+
return Fp.create(i);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
return Object.freeze({ ...opts, rounds, sboxFn, roundConstants, mds });
|
|
56
|
+
}
|
|
57
|
+
exports.validateOpts = validateOpts;
|
|
58
|
+
function splitConstants(rc, t) {
|
|
59
|
+
if (typeof t !== 'number')
|
|
60
|
+
throw new Error('poseidonSplitConstants: wrong t');
|
|
61
|
+
if (!Array.isArray(rc) || rc.length % t)
|
|
62
|
+
throw new Error('poseidonSplitConstants: wrong rc');
|
|
63
|
+
const res = [];
|
|
64
|
+
let tmp = [];
|
|
65
|
+
for (let i = 0; i < rc.length; i++) {
|
|
66
|
+
tmp.push(rc[i]);
|
|
67
|
+
if (tmp.length === t) {
|
|
68
|
+
res.push(tmp);
|
|
69
|
+
tmp = [];
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return res;
|
|
73
|
+
}
|
|
74
|
+
exports.splitConstants = splitConstants;
|
|
75
|
+
function poseidon(opts) {
|
|
76
|
+
const { t, Fp, rounds, sboxFn, reversePartialPowIdx } = validateOpts(opts);
|
|
77
|
+
const halfRoundsFull = Math.floor(opts.roundsFull / 2);
|
|
78
|
+
const partialIdx = reversePartialPowIdx ? t - 1 : 0;
|
|
79
|
+
const poseidonRound = (values, isFull, idx) => {
|
|
80
|
+
values = values.map((i, j) => Fp.add(i, opts.roundConstants[idx][j]));
|
|
81
|
+
if (isFull)
|
|
82
|
+
values = values.map((i) => sboxFn(i));
|
|
83
|
+
else
|
|
84
|
+
values[partialIdx] = sboxFn(values[partialIdx]);
|
|
85
|
+
// Matrix multiplication
|
|
86
|
+
values = opts.mds.map((i) => i.reduce((acc, i, j) => Fp.add(acc, Fp.mulN(i, values[j])), Fp.ZERO));
|
|
87
|
+
return values;
|
|
88
|
+
};
|
|
89
|
+
const poseidonHash = function poseidonHash(values) {
|
|
90
|
+
if (!Array.isArray(values) || values.length !== t)
|
|
91
|
+
throw new Error(`Poseidon: wrong values (expected array of bigints with length ${t})`);
|
|
92
|
+
values = values.map((i) => {
|
|
93
|
+
if (typeof i !== 'bigint')
|
|
94
|
+
throw new Error(`Poseidon: wrong value=${i} (${typeof i})`);
|
|
95
|
+
return Fp.create(i);
|
|
96
|
+
});
|
|
97
|
+
let round = 0;
|
|
98
|
+
// Apply r_f/2 full rounds.
|
|
99
|
+
for (let i = 0; i < halfRoundsFull; i++)
|
|
100
|
+
values = poseidonRound(values, true, round++);
|
|
101
|
+
// Apply r_p partial rounds.
|
|
102
|
+
for (let i = 0; i < opts.roundsPartial; i++)
|
|
103
|
+
values = poseidonRound(values, false, round++);
|
|
104
|
+
// Apply r_f/2 full rounds.
|
|
105
|
+
for (let i = 0; i < halfRoundsFull; i++)
|
|
106
|
+
values = poseidonRound(values, true, round++);
|
|
107
|
+
if (round !== rounds)
|
|
108
|
+
throw new Error(`Poseidon: wrong number of rounds: last round=${round}, total=${rounds}`);
|
|
109
|
+
return values;
|
|
110
|
+
};
|
|
111
|
+
// For verification in tests
|
|
112
|
+
poseidonHash.roundConstants = opts.roundConstants;
|
|
113
|
+
return poseidonHash;
|
|
114
|
+
}
|
|
115
|
+
exports.poseidon = poseidon;
|
package/lib/abstract/utils.d.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
|
-
import * as mod from './modular.js';
|
|
3
1
|
export declare type Hex = Uint8Array | string;
|
|
4
|
-
export declare type PrivKey = Hex | bigint
|
|
2
|
+
export declare type PrivKey = Hex | bigint;
|
|
5
3
|
export declare type CHash = {
|
|
6
4
|
(message: Uint8Array | string): Uint8Array;
|
|
7
5
|
blockLen: number;
|
|
@@ -10,47 +8,18 @@ export declare type CHash = {
|
|
|
10
8
|
dkLen?: number;
|
|
11
9
|
}): any;
|
|
12
10
|
};
|
|
13
|
-
export declare type
|
|
14
|
-
|
|
15
|
-
n: bigint;
|
|
16
|
-
nBitLength?: number;
|
|
17
|
-
nByteLength?: number;
|
|
18
|
-
h: bigint;
|
|
19
|
-
hEff?: bigint;
|
|
20
|
-
Gx: T;
|
|
21
|
-
Gy: T;
|
|
22
|
-
wrapPrivateKey?: boolean;
|
|
23
|
-
allowInfinityPoint?: boolean;
|
|
24
|
-
};
|
|
25
|
-
export declare function isPositiveInt(num: any): num is number;
|
|
26
|
-
export declare function validateOpts<FP, T>(curve: BasicCurve<FP> & T): Readonly<{
|
|
27
|
-
readonly nBitLength: number;
|
|
28
|
-
readonly nByteLength: number;
|
|
29
|
-
} & BasicCurve<FP> & T>;
|
|
30
|
-
export declare function bytesToHex(uint8a: Uint8Array): string;
|
|
11
|
+
export declare type FHash = (message: Uint8Array | string) => Uint8Array;
|
|
12
|
+
export declare function bytesToHex(bytes: Uint8Array): string;
|
|
31
13
|
export declare function numberToHexUnpadded(num: number | bigint): string;
|
|
32
14
|
export declare function hexToNumber(hex: string): bigint;
|
|
33
15
|
export declare function hexToBytes(hex: string): Uint8Array;
|
|
34
16
|
export declare function bytesToNumberBE(bytes: Uint8Array): bigint;
|
|
35
|
-
export declare function bytesToNumberLE(
|
|
17
|
+
export declare function bytesToNumberLE(bytes: Uint8Array): bigint;
|
|
36
18
|
export declare const numberToBytesBE: (n: bigint, len: number) => Uint8Array;
|
|
37
19
|
export declare const numberToBytesLE: (n: bigint, len: number) => Uint8Array;
|
|
20
|
+
export declare const numberToVarBytesBE: (n: bigint) => Uint8Array;
|
|
38
21
|
export declare function ensureBytes(hex: Hex, expectedLength?: number): Uint8Array;
|
|
39
22
|
export declare function concatBytes(...arrays: Uint8Array[]): Uint8Array;
|
|
40
|
-
export declare function nLength(n: bigint, nBitLength?: number): {
|
|
41
|
-
nBitLength: number;
|
|
42
|
-
nByteLength: number;
|
|
43
|
-
};
|
|
44
|
-
/**
|
|
45
|
-
* FIPS 186 B.4.1-compliant "constant-time" private key generation utility.
|
|
46
|
-
* Can take (n+8) or more bytes of uniform input e.g. from CSPRNG or KDF
|
|
47
|
-
* and convert them into private scalar, with the modulo bias being neglible.
|
|
48
|
-
* Needs at least 40 bytes of input for 32-byte private key.
|
|
49
|
-
* https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
|
|
50
|
-
* @param hash hash output from SHA3 or a similar function
|
|
51
|
-
* @returns valid private scalar
|
|
52
|
-
*/
|
|
53
|
-
export declare function hashToPrivateScalar(hash: Hex, groupOrder: bigint, isLE?: boolean): bigint;
|
|
54
23
|
export declare function equalBytes(b1: Uint8Array, b2: Uint8Array): boolean;
|
|
55
24
|
export declare function bitLen(n: bigint): number;
|
|
56
25
|
export declare const bitGet: (n: bigint, pos: number) => bigint;
|