@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.
Files changed (103) hide show
  1. package/README.md +399 -247
  2. package/_shortw_utils.d.ts +1 -1
  3. package/abstract/bls.d.ts.map +1 -1
  4. package/abstract/bls.js +2 -2
  5. package/abstract/bls.js.map +1 -1
  6. package/abstract/edwards.d.ts +7 -2
  7. package/abstract/edwards.d.ts.map +1 -1
  8. package/abstract/edwards.js +7 -2
  9. package/abstract/edwards.js.map +1 -1
  10. package/abstract/hash-to-curve.d.ts +1 -1
  11. package/abstract/hash-to-curve.d.ts.map +1 -1
  12. package/abstract/hash-to-curve.js +14 -8
  13. package/abstract/hash-to-curve.js.map +1 -1
  14. package/abstract/modular.d.ts +55 -13
  15. package/abstract/modular.d.ts.map +1 -1
  16. package/abstract/modular.js +82 -22
  17. package/abstract/modular.js.map +1 -1
  18. package/abstract/poseidon.d.ts.map +1 -1
  19. package/abstract/poseidon.js +39 -41
  20. package/abstract/poseidon.js.map +1 -1
  21. package/abstract/utils.d.ts +43 -5
  22. package/abstract/utils.d.ts.map +1 -1
  23. package/abstract/utils.js +70 -26
  24. package/abstract/utils.js.map +1 -1
  25. package/abstract/weierstrass.d.ts +18 -2
  26. package/abstract/weierstrass.d.ts.map +1 -1
  27. package/abstract/weierstrass.js +40 -22
  28. package/abstract/weierstrass.js.map +1 -1
  29. package/bls12-381.d.ts.map +1 -1
  30. package/bls12-381.js +11 -11
  31. package/bls12-381.js.map +1 -1
  32. package/ed25519.d.ts +33 -20
  33. package/ed25519.d.ts.map +1 -1
  34. package/ed25519.js +60 -38
  35. package/ed25519.js.map +1 -1
  36. package/ed448.d.ts +53 -4
  37. package/ed448.d.ts.map +1 -1
  38. package/ed448.js +217 -38
  39. package/ed448.js.map +1 -1
  40. package/esm/abstract/bls.js +3 -3
  41. package/esm/abstract/bls.js.map +1 -1
  42. package/esm/abstract/edwards.js +7 -2
  43. package/esm/abstract/edwards.js.map +1 -1
  44. package/esm/abstract/hash-to-curve.js +14 -8
  45. package/esm/abstract/hash-to-curve.js.map +1 -1
  46. package/esm/abstract/modular.js +78 -21
  47. package/esm/abstract/modular.js.map +1 -1
  48. package/esm/abstract/poseidon.js +39 -41
  49. package/esm/abstract/poseidon.js.map +1 -1
  50. package/esm/abstract/utils.js +70 -26
  51. package/esm/abstract/utils.js.map +1 -1
  52. package/esm/abstract/weierstrass.js +40 -22
  53. package/esm/abstract/weierstrass.js.map +1 -1
  54. package/esm/bls12-381.js +11 -11
  55. package/esm/bls12-381.js.map +1 -1
  56. package/esm/ed25519.js +60 -38
  57. package/esm/ed25519.js.map +1 -1
  58. package/esm/ed448.js +217 -38
  59. package/esm/ed448.js.map +1 -1
  60. package/esm/jubjub.js +1 -1
  61. package/esm/jubjub.js.map +1 -1
  62. package/esm/p256.js +10 -9
  63. package/esm/p256.js.map +1 -1
  64. package/esm/p384.js +7 -6
  65. package/esm/p384.js.map +1 -1
  66. package/esm/p521.js +7 -6
  67. package/esm/p521.js.map +1 -1
  68. package/esm/package.json +1 -4
  69. package/esm/secp256k1.js +11 -9
  70. package/esm/secp256k1.js.map +1 -1
  71. package/jubjub.js.map +1 -1
  72. package/p256.d.ts +4 -5
  73. package/p256.d.ts.map +1 -1
  74. package/p256.js +10 -10
  75. package/p256.js.map +1 -1
  76. package/p384.d.ts +4 -5
  77. package/p384.d.ts.map +1 -1
  78. package/p384.js +7 -7
  79. package/p384.js.map +1 -1
  80. package/p521.d.ts +4 -5
  81. package/p521.d.ts.map +1 -1
  82. package/p521.js +7 -7
  83. package/p521.js.map +1 -1
  84. package/package.json +7 -9
  85. package/secp256k1.d.ts +5 -5
  86. package/secp256k1.d.ts.map +1 -1
  87. package/secp256k1.js +11 -10
  88. package/secp256k1.js.map +1 -1
  89. package/src/abstract/bls.ts +3 -3
  90. package/src/abstract/edwards.ts +13 -4
  91. package/src/abstract/hash-to-curve.ts +14 -8
  92. package/src/abstract/modular.ts +84 -27
  93. package/src/abstract/poseidon.ts +39 -40
  94. package/src/abstract/utils.ts +77 -33
  95. package/src/abstract/weierstrass.ts +51 -29
  96. package/src/bls12-381.ts +12 -17
  97. package/src/ed25519.ts +105 -75
  98. package/src/ed448.ts +286 -64
  99. package/src/jubjub.ts +1 -1
  100. package/src/p256.ts +13 -14
  101. package/src/p384.ts +12 -13
  102. package/src/p521.ts +12 -13
  103. package/src/secp256k1.ts +60 -55
