@noble/curves 0.9.1 → 1.0.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 +197 -99
- package/abstract/bls.d.ts +43 -31
- package/abstract/bls.d.ts.map +1 -1
- package/abstract/bls.js +37 -28
- package/abstract/bls.js.map +1 -1
- package/abstract/edwards.d.ts +2 -2
- package/abstract/edwards.d.ts.map +1 -1
- package/abstract/edwards.js +30 -18
- 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 +3 -2
- package/abstract/hash-to-curve.js.map +1 -1
- package/abstract/utils.d.ts.map +1 -1
- package/abstract/utils.js +2 -2
- package/abstract/utils.js.map +1 -1
- package/abstract/weierstrass.d.ts +21 -0
- package/abstract/weierstrass.d.ts.map +1 -1
- package/abstract/weierstrass.js +27 -14
- package/abstract/weierstrass.js.map +1 -1
- package/bls12-381.d.ts.map +1 -1
- package/bls12-381.js +57 -61
- package/bls12-381.js.map +1 -1
- package/{bn.d.ts → bn254.d.ts} +1 -1
- package/bn254.d.ts.map +1 -0
- package/{bn.js → bn254.js} +1 -1
- package/bn254.js.map +1 -0
- package/ed25519.d.ts +9 -0
- package/ed25519.d.ts.map +1 -1
- package/ed25519.js +22 -8
- package/ed25519.js.map +1 -1
- package/ed448.d.ts +9 -0
- package/ed448.d.ts.map +1 -1
- package/ed448.js +16 -16
- package/ed448.js.map +1 -1
- package/esm/abstract/bls.js +37 -28
- package/esm/abstract/bls.js.map +1 -1
- package/esm/abstract/edwards.js +30 -18
- package/esm/abstract/edwards.js.map +1 -1
- package/esm/abstract/hash-to-curve.js +3 -2
- package/esm/abstract/hash-to-curve.js.map +1 -1
- package/esm/abstract/utils.js +2 -2
- package/esm/abstract/utils.js.map +1 -1
- package/esm/abstract/weierstrass.js +19 -6
- package/esm/abstract/weierstrass.js.map +1 -1
- package/esm/bls12-381.js +58 -62
- package/esm/bls12-381.js.map +1 -1
- package/esm/{bn.js → bn254.js} +1 -1
- package/esm/bn254.js.map +1 -0
- package/esm/ed25519.js +20 -7
- package/esm/ed25519.js.map +1 -1
- package/esm/ed448.js +14 -15
- package/esm/ed448.js.map +1 -1
- package/esm/p256.js +5 -6
- package/esm/p256.js.map +1 -1
- package/esm/p384.js +10 -12
- package/esm/p384.js.map +1 -1
- package/esm/p521.js +22 -18
- package/esm/p521.js.map +1 -1
- package/p256.d.ts +1 -1
- package/p256.d.ts.map +1 -1
- package/p256.js +6 -7
- package/p256.js.map +1 -1
- package/p384.d.ts +1 -1
- package/p384.d.ts.map +1 -1
- package/p384.js +11 -13
- package/p384.js.map +1 -1
- package/p521.d.ts +1 -1
- package/p521.d.ts.map +1 -1
- package/p521.js +23 -19
- package/p521.js.map +1 -1
- package/package.json +5 -8
- package/src/abstract/bls.ts +83 -61
- package/src/abstract/edwards.ts +38 -16
- package/src/abstract/hash-to-curve.ts +4 -3
- package/src/abstract/utils.ts +2 -2
- package/src/abstract/weierstrass.ts +18 -7
- package/src/bls12-381.ts +63 -67
- package/src/ed25519.ts +22 -8
- package/src/ed448.ts +15 -15
- package/src/p256.ts +15 -19
- package/src/p384.ts +17 -21
- package/src/p521.ts +34 -22
- package/bn.d.ts.map +0 -1
- package/bn.js.map +0 -1
- package/esm/bn.js.map +0 -1
- /package/src/{bn.ts → bn254.ts} +0 -0
package/src/abstract/edwards.ts
CHANGED
|
@@ -18,10 +18,13 @@ export type CurveType = BasicCurve<bigint> & {
|
|
|
18
18
|
adjustScalarBytes?: (bytes: Uint8Array) => Uint8Array; // clears bits to get valid field elemtn
|
|
19
19
|
domain?: (data: Uint8Array, ctx: Uint8Array, phflag: boolean) => Uint8Array; // Used for hashing
|
|
20
20
|
uvRatio?: (u: bigint, v: bigint) => { isValid: boolean; value: bigint }; // Ratio √(u/v)
|
|
21
|
-
|
|
21
|
+
prehash?: FHash; // RFC 8032 pre-hashing of messages to sign() / verify()
|
|
22
22
|
mapToCurve?: (scalar: bigint[]) => AffinePoint<bigint>; // for hash-to-curve standard
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
+
// verification rule is either zip215 or rfc8032 / nist186-5. Consult fromHex:
|
|
26
|
+
const VERIFY_DEFAULT = { zip215: true };
|
|
27
|
+
|
|
25
28
|
function validateOpts(curve: CurveType) {
|
|
26
29
|
const opts = validateBasic(curve);
|
|
27
30
|
ut.validateObject(
|
|
@@ -90,7 +93,15 @@ export type CurveFn = {
|
|
|
90
93
|
// It is not generic twisted curve for now, but ed25519/ed448 generic implementation
|
|
91
94
|
export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
92
95
|
const CURVE = validateOpts(curveDef) as ReturnType<typeof validateOpts>;
|
|
93
|
-
const {
|
|
96
|
+
const {
|
|
97
|
+
Fp,
|
|
98
|
+
n: CURVE_ORDER,
|
|
99
|
+
prehash: prehash,
|
|
100
|
+
hash: cHash,
|
|
101
|
+
randomBytes,
|
|
102
|
+
nByteLength,
|
|
103
|
+
h: cofactor,
|
|
104
|
+
} = CURVE;
|
|
94
105
|
const MASK = _2n ** BigInt(nByteLength * 8);
|
|
95
106
|
const modP = Fp.create; // Function overrides
|
|
96
107
|
|
|
@@ -344,7 +355,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
344
355
|
|
|
345
356
|
// Converts hash string or Uint8Array to Point.
|
|
346
357
|
// Uses algo from RFC8032 5.1.3.
|
|
347
|
-
static fromHex(hex: Hex,
|
|
358
|
+
static fromHex(hex: Hex, zip215 = false): Point {
|
|
348
359
|
const { d, a } = CURVE;
|
|
349
360
|
const len = Fp.BYTES;
|
|
350
361
|
hex = ensureBytes('pointHex', hex, len); // copy hex to a new array
|
|
@@ -356,8 +367,8 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
356
367
|
// y=0 is allowed
|
|
357
368
|
} else {
|
|
358
369
|
// RFC8032 prohibits >= p, but ZIP215 doesn't
|
|
359
|
-
if (
|
|
360
|
-
else assertInRange(y,
|
|
370
|
+
if (zip215) assertInRange(y, MASK); // zip215=true [1..P-1] (2^255-19-1 for ed25519)
|
|
371
|
+
else assertInRange(y, Fp.ORDER); // zip215=false [1..MASK-1] (2^256-1 for ed25519)
|
|
361
372
|
}
|
|
362
373
|
|
|
363
374
|
// Ed25519: x² = (y²-1)/(dy²+1) mod p. Ed448: x² = (y²-1)/(dy²-1) mod p. Generic case:
|
|
@@ -419,32 +430,43 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
419
430
|
// int('LE', SHA512(dom2(F, C) || msgs)) mod N
|
|
420
431
|
function hashDomainToScalar(context: Hex = new Uint8Array(), ...msgs: Uint8Array[]) {
|
|
421
432
|
const msg = ut.concatBytes(...msgs);
|
|
422
|
-
return modN_LE(cHash(domain(msg, ensureBytes('context', context), !!
|
|
433
|
+
return modN_LE(cHash(domain(msg, ensureBytes('context', context), !!prehash)));
|
|
423
434
|
}
|
|
424
435
|
|
|
425
436
|
/** Signs message with privateKey. RFC8032 5.1.6 */
|
|
426
|
-
function sign(msg: Hex, privKey: Hex, context?: Hex): Uint8Array {
|
|
437
|
+
function sign(msg: Hex, privKey: Hex, options: { context?: Hex } = {}): Uint8Array {
|
|
427
438
|
msg = ensureBytes('message', msg);
|
|
428
|
-
if (
|
|
439
|
+
if (prehash) msg = prehash(msg); // for ed25519ph etc.
|
|
429
440
|
const { prefix, scalar, pointBytes } = getExtendedPublicKey(privKey);
|
|
430
|
-
const r = hashDomainToScalar(context, prefix, msg); // r = dom2(F, C) || prefix || PH(M)
|
|
441
|
+
const r = hashDomainToScalar(options.context, prefix, msg); // r = dom2(F, C) || prefix || PH(M)
|
|
431
442
|
const R = G.multiply(r).toRawBytes(); // R = rG
|
|
432
|
-
const k = hashDomainToScalar(context, R, pointBytes, msg); // R || A || PH(M)
|
|
443
|
+
const k = hashDomainToScalar(options.context, R, pointBytes, msg); // R || A || PH(M)
|
|
433
444
|
const s = modN(r + k * scalar); // S = (r + k * s) mod L
|
|
434
445
|
assertGE0(s); // 0 <= s < l
|
|
435
446
|
const res = ut.concatBytes(R, ut.numberToBytesLE(s, Fp.BYTES));
|
|
436
447
|
return ensureBytes('result', res, nByteLength * 2); // 64-byte signature
|
|
437
448
|
}
|
|
438
449
|
|
|
439
|
-
|
|
450
|
+
const verifyOpts: { context?: Hex; zip215?: boolean } = VERIFY_DEFAULT;
|
|
451
|
+
function verify(sig: Hex, msg: Hex, publicKey: Hex, options = verifyOpts): boolean {
|
|
452
|
+
const { context, zip215 } = options;
|
|
440
453
|
const len = Fp.BYTES; // Verifies EdDSA signature against message and public key. RFC8032 5.1.7.
|
|
441
454
|
sig = ensureBytes('signature', sig, 2 * len); // An extended group equation is checked.
|
|
442
|
-
msg = ensureBytes('message', msg);
|
|
443
|
-
if (
|
|
444
|
-
|
|
445
|
-
const R = Point.fromHex(sig.slice(0, len), false); // 0 <= R < 2^256: ZIP215 R can be >= P
|
|
455
|
+
msg = ensureBytes('message', msg);
|
|
456
|
+
if (prehash) msg = prehash(msg); // for ed25519ph, etc
|
|
457
|
+
|
|
446
458
|
const s = ut.bytesToNumberLE(sig.slice(len, 2 * len));
|
|
447
|
-
|
|
459
|
+
// zip215: true is good for consensus-critical apps and allows points < 2^256
|
|
460
|
+
// zip215: false follows RFC8032 / NIST186-5 and restricts points to CURVE.p
|
|
461
|
+
let A, R, SB;
|
|
462
|
+
try {
|
|
463
|
+
A = Point.fromHex(publicKey, zip215);
|
|
464
|
+
R = Point.fromHex(sig.slice(0, len), zip215);
|
|
465
|
+
SB = G.multiplyUnsafe(s); // 0 <= s < l is done inside
|
|
466
|
+
} catch (error) {
|
|
467
|
+
return false;
|
|
468
|
+
}
|
|
469
|
+
|
|
448
470
|
const k = hashDomainToScalar(context, R.toRawBytes(), A.toRawBytes(), msg);
|
|
449
471
|
const RkA = R.add(A.multiplyUnsafe(k));
|
|
450
472
|
// [8][S]B = [8]R + [8][k]A'
|
|
@@ -17,7 +17,7 @@ export type Opts = {
|
|
|
17
17
|
p: bigint;
|
|
18
18
|
m: number;
|
|
19
19
|
k: number;
|
|
20
|
-
expand
|
|
20
|
+
expand: 'xmd' | 'xof';
|
|
21
21
|
hash: CHash;
|
|
22
22
|
};
|
|
23
23
|
|
|
@@ -145,10 +145,11 @@ export function hash_to_field(msg: Uint8Array, count: number, options: Opts): bi
|
|
|
145
145
|
prb = expand_message_xmd(msg, DST, len_in_bytes, hash);
|
|
146
146
|
} else if (expand === 'xof') {
|
|
147
147
|
prb = expand_message_xof(msg, DST, len_in_bytes, k, hash);
|
|
148
|
-
} else if (expand ===
|
|
148
|
+
} else if (expand === '_internal_pass') {
|
|
149
|
+
// for internal tests only
|
|
149
150
|
prb = msg;
|
|
150
151
|
} else {
|
|
151
|
-
throw new Error('expand must be "xmd"
|
|
152
|
+
throw new Error('expand must be "xmd" or "xof"');
|
|
152
153
|
}
|
|
153
154
|
const u = new Array(count);
|
|
154
155
|
for (let i = 0; i < count; i++) {
|
package/src/abstract/utils.ts
CHANGED
|
@@ -123,12 +123,12 @@ export function utf8ToBytes(str: string): Uint8Array {
|
|
|
123
123
|
// Amount of bits inside bigint (Same as n.toString(2).length)
|
|
124
124
|
export function bitLen(n: bigint) {
|
|
125
125
|
let len;
|
|
126
|
-
for (len = 0; n >
|
|
126
|
+
for (len = 0; n > _0n; n >>= _1n, len += 1);
|
|
127
127
|
return len;
|
|
128
128
|
}
|
|
129
129
|
// Gets single bit at position. NOTE: first bit position is 0 (same as arrays)
|
|
130
130
|
// Same as !!+Array.from(n.toString(2)).reverse()[pos]
|
|
131
|
-
export const bitGet = (n: bigint, pos: number) => (n >> BigInt(pos)) &
|
|
131
|
+
export const bitGet = (n: bigint, pos: number) => (n >> BigInt(pos)) & _1n;
|
|
132
132
|
// Sets single bit at position
|
|
133
133
|
export const bitSet = (n: bigint, pos: number, value: boolean) =>
|
|
134
134
|
n | ((value ? _1n : _0n) << BigInt(pos));
|
|
@@ -131,7 +131,7 @@ export type CurvePointsRes<T> = {
|
|
|
131
131
|
|
|
132
132
|
// ASN.1 DER encoding utilities
|
|
133
133
|
const { bytesToNumberBE: b2n, hexToBytes: h2b } = ut;
|
|
134
|
-
const DER = {
|
|
134
|
+
export const DER = {
|
|
135
135
|
// asn.1 DER encoding utils
|
|
136
136
|
Err: class DERErr extends Error {
|
|
137
137
|
constructor(m = '') {
|
|
@@ -144,9 +144,13 @@ const DER = {
|
|
|
144
144
|
const len = data[1];
|
|
145
145
|
const res = data.subarray(2, len + 2);
|
|
146
146
|
if (!len || res.length !== len) throw new E('Invalid signature integer: wrong length');
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
//
|
|
147
|
+
// https://crypto.stackexchange.com/a/57734 Leftmost bit of first byte is 'negative' flag,
|
|
148
|
+
// since we always use positive integers here. It must always be empty:
|
|
149
|
+
// - add zero byte if exists
|
|
150
|
+
// - if next byte doesn't have a flag, leading zero is not allowed (minimal encoding)
|
|
151
|
+
if (res[0] & 0b10000000) throw new E('Invalid signature integer: negative');
|
|
152
|
+
if (res[0] === 0x00 && !(res[1] & 0b10000000))
|
|
153
|
+
throw new E('Invalid signature integer: unnecessary leading zero');
|
|
150
154
|
return { d: b2n(res), l: data.subarray(len + 2) }; // d is data, l is left
|
|
151
155
|
},
|
|
152
156
|
toSig(hex: string | Uint8Array): { r: bigint; s: bigint } {
|
|
@@ -163,7 +167,8 @@ const DER = {
|
|
|
163
167
|
return { r, s };
|
|
164
168
|
},
|
|
165
169
|
hexFromSig(sig: { r: bigint; s: bigint }): string {
|
|
166
|
-
|
|
170
|
+
// Add leading zero if first byte has negative bit enabled. More details in '_parseInt'
|
|
171
|
+
const slice = (s: string): string => (Number.parseInt(s[0], 16) & 0b1000 ? '00' + s : s);
|
|
167
172
|
const h = (num: number | bigint) => {
|
|
168
173
|
const hex = num.toString(16);
|
|
169
174
|
return hex.length & 1 ? `0${hex}` : hex;
|
|
@@ -213,6 +218,12 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
|
|
|
213
218
|
const x3 = Fp.mul(x2, x); // x2 * x
|
|
214
219
|
return Fp.add(Fp.add(x3, Fp.mul(x, a)), b); // x3 + a * x + b
|
|
215
220
|
}
|
|
221
|
+
// Validate whether the passed curve params are valid.
|
|
222
|
+
// We check if curve equation works for generator point.
|
|
223
|
+
// `assertValidity()` won't work: `isTorsionFree()` is not available at this point in bls12-381.
|
|
224
|
+
// ProjectivePoint class has not been initialized yet.
|
|
225
|
+
if (!Fp.eql(Fp.sqr(CURVE.Gy), weierstrassEquation(CURVE.Gx)))
|
|
226
|
+
throw new Error('bad generator point: equation left != right');
|
|
216
227
|
|
|
217
228
|
// Valid group elements reside in range 1..n-1
|
|
218
229
|
function isWithinCurveOrder(num: bigint): boolean {
|
|
@@ -591,7 +602,7 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
|
|
|
591
602
|
}
|
|
592
603
|
const _bits = CURVE.nBitLength;
|
|
593
604
|
const wnaf = wNAF(Point, CURVE.endo ? Math.ceil(_bits / 2) : _bits);
|
|
594
|
-
|
|
605
|
+
// Validate if generator point is on curve
|
|
595
606
|
return {
|
|
596
607
|
CURVE,
|
|
597
608
|
ProjectivePoint: Point as ProjConstructor<T>,
|
|
@@ -1107,7 +1118,7 @@ export function SWUFpSqrtRatio<T>(Fp: mod.IField<T>, Z: T) {
|
|
|
1107
1118
|
tv3 = Fp.cmov(tv2, tv3, isQR); // 15. tv3 = CMOV(tv2, tv3, isQR)
|
|
1108
1119
|
tv4 = Fp.cmov(tv5, tv4, isQR); // 16. tv4 = CMOV(tv5, tv4, isQR)
|
|
1109
1120
|
// 17. for i in (c1, c1 - 1, ..., 2):
|
|
1110
|
-
for (let i = c1; i >
|
|
1121
|
+
for (let i = c1; i > _1n; i--) {
|
|
1111
1122
|
let tv5 = _2n ** (i - _2n); // 18. tv5 = i - 2; 19. tv5 = 2^tv5
|
|
1112
1123
|
let tvv5 = Fp.pow(tv4, tv5); // 20. tv5 = tv4^tv5
|
|
1113
1124
|
const e1 = Fp.eql(tvv5, Fp.ONE); // 21. e1 = tv5 == 1
|
package/src/bls12-381.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
//
|
|
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
|
-
// [pairing-curves-
|
|
10
|
+
// [pairing-curves-11](https://tools.ietf.org/html/draft-irtf-cfrg-pairing-friendly-curves-11),
|
|
11
11
|
// [bls-sigs-04](https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-04),
|
|
12
12
|
// [hash-to-curve-12](https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-12).
|
|
13
13
|
//
|
|
@@ -27,24 +27,6 @@
|
|
|
27
27
|
// - `e(G, S) = e(G, SUM(n)(Si)) = MUL(n)(e(G, Si))` - signature aggregation
|
|
28
28
|
// Filecoin uses little endian byte arrays for private keys -
|
|
29
29
|
// so ensure to reverse byte order if you'll use it with FIL.
|
|
30
|
-
//
|
|
31
|
-
// ### Resources
|
|
32
|
-
// - [BLS12-381 for the rest of us](https://hackmd.io/@benjaminion/bls12-381)
|
|
33
|
-
// - [Key concepts of pairings](https://medium.com/@alonmuroch_65570/bls-signatures-part-2-key-concepts-of-pairings-27a8a9533d0c)
|
|
34
|
-
// - Pairing over bls12-381:
|
|
35
|
-
// [part 1](https://research.nccgroup.com/2020/07/06/pairing-over-bls12-381-part-1-fields/),
|
|
36
|
-
// [part 2](https://research.nccgroup.com/2020/07/13/pairing-over-bls12-381-part-2-curves/),
|
|
37
|
-
// [part 3](https://research.nccgroup.com/2020/08/13/pairing-over-bls12-381-part-3-pairing/)
|
|
38
|
-
// - [Estimating the bit security of pairing-friendly curves](https://research.nccgroup.com/2022/02/03/estimating-the-bit-security-of-pairing-friendly-curves/)
|
|
39
|
-
//
|
|
40
|
-
// ### Differences from @noble/bls12-381 1.4
|
|
41
|
-
// - PointG1 -> G1.Point
|
|
42
|
-
// - PointG2 -> G2.Point
|
|
43
|
-
// - PointG2.fromSignature -> Signature.decode
|
|
44
|
-
// - PointG2.toSignature -> Signature.encode
|
|
45
|
-
// - Fixed Fp2 ORDER
|
|
46
|
-
// - Points now have only two coordinates
|
|
47
|
-
|
|
48
30
|
import { sha256 } from '@noble/hashes/sha256';
|
|
49
31
|
import { randomBytes } from '@noble/hashes/utils';
|
|
50
32
|
import { bls, CurveFn } from './abstract/bls.js';
|
|
@@ -59,6 +41,7 @@ import {
|
|
|
59
41
|
bitGet,
|
|
60
42
|
Hex,
|
|
61
43
|
bitMask,
|
|
44
|
+
bytesToHex,
|
|
62
45
|
} from './abstract/utils.js';
|
|
63
46
|
// Types
|
|
64
47
|
import {
|
|
@@ -72,8 +55,8 @@ import { isogenyMap } from './abstract/hash-to-curve.js';
|
|
|
72
55
|
// Be friendly to bad ECMAScript parsers by not using bigint literals
|
|
73
56
|
// prettier-ignore
|
|
74
57
|
const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3), _4n = BigInt(4);
|
|
75
|
-
|
|
76
|
-
|
|
58
|
+
// prettier-ignore
|
|
59
|
+
const _8n = BigInt(8), _16n = BigInt(16);
|
|
77
60
|
|
|
78
61
|
// CURVE FIELDS
|
|
79
62
|
// Finite field over p.
|
|
@@ -950,9 +933,9 @@ const isogenyMapG1 = isogenyMap(
|
|
|
950
933
|
|
|
951
934
|
// SWU Map - Fp2 to G2': y² = x³ + 240i * x + 1012 + 1012i
|
|
952
935
|
const G2_SWU = mapToCurveSimpleSWU(Fp2, {
|
|
953
|
-
A: Fp2.create({ c0: Fp.create(_0n), c1: Fp.create(
|
|
954
|
-
B: Fp2.create({ c0: Fp.create(
|
|
955
|
-
Z: Fp2.create({ c0: Fp.create(-
|
|
936
|
+
A: Fp2.create({ c0: Fp.create(_0n), c1: Fp.create(BigInt(240)) }), // A' = 240 * I
|
|
937
|
+
B: Fp2.create({ c0: Fp.create(BigInt(1012)), c1: Fp.create(BigInt(1012)) }), // B' = 1012 * (1 + I)
|
|
938
|
+
Z: Fp2.create({ c0: Fp.create(BigInt(-2)), c1: Fp.create(BigInt(-1)) }), // Z: -(2 + I)
|
|
956
939
|
});
|
|
957
940
|
// Optimized SWU Map - Fp to G1
|
|
958
941
|
const G1_SWU = mapToCurveSimpleSWU(Fp, {
|
|
@@ -966,7 +949,7 @@ const G1_SWU = mapToCurveSimpleSWU(Fp, {
|
|
|
966
949
|
'0x12e2908d11688030018b12e8753eee3b2016c1f0f24f4070a0b9c14fcef35ef55a23215a316ceaa5d1cc48e98e172be0'
|
|
967
950
|
)
|
|
968
951
|
),
|
|
969
|
-
Z: Fp.create(
|
|
952
|
+
Z: Fp.create(BigInt(11)),
|
|
970
953
|
});
|
|
971
954
|
|
|
972
955
|
// Endomorphisms (for fast cofactor clearing)
|
|
@@ -1042,7 +1025,23 @@ const C_BIT_POS = Fp.BITS; // C_bit, compression bit for serialization flag
|
|
|
1042
1025
|
const I_BIT_POS = Fp.BITS + 1; // I_bit, point-at-infinity bit for serialization flag
|
|
1043
1026
|
const S_BIT_POS = Fp.BITS + 2; // S_bit, sign bit for serialization flag
|
|
1044
1027
|
// Compressed point of infinity
|
|
1045
|
-
const COMPRESSED_ZERO = Fp.toBytes(bitSet(bitSet(
|
|
1028
|
+
const COMPRESSED_ZERO = Fp.toBytes(bitSet(bitSet(_0n, I_BIT_POS, true), S_BIT_POS, true)); // set compressed & point-at-infinity bits
|
|
1029
|
+
|
|
1030
|
+
function signatureG2ToRawBytes(point: ProjPointType<Fp2>) {
|
|
1031
|
+
// NOTE: by some reasons it was missed in bls12-381, looks like bug
|
|
1032
|
+
point.assertValidity();
|
|
1033
|
+
const len = Fp.BYTES;
|
|
1034
|
+
if (point.equals(bls12_381.G2.ProjectivePoint.ZERO))
|
|
1035
|
+
return concatB(COMPRESSED_ZERO, numberToBytesBE(_0n, len));
|
|
1036
|
+
const { x, y } = point.toAffine();
|
|
1037
|
+
const { re: x0, im: x1 } = Fp2.reim(x);
|
|
1038
|
+
const { re: y0, im: y1 } = Fp2.reim(y);
|
|
1039
|
+
const tmp = y1 > _0n ? y1 * _2n : y0 * _2n;
|
|
1040
|
+
const aflag1 = Boolean((tmp / Fp.ORDER) & _1n);
|
|
1041
|
+
const z1 = bitSet(bitSet(x1, 381, aflag1), S_BIT_POS, true);
|
|
1042
|
+
const z2 = x0;
|
|
1043
|
+
return concatB(numberToBytesBE(z1, len), numberToBytesBE(z2, len));
|
|
1044
|
+
}
|
|
1046
1045
|
|
|
1047
1046
|
// To verify curve parameters, see pairing-friendly-curves spec:
|
|
1048
1047
|
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-09
|
|
@@ -1056,13 +1055,13 @@ const COMPRESSED_ZERO = Fp.toBytes(bitSet(bitSet(0n, I_BIT_POS, true), S_BIT_POS
|
|
|
1056
1055
|
// Here goes constants && point encoding format
|
|
1057
1056
|
export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
1058
1057
|
// Fields
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1058
|
+
fields: {
|
|
1059
|
+
Fp,
|
|
1060
|
+
Fp2,
|
|
1061
|
+
Fp6,
|
|
1062
|
+
Fp12,
|
|
1063
|
+
Fr,
|
|
1064
|
+
},
|
|
1066
1065
|
// G1 is the order-q subgroup of E1(Fp) : y² = x³ + 4, #E1(Fp) = h1q, where
|
|
1067
1066
|
// characteristic; z + (z⁴ - z² + 1)(z - 1)²/3
|
|
1068
1067
|
G1: {
|
|
@@ -1095,8 +1094,8 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
|
1095
1094
|
const phi = new c(Fp.mul(point.px, cubicRootOfUnityModP), point.py, point.pz);
|
|
1096
1095
|
|
|
1097
1096
|
// todo: unroll
|
|
1098
|
-
const xP = point.multiplyUnsafe(bls12_381.
|
|
1099
|
-
const u2P = xP.multiplyUnsafe(bls12_381.
|
|
1097
|
+
const xP = point.multiplyUnsafe(bls12_381.params.x).negate(); // [x]P
|
|
1098
|
+
const u2P = xP.multiplyUnsafe(bls12_381.params.x); // [u2]P
|
|
1100
1099
|
return u2P.equals(phi);
|
|
1101
1100
|
|
|
1102
1101
|
// https://eprint.iacr.org/2019/814.pdf
|
|
@@ -1115,21 +1114,23 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
|
1115
1114
|
// https://eprint.iacr.org/2019/403
|
|
1116
1115
|
clearCofactor: (c, point) => {
|
|
1117
1116
|
// return this.multiplyUnsafe(CURVE.h);
|
|
1118
|
-
return point.multiplyUnsafe(bls12_381.
|
|
1117
|
+
return point.multiplyUnsafe(bls12_381.params.x).add(point); // x*P + P
|
|
1119
1118
|
},
|
|
1120
1119
|
mapToCurve: (scalars: bigint[]) => {
|
|
1121
1120
|
const { x, y } = G1_SWU(Fp.create(scalars[0]));
|
|
1122
1121
|
return isogenyMapG1(x, y);
|
|
1123
1122
|
},
|
|
1124
1123
|
fromBytes: (bytes: Uint8Array): AffinePoint<Fp> => {
|
|
1124
|
+
bytes = bytes.slice();
|
|
1125
1125
|
if (bytes.length === 48) {
|
|
1126
|
+
// TODO: Fp.bytes
|
|
1126
1127
|
const P = Fp.ORDER;
|
|
1127
1128
|
const compressedValue = bytesToNumberBE(bytes);
|
|
1128
1129
|
const bflag = bitGet(compressedValue, I_BIT_POS);
|
|
1129
1130
|
// Zero
|
|
1130
1131
|
if (bflag === _1n) return { x: _0n, y: _0n };
|
|
1131
1132
|
const x = Fp.create(compressedValue & Fp.MASK);
|
|
1132
|
-
const right = Fp.add(Fp.pow(x, _3n), Fp.create(bls12_381.
|
|
1133
|
+
const right = Fp.add(Fp.pow(x, _3n), Fp.create(bls12_381.params.G1b)); // y² = x³ + b
|
|
1133
1134
|
let y = Fp.sqrt(right);
|
|
1134
1135
|
if (!y) throw new Error('Invalid compressed G1 point');
|
|
1135
1136
|
const aflag = bitGet(compressedValue, C_BIT_POS);
|
|
@@ -1138,8 +1139,8 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
|
1138
1139
|
} else if (bytes.length === 96) {
|
|
1139
1140
|
// Check if the infinity flag is set
|
|
1140
1141
|
if ((bytes[0] & (1 << 6)) !== 0) return bls12_381.G1.ProjectivePoint.ZERO.toAffine();
|
|
1141
|
-
const x = bytesToNumberBE(bytes.
|
|
1142
|
-
const y = bytesToNumberBE(bytes.
|
|
1142
|
+
const x = bytesToNumberBE(bytes.subarray(0, Fp.BYTES));
|
|
1143
|
+
const y = bytesToNumberBE(bytes.subarray(Fp.BYTES));
|
|
1143
1144
|
return { x: Fp.create(x), y: Fp.create(y) };
|
|
1144
1145
|
} else {
|
|
1145
1146
|
throw new Error('Invalid point G1, expected 48/96 bytes');
|
|
@@ -1212,7 +1213,7 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
|
1212
1213
|
// It returns false for shitty points.
|
|
1213
1214
|
// https://eprint.iacr.org/2021/1130.pdf
|
|
1214
1215
|
isTorsionFree: (c, P): boolean => {
|
|
1215
|
-
return P.multiplyUnsafe(bls12_381.
|
|
1216
|
+
return P.multiplyUnsafe(bls12_381.params.x).negate().equals(G2psi(c, P)); // ψ(P) == [u](P)
|
|
1216
1217
|
// Older version: https://eprint.iacr.org/2019/814.pdf
|
|
1217
1218
|
// Ψ²(P) => Ψ³(P) => [z]Ψ³(P) where z = -x => [z]Ψ³(P) - Ψ²(P) + P == O
|
|
1218
1219
|
// return P.psi2().psi().mulNegX().subtract(psi2).add(P).isZero();
|
|
@@ -1222,7 +1223,7 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
|
1222
1223
|
// https://eprint.iacr.org/2017/419.pdf
|
|
1223
1224
|
// prettier-ignore
|
|
1224
1225
|
clearCofactor: (c, P) => {
|
|
1225
|
-
const
|
|
1226
|
+
const x = bls12_381.params.x;
|
|
1226
1227
|
let t1 = P.multiplyUnsafe(x).negate(); // [-x]P
|
|
1227
1228
|
let t2 = G2psi(c, P); // Ψ(P)
|
|
1228
1229
|
let t3 = P.double(); // 2P
|
|
@@ -1236,6 +1237,7 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
|
1236
1237
|
return Q; // [x²-x-1]P + [x-1]Ψ(P) + Ψ²(2P)
|
|
1237
1238
|
},
|
|
1238
1239
|
fromBytes: (bytes: Uint8Array): AffinePoint<Fp2> => {
|
|
1240
|
+
bytes = bytes.slice();
|
|
1239
1241
|
const m_byte = bytes[0] & 0xe0;
|
|
1240
1242
|
if (m_byte === 0x20 || m_byte === 0x60 || m_byte === 0xe0) {
|
|
1241
1243
|
throw new Error('Invalid encoding flag: ' + m_byte);
|
|
@@ -1246,7 +1248,7 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
|
1246
1248
|
const L = Fp.BYTES;
|
|
1247
1249
|
const slc = (b: Uint8Array, from: number, to?: number) => bytesToNumberBE(b.slice(from, to));
|
|
1248
1250
|
if (bytes.length === 96 && bitC) {
|
|
1249
|
-
const
|
|
1251
|
+
const b = bls12_381.params.G2b;
|
|
1250
1252
|
const P = Fp.ORDER;
|
|
1251
1253
|
|
|
1252
1254
|
bytes[0] = bytes[0] & 0x1f; // clear flags
|
|
@@ -1280,31 +1282,31 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
|
1280
1282
|
}
|
|
1281
1283
|
},
|
|
1282
1284
|
toBytes: (c, point, isCompressed) => {
|
|
1285
|
+
const { BYTES: len, ORDER: P } = Fp;
|
|
1283
1286
|
const isZero = point.equals(c.ZERO);
|
|
1284
1287
|
const { x, y } = point.toAffine();
|
|
1285
1288
|
if (isCompressed) {
|
|
1286
|
-
|
|
1287
|
-
if (isZero) return concatB(COMPRESSED_ZERO, numberToBytesBE(0n, Fp.BYTES));
|
|
1289
|
+
if (isZero) return concatB(COMPRESSED_ZERO, numberToBytesBE(_0n, len));
|
|
1288
1290
|
const flag = Boolean(y.c1 === _0n ? (y.c0 * _2n) / P : (y.c1 * _2n) / P);
|
|
1289
1291
|
// set compressed & sign bits (looks like different offsets than for G1/Fp?)
|
|
1290
1292
|
let x_1 = bitSet(x.c1, C_BIT_POS, flag);
|
|
1291
1293
|
x_1 = bitSet(x_1, S_BIT_POS, true);
|
|
1292
|
-
return concatB(numberToBytesBE(x_1,
|
|
1294
|
+
return concatB(numberToBytesBE(x_1, len), numberToBytesBE(x.c0, len));
|
|
1293
1295
|
} else {
|
|
1294
|
-
if (isZero) return concatB(new Uint8Array([0x40]), new Uint8Array(4 *
|
|
1296
|
+
if (isZero) return concatB(new Uint8Array([0x40]), new Uint8Array(4 * len - 1)); // bytes[0] |= 1 << 6;
|
|
1295
1297
|
const { re: x0, im: x1 } = Fp2.reim(x);
|
|
1296
1298
|
const { re: y0, im: y1 } = Fp2.reim(y);
|
|
1297
1299
|
return concatB(
|
|
1298
|
-
numberToBytesBE(x1,
|
|
1299
|
-
numberToBytesBE(x0,
|
|
1300
|
-
numberToBytesBE(y1,
|
|
1301
|
-
numberToBytesBE(y0,
|
|
1300
|
+
numberToBytesBE(x1, len),
|
|
1301
|
+
numberToBytesBE(x0, len),
|
|
1302
|
+
numberToBytesBE(y1, len),
|
|
1303
|
+
numberToBytesBE(y0, len)
|
|
1302
1304
|
);
|
|
1303
1305
|
}
|
|
1304
1306
|
},
|
|
1305
1307
|
Signature: {
|
|
1306
1308
|
// TODO: Optimize, it's very slow because of sqrt.
|
|
1307
|
-
|
|
1309
|
+
fromHex(hex: Hex): ProjPointType<Fp2> {
|
|
1308
1310
|
hex = ensureBytes('signatureHex', hex);
|
|
1309
1311
|
const P = Fp.ORDER;
|
|
1310
1312
|
const half = hex.length / 2;
|
|
@@ -1319,7 +1321,7 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
|
1319
1321
|
const x1 = Fp.create(z1 & Fp.MASK);
|
|
1320
1322
|
const x2 = Fp.create(z2);
|
|
1321
1323
|
const x = Fp2.create({ c0: x2, c1: x1 });
|
|
1322
|
-
const y2 = Fp2.add(Fp2.pow(x, _3n), bls12_381.
|
|
1324
|
+
const y2 = Fp2.add(Fp2.pow(x, _3n), bls12_381.params.G2b); // y² = x³ + 4
|
|
1323
1325
|
// The slow part
|
|
1324
1326
|
let y = Fp2.sqrt(y2);
|
|
1325
1327
|
if (!y) throw new Error('Failed to find a square root');
|
|
@@ -1335,24 +1337,18 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
|
|
|
1335
1337
|
point.assertValidity();
|
|
1336
1338
|
return point;
|
|
1337
1339
|
},
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
const a = point.toAffine();
|
|
1344
|
-
const { re: x0, im: x1 } = Fp2.reim(a.x);
|
|
1345
|
-
const { re: y0, im: y1 } = Fp2.reim(a.y);
|
|
1346
|
-
const tmp = y1 > _0n ? y1 * _2n : y0 * _2n;
|
|
1347
|
-
const aflag1 = Boolean((tmp / Fp.ORDER) & _1n);
|
|
1348
|
-
const z1 = bitSet(bitSet(x1, 381, aflag1), S_BIT_POS, true);
|
|
1349
|
-
const z2 = x0;
|
|
1350
|
-
return concatB(numberToBytesBE(z1, Fp.BYTES), numberToBytesBE(z2, Fp.BYTES));
|
|
1340
|
+
toRawBytes(point: ProjPointType<Fp2>) {
|
|
1341
|
+
return signatureG2ToRawBytes(point);
|
|
1342
|
+
},
|
|
1343
|
+
toHex(point: ProjPointType<Fp2>) {
|
|
1344
|
+
return bytesToHex(signatureG2ToRawBytes(point));
|
|
1351
1345
|
},
|
|
1352
1346
|
},
|
|
1353
1347
|
},
|
|
1354
|
-
|
|
1355
|
-
|
|
1348
|
+
params: {
|
|
1349
|
+
x: BLS_X, // The BLS parameter x for BLS12-381
|
|
1350
|
+
r: Fr.ORDER, // order; z⁴ − z² + 1; CURVE.n from other curves
|
|
1351
|
+
},
|
|
1356
1352
|
htfDefaults,
|
|
1357
1353
|
hash: sha256,
|
|
1358
1354
|
randomBytes,
|
package/src/ed25519.ts
CHANGED
|
@@ -95,15 +95,15 @@ export const ED25519_TORSION_SUBGROUP = [
|
|
|
95
95
|
|
|
96
96
|
const Fp = Field(ED25519_P, undefined, true);
|
|
97
97
|
|
|
98
|
-
const
|
|
98
|
+
const ed25519Defaults = {
|
|
99
99
|
// Param: a
|
|
100
|
-
a: BigInt(-1),
|
|
101
|
-
//
|
|
100
|
+
a: BigInt(-1), // Fp.create(-1) is proper; our way still works and is faster
|
|
101
|
+
// d is equal to -121665/121666 over finite field.
|
|
102
102
|
// Negative number is P - number, and division is invert(number, P)
|
|
103
103
|
d: BigInt('37095705934669439343138083508754565189542113879843219016388785533085940283555'),
|
|
104
104
|
// Finite field 𝔽p over which we'll do calculations; 2n ** 255n - 19n
|
|
105
105
|
Fp,
|
|
106
|
-
// Subgroup order: how many points
|
|
106
|
+
// Subgroup order: how many points curve has
|
|
107
107
|
// 2n ** 252n + 27742317777372353535851937790883648493n;
|
|
108
108
|
n: BigInt('7237005577332262213973186563042994240857116359379907606001950938285454250989'),
|
|
109
109
|
// Cofactor
|
|
@@ -120,7 +120,7 @@ const ED25519_DEF = {
|
|
|
120
120
|
uvRatio,
|
|
121
121
|
} as const;
|
|
122
122
|
|
|
123
|
-
export const ed25519 = twistedEdwards(
|
|
123
|
+
export const ed25519 = twistedEdwards(ed25519Defaults);
|
|
124
124
|
function ed25519_domain(data: Uint8Array, ctx: Uint8Array, phflag: boolean) {
|
|
125
125
|
if (ctx.length > 255) throw new Error('Context is too big');
|
|
126
126
|
return concatBytes(
|
|
@@ -130,11 +130,11 @@ function ed25519_domain(data: Uint8Array, ctx: Uint8Array, phflag: boolean) {
|
|
|
130
130
|
data
|
|
131
131
|
);
|
|
132
132
|
}
|
|
133
|
-
export const ed25519ctx = twistedEdwards({ ...
|
|
133
|
+
export const ed25519ctx = twistedEdwards({ ...ed25519Defaults, domain: ed25519_domain });
|
|
134
134
|
export const ed25519ph = twistedEdwards({
|
|
135
|
-
...
|
|
135
|
+
...ed25519Defaults,
|
|
136
136
|
domain: ed25519_domain,
|
|
137
|
-
|
|
137
|
+
prehash: sha512,
|
|
138
138
|
});
|
|
139
139
|
|
|
140
140
|
export const x25519 = montgomery({
|
|
@@ -153,6 +153,20 @@ export const x25519 = montgomery({
|
|
|
153
153
|
randomBytes,
|
|
154
154
|
});
|
|
155
155
|
|
|
156
|
+
/**
|
|
157
|
+
* Converts ed25519 public key to x25519 public key. Uses formula:
|
|
158
|
+
* * `(u, v) = ((1+y)/(1-y), sqrt(-486664)*u/x)`
|
|
159
|
+
* * `(x, y) = (sqrt(-486664)*u/v, (u-1)/(u+1))`
|
|
160
|
+
* @example
|
|
161
|
+
* const aPub = ed25519.getPublicKey(utils.randomPrivateKey());
|
|
162
|
+
* x25519.getSharedSecret(edwardsToMontgomery(aPub), edwardsToMontgomery(someonesPub))
|
|
163
|
+
*/
|
|
164
|
+
export function edwardsToMontgomery(edwardsPub: Hex): Uint8Array {
|
|
165
|
+
const { y } = ed25519.ExtendedPoint.fromHex(edwardsPub);
|
|
166
|
+
const _1n = BigInt(1);
|
|
167
|
+
return Fp.toBytes(Fp.create((y - _1n) * Fp.inv(y + _1n)));
|
|
168
|
+
}
|
|
169
|
+
|
|
156
170
|
// Hash To Curve Elligator2 Map (NOTE: different from ristretto255 elligator)
|
|
157
171
|
// NOTE: very important part is usage of FpSqrtEven for ELL2_C1_EDWARDS, since
|
|
158
172
|
// SageMath returns different root first and everything falls apart
|
package/src/ed448.ts
CHANGED
|
@@ -120,7 +120,7 @@ const ED448_DEF = {
|
|
|
120
120
|
|
|
121
121
|
export const ed448 = twistedEdwards(ED448_DEF);
|
|
122
122
|
// NOTE: there is no ed448ctx, since ed448 supports ctx by default
|
|
123
|
-
export const ed448ph = twistedEdwards({ ...ED448_DEF,
|
|
123
|
+
export const ed448ph = twistedEdwards({ ...ED448_DEF, prehash: shake256_64 });
|
|
124
124
|
|
|
125
125
|
export const x448 = montgomery({
|
|
126
126
|
a: BigInt(156326),
|
|
@@ -136,22 +136,22 @@ export const x448 = montgomery({
|
|
|
136
136
|
},
|
|
137
137
|
adjustScalarBytes,
|
|
138
138
|
randomBytes,
|
|
139
|
-
// The 4-isogeny maps between the Montgomery curve and this Edwards
|
|
140
|
-
// curve are:
|
|
141
|
-
// (u, v) = (y^2/x^2, (2 - x^2 - y^2)*y/x^3)
|
|
142
|
-
// (x, y) = (4*v*(u^2 - 1)/(u^4 - 2*u^2 + 4*v^2 + 1),
|
|
143
|
-
// -(u^5 - 2*u^3 - 4*u*v^2 + u)/
|
|
144
|
-
// (u^5 - 2*u^2*v^2 - 2*u^3 - 2*v^2 + u))
|
|
145
|
-
// xyToU: (p: PointType) => {
|
|
146
|
-
// const P = ed448P;
|
|
147
|
-
// const { x, y } = p;
|
|
148
|
-
// if (x === _0n) throw new Error(`Point with x=0 doesn't have mapping`);
|
|
149
|
-
// const invX = invert(x * x, P); // x^2
|
|
150
|
-
// const u = mod(y * y * invX, P); // (y^2/x^2)
|
|
151
|
-
// return numberToBytesLE(u, 56);
|
|
152
|
-
// },
|
|
153
139
|
});
|
|
154
140
|
|
|
141
|
+
/**
|
|
142
|
+
* Converts edwards448 public key to x448 public key. Uses formula:
|
|
143
|
+
* * `(u, v) = ((y-1)/(y+1), sqrt(156324)*u/x)`
|
|
144
|
+
* * `(x, y) = (sqrt(156324)*u/v, (1+u)/(1-u))`
|
|
145
|
+
* @example
|
|
146
|
+
* const aPub = ed448.getPublicKey(utils.randomPrivateKey());
|
|
147
|
+
* x448.getSharedSecret(edwardsToMontgomery(aPub), edwardsToMontgomery(someonesPub))
|
|
148
|
+
*/
|
|
149
|
+
export function edwardsToMontgomery(edwardsPub: string | Uint8Array): Uint8Array {
|
|
150
|
+
const { y } = ed448.ExtendedPoint.fromHex(edwardsPub);
|
|
151
|
+
const _1n = BigInt(1);
|
|
152
|
+
return Fp.toBytes(Fp.create((y - _1n) * Fp.inv(y + _1n)));
|
|
153
|
+
}
|
|
154
|
+
|
|
155
155
|
// Hash To Curve Elligator2 Map
|
|
156
156
|
const ELL2_C1 = (Fp.ORDER - BigInt(3)) / BigInt(4); // 1. c1 = (q - 3) / 4 # Integer arithmetic
|
|
157
157
|
const ELL2_J = BigInt(156326);
|