@noble/curves 2.0.0 → 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 +89 -24
- 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 +327 -10
- package/abstract/fft.d.ts.map +1 -1
- package/abstract/fft.js +155 -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 +135 -14
- package/ed25519.d.ts.map +1 -1
- package/ed25519.js +207 -41
- 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 +34 -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 +356 -69
- package/src/abstract/curve.ts +327 -44
- package/src/abstract/edwards.ts +367 -143
- package/src/abstract/fft.ts +371 -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 +234 -56
- 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,20 +257,28 @@ 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
|
|
|
267
|
+
/**
|
|
268
|
+
* RFC 9380 method `map_to_curve_elligator2_curve25519`. Experimental name: may be renamed later.
|
|
269
|
+
* @private
|
|
270
|
+
*/
|
|
189
271
|
// prettier-ignore
|
|
190
|
-
function
|
|
272
|
+
export function _map_to_curve_elligator2_curve25519(u: bigint): {
|
|
273
|
+
xMn: bigint, xMd: bigint, yMn: bigint, yMd: bigint
|
|
274
|
+
} {
|
|
191
275
|
const ELL2_C4 = (ed25519_CURVE_p - _5n) / _8n; // 4. c4 = (q - 5) / 8 # Integer arithmetic
|
|
192
276
|
const ELL2_J = BigInt(486662);
|
|
193
277
|
|
|
194
278
|
let tv1 = Fp.sqr(u); // 1. tv1 = u^2
|
|
195
279
|
tv1 = Fp.mul(tv1, _2n); // 2. tv1 = 2 * tv1
|
|
196
|
-
|
|
280
|
+
// 3. xd = tv1 + 1 # Nonzero: -1 is square (mod p), tv1 is not
|
|
281
|
+
let xd = Fp.add(tv1, Fp.ONE);
|
|
197
282
|
let x1n = Fp.neg(ELL2_J); // 4. x1n = -J # x1 = x1n / xd = -J / (1 + 2 * u^2)
|
|
198
283
|
let tv2 = Fp.sqr(xd); // 5. tv2 = xd^2
|
|
199
284
|
let gxd = Fp.mul(tv2, xd); // 6. gxd = tv2 * xd # gxd = xd^3
|
|
@@ -212,7 +297,8 @@ function map_to_curve_elligator2_curve25519(u: bigint) {
|
|
|
212
297
|
tv2 = Fp.sqr(y11); // 19. tv2 = y11^2
|
|
213
298
|
tv2 = Fp.mul(tv2, gxd); // 20. tv2 = tv2 * gxd
|
|
214
299
|
let e1 = Fp.eql(tv2, gx1); // 21. e1 = tv2 == gx1
|
|
215
|
-
|
|
300
|
+
// 22. y1 = CMOV(y12, y11, e1) # If g(x1) is square, this is its sqrt
|
|
301
|
+
let y1 = Fp.cmov(y12, y11, e1);
|
|
216
302
|
let x2n = Fp.mul(x1n, tv1); // 23. x2n = x1n * tv1 # x2 = x2n / xd = 2 * u^2 * x1n / xd
|
|
217
303
|
let y21 = Fp.mul(y11, u); // 24. y21 = y11 * u
|
|
218
304
|
y21 = Fp.mul(y21, ELL2_C2); // 25. y21 = y21 * c2
|
|
@@ -221,7 +307,8 @@ function map_to_curve_elligator2_curve25519(u: bigint) {
|
|
|
221
307
|
tv2 = Fp.sqr(y21); // 28. tv2 = y21^2
|
|
222
308
|
tv2 = Fp.mul(tv2, gxd); // 29. tv2 = tv2 * gxd
|
|
223
309
|
let e2 = Fp.eql(tv2, gx2); // 30. e2 = tv2 == gx2
|
|
224
|
-
|
|
310
|
+
// 31. y2 = CMOV(y22, y21, e2) # If g(x2) is square, this is its sqrt
|
|
311
|
+
let y2 = Fp.cmov(y22, y21, e2);
|
|
225
312
|
tv2 = Fp.sqr(y1); // 32. tv2 = y1^2
|
|
226
313
|
tv2 = Fp.mul(tv2, gxd); // 33. tv2 = tv2 * gxd
|
|
227
314
|
let e3 = Fp.eql(tv2, gx1); // 34. e3 = tv2 == gx1
|
|
@@ -232,15 +319,18 @@ function map_to_curve_elligator2_curve25519(u: bigint) {
|
|
|
232
319
|
return { xMn: xn, xMd: xd, yMn: y, yMd: _1n }; // 39. return (xn, xd, y, 1)
|
|
233
320
|
}
|
|
234
321
|
|
|
235
|
-
|
|
322
|
+
// sgn0(c1) MUST equal 0
|
|
323
|
+
const ELL2_C1_EDWARDS = /* @__PURE__ */ (() => FpSqrtEven(Fp, Fp.neg(BigInt(486664))))();
|
|
236
324
|
function map_to_curve_elligator2_edwards25519(u: bigint) {
|
|
237
|
-
|
|
325
|
+
// 1. (xMn, xMd, yMn, yMd) = map_to_curve_elligator2_curve25519(u)
|
|
326
|
+
const { xMn, xMd, yMn, yMd } = _map_to_curve_elligator2_curve25519(u);
|
|
238
327
|
// map_to_curve_elligator2_curve25519(u)
|
|
239
328
|
let xn = Fp.mul(xMn, yMd); // 2. xn = xMn * yMd
|
|
240
329
|
xn = Fp.mul(xn, ELL2_C1_EDWARDS); // 3. xn = xn * c1
|
|
241
330
|
let xd = Fp.mul(xMd, yMn); // 4. xd = xMd * yMn # xn / xd = c1 * xM / yM
|
|
242
331
|
let yn = Fp.sub(xMn, xMd); // 5. yn = xMn - xMd
|
|
243
|
-
|
|
332
|
+
// 6. yd = xMn + xMd # (n / d - 1) / (n / d + 1) = (n - d) / (n + d)
|
|
333
|
+
let yd = Fp.add(xMn, xMd);
|
|
244
334
|
let tv1 = Fp.mul(xd, yd); // 7. tv1 = xd * yd
|
|
245
335
|
let e = Fp.eql(tv1, Fp.ZERO); // 8. e = tv1 == 0
|
|
246
336
|
xn = Fp.cmov(xn, Fp.ZERO, e); // 9. xn = CMOV(xn, 0, e)
|
|
@@ -248,10 +338,22 @@ function map_to_curve_elligator2_edwards25519(u: bigint) {
|
|
|
248
338
|
yn = Fp.cmov(yn, Fp.ONE, e); // 11. yn = CMOV(yn, 1, e)
|
|
249
339
|
yd = Fp.cmov(yd, Fp.ONE, e); // 12. yd = CMOV(yd, 1, e)
|
|
250
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.
|
|
251
343
|
return { x: Fp.mul(xn, xd_inv), y: Fp.mul(yn, yd_inv) }; // 13. return (xn, xd, yn, yd)
|
|
252
344
|
}
|
|
253
345
|
|
|
254
|
-
/**
|
|
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
|
+
*/
|
|
255
357
|
export const ed25519_hasher: H2CHasher<EdwardsPointCons> = /* @__PURE__ */ (() =>
|
|
256
358
|
createHasher(
|
|
257
359
|
ed25519_Point,
|
|
@@ -285,18 +387,23 @@ const ONE_MINUS_D_SQ = /* @__PURE__ */ BigInt(
|
|
|
285
387
|
const D_MINUS_ONE_SQ = /* @__PURE__ */ BigInt(
|
|
286
388
|
'40440834346308536858101042469323190826248399146238708352240133220865137265952'
|
|
287
389
|
);
|
|
288
|
-
//
|
|
390
|
+
// `SQRT_RATIO_M1(1, number)` specialization. Returns `{ isValid, value }`,
|
|
391
|
+
// where non-squares get the nonnegative `sqrt(SQRT_M1 / number)` branch.
|
|
289
392
|
const invertSqrt = (number: bigint) => uvRatio(_1n, number);
|
|
290
393
|
|
|
291
394
|
const MAX_255B = /* @__PURE__ */ BigInt(
|
|
292
395
|
'0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
|
|
293
396
|
);
|
|
294
|
-
|
|
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);
|
|
295
401
|
|
|
296
402
|
/**
|
|
297
403
|
* Computes Elligator map for Ristretto255.
|
|
298
|
-
*
|
|
299
|
-
*
|
|
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`.
|
|
300
407
|
*/
|
|
301
408
|
function calcElligatorRistrettoMap(r0: bigint): EdwardsPoint {
|
|
302
409
|
const { d } = ed25519_CURVE;
|
|
@@ -349,6 +456,12 @@ class _RistrettoPoint extends PrimeEdwardsPoint<_RistrettoPoint> {
|
|
|
349
456
|
super(ep);
|
|
350
457
|
}
|
|
351
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
|
+
*/
|
|
352
465
|
static fromAffine(ap: AffinePoint<bigint>): _RistrettoPoint {
|
|
353
466
|
return new _RistrettoPoint(ed25519_Point.fromAffine(ap));
|
|
354
467
|
}
|
|
@@ -361,7 +474,7 @@ class _RistrettoPoint extends PrimeEdwardsPoint<_RistrettoPoint> {
|
|
|
361
474
|
return new _RistrettoPoint(ep);
|
|
362
475
|
}
|
|
363
476
|
|
|
364
|
-
static fromBytes(bytes: Uint8Array): _RistrettoPoint {
|
|
477
|
+
static fromBytes(bytes: TArg<Uint8Array>): _RistrettoPoint {
|
|
365
478
|
abytes(bytes, 32);
|
|
366
479
|
const { a, d } = ed25519_CURVE;
|
|
367
480
|
const P = ed25519_CURVE_p;
|
|
@@ -392,7 +505,7 @@ class _RistrettoPoint extends PrimeEdwardsPoint<_RistrettoPoint> {
|
|
|
392
505
|
/**
|
|
393
506
|
* Converts ristretto-encoded string to ristretto point.
|
|
394
507
|
* Described in [RFC9496](https://www.rfc-editor.org/rfc/rfc9496#name-decode).
|
|
395
|
-
* @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
|
|
396
509
|
*/
|
|
397
510
|
static fromHex(hex: string): _RistrettoPoint {
|
|
398
511
|
return _RistrettoPoint.fromBytes(hexToBytes(hex));
|
|
@@ -402,7 +515,7 @@ class _RistrettoPoint extends PrimeEdwardsPoint<_RistrettoPoint> {
|
|
|
402
515
|
* Encodes ristretto point to Uint8Array.
|
|
403
516
|
* Described in [RFC9496](https://www.rfc-editor.org/rfc/rfc9496#name-encode).
|
|
404
517
|
*/
|
|
405
|
-
toBytes(): Uint8Array {
|
|
518
|
+
toBytes(): TRet<Uint8Array> {
|
|
406
519
|
let { X, Y, Z, T } = this.ep;
|
|
407
520
|
const P = ed25519_CURVE_p;
|
|
408
521
|
const mod = (n: bigint) => Fp.create(n);
|
|
@@ -427,7 +540,7 @@ class _RistrettoPoint extends PrimeEdwardsPoint<_RistrettoPoint> {
|
|
|
427
540
|
if (isNegativeLE(X * zInv, P)) Y = mod(-Y); // 9
|
|
428
541
|
let s = mod((Z - Y) * D); // 10 (check footer's note, no sqrt(-a))
|
|
429
542
|
if (isNegativeLE(s, P)) s = mod(-s);
|
|
430
|
-
return Fp.toBytes(s)
|
|
543
|
+
return Fp.toBytes(s) as TRet<Uint8Array>; // 11
|
|
431
544
|
}
|
|
432
545
|
|
|
433
546
|
/**
|
|
@@ -449,13 +562,29 @@ class _RistrettoPoint extends PrimeEdwardsPoint<_RistrettoPoint> {
|
|
|
449
562
|
return this.equals(_RistrettoPoint.ZERO);
|
|
450
563
|
}
|
|
451
564
|
}
|
|
565
|
+
Object.freeze(_RistrettoPoint.BASE);
|
|
566
|
+
Object.freeze(_RistrettoPoint.ZERO);
|
|
567
|
+
Object.freeze(_RistrettoPoint.prototype);
|
|
568
|
+
Object.freeze(_RistrettoPoint);
|
|
452
569
|
|
|
570
|
+
/** Prime-order Ristretto255 group bundle. */
|
|
453
571
|
export const ristretto255: {
|
|
454
572
|
Point: typeof _RistrettoPoint;
|
|
455
|
-
} = { Point: _RistrettoPoint };
|
|
573
|
+
} = /* @__PURE__ */ Object.freeze({ Point: _RistrettoPoint });
|
|
456
574
|
|
|
457
|
-
/**
|
|
458
|
-
|
|
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({
|
|
459
588
|
Point: _RistrettoPoint,
|
|
460
589
|
/**
|
|
461
590
|
* Spec: https://www.rfc-editor.org/rfc/rfc9380.html#name-hashing-to-ristretto255. Caveats:
|
|
@@ -466,18 +595,23 @@ export const ristretto255_hasher: H2CHasherBase<typeof _RistrettoPoint> = {
|
|
|
466
595
|
* * We cannot re-use 'createHasher', because ristretto255_map is different algorithm/RFC
|
|
467
596
|
(os2ip -> bytes255ToNumberLE)
|
|
468
597
|
* * mapToCurve == calcElligatorRistrettoMap, hashToCurve == ristretto255_map
|
|
469
|
-
* * 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
|
|
470
601
|
* * current version is closest to spec.
|
|
471
602
|
*/
|
|
472
|
-
hashToCurve(msg: Uint8Array
|
|
603
|
+
hashToCurve(msg: TArg<Uint8Array>, options?: TArg<H2CDSTOpts>): _RistrettoPoint {
|
|
473
604
|
// == 'hash_to_ristretto255'
|
|
474
|
-
|
|
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;
|
|
475
607
|
const xmd = expand_message_xmd(msg, DST, 64, sha512);
|
|
476
|
-
// NOTE: RFC 9380 incorrectly calls this function
|
|
477
|
-
//
|
|
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.
|
|
478
612
|
return ristretto255_hasher.deriveToCurve!(xmd);
|
|
479
613
|
},
|
|
480
|
-
hashToScalar(msg: Uint8Array
|
|
614
|
+
hashToScalar(msg: TArg<Uint8Array>, options: TArg<H2CDSTOpts> = { DST: _DST_scalar }) {
|
|
481
615
|
const xmd = expand_message_xmd(msg, options.DST, 64, sha512);
|
|
482
616
|
return Fn.create(bytesToNumberLE(xmd));
|
|
483
617
|
},
|
|
@@ -485,10 +619,12 @@ export const ristretto255_hasher: H2CHasherBase<typeof _RistrettoPoint> = {
|
|
|
485
619
|
* HashToCurve-like construction based on RFC 9496 (Element Derivation).
|
|
486
620
|
* Converts 64 uniform random bytes into a curve point.
|
|
487
621
|
*
|
|
488
|
-
* WARNING: This represents an older hash-to-curve construction
|
|
489
|
-
*
|
|
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.
|
|
490
626
|
*/
|
|
491
|
-
deriveToCurve(bytes: Uint8Array): _RistrettoPoint {
|
|
627
|
+
deriveToCurve(bytes: TArg<Uint8Array>): _RistrettoPoint {
|
|
492
628
|
// https://www.rfc-editor.org/rfc/rfc9496.html#name-element-derivation
|
|
493
629
|
abytes(bytes, 64);
|
|
494
630
|
const r1 = bytes255ToNumberLE(bytes.subarray(0, 32));
|
|
@@ -497,25 +633,67 @@ export const ristretto255_hasher: H2CHasherBase<typeof _RistrettoPoint> = {
|
|
|
497
633
|
const R2 = calcElligatorRistrettoMap(r2);
|
|
498
634
|
return new _RistrettoPoint(R1.add(R2));
|
|
499
635
|
},
|
|
500
|
-
};
|
|
636
|
+
});
|
|
501
637
|
|
|
502
|
-
/**
|
|
503
|
-
|
|
504
|
-
|
|
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({
|
|
505
653
|
name: 'ristretto255-SHA512',
|
|
506
654
|
Point: _RistrettoPoint,
|
|
507
655
|
hash: sha512,
|
|
508
656
|
hashToGroup: ristretto255_hasher.hashToCurve,
|
|
509
657
|
hashToScalar: ristretto255_hasher.hashToScalar,
|
|
510
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
|
+
}))();
|
|
511
681
|
|
|
512
682
|
/**
|
|
513
683
|
* Weird / bogus points, useful for debugging.
|
|
514
684
|
* All 8 ed25519 points of 8-torsion subgroup can be generated from the point
|
|
515
685
|
* T = `26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05`.
|
|
516
|
-
*
|
|
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
|
+
* ```
|
|
517
695
|
*/
|
|
518
|
-
export const ED25519_TORSION_SUBGROUP: string[] = [
|
|
696
|
+
export const ED25519_TORSION_SUBGROUP: readonly string[] = /* @__PURE__ */ Object.freeze([
|
|
519
697
|
'0100000000000000000000000000000000000000000000000000000000000000',
|
|
520
698
|
'c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a',
|
|
521
699
|
'0000000000000000000000000000000000000000000000000000000000000080',
|
|
@@ -524,4 +702,4 @@ export const ED25519_TORSION_SUBGROUP: string[] = [
|
|
|
524
702
|
'26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85',
|
|
525
703
|
'0000000000000000000000000000000000000000000000000000000000000000',
|
|
526
704
|
'c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa',
|
|
527
|
-
];
|
|
705
|
+
]);
|