@@ -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
- // We accept hex strings besides Uint8Array for simplicity
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 }, (v, i) => i.toString(16).padStart(2, '0'));
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
- // Caching slows it down 2-3x
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
- if (hex.length % 2) throw new Error('hex string is invalid: unpadded ' + hex.length);
45
- const array = new Uint8Array(hex.length / 2);
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('invalid byte sequence');
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 const numberToBytesBE = (n: bigint, len: number) =>
66
- hexToBytes(n.toString(16).padStart(len * 2, '0'));
67
- export const numberToBytesLE = (n: bigint, len: number) => numberToBytesBE(n, len).reverse();
68
- // Returns variable number bytes (minimal bigint encoding?)
69
- export const numberToVarBytesBE = (n: bigint) => hexToBytes(numberToHexUnpadded(n));
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
- // Copies several Uint8Arrays into one.
93
- export function concatBytes(...arrs: Uint8Array[]): Uint8Array {
94
- const r = new Uint8Array(arrs.reduce((sum, a) => sum + a.length, 0));
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
- arrs.forEach((a) => {
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
- throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
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
- // Amount of bits inside bigint (Same as n.toString(2).length)
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
- // Gets single bit at position. NOTE: first bit position is 0 (same as arrays)
130
- // Same as !!+Array.from(n.toString(2)).reverse()[pos]
131
- export const bitGet = (n: bigint, pos: number) => (n >> BigInt(pos)) & _1n;
132
- // Sets single bit at position
133
- export const bitSet = (n: bigint, pos: number, value: boolean) =>
134
- n | ((value ? _1n : _0n) << BigInt(pos));
135
- // Return mask for N bits (Same as BigInt(`0b${Array(i).fill('1').join('')}`))
136
- // Not using ** operator with bigints for old engines.
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
- ((c: ProjConstructor<T>, point: ProjPointType<T>, isCompressed: boolean) => {
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
- if (CURVE.allowInfinityPoint) return;
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): SignatureType;
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) => SignatureType;
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(c, point, isCompressed: boolean): Uint8Array {
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 (nBitLength+64)
845
- * as per FIPS 186 B.4.1 with modulo bias being neglible.
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 rand = CURVE.randomBytes(Fp.BYTES + 8);
849
- const num = mod.hashToPrivateScalar(rand, CURVE_ORDER);
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, Fp.BYTES)); // check for being of size BYTES
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): Signature | undefined {
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 (not message: you need to hash it by yourself).
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 opts `lowS, extraEntropy, prehash`
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): Signature {
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 drbg = ut.createHmacDrbg<Signature>(CURVE.hash.outputLen, CURVE.nByteLength, CURVE.hmac);
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
- // Implementation of the Shallue and van de Woestijne method for any Weierstrass curve
1088
- // TODO: check if there is a way to merge this with uvRatio in Edwards && move to modular?
1089
- // b = True and y = sqrt(u / v) if (u / v) is square in F, and
1090
- // b = False and y = sqrt(Z * (u / v)) otherwise.
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
- const c2 = (q - _1n) / _2n ** c1; // 2. c2 = (q - 1) / (2^c1) # Integer arithmetic
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 = _2n ** c1 - _1n; // 4. c4 = 2^c1 - 1 # Integer arithmetic
1100
- const c5 = _2n ** (c1 - _1n); // 5. c5 = 2^(c1 - 1) # Integer arithmetic
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 = _2n ** (i - _2n); // 18. tv5 = i - 2; 19. tv5 = 2^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
- // From draft-irtf-cfrg-hash-to-curve-16
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://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-04),
12
- // [hash-to-curve-12](https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-12).
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 Fp = mod.Field(
64
- BigInt(
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 sgn0_fp2 in draft-irtf-cfrg-hash-to-curve-16
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://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-8.8.2
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-09
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: (c, point) => {
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([4n, _4n]),
1195
+ b: Fp2.fromBigTuple([_4n, _4n]),
1201
1196
  hEff: BigInt(
1202
1197
  '0xbc69f08f2ee75b3584c6a0ea91b352888e2a8e9145ad7689986ff031508ffe1329c2f178731db956d82bf015d1212b02ec0ec69d7477c1ae954cbc06689f6a359894c0adebbf6b4e8020005aaa95551'
1203
1198
  ),