@noble/curves 2.0.1 → 2.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 +214 -122
- package/abstract/bls.d.ts +299 -16
- package/abstract/bls.d.ts.map +1 -1
- package/abstract/bls.js +82 -22
- package/abstract/bls.js.map +1 -1
- package/abstract/curve.d.ts +274 -27
- package/abstract/curve.d.ts.map +1 -1
- package/abstract/curve.js +177 -23
- package/abstract/curve.js.map +1 -1
- package/abstract/edwards.d.ts +166 -30
- package/abstract/edwards.d.ts.map +1 -1
- package/abstract/edwards.js +221 -86
- package/abstract/edwards.js.map +1 -1
- package/abstract/fft.d.ts +322 -10
- package/abstract/fft.d.ts.map +1 -1
- package/abstract/fft.js +154 -12
- package/abstract/fft.js.map +1 -1
- package/abstract/frost.d.ts +293 -0
- package/abstract/frost.d.ts.map +1 -0
- package/abstract/frost.js +704 -0
- package/abstract/frost.js.map +1 -0
- package/abstract/hash-to-curve.d.ts +173 -24
- package/abstract/hash-to-curve.d.ts.map +1 -1
- package/abstract/hash-to-curve.js +170 -31
- package/abstract/hash-to-curve.js.map +1 -1
- package/abstract/modular.d.ts +429 -37
- package/abstract/modular.d.ts.map +1 -1
- package/abstract/modular.js +414 -119
- package/abstract/modular.js.map +1 -1
- package/abstract/montgomery.d.ts +83 -12
- package/abstract/montgomery.d.ts.map +1 -1
- package/abstract/montgomery.js +32 -7
- package/abstract/montgomery.js.map +1 -1
- package/abstract/oprf.d.ts +164 -91
- package/abstract/oprf.d.ts.map +1 -1
- package/abstract/oprf.js +88 -29
- package/abstract/oprf.js.map +1 -1
- package/abstract/poseidon.d.ts +138 -7
- package/abstract/poseidon.d.ts.map +1 -1
- package/abstract/poseidon.js +178 -15
- package/abstract/poseidon.js.map +1 -1
- package/abstract/tower.d.ts +122 -3
- package/abstract/tower.d.ts.map +1 -1
- package/abstract/tower.js +323 -139
- package/abstract/tower.js.map +1 -1
- package/abstract/weierstrass.d.ts +339 -76
- package/abstract/weierstrass.d.ts.map +1 -1
- package/abstract/weierstrass.js +395 -205
- package/abstract/weierstrass.js.map +1 -1
- package/bls12-381.d.ts +16 -2
- package/bls12-381.d.ts.map +1 -1
- package/bls12-381.js +199 -209
- package/bls12-381.js.map +1 -1
- package/bn254.d.ts +11 -2
- package/bn254.d.ts.map +1 -1
- package/bn254.js +93 -38
- package/bn254.js.map +1 -1
- package/ed25519.d.ts +125 -14
- package/ed25519.d.ts.map +1 -1
- package/ed25519.js +202 -40
- package/ed25519.js.map +1 -1
- package/ed448.d.ts +108 -14
- package/ed448.d.ts.map +1 -1
- package/ed448.js +194 -42
- package/ed448.js.map +1 -1
- package/index.js +7 -1
- package/index.js.map +1 -1
- package/misc.d.ts +106 -7
- package/misc.d.ts.map +1 -1
- package/misc.js +141 -32
- package/misc.js.map +1 -1
- package/nist.d.ts +112 -11
- package/nist.d.ts.map +1 -1
- package/nist.js +139 -17
- package/nist.js.map +1 -1
- package/package.json +11 -6
- package/secp256k1.d.ts +92 -15
- package/secp256k1.d.ts.map +1 -1
- package/secp256k1.js +211 -28
- package/secp256k1.js.map +1 -1
- package/src/abstract/bls.ts +350 -67
- package/src/abstract/curve.ts +327 -44
- package/src/abstract/edwards.ts +367 -143
- package/src/abstract/fft.ts +369 -36
- package/src/abstract/frost.ts +1092 -0
- package/src/abstract/hash-to-curve.ts +255 -56
- package/src/abstract/modular.ts +591 -144
- package/src/abstract/montgomery.ts +114 -30
- package/src/abstract/oprf.ts +383 -194
- package/src/abstract/poseidon.ts +235 -35
- package/src/abstract/tower.ts +428 -159
- package/src/abstract/weierstrass.ts +710 -312
- package/src/bls12-381.ts +239 -236
- package/src/bn254.ts +107 -46
- package/src/ed25519.ts +227 -55
- package/src/ed448.ts +227 -57
- package/src/index.ts +7 -1
- package/src/misc.ts +154 -35
- package/src/nist.ts +143 -20
- package/src/secp256k1.ts +284 -41
- package/src/utils.ts +583 -81
- package/src/webcrypto.ts +302 -73
- package/utils.d.ts +457 -24
- package/utils.d.ts.map +1 -1
- package/utils.js +410 -53
- package/utils.js.map +1 -1
- package/webcrypto.d.ts +167 -25
- package/webcrypto.d.ts.map +1 -1
- package/webcrypto.js +165 -58
- package/webcrypto.js.map +1 -1
package/src/ed25519.ts
CHANGED
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
type EdwardsPoint,
|
|
20
20
|
type EdwardsPointCons,
|
|
21
21
|
} from './abstract/edwards.ts';
|
|
22
|
+
import { createFROST, type FROST } from './abstract/frost.ts';
|
|
22
23
|
import {
|
|
23
24
|
_DST_scalar,
|
|
24
25
|
createHasher,
|
|
@@ -36,16 +37,16 @@ import {
|
|
|
36
37
|
type IField,
|
|
37
38
|
} from './abstract/modular.ts';
|
|
38
39
|
import { montgomery, type MontgomeryECDH } from './abstract/montgomery.ts';
|
|
39
|
-
import {
|
|
40
|
-
import { asciiToBytes, bytesToNumberLE, equalBytes } from './utils.ts';
|
|
40
|
+
import { createOPRF, type OPRF } from './abstract/oprf.ts';
|
|
41
|
+
import { asciiToBytes, bytesToNumberLE, equalBytes, type TArg, type TRet } from './utils.ts';
|
|
41
42
|
|
|
42
43
|
// prettier-ignore
|
|
43
|
-
const _0n = /* @__PURE__ */ BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = /* @__PURE__ */ BigInt(3);
|
|
44
|
+
const _0n = /* @__PURE__ */ BigInt(0), _1n = /* @__PURE__ */ BigInt(1), _2n = /* @__PURE__ */ BigInt(2), _3n = /* @__PURE__ */ BigInt(3);
|
|
44
45
|
// prettier-ignore
|
|
45
|
-
const _5n = BigInt(5), _8n = BigInt(8);
|
|
46
|
+
const _5n = /* @__PURE__ */ BigInt(5), _8n = /* @__PURE__ */ BigInt(8);
|
|
46
47
|
|
|
47
48
|
// P = 2n**255n - 19n
|
|
48
|
-
const ed25519_CURVE_p = BigInt(
|
|
49
|
+
const ed25519_CURVE_p = /* @__PURE__ */ BigInt(
|
|
49
50
|
'0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed'
|
|
50
51
|
);
|
|
51
52
|
// N = 2n**252n + 27742317777372353535851937790883648493n
|
|
@@ -77,11 +78,12 @@ function ed25519_pow_2_252_3(x: bigint) {
|
|
|
77
78
|
const b240 = (pow2(b160, _80n, P) * b80) % P;
|
|
78
79
|
const b250 = (pow2(b240, _10n, P) * b10) % P;
|
|
79
80
|
const pow_p_5_8 = (pow2(b250, _2n, P) * x) % P;
|
|
80
|
-
// ^
|
|
81
|
+
// ^ This is x^((p-5)/8); multiply by x once more to get x^((p+3)/8).
|
|
81
82
|
return { pow_p_5_8, b2 };
|
|
82
83
|
}
|
|
83
84
|
|
|
84
|
-
|
|
85
|
+
// Mutates and returns the provided 32-byte buffer in place.
|
|
86
|
+
function adjustScalarBytes(bytes: TArg<Uint8Array>): TRet<Uint8Array> {
|
|
85
87
|
// Section 5: For X25519, in order to decode 32 random bytes as an integer scalar,
|
|
86
88
|
// set the three least significant bits of the first byte
|
|
87
89
|
bytes[0] &= 248; // 0b1111_1000
|
|
@@ -89,7 +91,7 @@ function adjustScalarBytes(bytes: Uint8Array): Uint8Array {
|
|
|
89
91
|
bytes[31] &= 127; // 0b0111_1111
|
|
90
92
|
// set the second most significant bit of the last byte to 1
|
|
91
93
|
bytes[31] |= 64; // 0b0100_0000
|
|
92
|
-
return bytes
|
|
94
|
+
return bytes as TRet<Uint8Array>;
|
|
93
95
|
}
|
|
94
96
|
|
|
95
97
|
// √(-1) aka √(a) aka 2^((p-1)/4)
|
|
@@ -97,7 +99,8 @@ function adjustScalarBytes(bytes: Uint8Array): Uint8Array {
|
|
|
97
99
|
const ED25519_SQRT_M1 = /* @__PURE__ */ BigInt(
|
|
98
100
|
'19681161376707505956807079304988542015446066515923890162744021073123829784752'
|
|
99
101
|
);
|
|
100
|
-
// sqrt(u/v)
|
|
102
|
+
// sqrt(u/v). Returns `{ isValid, value }`; on non-squares `value` is still a
|
|
103
|
+
// dummy root-shaped field element so callers can stay constant-time.
|
|
101
104
|
function uvRatio(u: bigint, v: bigint): { isValid: boolean; value: bigint } {
|
|
102
105
|
const P = ed25519_CURVE_p;
|
|
103
106
|
const v3 = mod(v * v * v, P); // v³
|
|
@@ -118,46 +121,120 @@ function uvRatio(u: bigint, v: bigint): { isValid: boolean; value: bigint } {
|
|
|
118
121
|
}
|
|
119
122
|
|
|
120
123
|
const ed25519_Point = /* @__PURE__ */ edwards(ed25519_CURVE, { uvRatio });
|
|
124
|
+
// Public field alias stays stricter than the RFC 8032 Appendix A sample code:
|
|
125
|
+
// `Fp.inv(0)` throws instead of returning `0`.
|
|
121
126
|
const Fp = /* @__PURE__ */ (() => ed25519_Point.Fp)();
|
|
122
127
|
const Fn = /* @__PURE__ */ (() => ed25519_Point.Fn)();
|
|
123
128
|
|
|
124
|
-
|
|
129
|
+
// RFC 8032 `dom2` helper for ctx/ph variants only. Plain Ed25519 keeps the
|
|
130
|
+
// empty-domain path in `ed()` and would be wrong if routed through this helper.
|
|
131
|
+
function ed25519_domain(
|
|
132
|
+
data: TArg<Uint8Array>,
|
|
133
|
+
ctx: TArg<Uint8Array>,
|
|
134
|
+
phflag: boolean
|
|
135
|
+
): TRet<Uint8Array> {
|
|
125
136
|
if (ctx.length > 255) throw new Error('Context is too big');
|
|
126
137
|
return concatBytes(
|
|
127
138
|
asciiToBytes('SigEd25519 no Ed25519 collisions'),
|
|
128
139
|
new Uint8Array([phflag ? 1 : 0, ctx.length]),
|
|
129
140
|
ctx,
|
|
130
141
|
data
|
|
131
|
-
)
|
|
142
|
+
) as TRet<Uint8Array>;
|
|
132
143
|
}
|
|
133
144
|
|
|
134
|
-
function ed(opts: EdDSAOpts) {
|
|
135
|
-
|
|
145
|
+
function ed(opts: TArg<EdDSAOpts>) {
|
|
146
|
+
// Ed25519 keeps ZIP-215 default verification semantics for consensus compatibility.
|
|
147
|
+
return eddsa(
|
|
148
|
+
ed25519_Point,
|
|
149
|
+
sha512,
|
|
150
|
+
Object.assign({ adjustScalarBytes, zip215: true }, opts as EdDSAOpts)
|
|
151
|
+
);
|
|
136
152
|
}
|
|
137
153
|
|
|
138
154
|
/**
|
|
139
155
|
* ed25519 curve with EdDSA signatures.
|
|
156
|
+
* Seeded `keygen(seed)` / `utils.randomSecretKey(seed)` reuse the provided
|
|
157
|
+
* 32-byte seed buffer instead of copying it.
|
|
140
158
|
* @example
|
|
159
|
+
* Generate one Ed25519 keypair, sign a message, and verify it.
|
|
160
|
+
*
|
|
141
161
|
* ```js
|
|
142
162
|
* import { ed25519 } from '@noble/curves/ed25519.js';
|
|
143
163
|
* const { secretKey, publicKey } = ed25519.keygen();
|
|
144
164
|
* // const publicKey = ed25519.getPublicKey(secretKey);
|
|
145
165
|
* const msg = new TextEncoder().encode('hello noble');
|
|
146
166
|
* const sig = ed25519.sign(msg, secretKey);
|
|
147
|
-
* const isValid = ed25519.verify(sig, msg,
|
|
167
|
+
* const isValid = ed25519.verify(sig, msg, publicKey); // ZIP215
|
|
148
168
|
* // RFC8032 / FIPS 186-5
|
|
149
|
-
* const isValid2 = ed25519.verify(sig, msg,
|
|
169
|
+
* const isValid2 = ed25519.verify(sig, msg, publicKey, { zip215: false });
|
|
150
170
|
* ```
|
|
151
171
|
*/
|
|
152
172
|
export const ed25519: EdDSA = /* @__PURE__ */ ed({});
|
|
153
|
-
/**
|
|
173
|
+
/**
|
|
174
|
+
* Context version of ed25519 (ctx for domain separation). See {@link ed25519}
|
|
175
|
+
* Seeded `keygen(seed)` / `utils.randomSecretKey(seed)` reuse the provided
|
|
176
|
+
* 32-byte seed buffer instead of copying it.
|
|
177
|
+
* @example
|
|
178
|
+
* Sign and verify with Ed25519ctx under one explicit context.
|
|
179
|
+
*
|
|
180
|
+
* ```ts
|
|
181
|
+
* const context = new TextEncoder().encode('docs');
|
|
182
|
+
* const { secretKey, publicKey } = ed25519ctx.keygen();
|
|
183
|
+
* const msg = new TextEncoder().encode('hello noble');
|
|
184
|
+
* const sig = ed25519ctx.sign(msg, secretKey, { context });
|
|
185
|
+
* const isValid = ed25519ctx.verify(sig, msg, publicKey, { context });
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
154
188
|
export const ed25519ctx: EdDSA = /* @__PURE__ */ ed({ domain: ed25519_domain });
|
|
155
|
-
/**
|
|
189
|
+
/**
|
|
190
|
+
* Prehashed version of ed25519. See {@link ed25519}
|
|
191
|
+
* Seeded `keygen(seed)` / `utils.randomSecretKey(seed)` reuse the provided
|
|
192
|
+
* 32-byte seed buffer instead of copying it.
|
|
193
|
+
* @example
|
|
194
|
+
* Use the prehashed Ed25519 variant for one message.
|
|
195
|
+
*
|
|
196
|
+
* ```ts
|
|
197
|
+
* const { secretKey, publicKey } = ed25519ph.keygen();
|
|
198
|
+
* const msg = new TextEncoder().encode('hello noble');
|
|
199
|
+
* const sig = ed25519ph.sign(msg, secretKey);
|
|
200
|
+
* const isValid = ed25519ph.verify(sig, msg, publicKey);
|
|
201
|
+
* ```
|
|
202
|
+
*/
|
|
156
203
|
export const ed25519ph: EdDSA = /* @__PURE__ */ ed({ domain: ed25519_domain, prehash: sha512 });
|
|
204
|
+
/**
|
|
205
|
+
* FROST threshold signatures over ed25519. RFC 9591.
|
|
206
|
+
* @example
|
|
207
|
+
* Create one trusted-dealer package for 2-of-3 ed25519 signing.
|
|
208
|
+
*
|
|
209
|
+
* ```ts
|
|
210
|
+
* const alice = ed25519_FROST.Identifier.derive('alice@example.com');
|
|
211
|
+
* const bob = ed25519_FROST.Identifier.derive('bob@example.com');
|
|
212
|
+
* const carol = ed25519_FROST.Identifier.derive('carol@example.com');
|
|
213
|
+
* const deal = ed25519_FROST.trustedDealer({ min: 2, max: 3 }, [alice, bob, carol]);
|
|
214
|
+
* ```
|
|
215
|
+
*/
|
|
216
|
+
export const ed25519_FROST: TRet<FROST> = /* @__PURE__ */ (() =>
|
|
217
|
+
createFROST({
|
|
218
|
+
name: 'FROST-ED25519-SHA512-v1',
|
|
219
|
+
Point: ed25519_Point,
|
|
220
|
+
validatePoint: (p) => {
|
|
221
|
+
p.assertValidity();
|
|
222
|
+
if (!p.isTorsionFree()) throw new Error('bad point: not torsion-free');
|
|
223
|
+
},
|
|
224
|
+
hash: sha512,
|
|
225
|
+
// RFC 9591 keeps H2 undecorated here for RFC 8032 compatibility. In createFROST(),
|
|
226
|
+
// `H2: ''` becomes an empty DST prefix; the built-in hashToScalar fallback treats
|
|
227
|
+
// that the same as omitted DST, even though custom hooks can still observe the empty bag.
|
|
228
|
+
H2: '',
|
|
229
|
+
}))();
|
|
157
230
|
|
|
158
231
|
/**
|
|
159
232
|
* ECDH using curve25519 aka x25519.
|
|
233
|
+
* `getSharedSecret()` rejects low-order peer inputs by default, and seeded
|
|
234
|
+
* `keygen(seed)` reuses the provided 32-byte seed buffer instead of copying it.
|
|
160
235
|
* @example
|
|
236
|
+
* Derive one shared secret between two X25519 peers.
|
|
237
|
+
*
|
|
161
238
|
* ```js
|
|
162
239
|
* import { x25519 } from '@noble/curves/ed25519.js';
|
|
163
240
|
* const alice = x25519.keygen();
|
|
@@ -165,7 +242,7 @@ export const ed25519ph: EdDSA = /* @__PURE__ */ ed({ domain: ed25519_domain, pre
|
|
|
165
242
|
* const shared = x25519.getSharedSecret(alice.secretKey, bob.publicKey);
|
|
166
243
|
* ```
|
|
167
244
|
*/
|
|
168
|
-
export const x25519: MontgomeryECDH = /* @__PURE__ */ (() => {
|
|
245
|
+
export const x25519: TRet<MontgomeryECDH> = /* @__PURE__ */ (() => {
|
|
169
246
|
const P = ed25519_CURVE_p;
|
|
170
247
|
return montgomery({
|
|
171
248
|
P,
|
|
@@ -180,9 +257,10 @@ export const x25519: MontgomeryECDH = /* @__PURE__ */ (() => {
|
|
|
180
257
|
})();
|
|
181
258
|
|
|
182
259
|
// Hash To Curve Elligator2 Map (NOTE: different from ristretto255 elligator)
|
|
183
|
-
//
|
|
184
|
-
//
|
|
185
|
-
|
|
260
|
+
// RFC 9380 Appendix G.2.2 / Err4730 requires `sgn0(c1) = 0` for the Edwards
|
|
261
|
+
// map constant below, so use the even root explicitly.
|
|
262
|
+
// 1. c1 = (q + 3) / 8 # Integer arithmetic
|
|
263
|
+
const ELL2_C1 = /* @__PURE__ */ (() => (ed25519_CURVE_p + _3n) / _8n)();
|
|
186
264
|
const ELL2_C2 = /* @__PURE__ */ (() => Fp.pow(_2n, ELL2_C1))(); // 2. c2 = 2^c1
|
|
187
265
|
const ELL2_C3 = /* @__PURE__ */ (() => Fp.sqrt(Fp.neg(Fp.ONE)))(); // 3. c3 = sqrt(-1)
|
|
188
266
|
|
|
@@ -199,7 +277,8 @@ export function _map_to_curve_elligator2_curve25519(u: bigint): {
|
|
|
199
277
|
|
|
200
278
|
let tv1 = Fp.sqr(u); // 1. tv1 = u^2
|
|
201
279
|
tv1 = Fp.mul(tv1, _2n); // 2. tv1 = 2 * tv1
|
|
202
|
-
|
|
280
|
+
// 3. xd = tv1 + 1 # Nonzero: -1 is square (mod p), tv1 is not
|
|
281
|
+
let xd = Fp.add(tv1, Fp.ONE);
|
|
203
282
|
let x1n = Fp.neg(ELL2_J); // 4. x1n = -J # x1 = x1n / xd = -J / (1 + 2 * u^2)
|
|
204
283
|
let tv2 = Fp.sqr(xd); // 5. tv2 = xd^2
|
|
205
284
|
let gxd = Fp.mul(tv2, xd); // 6. gxd = tv2 * xd # gxd = xd^3
|
|
@@ -218,7 +297,8 @@ export function _map_to_curve_elligator2_curve25519(u: bigint): {
|
|
|
218
297
|
tv2 = Fp.sqr(y11); // 19. tv2 = y11^2
|
|
219
298
|
tv2 = Fp.mul(tv2, gxd); // 20. tv2 = tv2 * gxd
|
|
220
299
|
let e1 = Fp.eql(tv2, gx1); // 21. e1 = tv2 == gx1
|
|
221
|
-
|
|
300
|
+
// 22. y1 = CMOV(y12, y11, e1) # If g(x1) is square, this is its sqrt
|
|
301
|
+
let y1 = Fp.cmov(y12, y11, e1);
|
|
222
302
|
let x2n = Fp.mul(x1n, tv1); // 23. x2n = x1n * tv1 # x2 = x2n / xd = 2 * u^2 * x1n / xd
|
|
223
303
|
let y21 = Fp.mul(y11, u); // 24. y21 = y11 * u
|
|
224
304
|
y21 = Fp.mul(y21, ELL2_C2); // 25. y21 = y21 * c2
|
|
@@ -227,7 +307,8 @@ export function _map_to_curve_elligator2_curve25519(u: bigint): {
|
|
|
227
307
|
tv2 = Fp.sqr(y21); // 28. tv2 = y21^2
|
|
228
308
|
tv2 = Fp.mul(tv2, gxd); // 29. tv2 = tv2 * gxd
|
|
229
309
|
let e2 = Fp.eql(tv2, gx2); // 30. e2 = tv2 == gx2
|
|
230
|
-
|
|
310
|
+
// 31. y2 = CMOV(y22, y21, e2) # If g(x2) is square, this is its sqrt
|
|
311
|
+
let y2 = Fp.cmov(y22, y21, e2);
|
|
231
312
|
tv2 = Fp.sqr(y1); // 32. tv2 = y1^2
|
|
232
313
|
tv2 = Fp.mul(tv2, gxd); // 33. tv2 = tv2 * gxd
|
|
233
314
|
let e3 = Fp.eql(tv2, gx1); // 34. e3 = tv2 == gx1
|
|
@@ -238,15 +319,18 @@ export function _map_to_curve_elligator2_curve25519(u: bigint): {
|
|
|
238
319
|
return { xMn: xn, xMd: xd, yMn: y, yMd: _1n }; // 39. return (xn, xd, y, 1)
|
|
239
320
|
}
|
|
240
321
|
|
|
241
|
-
|
|
322
|
+
// sgn0(c1) MUST equal 0
|
|
323
|
+
const ELL2_C1_EDWARDS = /* @__PURE__ */ (() => FpSqrtEven(Fp, Fp.neg(BigInt(486664))))();
|
|
242
324
|
function map_to_curve_elligator2_edwards25519(u: bigint) {
|
|
243
|
-
|
|
325
|
+
// 1. (xMn, xMd, yMn, yMd) = map_to_curve_elligator2_curve25519(u)
|
|
326
|
+
const { xMn, xMd, yMn, yMd } = _map_to_curve_elligator2_curve25519(u);
|
|
244
327
|
// map_to_curve_elligator2_curve25519(u)
|
|
245
328
|
let xn = Fp.mul(xMn, yMd); // 2. xn = xMn * yMd
|
|
246
329
|
xn = Fp.mul(xn, ELL2_C1_EDWARDS); // 3. xn = xn * c1
|
|
247
330
|
let xd = Fp.mul(xMd, yMn); // 4. xd = xMd * yMn # xn / xd = c1 * xM / yM
|
|
248
331
|
let yn = Fp.sub(xMn, xMd); // 5. yn = xMn - xMd
|
|
249
|
-
|
|
332
|
+
// 6. yd = xMn + xMd # (n / d - 1) / (n / d + 1) = (n - d) / (n + d)
|
|
333
|
+
let yd = Fp.add(xMn, xMd);
|
|
250
334
|
let tv1 = Fp.mul(xd, yd); // 7. tv1 = xd * yd
|
|
251
335
|
let e = Fp.eql(tv1, Fp.ZERO); // 8. e = tv1 == 0
|
|
252
336
|
xn = Fp.cmov(xn, Fp.ZERO, e); // 9. xn = CMOV(xn, 0, e)
|
|
@@ -254,10 +338,22 @@ function map_to_curve_elligator2_edwards25519(u: bigint) {
|
|
|
254
338
|
yn = Fp.cmov(yn, Fp.ONE, e); // 11. yn = CMOV(yn, 1, e)
|
|
255
339
|
yd = Fp.cmov(yd, Fp.ONE, e); // 12. yd = CMOV(yd, 1, e)
|
|
256
340
|
const [xd_inv, yd_inv] = FpInvertBatch(Fp, [xd, yd], true); // batch division
|
|
341
|
+
// Noble normalizes the RFC rational representation to affine `{ x, y }`
|
|
342
|
+
// before returning from the internal helper.
|
|
257
343
|
return { x: Fp.mul(xn, xd_inv), y: Fp.mul(yn, yd_inv) }; // 13. return (xn, xd, yn, yd)
|
|
258
344
|
}
|
|
259
345
|
|
|
260
|
-
/**
|
|
346
|
+
/**
|
|
347
|
+
* Hashing to ed25519 points / field. RFC 9380 methods.
|
|
348
|
+
* Public `mapToCurve()` returns the cofactor-cleared subgroup point; the
|
|
349
|
+
* internal map callback below consumes one field element bigint, not `[bigint]`.
|
|
350
|
+
* @example
|
|
351
|
+
* Hash one message onto the ed25519 curve.
|
|
352
|
+
*
|
|
353
|
+
* ```ts
|
|
354
|
+
* const point = ed25519_hasher.hashToCurve(new TextEncoder().encode('hello noble'));
|
|
355
|
+
* ```
|
|
356
|
+
*/
|
|
261
357
|
export const ed25519_hasher: H2CHasher<EdwardsPointCons> = /* @__PURE__ */ (() =>
|
|
262
358
|
createHasher(
|
|
263
359
|
ed25519_Point,
|
|
@@ -291,18 +387,23 @@ const ONE_MINUS_D_SQ = /* @__PURE__ */ BigInt(
|
|
|
291
387
|
const D_MINUS_ONE_SQ = /* @__PURE__ */ BigInt(
|
|
292
388
|
'40440834346308536858101042469323190826248399146238708352240133220865137265952'
|
|
293
389
|
);
|
|
294
|
-
//
|
|
390
|
+
// `SQRT_RATIO_M1(1, number)` specialization. Returns `{ isValid, value }`,
|
|
391
|
+
// where non-squares get the nonnegative `sqrt(SQRT_M1 / number)` branch.
|
|
295
392
|
const invertSqrt = (number: bigint) => uvRatio(_1n, number);
|
|
296
393
|
|
|
297
394
|
const MAX_255B = /* @__PURE__ */ BigInt(
|
|
298
395
|
'0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
|
|
299
396
|
);
|
|
300
|
-
|
|
397
|
+
// RFC 9496 §4.3.4 MAP parser: masks bit 255 and reduces modulo p for element
|
|
398
|
+
// derivation. The decode path has the opposite contract and rejects that bit.
|
|
399
|
+
const bytes255ToNumberLE = (bytes: TArg<Uint8Array>) =>
|
|
400
|
+
Fp.create(bytesToNumberLE(bytes) & MAX_255B);
|
|
301
401
|
|
|
302
402
|
/**
|
|
303
403
|
* Computes Elligator map for Ristretto255.
|
|
304
|
-
*
|
|
305
|
-
*
|
|
404
|
+
* Primary formula source is RFC 9496 §4.3.4 MAP; RFC 9380 Appendix B builds
|
|
405
|
+
* `hash_to_ristretto255` on top of this helper.
|
|
406
|
+
* Returns an internal Edwards representative, not a public `_RistrettoPoint`.
|
|
306
407
|
*/
|
|
307
408
|
function calcElligatorRistrettoMap(r0: bigint): EdwardsPoint {
|
|
308
409
|
const { d } = ed25519_CURVE;
|
|
@@ -355,6 +456,12 @@ class _RistrettoPoint extends PrimeEdwardsPoint<_RistrettoPoint> {
|
|
|
355
456
|
super(ep);
|
|
356
457
|
}
|
|
357
458
|
|
|
459
|
+
/**
|
|
460
|
+
* Create one Ristretto255 point from affine Edwards coordinates.
|
|
461
|
+
* This wraps the internal Edwards representative directly and is not a
|
|
462
|
+
* canonical ristretto255 decoding path.
|
|
463
|
+
* Use `toBytes()` / `fromBytes()` if canonical ristretto255 bytes matter.
|
|
464
|
+
*/
|
|
358
465
|
static fromAffine(ap: AffinePoint<bigint>): _RistrettoPoint {
|
|
359
466
|
return new _RistrettoPoint(ed25519_Point.fromAffine(ap));
|
|
360
467
|
}
|
|
@@ -367,7 +474,7 @@ class _RistrettoPoint extends PrimeEdwardsPoint<_RistrettoPoint> {
|
|
|
367
474
|
return new _RistrettoPoint(ep);
|
|
368
475
|
}
|
|
369
476
|
|
|
370
|
-
static fromBytes(bytes: Uint8Array): _RistrettoPoint {
|
|
477
|
+
static fromBytes(bytes: TArg<Uint8Array>): _RistrettoPoint {
|
|
371
478
|
abytes(bytes, 32);
|
|
372
479
|
const { a, d } = ed25519_CURVE;
|
|
373
480
|
const P = ed25519_CURVE_p;
|
|
@@ -398,7 +505,7 @@ class _RistrettoPoint extends PrimeEdwardsPoint<_RistrettoPoint> {
|
|
|
398
505
|
/**
|
|
399
506
|
* Converts ristretto-encoded string to ristretto point.
|
|
400
507
|
* Described in [RFC9496](https://www.rfc-editor.org/rfc/rfc9496#name-decode).
|
|
401
|
-
* @param hex Ristretto-encoded 32 bytes. Not every 32-byte string is valid ristretto encoding
|
|
508
|
+
* @param hex - Ristretto-encoded 32 bytes. Not every 32-byte string is valid ristretto encoding
|
|
402
509
|
*/
|
|
403
510
|
static fromHex(hex: string): _RistrettoPoint {
|
|
404
511
|
return _RistrettoPoint.fromBytes(hexToBytes(hex));
|
|
@@ -408,7 +515,7 @@ class _RistrettoPoint extends PrimeEdwardsPoint<_RistrettoPoint> {
|
|
|
408
515
|
* Encodes ristretto point to Uint8Array.
|
|
409
516
|
* Described in [RFC9496](https://www.rfc-editor.org/rfc/rfc9496#name-encode).
|
|
410
517
|
*/
|
|
411
|
-
toBytes(): Uint8Array {
|
|
518
|
+
toBytes(): TRet<Uint8Array> {
|
|
412
519
|
let { X, Y, Z, T } = this.ep;
|
|
413
520
|
const P = ed25519_CURVE_p;
|
|
414
521
|
const mod = (n: bigint) => Fp.create(n);
|
|
@@ -433,7 +540,7 @@ class _RistrettoPoint extends PrimeEdwardsPoint<_RistrettoPoint> {
|
|
|
433
540
|
if (isNegativeLE(X * zInv, P)) Y = mod(-Y); // 9
|
|
434
541
|
let s = mod((Z - Y) * D); // 10 (check footer's note, no sqrt(-a))
|
|
435
542
|
if (isNegativeLE(s, P)) s = mod(-s);
|
|
436
|
-
return Fp.toBytes(s)
|
|
543
|
+
return Fp.toBytes(s) as TRet<Uint8Array>; // 11
|
|
437
544
|
}
|
|
438
545
|
|
|
439
546
|
/**
|
|
@@ -455,13 +562,29 @@ class _RistrettoPoint extends PrimeEdwardsPoint<_RistrettoPoint> {
|
|
|
455
562
|
return this.equals(_RistrettoPoint.ZERO);
|
|
456
563
|
}
|
|
457
564
|
}
|
|
565
|
+
Object.freeze(_RistrettoPoint.BASE);
|
|
566
|
+
Object.freeze(_RistrettoPoint.ZERO);
|
|
567
|
+
Object.freeze(_RistrettoPoint.prototype);
|
|
568
|
+
Object.freeze(_RistrettoPoint);
|
|
458
569
|
|
|
570
|
+
/** Prime-order Ristretto255 group bundle. */
|
|
459
571
|
export const ristretto255: {
|
|
460
572
|
Point: typeof _RistrettoPoint;
|
|
461
|
-
} = { Point: _RistrettoPoint };
|
|
573
|
+
} = /* @__PURE__ */ Object.freeze({ Point: _RistrettoPoint });
|
|
462
574
|
|
|
463
|
-
/**
|
|
464
|
-
|
|
575
|
+
/**
|
|
576
|
+
* Hashing to ristretto255 points / field. RFC 9380 methods.
|
|
577
|
+
* `hashToCurve()` is RFC 9380 Appendix B, `deriveToCurve()` is the RFC 9496
|
|
578
|
+
* §4.3.4 element-derivation building block, and `hashToScalar()` is a
|
|
579
|
+
* library-specific helper for OPRF-style use.
|
|
580
|
+
* @example
|
|
581
|
+
* Hash one message onto ristretto255.
|
|
582
|
+
*
|
|
583
|
+
* ```ts
|
|
584
|
+
* const point = ristretto255_hasher.hashToCurve(new TextEncoder().encode('hello noble'));
|
|
585
|
+
* ```
|
|
586
|
+
*/
|
|
587
|
+
export const ristretto255_hasher: H2CHasherBase<typeof _RistrettoPoint> = Object.freeze({
|
|
465
588
|
Point: _RistrettoPoint,
|
|
466
589
|
/**
|
|
467
590
|
* Spec: https://www.rfc-editor.org/rfc/rfc9380.html#name-hashing-to-ristretto255. Caveats:
|
|
@@ -472,18 +595,23 @@ export const ristretto255_hasher: H2CHasherBase<typeof _RistrettoPoint> = {
|
|
|
472
595
|
* * We cannot re-use 'createHasher', because ristretto255_map is different algorithm/RFC
|
|
473
596
|
(os2ip -> bytes255ToNumberLE)
|
|
474
597
|
* * mapToCurve == calcElligatorRistrettoMap, hashToCurve == ristretto255_map
|
|
475
|
-
* * hashToScalar is undefined in RFC9380 for ristretto,
|
|
598
|
+
* * hashToScalar is undefined in RFC9380 for ristretto, so we use the OPRF
|
|
599
|
+
version here. Using `bytes255ToNumblerLE` will create a different result
|
|
600
|
+
if we use `bytes255ToNumberLE` as os2ip
|
|
476
601
|
* * current version is closest to spec.
|
|
477
602
|
*/
|
|
478
|
-
hashToCurve(msg: Uint8Array
|
|
603
|
+
hashToCurve(msg: TArg<Uint8Array>, options?: TArg<H2CDSTOpts>): _RistrettoPoint {
|
|
479
604
|
// == 'hash_to_ristretto255'
|
|
480
|
-
|
|
605
|
+
// Preserve explicit empty/invalid DST overrides so expand_message_xmd() can reject them.
|
|
606
|
+
const DST = options?.DST === undefined ? 'ristretto255_XMD:SHA-512_R255MAP_RO_' : options.DST;
|
|
481
607
|
const xmd = expand_message_xmd(msg, DST, 64, sha512);
|
|
482
|
-
// NOTE: RFC 9380 incorrectly calls this function
|
|
483
|
-
//
|
|
608
|
+
// NOTE: RFC 9380 incorrectly calls this function `ristretto255_map`.
|
|
609
|
+
// In RFC 9496, `map` was the per-point function inside the construction.
|
|
610
|
+
// That also led to confusion that `ristretto255_map` is `mapToCurve`.
|
|
611
|
+
// It is not: it is the older hash-to-curve construction.
|
|
484
612
|
return ristretto255_hasher.deriveToCurve!(xmd);
|
|
485
613
|
},
|
|
486
|
-
hashToScalar(msg: Uint8Array
|
|
614
|
+
hashToScalar(msg: TArg<Uint8Array>, options: TArg<H2CDSTOpts> = { DST: _DST_scalar }) {
|
|
487
615
|
const xmd = expand_message_xmd(msg, options.DST, 64, sha512);
|
|
488
616
|
return Fn.create(bytesToNumberLE(xmd));
|
|
489
617
|
},
|
|
@@ -491,10 +619,12 @@ export const ristretto255_hasher: H2CHasherBase<typeof _RistrettoPoint> = {
|
|
|
491
619
|
* HashToCurve-like construction based on RFC 9496 (Element Derivation).
|
|
492
620
|
* Converts 64 uniform random bytes into a curve point.
|
|
493
621
|
*
|
|
494
|
-
* WARNING: This represents an older hash-to-curve construction
|
|
495
|
-
*
|
|
622
|
+
* WARNING: This represents an older hash-to-curve construction from before
|
|
623
|
+
* RFC 9380 was finalized.
|
|
624
|
+
* It was later reused as a component in the newer
|
|
625
|
+
* `hash_to_ristretto255` function defined in RFC 9380.
|
|
496
626
|
*/
|
|
497
|
-
deriveToCurve(bytes: Uint8Array): _RistrettoPoint {
|
|
627
|
+
deriveToCurve(bytes: TArg<Uint8Array>): _RistrettoPoint {
|
|
498
628
|
// https://www.rfc-editor.org/rfc/rfc9496.html#name-element-derivation
|
|
499
629
|
abytes(bytes, 64);
|
|
500
630
|
const r1 = bytes255ToNumberLE(bytes.subarray(0, 32));
|
|
@@ -503,25 +633,67 @@ export const ristretto255_hasher: H2CHasherBase<typeof _RistrettoPoint> = {
|
|
|
503
633
|
const R2 = calcElligatorRistrettoMap(r2);
|
|
504
634
|
return new _RistrettoPoint(R1.add(R2));
|
|
505
635
|
},
|
|
506
|
-
};
|
|
636
|
+
});
|
|
507
637
|
|
|
508
|
-
/**
|
|
509
|
-
|
|
510
|
-
|
|
638
|
+
/**
|
|
639
|
+
* ristretto255 OPRF/VOPRF/POPRF bundle, defined in RFC 9497.
|
|
640
|
+
* @example
|
|
641
|
+
* Run one blind/evaluate/finalize OPRF round over ristretto255.
|
|
642
|
+
*
|
|
643
|
+
* ```ts
|
|
644
|
+
* const input = new TextEncoder().encode('hello noble');
|
|
645
|
+
* const keys = ristretto255_oprf.oprf.generateKeyPair();
|
|
646
|
+
* const blind = ristretto255_oprf.oprf.blind(input);
|
|
647
|
+
* const evaluated = ristretto255_oprf.oprf.blindEvaluate(keys.secretKey, blind.blinded);
|
|
648
|
+
* const output = ristretto255_oprf.oprf.finalize(input, blind.blind, evaluated);
|
|
649
|
+
* ```
|
|
650
|
+
*/
|
|
651
|
+
export const ristretto255_oprf: TRet<OPRF> = /* @__PURE__ */ (() =>
|
|
652
|
+
createOPRF({
|
|
511
653
|
name: 'ristretto255-SHA512',
|
|
512
654
|
Point: _RistrettoPoint,
|
|
513
655
|
hash: sha512,
|
|
514
656
|
hashToGroup: ristretto255_hasher.hashToCurve,
|
|
515
657
|
hashToScalar: ristretto255_hasher.hashToScalar,
|
|
516
658
|
}))();
|
|
659
|
+
/**
|
|
660
|
+
* FROST threshold signatures over ristretto255. RFC 9591.
|
|
661
|
+
* @example
|
|
662
|
+
* Create one trusted-dealer package for 2-of-3 ristretto255 signing.
|
|
663
|
+
*
|
|
664
|
+
* ```ts
|
|
665
|
+
* const alice = ristretto255_FROST.Identifier.derive('alice@example.com');
|
|
666
|
+
* const bob = ristretto255_FROST.Identifier.derive('bob@example.com');
|
|
667
|
+
* const carol = ristretto255_FROST.Identifier.derive('carol@example.com');
|
|
668
|
+
* const deal = ristretto255_FROST.trustedDealer({ min: 2, max: 3 }, [alice, bob, carol]);
|
|
669
|
+
* ```
|
|
670
|
+
*/
|
|
671
|
+
export const ristretto255_FROST: TRet<FROST> = /* @__PURE__ */ (() =>
|
|
672
|
+
createFROST({
|
|
673
|
+
name: 'FROST-RISTRETTO255-SHA512-v1',
|
|
674
|
+
Point: _RistrettoPoint,
|
|
675
|
+
validatePoint: (p) => {
|
|
676
|
+
// Prime-order wrappers are torsion-free at the abstract-group level.
|
|
677
|
+
p.assertValidity();
|
|
678
|
+
},
|
|
679
|
+
hash: sha512,
|
|
680
|
+
}))();
|
|
517
681
|
|
|
518
682
|
/**
|
|
519
683
|
* Weird / bogus points, useful for debugging.
|
|
520
684
|
* All 8 ed25519 points of 8-torsion subgroup can be generated from the point
|
|
521
685
|
* T = `26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05`.
|
|
522
|
-
*
|
|
686
|
+
* The subgroup generated by `T` is `{ O, T, 2T, 3T, 4T, 5T, 6T, 7T }`; the
|
|
687
|
+
* array below is that set, not the powers in that exact index order.
|
|
688
|
+
* @example
|
|
689
|
+
* Decode one known torsion point for debugging.
|
|
690
|
+
*
|
|
691
|
+
* ```ts
|
|
692
|
+
* import { ED25519_TORSION_SUBGROUP, ed25519 } from '@noble/curves/ed25519.js';
|
|
693
|
+
* const point = ed25519.Point.fromHex(ED25519_TORSION_SUBGROUP[1]);
|
|
694
|
+
* ```
|
|
523
695
|
*/
|
|
524
|
-
export const ED25519_TORSION_SUBGROUP: string[] = [
|
|
696
|
+
export const ED25519_TORSION_SUBGROUP: readonly string[] = /* @__PURE__ */ Object.freeze([
|
|
525
697
|
'0100000000000000000000000000000000000000000000000000000000000000',
|
|
526
698
|
'c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a',
|
|
527
699
|
'0000000000000000000000000000000000000000000000000000000000000080',
|
|
@@ -530,4 +702,4 @@ export const ED25519_TORSION_SUBGROUP: string[] = [
|
|
|
530
702
|
'26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85',
|
|
531
703
|
'0000000000000000000000000000000000000000000000000000000000000000',
|
|
532
704
|
'c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa',
|
|
533
|
-
];
|
|
705
|
+
]);
|