@noble/curves 1.0.0 → 1.2.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 +399 -247
- package/_shortw_utils.d.ts +1 -1
- package/abstract/bls.d.ts.map +1 -1
- package/abstract/bls.js +2 -2
- package/abstract/bls.js.map +1 -1
- package/abstract/edwards.d.ts +7 -2
- package/abstract/edwards.d.ts.map +1 -1
- package/abstract/edwards.js +7 -2
- package/abstract/edwards.js.map +1 -1
- package/abstract/hash-to-curve.d.ts +1 -1
- package/abstract/hash-to-curve.d.ts.map +1 -1
- package/abstract/hash-to-curve.js +14 -8
- package/abstract/hash-to-curve.js.map +1 -1
- package/abstract/modular.d.ts +55 -13
- package/abstract/modular.d.ts.map +1 -1
- package/abstract/modular.js +82 -22
- package/abstract/modular.js.map +1 -1
- package/abstract/poseidon.d.ts.map +1 -1
- package/abstract/poseidon.js +39 -41
- package/abstract/poseidon.js.map +1 -1
- package/abstract/utils.d.ts +43 -5
- package/abstract/utils.d.ts.map +1 -1
- package/abstract/utils.js +70 -26
- package/abstract/utils.js.map +1 -1
- package/abstract/weierstrass.d.ts +18 -2
- package/abstract/weierstrass.d.ts.map +1 -1
- package/abstract/weierstrass.js +40 -22
- package/abstract/weierstrass.js.map +1 -1
- package/bls12-381.d.ts.map +1 -1
- package/bls12-381.js +11 -11
- package/bls12-381.js.map +1 -1
- package/ed25519.d.ts +33 -20
- package/ed25519.d.ts.map +1 -1
- package/ed25519.js +60 -38
- package/ed25519.js.map +1 -1
- package/ed448.d.ts +53 -4
- package/ed448.d.ts.map +1 -1
- package/ed448.js +217 -38
- package/ed448.js.map +1 -1
- package/esm/abstract/bls.js +3 -3
- package/esm/abstract/bls.js.map +1 -1
- package/esm/abstract/edwards.js +7 -2
- package/esm/abstract/edwards.js.map +1 -1
- package/esm/abstract/hash-to-curve.js +14 -8
- package/esm/abstract/hash-to-curve.js.map +1 -1
- package/esm/abstract/modular.js +78 -21
- package/esm/abstract/modular.js.map +1 -1
- package/esm/abstract/poseidon.js +39 -41
- package/esm/abstract/poseidon.js.map +1 -1
- package/esm/abstract/utils.js +70 -26
- package/esm/abstract/utils.js.map +1 -1
- package/esm/abstract/weierstrass.js +40 -22
- package/esm/abstract/weierstrass.js.map +1 -1
- package/esm/bls12-381.js +11 -11
- package/esm/bls12-381.js.map +1 -1
- package/esm/ed25519.js +60 -38
- package/esm/ed25519.js.map +1 -1
- package/esm/ed448.js +217 -38
- package/esm/ed448.js.map +1 -1
- package/esm/jubjub.js +1 -1
- package/esm/jubjub.js.map +1 -1
- package/esm/p256.js +10 -9
- package/esm/p256.js.map +1 -1
- package/esm/p384.js +7 -6
- package/esm/p384.js.map +1 -1
- package/esm/p521.js +7 -6
- package/esm/p521.js.map +1 -1
- package/esm/package.json +1 -4
- package/esm/secp256k1.js +11 -9
- package/esm/secp256k1.js.map +1 -1
- package/jubjub.js.map +1 -1
- package/p256.d.ts +4 -5
- package/p256.d.ts.map +1 -1
- package/p256.js +10 -10
- package/p256.js.map +1 -1
- package/p384.d.ts +4 -5
- package/p384.d.ts.map +1 -1
- package/p384.js +7 -7
- package/p384.js.map +1 -1
- package/p521.d.ts +4 -5
- package/p521.d.ts.map +1 -1
- package/p521.js +7 -7
- package/p521.js.map +1 -1
- package/package.json +7 -9
- package/secp256k1.d.ts +5 -5
- package/secp256k1.d.ts.map +1 -1
- package/secp256k1.js +11 -10
- package/secp256k1.js.map +1 -1
- package/src/abstract/bls.ts +3 -3
- package/src/abstract/edwards.ts +13 -4
- package/src/abstract/hash-to-curve.ts +14 -8
- package/src/abstract/modular.ts +84 -27
- package/src/abstract/poseidon.ts +39 -40
- package/src/abstract/utils.ts +77 -33
- package/src/abstract/weierstrass.ts +51 -29
- package/src/bls12-381.ts +12 -17
- package/src/ed25519.ts +105 -75
- package/src/ed448.ts +286 -64
- package/src/jubjub.ts +1 -1
- package/src/p256.ts +13 -14
- package/src/p384.ts +12 -13
- package/src/p521.ts +12 -13
- package/src/secp256k1.ts +60 -55
package/src/abstract/utils.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
|
+
// 100 lines of code in the file are duplicated from noble-hashes (utils).
|
|
3
|
+
// This is OK: `abstract` directory does not use noble-hashes.
|
|
4
|
+
// User may opt-in into using different hashing library. This way, noble-hashes
|
|
5
|
+
// won't be included into their bundle.
|
|
2
6
|
const _0n = BigInt(0);
|
|
3
7
|
const _1n = BigInt(1);
|
|
4
8
|
const _2n = BigInt(2);
|
|
5
9
|
const u8a = (a: any): a is Uint8Array => a instanceof Uint8Array;
|
|
6
|
-
|
|
7
|
-
//
|
|
8
|
-
export type Hex = Uint8Array | string;
|
|
9
|
-
// Very few implementations accept numbers, we do it to ease learning curve
|
|
10
|
-
export type PrivKey = Hex | bigint;
|
|
10
|
+
export type Hex = Uint8Array | string; // hex strings are accepted for simplicity
|
|
11
|
+
export type PrivKey = Hex | bigint; // bigints are accepted to ease learning curve
|
|
11
12
|
export type CHash = {
|
|
12
13
|
(message: Uint8Array | string): Uint8Array;
|
|
13
14
|
blockLen: number;
|
|
@@ -16,7 +17,12 @@ export type CHash = {
|
|
|
16
17
|
};
|
|
17
18
|
export type FHash = (message: Uint8Array | string) => Uint8Array;
|
|
18
19
|
|
|
19
|
-
const hexes = Array.from({ length: 256 }, (
|
|
20
|
+
const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) =>
|
|
21
|
+
i.toString(16).padStart(2, '0')
|
|
22
|
+
);
|
|
23
|
+
/**
|
|
24
|
+
* @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'
|
|
25
|
+
*/
|
|
20
26
|
export function bytesToHex(bytes: Uint8Array): string {
|
|
21
27
|
if (!u8a(bytes)) throw new Error('Uint8Array expected');
|
|
22
28
|
// pre-caching improves the speed 6x
|
|
@@ -38,22 +44,25 @@ export function hexToNumber(hex: string): bigint {
|
|
|
38
44
|
return BigInt(hex === '' ? '0' : `0x${hex}`);
|
|
39
45
|
}
|
|
40
46
|
|
|
41
|
-
|
|
47
|
+
/**
|
|
48
|
+
* @example hexToBytes('cafe0123') // Uint8Array.from([0xca, 0xfe, 0x01, 0x23])
|
|
49
|
+
*/
|
|
42
50
|
export function hexToBytes(hex: string): Uint8Array {
|
|
43
51
|
if (typeof hex !== 'string') throw new Error('hex string expected, got ' + typeof hex);
|
|
44
|
-
|
|
45
|
-
|
|
52
|
+
const len = hex.length;
|
|
53
|
+
if (len % 2) throw new Error('padded hex string expected, got unpadded hex of length ' + len);
|
|
54
|
+
const array = new Uint8Array(len / 2);
|
|
46
55
|
for (let i = 0; i < array.length; i++) {
|
|
47
56
|
const j = i * 2;
|
|
48
57
|
const hexByte = hex.slice(j, j + 2);
|
|
49
58
|
const byte = Number.parseInt(hexByte, 16);
|
|
50
|
-
if (Number.isNaN(byte) || byte < 0) throw new Error('
|
|
59
|
+
if (Number.isNaN(byte) || byte < 0) throw new Error('Invalid byte sequence');
|
|
51
60
|
array[i] = byte;
|
|
52
61
|
}
|
|
53
62
|
return array;
|
|
54
63
|
}
|
|
55
64
|
|
|
56
|
-
// Big Endian
|
|
65
|
+
// BE: Big Endian, LE: Little Endian
|
|
57
66
|
export function bytesToNumberBE(bytes: Uint8Array): bigint {
|
|
58
67
|
return hexToNumber(bytesToHex(bytes));
|
|
59
68
|
}
|
|
@@ -62,12 +71,26 @@ export function bytesToNumberLE(bytes: Uint8Array): bigint {
|
|
|
62
71
|
return hexToNumber(bytesToHex(Uint8Array.from(bytes).reverse()));
|
|
63
72
|
}
|
|
64
73
|
|
|
65
|
-
export
|
|
66
|
-
hexToBytes(n.toString(16).padStart(len * 2, '0'));
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
74
|
+
export function numberToBytesBE(n: number | bigint, len: number): Uint8Array {
|
|
75
|
+
return hexToBytes(n.toString(16).padStart(len * 2, '0'));
|
|
76
|
+
}
|
|
77
|
+
export function numberToBytesLE(n: number | bigint, len: number): Uint8Array {
|
|
78
|
+
return numberToBytesBE(n, len).reverse();
|
|
79
|
+
}
|
|
80
|
+
// Unpadded, rarely used
|
|
81
|
+
export function numberToVarBytesBE(n: number | bigint): Uint8Array {
|
|
82
|
+
return hexToBytes(numberToHexUnpadded(n));
|
|
83
|
+
}
|
|
70
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Takes hex string or Uint8Array, converts to Uint8Array.
|
|
87
|
+
* Validates output length.
|
|
88
|
+
* Will throw error for other types.
|
|
89
|
+
* @param title descriptive title for an error e.g. 'private key'
|
|
90
|
+
* @param hex hex string or Uint8Array
|
|
91
|
+
* @param expectedLength optional, will compare to result array's length
|
|
92
|
+
* @returns
|
|
93
|
+
*/
|
|
71
94
|
export function ensureBytes(title: string, hex: Hex, expectedLength?: number): Uint8Array {
|
|
72
95
|
let res: Uint8Array;
|
|
73
96
|
if (typeof hex === 'string') {
|
|
@@ -89,11 +112,13 @@ export function ensureBytes(title: string, hex: Hex, expectedLength?: number): U
|
|
|
89
112
|
return res;
|
|
90
113
|
}
|
|
91
114
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
115
|
+
/**
|
|
116
|
+
* Copies several Uint8Arrays into one.
|
|
117
|
+
*/
|
|
118
|
+
export function concatBytes(...arrays: Uint8Array[]): Uint8Array {
|
|
119
|
+
const r = new Uint8Array(arrays.reduce((sum, a) => sum + a.length, 0));
|
|
95
120
|
let pad = 0; // walk through each item, ensure they have proper type
|
|
96
|
-
|
|
121
|
+
arrays.forEach((a) => {
|
|
97
122
|
if (!u8a(a)) throw new Error('Uint8Array expected');
|
|
98
123
|
r.set(a, pad);
|
|
99
124
|
pad += a.length;
|
|
@@ -111,29 +136,47 @@ export function equalBytes(b1: Uint8Array, b2: Uint8Array) {
|
|
|
111
136
|
// Global symbols in both browsers and Node.js since v11
|
|
112
137
|
// See https://github.com/microsoft/TypeScript/issues/31535
|
|
113
138
|
declare const TextEncoder: any;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])
|
|
142
|
+
*/
|
|
114
143
|
export function utf8ToBytes(str: string): Uint8Array {
|
|
115
|
-
if (typeof str !== 'string') {
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
return new TextEncoder().encode(str);
|
|
144
|
+
if (typeof str !== 'string') throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
|
|
145
|
+
return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809
|
|
119
146
|
}
|
|
120
147
|
|
|
121
148
|
// Bit operations
|
|
122
149
|
|
|
123
|
-
|
|
150
|
+
/**
|
|
151
|
+
* Calculates amount of bits in a bigint.
|
|
152
|
+
* Same as `n.toString(2).length`
|
|
153
|
+
*/
|
|
124
154
|
export function bitLen(n: bigint) {
|
|
125
155
|
let len;
|
|
126
156
|
for (len = 0; n > _0n; n >>= _1n, len += 1);
|
|
127
157
|
return len;
|
|
128
158
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Gets single bit at position.
|
|
162
|
+
* NOTE: first bit position is 0 (same as arrays)
|
|
163
|
+
* Same as `!!+Array.from(n.toString(2)).reverse()[pos]`
|
|
164
|
+
*/
|
|
165
|
+
export function bitGet(n: bigint, pos: number) {
|
|
166
|
+
return (n >> BigInt(pos)) & _1n;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Sets single bit at position.
|
|
171
|
+
*/
|
|
172
|
+
export const bitSet = (n: bigint, pos: number, value: boolean) => {
|
|
173
|
+
return n | ((value ? _1n : _0n) << BigInt(pos));
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Calculate mask for N bits. Not using ** operator with bigints because of old engines.
|
|
178
|
+
* Same as BigInt(`0b${Array(i).fill('1').join('')}`)
|
|
179
|
+
*/
|
|
137
180
|
export const bitMask = (n: number) => (_2n << BigInt(n - 1)) - _1n;
|
|
138
181
|
|
|
139
182
|
// DRBG
|
|
@@ -205,6 +248,7 @@ const validatorFns = {
|
|
|
205
248
|
function: (val: any) => typeof val === 'function',
|
|
206
249
|
boolean: (val: any) => typeof val === 'boolean',
|
|
207
250
|
string: (val: any) => typeof val === 'string',
|
|
251
|
+
stringOrUint8Array: (val: any) => typeof val === 'string' || val instanceof Uint8Array,
|
|
208
252
|
isSafeInteger: (val: any) => Number.isSafeInteger(val),
|
|
209
253
|
array: (val: any) => Array.isArray(val),
|
|
210
254
|
field: (val: any, object: any) => (object as any).Fp.isValid(val),
|
|
@@ -193,7 +193,7 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
|
|
|
193
193
|
|
|
194
194
|
const toBytes =
|
|
195
195
|
CURVE.toBytes ||
|
|
196
|
-
((
|
|
196
|
+
((_c: ProjConstructor<T>, point: ProjPointType<T>, _isCompressed: boolean) => {
|
|
197
197
|
const a = point.toAffine();
|
|
198
198
|
return ut.concatBytes(Uint8Array.from([0x04]), Fp.toBytes(a.x), Fp.toBytes(a.y));
|
|
199
199
|
});
|
|
@@ -333,9 +333,11 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
|
|
|
333
333
|
|
|
334
334
|
// A point on curve is valid if it conforms to equation.
|
|
335
335
|
assertValidity(): void {
|
|
336
|
-
// Zero is valid point too!
|
|
337
336
|
if (this.is0()) {
|
|
338
|
-
|
|
337
|
+
// (0, 1, 0) aka ZERO is invalid in most contexts.
|
|
338
|
+
// In BLS, ZERO can be serialized, so we allow it.
|
|
339
|
+
// (0, 0, 0) is wrong representation of ZERO and is always invalid.
|
|
340
|
+
if (CURVE.allowInfinityPoint && !Fp.is0(this.py)) return;
|
|
339
341
|
throw new Error('bad point: ZERO');
|
|
340
342
|
}
|
|
341
343
|
// Some 3rd-party test vectors require different wording between here & `fromCompressedHex`
|
|
@@ -618,7 +620,7 @@ export interface SignatureType {
|
|
|
618
620
|
readonly s: bigint;
|
|
619
621
|
readonly recovery?: number;
|
|
620
622
|
assertValidity(): void;
|
|
621
|
-
addRecoveryBit(recovery: number):
|
|
623
|
+
addRecoveryBit(recovery: number): RecoveredSignatureType;
|
|
622
624
|
hasHighS(): boolean;
|
|
623
625
|
normalizeS(): SignatureType;
|
|
624
626
|
recoverPublicKey(msgHash: Hex): ProjPointType<bigint>;
|
|
@@ -628,6 +630,9 @@ export interface SignatureType {
|
|
|
628
630
|
toDERRawBytes(isCompressed?: boolean): Uint8Array;
|
|
629
631
|
toDERHex(isCompressed?: boolean): string;
|
|
630
632
|
}
|
|
633
|
+
export type RecoveredSignatureType = SignatureType & {
|
|
634
|
+
readonly recovery: number;
|
|
635
|
+
};
|
|
631
636
|
// Static methods
|
|
632
637
|
export type SignatureConstructor = {
|
|
633
638
|
new (r: bigint, s: bigint): SignatureType;
|
|
@@ -669,7 +674,7 @@ export type CurveFn = {
|
|
|
669
674
|
CURVE: ReturnType<typeof validateOpts>;
|
|
670
675
|
getPublicKey: (privateKey: PrivKey, isCompressed?: boolean) => Uint8Array;
|
|
671
676
|
getSharedSecret: (privateA: PrivKey, publicB: Hex, isCompressed?: boolean) => Uint8Array;
|
|
672
|
-
sign: (msgHash: Hex, privKey: PrivKey, opts?: SignOpts) =>
|
|
677
|
+
sign: (msgHash: Hex, privKey: PrivKey, opts?: SignOpts) => RecoveredSignatureType;
|
|
673
678
|
verify: (signature: Hex | SignatureLike, msgHash: Hex, publicKey: Hex, opts?: VerOpts) => boolean;
|
|
674
679
|
ProjectivePoint: ProjConstructor<bigint>;
|
|
675
680
|
Signature: SignatureConstructor;
|
|
@@ -704,7 +709,7 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|
|
704
709
|
isWithinCurveOrder,
|
|
705
710
|
} = weierstrassPoints({
|
|
706
711
|
...CURVE,
|
|
707
|
-
toBytes(
|
|
712
|
+
toBytes(_c, point, isCompressed: boolean): Uint8Array {
|
|
708
713
|
const a = point.toAffine();
|
|
709
714
|
const x = Fp.toBytes(a.x);
|
|
710
715
|
const cat = ut.concatBytes;
|
|
@@ -782,8 +787,8 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|
|
782
787
|
if (!isWithinCurveOrder(this.s)) throw new Error('s must be 0 < s < CURVE.n');
|
|
783
788
|
}
|
|
784
789
|
|
|
785
|
-
addRecoveryBit(recovery: number) {
|
|
786
|
-
return new Signature(this.r, this.s, recovery);
|
|
790
|
+
addRecoveryBit(recovery: number): RecoveredSignature {
|
|
791
|
+
return new Signature(this.r, this.s, recovery) as RecoveredSignature;
|
|
787
792
|
}
|
|
788
793
|
|
|
789
794
|
recoverPublicKey(msgHash: Hex): typeof Point.BASE {
|
|
@@ -828,6 +833,7 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|
|
828
833
|
return numToNByteStr(this.r) + numToNByteStr(this.s);
|
|
829
834
|
}
|
|
830
835
|
}
|
|
836
|
+
type RecoveredSignature = Signature & { recovery: number };
|
|
831
837
|
|
|
832
838
|
const utils = {
|
|
833
839
|
isValidPrivateKey(privateKey: PrivKey) {
|
|
@@ -841,13 +847,12 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|
|
841
847
|
normPrivateKeyToScalar: normPrivateKeyToScalar,
|
|
842
848
|
|
|
843
849
|
/**
|
|
844
|
-
* Produces cryptographically secure private key from random of size
|
|
845
|
-
*
|
|
850
|
+
* Produces cryptographically secure private key from random of size
|
|
851
|
+
* (groupLen + ceil(groupLen / 2)) with modulo bias being negligible.
|
|
846
852
|
*/
|
|
847
853
|
randomPrivateKey: (): Uint8Array => {
|
|
848
|
-
const
|
|
849
|
-
|
|
850
|
-
return ut.numberToBytesBE(num, CURVE.nByteLength);
|
|
854
|
+
const length = mod.getMinHashLength(CURVE.n);
|
|
855
|
+
return mod.mapHashToField(CURVE.randomBytes(length), CURVE.n);
|
|
851
856
|
},
|
|
852
857
|
|
|
853
858
|
/**
|
|
@@ -960,12 +965,12 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|
|
960
965
|
if (ent != null) {
|
|
961
966
|
// K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) || k')
|
|
962
967
|
const e = ent === true ? randomBytes(Fp.BYTES) : ent; // generate random bytes OR pass as-is
|
|
963
|
-
seedArgs.push(ensureBytes('extraEntropy', e
|
|
968
|
+
seedArgs.push(ensureBytes('extraEntropy', e)); // check for being bytes
|
|
964
969
|
}
|
|
965
970
|
const seed = ut.concatBytes(...seedArgs); // Step D of RFC6979 3.2
|
|
966
971
|
const m = h1int; // NOTE: no need to call bits2int second time here, it is inside truncateHash!
|
|
967
972
|
// Converts signature params into point w r/s, checks result for validity.
|
|
968
|
-
function k2sig(kBytes: Uint8Array):
|
|
973
|
+
function k2sig(kBytes: Uint8Array): RecoveredSignature | undefined {
|
|
969
974
|
// RFC 6979 Section 3.2, step 3: k = bits2int(T)
|
|
970
975
|
const k = bits2int(kBytes); // Cannot use fields methods, since it is group element
|
|
971
976
|
if (!isWithinCurveOrder(k)) return; // Important: all mod() calls here must be done over N
|
|
@@ -984,7 +989,7 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|
|
984
989
|
normS = normalizeS(s); // if lowS was passed, ensure s is always
|
|
985
990
|
recovery ^= 1; // // in the bottom half of N
|
|
986
991
|
}
|
|
987
|
-
return new Signature(r, normS, recovery); // use normS, not s
|
|
992
|
+
return new Signature(r, normS, recovery) as RecoveredSignature; // use normS, not s
|
|
988
993
|
}
|
|
989
994
|
return { seed, k2sig };
|
|
990
995
|
}
|
|
@@ -992,18 +997,22 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|
|
992
997
|
const defaultVerOpts: VerOpts = { lowS: CURVE.lowS, prehash: false };
|
|
993
998
|
|
|
994
999
|
/**
|
|
995
|
-
* Signs message hash
|
|
1000
|
+
* Signs message hash with a private key.
|
|
996
1001
|
* ```
|
|
997
1002
|
* sign(m, d, k) where
|
|
998
1003
|
* (x, y) = G × k
|
|
999
1004
|
* r = x mod n
|
|
1000
1005
|
* s = (m + dr)/k mod n
|
|
1001
1006
|
* ```
|
|
1002
|
-
* @param
|
|
1007
|
+
* @param msgHash NOT message. msg needs to be hashed to `msgHash`, or use `prehash`.
|
|
1008
|
+
* @param privKey private key
|
|
1009
|
+
* @param opts lowS for non-malleable sigs. extraEntropy for mixing randomness into k. prehash will hash first arg.
|
|
1010
|
+
* @returns signature with recovery param
|
|
1003
1011
|
*/
|
|
1004
|
-
function sign(msgHash: Hex, privKey: PrivKey, opts = defaultSigOpts):
|
|
1012
|
+
function sign(msgHash: Hex, privKey: PrivKey, opts = defaultSigOpts): RecoveredSignature {
|
|
1005
1013
|
const { seed, k2sig } = prepSig(msgHash, privKey, opts); // Steps A, D of RFC6979 3.2.
|
|
1006
|
-
const
|
|
1014
|
+
const C = CURVE;
|
|
1015
|
+
const drbg = ut.createHmacDrbg<RecoveredSignature>(C.hash.outputLen, C.nByteLength, C.hmac);
|
|
1007
1016
|
return drbg(seed, k2sig); // Steps B, C, D, E, F, G
|
|
1008
1017
|
}
|
|
1009
1018
|
|
|
@@ -1084,20 +1093,29 @@ export function weierstrass(curveDef: CurveType): CurveFn {
|
|
|
1084
1093
|
};
|
|
1085
1094
|
}
|
|
1086
1095
|
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1096
|
+
/**
|
|
1097
|
+
* Implementation of the Shallue and van de Woestijne method for any weierstrass curve.
|
|
1098
|
+
* TODO: check if there is a way to merge this with uvRatio in Edwards; move to modular.
|
|
1099
|
+
* b = True and y = sqrt(u / v) if (u / v) is square in F, and
|
|
1100
|
+
* b = False and y = sqrt(Z * (u / v)) otherwise.
|
|
1101
|
+
* @param Fp
|
|
1102
|
+
* @param Z
|
|
1103
|
+
* @returns
|
|
1104
|
+
*/
|
|
1091
1105
|
export function SWUFpSqrtRatio<T>(Fp: mod.IField<T>, Z: T) {
|
|
1092
1106
|
// Generic implementation
|
|
1093
1107
|
const q = Fp.ORDER;
|
|
1094
1108
|
let l = _0n;
|
|
1095
1109
|
for (let o = q - _1n; o % _2n === _0n; o /= _2n) l += _1n;
|
|
1096
1110
|
const c1 = l; // 1. c1, the largest integer such that 2^c1 divides q - 1.
|
|
1097
|
-
|
|
1111
|
+
// We need 2n ** c1 and 2n ** (c1-1). We can't use **; but we can use <<.
|
|
1112
|
+
// 2n ** c1 == 2n << (c1-1)
|
|
1113
|
+
const _2n_pow_c1_1 = _2n << (c1 - _1n - _1n);
|
|
1114
|
+
const _2n_pow_c1 = _2n_pow_c1_1 * _2n;
|
|
1115
|
+
const c2 = (q - _1n) / _2n_pow_c1; // 2. c2 = (q - 1) / (2^c1) # Integer arithmetic
|
|
1098
1116
|
const c3 = (c2 - _1n) / _2n; // 3. c3 = (c2 - 1) / 2 # Integer arithmetic
|
|
1099
|
-
const c4 =
|
|
1100
|
-
const c5 =
|
|
1117
|
+
const c4 = _2n_pow_c1 - _1n; // 4. c4 = 2^c1 - 1 # Integer arithmetic
|
|
1118
|
+
const c5 = _2n_pow_c1_1; // 5. c5 = 2^(c1 - 1) # Integer arithmetic
|
|
1101
1119
|
const c6 = Fp.pow(Z, c2); // 6. c6 = Z^c2
|
|
1102
1120
|
const c7 = Fp.pow(Z, (c2 + _1n) / _2n); // 7. c7 = Z^((c2 + 1) / 2)
|
|
1103
1121
|
let sqrtRatio = (u: T, v: T): { isValid: boolean; value: T } => {
|
|
@@ -1119,7 +1137,8 @@ export function SWUFpSqrtRatio<T>(Fp: mod.IField<T>, Z: T) {
|
|
|
1119
1137
|
tv4 = Fp.cmov(tv5, tv4, isQR); // 16. tv4 = CMOV(tv5, tv4, isQR)
|
|
1120
1138
|
// 17. for i in (c1, c1 - 1, ..., 2):
|
|
1121
1139
|
for (let i = c1; i > _1n; i--) {
|
|
1122
|
-
let tv5 =
|
|
1140
|
+
let tv5 = i - _2n; // 18. tv5 = i - 2
|
|
1141
|
+
tv5 = _2n << (tv5 - _1n); // 19. tv5 = 2^tv5
|
|
1123
1142
|
let tvv5 = Fp.pow(tv4, tv5); // 20. tv5 = tv4^tv5
|
|
1124
1143
|
const e1 = Fp.eql(tvv5, Fp.ONE); // 21. e1 = tv5 == 1
|
|
1125
1144
|
tv2 = Fp.mul(tv3, tv1); // 22. tv2 = tv3 * tv1
|
|
@@ -1151,7 +1170,10 @@ export function SWUFpSqrtRatio<T>(Fp: mod.IField<T>, Z: T) {
|
|
|
1151
1170
|
// if (Fp.ORDER % _8n === _5n) // sqrt_ratio_5mod8
|
|
1152
1171
|
return sqrtRatio;
|
|
1153
1172
|
}
|
|
1154
|
-
|
|
1173
|
+
/**
|
|
1174
|
+
* Simplified Shallue-van de Woestijne-Ulas Method
|
|
1175
|
+
* https://www.rfc-editor.org/rfc/rfc9380#section-6.6.2
|
|
1176
|
+
*/
|
|
1155
1177
|
export function mapToCurveSimpleSWU<T>(
|
|
1156
1178
|
Fp: mod.IField<T>,
|
|
1157
1179
|
opts: {
|
package/src/bls12-381.ts
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
// The library uses G1 for public keys and G2 for signatures. Support for G1 signatures is planned.
|
|
9
9
|
// Compatible with Algorand, Chia, Dfinity, Ethereum, FIL, Zcash. Matches specs
|
|
10
10
|
// [pairing-curves-11](https://tools.ietf.org/html/draft-irtf-cfrg-pairing-friendly-curves-11),
|
|
11
|
-
// [bls-sigs-04](https
|
|
12
|
-
// [hash-to-curve-12](https://tools.ietf.org/html/draft-irtf
|
|
11
|
+
// [bls-sigs-04](https:/cfrg-hash-to/tools.ietf.org/html/draft-irtf-cfrg-bls-signature-04),
|
|
12
|
+
// [hash-to-curve-12](https://tools.ietf.org/html/draft-irtf--curve-12).
|
|
13
13
|
//
|
|
14
14
|
// ### Summary
|
|
15
15
|
// 1. BLS Relies on Bilinear Pairing (expensive)
|
|
@@ -60,11 +60,10 @@ const _8n = BigInt(8), _16n = BigInt(16);
|
|
|
60
60
|
|
|
61
61
|
// CURVE FIELDS
|
|
62
62
|
// Finite field over p.
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
'0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab'
|
|
66
|
-
)
|
|
63
|
+
const Fp_raw = BigInt(
|
|
64
|
+
'0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab'
|
|
67
65
|
);
|
|
66
|
+
const Fp = mod.Field(Fp_raw);
|
|
68
67
|
type Fp = bigint;
|
|
69
68
|
// Finite field over r.
|
|
70
69
|
// This particular field is not used anywhere in bls12-381, but it is still useful.
|
|
@@ -110,10 +109,7 @@ type Fp2Utils = {
|
|
|
110
109
|
// G² - 1
|
|
111
110
|
// h2q
|
|
112
111
|
// NOTE: ORDER was wrong!
|
|
113
|
-
const FP2_ORDER =
|
|
114
|
-
BigInt(
|
|
115
|
-
'0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab'
|
|
116
|
-
) ** _2n;
|
|
112
|
+
const FP2_ORDER = Fp_raw * Fp_raw;
|
|
117
113
|
|
|
118
114
|
const Fp2: mod.IField<Fp2> & Fp2Utils = {
|
|
119
115
|
ORDER: FP2_ORDER,
|
|
@@ -181,7 +177,7 @@ const Fp2: mod.IField<Fp2> & Fp2Utils = {
|
|
|
181
177
|
if (im1 > im2 || (im1 === im2 && re1 > re2)) return x1;
|
|
182
178
|
return x2;
|
|
183
179
|
},
|
|
184
|
-
// Same as
|
|
180
|
+
// Same as sgn0_m_eq_2 in RFC 9380
|
|
185
181
|
isOdd: (x: Fp2) => {
|
|
186
182
|
const { re: x0, im: x1 } = Fp2.reim(x);
|
|
187
183
|
const sign_0 = x0 % _2n;
|
|
@@ -784,8 +780,7 @@ const FP12_FROBENIUS_COEFFICIENTS = [
|
|
|
784
780
|
|
|
785
781
|
// HashToCurve
|
|
786
782
|
|
|
787
|
-
// 3-isogeny map from E' to E
|
|
788
|
-
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-E.3
|
|
783
|
+
// 3-isogeny map from E' to E https://www.rfc-editor.org/rfc/rfc9380#appendix-E.3
|
|
789
784
|
const isogenyMapG2 = isogenyMap(
|
|
790
785
|
Fp2,
|
|
791
786
|
[
|
|
@@ -989,7 +984,7 @@ function G2psi2(c: ProjConstructor<Fp2>, P: ProjPointType<Fp2>) {
|
|
|
989
984
|
//
|
|
990
985
|
// Parameter definitions are in section 5.3 of the spec unless otherwise noted.
|
|
991
986
|
// Parameter values come from section 8.8.2 of the spec.
|
|
992
|
-
// https://
|
|
987
|
+
// https://www.rfc-editor.org/rfc/rfc9380#section-8.8.2
|
|
993
988
|
//
|
|
994
989
|
// Base field F is GF(p^m)
|
|
995
990
|
// p = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab
|
|
@@ -1044,7 +1039,7 @@ function signatureG2ToRawBytes(point: ProjPointType<Fp2>) {
|
|
|
1044
1039
|
}
|
|
1045
1040
|
|
|
1046
1041
|
// To verify curve parameters, see pairing-friendly-curves spec:
|
|
1047
|
-
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-
|
|
1042
|
+
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-11
|
|
1048
1043
|
// Basic math is done over finite fields over p.
|
|
1049
1044
|
// More complicated math is done over polynominal extension fields.
|
|
1050
1045
|
// To simplify calculations in Fp12, we construct extension tower:
|
|
@@ -1112,7 +1107,7 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
|
1112
1107
|
},
|
|
1113
1108
|
// Clear cofactor of G1
|
|
1114
1109
|
// https://eprint.iacr.org/2019/403
|
|
1115
|
-
clearCofactor: (
|
|
1110
|
+
clearCofactor: (_c, point) => {
|
|
1116
1111
|
// return this.multiplyUnsafe(CURVE.h);
|
|
1117
1112
|
return point.multiplyUnsafe(bls12_381.params.x).add(point); // x*P + P
|
|
1118
1113
|
},
|
|
@@ -1197,7 +1192,7 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
|
1197
1192
|
),
|
|
1198
1193
|
]),
|
|
1199
1194
|
a: Fp2.ZERO,
|
|
1200
|
-
b: Fp2.fromBigTuple([
|
|
1195
|
+
b: Fp2.fromBigTuple([_4n, _4n]),
|
|
1201
1196
|
hEff: BigInt(
|
|
1202
1197
|
'0xbc69f08f2ee75b3584c6a0ea91b352888e2a8e9145ad7689986ff031508ffe1329c2f178731db956d82bf015d1212b02ec0ec69d7477c1ae954cbc06689f6a359894c0adebbf6b4e8020005aaa95551'
|
|
1203
1198
|
),
|