@noble/curves 1.5.0 → 1.6.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 +26 -7
- package/_shortw_utils.d.ts.map +1 -1
- package/abstract/curve.d.ts +12 -0
- package/abstract/curve.d.ts.map +1 -1
- package/abstract/curve.js +55 -0
- package/abstract/curve.js.map +1 -1
- package/abstract/edwards.d.ts +1 -0
- package/abstract/edwards.d.ts.map +1 -1
- package/abstract/edwards.js +5 -0
- package/abstract/edwards.js.map +1 -1
- package/abstract/hash-to-curve.d.ts.map +1 -1
- package/abstract/hash-to-curve.js +4 -2
- package/abstract/hash-to-curve.js.map +1 -1
- package/abstract/tower.d.ts +1 -0
- package/abstract/tower.d.ts.map +1 -1
- package/abstract/tower.js +1 -0
- package/abstract/tower.js.map +1 -1
- package/abstract/weierstrass.d.ts +18 -3
- package/abstract/weierstrass.d.ts.map +1 -1
- package/abstract/weierstrass.js +101 -41
- package/abstract/weierstrass.js.map +1 -1
- package/esm/_shortw_utils.d.ts.map +1 -1
- package/esm/abstract/curve.d.ts +12 -0
- package/esm/abstract/curve.d.ts.map +1 -1
- package/esm/abstract/curve.js +55 -1
- package/esm/abstract/curve.js.map +1 -1
- package/esm/abstract/edwards.d.ts +1 -0
- package/esm/abstract/edwards.d.ts.map +1 -1
- package/esm/abstract/edwards.js +7 -2
- package/esm/abstract/edwards.js.map +1 -1
- package/esm/abstract/hash-to-curve.d.ts.map +1 -1
- package/esm/abstract/hash-to-curve.js +4 -2
- package/esm/abstract/hash-to-curve.js.map +1 -1
- package/esm/abstract/tower.d.ts +1 -0
- package/esm/abstract/tower.d.ts.map +1 -1
- package/esm/abstract/tower.js +1 -0
- package/esm/abstract/tower.js.map +1 -1
- package/esm/abstract/weierstrass.d.ts +18 -3
- package/esm/abstract/weierstrass.d.ts.map +1 -1
- package/esm/abstract/weierstrass.js +102 -42
- package/esm/abstract/weierstrass.js.map +1 -1
- package/esm/jubjub.d.ts.map +1 -1
- package/esm/jubjub.js +8 -2
- package/esm/jubjub.js.map +1 -1
- package/esm/p256.d.ts.map +1 -1
- package/esm/p384.d.ts.map +1 -1
- package/esm/p521.d.ts.map +1 -1
- package/esm/secp256k1.d.ts.map +1 -1
- package/jubjub.d.ts.map +1 -1
- package/jubjub.js +8 -2
- package/jubjub.js.map +1 -1
- package/p256.d.ts.map +1 -1
- package/p384.d.ts.map +1 -1
- package/p521.d.ts.map +1 -1
- package/package.json +26 -19
- package/secp256k1.d.ts.map +1 -1
- package/src/abstract/curve.ts +57 -1
- package/src/abstract/edwards.ts +16 -2
- package/src/abstract/hash-to-curve.ts +3 -1
- package/src/abstract/tower.ts +1 -0
- package/src/abstract/weierstrass.ts +95 -37
- package/src/jubjub.ts +7 -2
package/secp256k1.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"secp256k1.d.ts","sourceRoot":"","sources":["src/secp256k1.ts"],"names":[],"mappings":"AAKA,OAAO,EAAS,GAAG,EAAQ,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAGL,eAAe,EAGf,eAAe,EAChB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,aAAa,IAAI,SAAS,EAAuB,MAAM,2BAA2B,CAAC;AAsC5F;;GAEG;AACH,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"secp256k1.d.ts","sourceRoot":"","sources":["src/secp256k1.ts"],"names":[],"mappings":"AAKA,OAAO,EAAS,GAAG,EAAQ,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAGL,eAAe,EAGf,eAAe,EAChB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,aAAa,IAAI,SAAS,EAAuB,MAAM,2BAA2B,CAAC;AAsC5F;;GAEG;AACH,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0CAsOqje,CAAC;;;;;;oDAAwmB,CAAC;mEAA2F,CAAC;+CAAuE,CAAC;;;;yCAAoH,CAAC;;;;;;;+BAA+R,CAAC,eAAe,CAAC;;EA3L7vgB,CAAC;AAOF,iBAAS,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,UAAU,EAAE,GAAG,UAAU,CAQtE;AAkBD;;;GAGG;AACH,iBAAS,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAS5C;AASD;;GAEG;AACH,iBAAS,mBAAmB,CAAC,UAAU,EAAE,GAAG,GAAG,UAAU,CAExD;AAED;;;GAGG;AACH,iBAAS,WAAW,CAClB,OAAO,EAAE,GAAG,EACZ,UAAU,EAAE,OAAO,EACnB,OAAO,GAAE,GAAqB,GAC7B,UAAU,CAgBZ;AAED;;;GAGG;AACH,iBAAS,aAAa,CAAC,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,GAAG,OAAO,CAiB5E;AAED;;GAEG;AACH,eAAO,MAAM,OAAO;;;;;;;8BAhGS,SAAS,CAAC,MAAM,CAAC;;;;;;CA6GzC,CAAC;AA0DN,eAAO,MAAM,WAAW,2IAA4C,CAAC;AACrE,eAAO,MAAM,aAAa,2IAA8C,CAAC"}
|
package/src/abstract/curve.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
2
|
// Abelian group utilities
|
|
3
3
|
import { IField, validateField, nLength } from './modular.js';
|
|
4
|
-
import { validateObject } from './utils.js';
|
|
4
|
+
import { validateObject, bitLen } from './utils.js';
|
|
5
5
|
const _0n = BigInt(0);
|
|
6
6
|
const _1n = BigInt(1);
|
|
7
7
|
|
|
@@ -181,6 +181,62 @@ export function wNAF<T extends Group<T>>(c: GroupConstructor<T>, bits: number) {
|
|
|
181
181
|
};
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
+
/**
|
|
185
|
+
* Pippenger algorithm for multi-scalar multiplication (MSM).
|
|
186
|
+
* MSM is basically (Pa + Qb + Rc + ...).
|
|
187
|
+
* 30x faster vs naive addition on L=4096, 10x faster with precomputes.
|
|
188
|
+
* For N=254bit, L=1, it does: 1024 ADD + 254 DBL. For L=5: 1536 ADD + 254 DBL.
|
|
189
|
+
* Algorithmically constant-time (for same L), even when 1 point + scalar, or when scalar = 0.
|
|
190
|
+
* @param c Curve Point constructor
|
|
191
|
+
* @param field field over CURVE.N - important that it's not over CURVE.P
|
|
192
|
+
* @param points array of L curve points
|
|
193
|
+
* @param scalars array of L scalars (aka private keys / bigints)
|
|
194
|
+
*/
|
|
195
|
+
export function pippenger<T extends Group<T>>(
|
|
196
|
+
c: GroupConstructor<T>,
|
|
197
|
+
field: IField<bigint>,
|
|
198
|
+
points: T[],
|
|
199
|
+
scalars: bigint[]
|
|
200
|
+
): T {
|
|
201
|
+
// If we split scalars by some window (let's say 8 bits), every chunk will only
|
|
202
|
+
// take 256 buckets even if there are 4096 scalars, also re-uses double.
|
|
203
|
+
// TODO:
|
|
204
|
+
// - https://eprint.iacr.org/2024/750.pdf
|
|
205
|
+
// - https://tches.iacr.org/index.php/TCHES/article/view/10287
|
|
206
|
+
// 0 is accepted in scalars
|
|
207
|
+
if (!Array.isArray(points) || !Array.isArray(scalars) || scalars.length !== points.length)
|
|
208
|
+
throw new Error('arrays of points and scalars must have equal length');
|
|
209
|
+
scalars.forEach((s, i) => {
|
|
210
|
+
if (!field.isValid(s)) throw new Error(`wrong scalar at index ${i}`);
|
|
211
|
+
});
|
|
212
|
+
points.forEach((p, i) => {
|
|
213
|
+
if (!(p instanceof (c as any))) throw new Error(`wrong point at index ${i}`);
|
|
214
|
+
});
|
|
215
|
+
const wbits = bitLen(BigInt(points.length));
|
|
216
|
+
const windowSize = wbits > 12 ? wbits - 3 : wbits > 4 ? wbits - 2 : wbits ? 2 : 1; // in bits
|
|
217
|
+
const MASK = (1 << windowSize) - 1;
|
|
218
|
+
const buckets = new Array(MASK + 1).fill(c.ZERO); // +1 for zero array
|
|
219
|
+
const lastBits = Math.floor((field.BITS - 1) / windowSize) * windowSize;
|
|
220
|
+
let sum = c.ZERO;
|
|
221
|
+
for (let i = lastBits; i >= 0; i -= windowSize) {
|
|
222
|
+
buckets.fill(c.ZERO);
|
|
223
|
+
for (let j = 0; j < scalars.length; j++) {
|
|
224
|
+
const scalar = scalars[j];
|
|
225
|
+
const wbits = Number((scalar >> BigInt(i)) & BigInt(MASK));
|
|
226
|
+
buckets[wbits] = buckets[wbits].add(points[j]);
|
|
227
|
+
}
|
|
228
|
+
let resI = c.ZERO; // not using this will do small speed-up, but will lose ct
|
|
229
|
+
// Skip first bucket, because it is zero
|
|
230
|
+
for (let j = buckets.length - 1, sumI = c.ZERO; j > 0; j--) {
|
|
231
|
+
sumI = sumI.add(buckets[j]);
|
|
232
|
+
resI = resI.add(sumI);
|
|
233
|
+
}
|
|
234
|
+
sum = sum.add(resI);
|
|
235
|
+
if (i !== 0) for (let j = 0; j < windowSize; j++) sum = sum.double();
|
|
236
|
+
}
|
|
237
|
+
return sum as T;
|
|
238
|
+
}
|
|
239
|
+
|
|
184
240
|
// Generic BasicCurve interface: works even for polynomial fields (BLS): P, n, h would be ok.
|
|
185
241
|
// Though generator can be different (Fp2 / Fp6 for BLS).
|
|
186
242
|
export type BasicCurve<T> = {
|
package/src/abstract/edwards.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
2
|
// Twisted Edwards curve. The formula is: ax² + y² = 1 + dx²y²
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import {
|
|
4
|
+
AffinePoint,
|
|
5
|
+
BasicCurve,
|
|
6
|
+
Group,
|
|
7
|
+
GroupConstructor,
|
|
8
|
+
validateBasic,
|
|
9
|
+
wNAF,
|
|
10
|
+
pippenger,
|
|
11
|
+
} from './curve.js';
|
|
12
|
+
import { mod, Field } from './modular.js';
|
|
5
13
|
import * as ut from './utils.js';
|
|
6
14
|
import { ensureBytes, FHash, Hex, memoized, abool } from './utils.js';
|
|
7
15
|
|
|
@@ -70,6 +78,7 @@ export interface ExtPointConstructor extends GroupConstructor<ExtPointType> {
|
|
|
70
78
|
fromAffine(p: AffinePoint<bigint>): ExtPointType;
|
|
71
79
|
fromHex(hex: Hex): ExtPointType;
|
|
72
80
|
fromPrivateKey(privateKey: Hex): ExtPointType;
|
|
81
|
+
msm(points: ExtPointType[], scalars: bigint[]): ExtPointType;
|
|
73
82
|
}
|
|
74
83
|
|
|
75
84
|
/**
|
|
@@ -119,6 +128,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
119
128
|
} = CURVE;
|
|
120
129
|
const MASK = _2n << (BigInt(nByteLength * 8) - _1n);
|
|
121
130
|
const modP = Fp.create; // Function overrides
|
|
131
|
+
const Fn = Field(CURVE.n, CURVE.nBitLength);
|
|
122
132
|
|
|
123
133
|
// sqrt(u/v)
|
|
124
134
|
const uvRatio =
|
|
@@ -218,6 +228,10 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
218
228
|
const toInv = Fp.invertBatch(points.map((p) => p.ez));
|
|
219
229
|
return points.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
|
|
220
230
|
}
|
|
231
|
+
// Multiscalar Multiplication
|
|
232
|
+
static msm(points: Point[], scalars: bigint[]) {
|
|
233
|
+
return pippenger(Point, Fn, points, scalars);
|
|
234
|
+
}
|
|
221
235
|
|
|
222
236
|
// "Private method", don't use it directly
|
|
223
237
|
_setWindowSize(windowSize: number) {
|
|
@@ -27,6 +27,8 @@ const os2ip = bytesToNumberBE;
|
|
|
27
27
|
|
|
28
28
|
// Integer to Octet Stream (numberToBytesBE)
|
|
29
29
|
function i2osp(value: number, length: number): Uint8Array {
|
|
30
|
+
anum(value);
|
|
31
|
+
anum(length);
|
|
30
32
|
if (value < 0 || value >= 1 << (8 * length)) {
|
|
31
33
|
throw new Error(`bad I2OSP call: value=${value} length=${length}`);
|
|
32
34
|
}
|
|
@@ -65,7 +67,7 @@ export function expand_message_xmd(
|
|
|
65
67
|
if (DST.length > 255) DST = H(concatBytes(utf8ToBytes('H2C-OVERSIZE-DST-'), DST));
|
|
66
68
|
const { outputLen: b_in_bytes, blockLen: r_in_bytes } = H;
|
|
67
69
|
const ell = Math.ceil(lenInBytes / b_in_bytes);
|
|
68
|
-
if (ell > 255) throw new Error('
|
|
70
|
+
if (lenInBytes > 65535 || ell > 255) throw new Error('expand_message_xmd: invalid lenInBytes');
|
|
69
71
|
const DST_prime = concatBytes(DST, i2osp(DST.length, 1));
|
|
70
72
|
const Z_pad = i2osp(0, r_in_bytes);
|
|
71
73
|
const l_i_b_str = i2osp(lenInBytes, 2); // len_in_bytes_str
|
package/src/abstract/tower.ts
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
2
|
// Short Weierstrass curve. The formula is: y² = x³ + ax + b
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
AffinePoint,
|
|
5
|
+
BasicCurve,
|
|
6
|
+
Group,
|
|
7
|
+
GroupConstructor,
|
|
8
|
+
validateBasic,
|
|
9
|
+
wNAF,
|
|
10
|
+
pippenger,
|
|
11
|
+
} from './curve.js';
|
|
4
12
|
import * as mod from './modular.js';
|
|
5
13
|
import * as ut from './utils.js';
|
|
6
14
|
import { CHash, Hex, PrivKey, ensureBytes, memoized, abool } from './utils.js';
|
|
@@ -85,6 +93,7 @@ export interface ProjConstructor<T> extends GroupConstructor<ProjPointType<T>> {
|
|
|
85
93
|
fromHex(hex: Hex): ProjPointType<T>;
|
|
86
94
|
fromPrivateKey(privateKey: PrivKey): ProjPointType<T>;
|
|
87
95
|
normalizeZ(points: ProjPointType<T>[]): ProjPointType<T>[];
|
|
96
|
+
msm(points: ProjPointType<T>[], scalars: bigint[]): ProjPointType<T>;
|
|
88
97
|
}
|
|
89
98
|
|
|
90
99
|
export type CurvePointsType<T> = BasicWCurve<T> & {
|
|
@@ -135,8 +144,15 @@ export type CurvePointsRes<T> = {
|
|
|
135
144
|
isWithinCurveOrder: (num: bigint) => boolean;
|
|
136
145
|
};
|
|
137
146
|
|
|
138
|
-
// ASN.1 DER encoding utilities
|
|
139
147
|
const { bytesToNumberBE: b2n, hexToBytes: h2b } = ut;
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* ASN.1 DER encoding utilities. ASN is very complex & fragile. Format:
|
|
151
|
+
*
|
|
152
|
+
* [0x30 (SEQUENCE), bytelength, 0x02 (INTEGER), intLength, R, 0x02 (INTEGER), intLength, S]
|
|
153
|
+
*
|
|
154
|
+
* Docs: https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der/, https://luca.ntop.org/Teaching/Appunti/asn1.html
|
|
155
|
+
*/
|
|
140
156
|
export const DER = {
|
|
141
157
|
// asn.1 DER encoding utils
|
|
142
158
|
Err: class DERErr extends Error {
|
|
@@ -144,48 +160,84 @@ export const DER = {
|
|
|
144
160
|
super(m);
|
|
145
161
|
}
|
|
146
162
|
},
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
163
|
+
// Basic building block is TLV (Tag-Length-Value)
|
|
164
|
+
_tlv: {
|
|
165
|
+
encode: (tag: number, data: string) => {
|
|
166
|
+
const { Err: E } = DER;
|
|
167
|
+
if (tag < 0 || tag > 256) throw new E('tlv.encode: wrong tag');
|
|
168
|
+
if (data.length & 1) throw new E('tlv.encode: unpadded data');
|
|
169
|
+
const dataLen = data.length / 2;
|
|
170
|
+
const len = ut.numberToHexUnpadded(dataLen);
|
|
171
|
+
if ((len.length / 2) & 0b1000_0000) throw new E('tlv.encode: long form length too big');
|
|
172
|
+
// length of length with long form flag
|
|
173
|
+
const lenLen = dataLen > 127 ? ut.numberToHexUnpadded((len.length / 2) | 0b1000_0000) : '';
|
|
174
|
+
return `${ut.numberToHexUnpadded(tag)}${lenLen}${len}${data}`;
|
|
175
|
+
},
|
|
176
|
+
// v - value, l - left bytes (unparsed)
|
|
177
|
+
decode(tag: number, data: Uint8Array): { v: Uint8Array; l: Uint8Array } {
|
|
178
|
+
const { Err: E } = DER;
|
|
179
|
+
let pos = 0;
|
|
180
|
+
if (tag < 0 || tag > 256) throw new E('tlv.encode: wrong tag');
|
|
181
|
+
if (data.length < 2 || data[pos++] !== tag) throw new E('tlv.decode: wrong tlv');
|
|
182
|
+
const first = data[pos++];
|
|
183
|
+
const isLong = !!(first & 0b1000_0000); // First bit of first length byte is flag for short/long form
|
|
184
|
+
let length = 0;
|
|
185
|
+
if (!isLong) length = first;
|
|
186
|
+
else {
|
|
187
|
+
// Long form: [longFlag(1bit), lengthLength(7bit), length (BE)]
|
|
188
|
+
const lenLen = first & 0b0111_1111;
|
|
189
|
+
if (!lenLen) throw new E('tlv.decode(long): indefinite length not supported');
|
|
190
|
+
if (lenLen > 4) throw new E('tlv.decode(long): byte length is too big'); // this will overflow u32 in js
|
|
191
|
+
const lengthBytes = data.subarray(pos, pos + lenLen);
|
|
192
|
+
if (lengthBytes.length !== lenLen) throw new E('tlv.decode: length bytes not complete');
|
|
193
|
+
if (lengthBytes[0] === 0) throw new E('tlv.decode(long): zero leftmost byte');
|
|
194
|
+
for (const b of lengthBytes) length = (length << 8) | b;
|
|
195
|
+
pos += lenLen;
|
|
196
|
+
if (length < 128) throw new E('tlv.decode(long): not minimal encoding');
|
|
197
|
+
}
|
|
198
|
+
const v = data.subarray(pos, pos + length);
|
|
199
|
+
if (v.length !== length) throw new E('tlv.decode: wrong value length');
|
|
200
|
+
return { v, l: data.subarray(pos + length) };
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
// https://crypto.stackexchange.com/a/57734 Leftmost bit of first byte is 'negative' flag,
|
|
204
|
+
// since we always use positive integers here. It must always be empty:
|
|
205
|
+
// - add zero byte if exists
|
|
206
|
+
// - if next byte doesn't have a flag, leading zero is not allowed (minimal encoding)
|
|
207
|
+
_int: {
|
|
208
|
+
encode(num: bigint) {
|
|
209
|
+
const { Err: E } = DER;
|
|
210
|
+
if (num < _0n) throw new E('integer: negative integers are not allowed');
|
|
211
|
+
let hex = ut.numberToHexUnpadded(num);
|
|
212
|
+
// Pad with zero byte if negative flag is present
|
|
213
|
+
if (Number.parseInt(hex[0], 16) & 0b1000) hex = '00' + hex;
|
|
214
|
+
if (hex.length & 1) throw new E('unexpected assertion');
|
|
215
|
+
return hex;
|
|
216
|
+
},
|
|
217
|
+
decode(data: Uint8Array): bigint {
|
|
218
|
+
const { Err: E } = DER;
|
|
219
|
+
if (data[0] & 0b1000_0000) throw new E('Invalid signature integer: negative');
|
|
220
|
+
if (data[0] === 0x00 && !(data[1] & 0b1000_0000))
|
|
221
|
+
throw new E('Invalid signature integer: unnecessary leading zero');
|
|
222
|
+
return b2n(data);
|
|
223
|
+
},
|
|
161
224
|
},
|
|
162
225
|
toSig(hex: string | Uint8Array): { r: bigint; s: bigint } {
|
|
163
226
|
// parse DER signature
|
|
164
|
-
const { Err: E } = DER;
|
|
227
|
+
const { Err: E, _int: int, _tlv: tlv } = DER;
|
|
165
228
|
const data = typeof hex === 'string' ? h2b(hex) : hex;
|
|
166
229
|
ut.abytes(data);
|
|
167
|
-
|
|
168
|
-
if (
|
|
169
|
-
|
|
170
|
-
const {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
return { r, s };
|
|
230
|
+
const { v: seqBytes, l: seqLeftBytes } = tlv.decode(0x30, data);
|
|
231
|
+
if (seqLeftBytes.length) throw new E('Invalid signature: left bytes after parsing');
|
|
232
|
+
const { v: rBytes, l: rLeftBytes } = tlv.decode(0x02, seqBytes);
|
|
233
|
+
const { v: sBytes, l: sLeftBytes } = tlv.decode(0x02, rLeftBytes);
|
|
234
|
+
if (sLeftBytes.length) throw new E('Invalid signature: left bytes after parsing');
|
|
235
|
+
return { r: int.decode(rBytes), s: int.decode(sBytes) };
|
|
174
236
|
},
|
|
175
237
|
hexFromSig(sig: { r: bigint; s: bigint }): string {
|
|
176
|
-
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
const hex = num.toString(16);
|
|
180
|
-
return hex.length & 1 ? `0${hex}` : hex;
|
|
181
|
-
};
|
|
182
|
-
const s = slice(h(sig.s));
|
|
183
|
-
const r = slice(h(sig.r));
|
|
184
|
-
const shl = s.length / 2;
|
|
185
|
-
const rhl = r.length / 2;
|
|
186
|
-
const sl = h(shl);
|
|
187
|
-
const rl = h(rhl);
|
|
188
|
-
return `30${h(rhl + shl + 4)}02${rl}${r}02${sl}${s}`;
|
|
238
|
+
const { _tlv: tlv, _int: int } = DER;
|
|
239
|
+
const seq = `${tlv.encode(0x02, int.encode(sig.r))}${tlv.encode(0x02, int.encode(sig.s))}`;
|
|
240
|
+
return tlv.encode(0x30, seq);
|
|
189
241
|
},
|
|
190
242
|
};
|
|
191
243
|
|
|
@@ -196,6 +248,7 @@ const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3), _4n =
|
|
|
196
248
|
export function weierstrassPoints<T>(opts: CurvePointsType<T>): CurvePointsRes<T> {
|
|
197
249
|
const CURVE = validatePointOpts(opts);
|
|
198
250
|
const { Fp } = CURVE; // All curves has same field / group length as for now, but they can differ
|
|
251
|
+
const Fn = mod.Field(CURVE.n, CURVE.nBitLength);
|
|
199
252
|
|
|
200
253
|
const toBytes =
|
|
201
254
|
CURVE.toBytes ||
|
|
@@ -369,6 +422,11 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>): CurvePointsRes<T
|
|
|
369
422
|
return Point.BASE.multiply(normPrivateKeyToScalar(privateKey));
|
|
370
423
|
}
|
|
371
424
|
|
|
425
|
+
// Multiscalar Multiplication
|
|
426
|
+
static msm(points: Point[], scalars: bigint[]) {
|
|
427
|
+
return pippenger(Point, Fn, points, scalars);
|
|
428
|
+
}
|
|
429
|
+
|
|
372
430
|
// "Private method", don't use it directly
|
|
373
431
|
_setWindowSize(windowSize: number) {
|
|
374
432
|
wnaf.setWindowSize(this, windowSize);
|
package/src/jubjub.ts
CHANGED
|
@@ -46,13 +46,18 @@ export function groupHash(tag: Uint8Array, personalization: Uint8Array) {
|
|
|
46
46
|
return p;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
// No secret data is leaked here at all.
|
|
50
|
+
// It operates over public data:
|
|
51
|
+
// const G_SPEND = jubjub.findGroupHash(new Uint8Array(), utf8ToBytes('Item_G_'));
|
|
49
52
|
export function findGroupHash(m: Uint8Array, personalization: Uint8Array) {
|
|
50
53
|
const tag = concatBytes(m, new Uint8Array([0]));
|
|
54
|
+
const hashes = [];
|
|
51
55
|
for (let i = 0; i < 256; i++) {
|
|
52
56
|
tag[tag.length - 1] = i;
|
|
53
57
|
try {
|
|
54
|
-
|
|
58
|
+
hashes.push(groupHash(tag, personalization));
|
|
55
59
|
} catch (e) {}
|
|
56
60
|
}
|
|
57
|
-
throw new Error('findGroupHash tag overflow');
|
|
61
|
+
if (!hashes.length) throw new Error('findGroupHash tag overflow');
|
|
62
|
+
return hashes[0];
|
|
58
63
|
}
|