@noble/curves 1.9.1 → 1.9.2
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 +56 -25
- package/_shortw_utils.d.ts +7 -5
- package/_shortw_utils.d.ts.map +1 -1
- package/_shortw_utils.js +2 -8
- package/_shortw_utils.js.map +1 -1
- package/abstract/bls.d.ts +60 -24
- package/abstract/bls.d.ts.map +1 -1
- package/abstract/bls.js +158 -109
- package/abstract/bls.js.map +1 -1
- package/abstract/curve.d.ts +44 -9
- package/abstract/curve.d.ts.map +1 -1
- package/abstract/curve.js +86 -7
- package/abstract/curve.js.map +1 -1
- package/abstract/edwards.d.ts +112 -25
- package/abstract/edwards.d.ts.map +1 -1
- package/abstract/edwards.js +138 -102
- package/abstract/edwards.js.map +1 -1
- package/abstract/fft.d.ts +12 -10
- package/abstract/fft.d.ts.map +1 -1
- package/abstract/fft.js +12 -13
- package/abstract/fft.js.map +1 -1
- package/abstract/hash-to-curve.d.ts +25 -11
- package/abstract/hash-to-curve.d.ts.map +1 -1
- package/abstract/hash-to-curve.js +17 -14
- package/abstract/hash-to-curve.js.map +1 -1
- package/abstract/modular.d.ts +24 -11
- package/abstract/modular.d.ts.map +1 -1
- package/abstract/modular.js +49 -20
- package/abstract/modular.js.map +1 -1
- package/abstract/montgomery.d.ts +1 -1
- package/abstract/montgomery.d.ts.map +1 -1
- package/abstract/montgomery.js +5 -4
- package/abstract/montgomery.js.map +1 -1
- package/abstract/poseidon.d.ts +5 -13
- package/abstract/poseidon.d.ts.map +1 -1
- package/abstract/poseidon.js +12 -7
- package/abstract/poseidon.js.map +1 -1
- package/abstract/tower.d.ts +20 -46
- package/abstract/tower.d.ts.map +1 -1
- package/abstract/tower.js +9 -3
- package/abstract/tower.js.map +1 -1
- package/abstract/utils.d.ts +1 -115
- package/abstract/utils.d.ts.map +1 -1
- package/abstract/utils.js +17 -371
- package/abstract/utils.js.map +1 -1
- package/abstract/weierstrass.d.ts +132 -76
- package/abstract/weierstrass.d.ts.map +1 -1
- package/abstract/weierstrass.js +462 -398
- package/abstract/weierstrass.js.map +1 -1
- package/bls12-381.d.ts +2 -0
- package/bls12-381.d.ts.map +1 -1
- package/bls12-381.js +504 -466
- package/bls12-381.js.map +1 -1
- package/bn254.d.ts +2 -0
- package/bn254.d.ts.map +1 -1
- package/bn254.js +44 -32
- package/bn254.js.map +1 -1
- package/ed25519.d.ts +8 -5
- package/ed25519.d.ts.map +1 -1
- package/ed25519.js +67 -54
- package/ed25519.js.map +1 -1
- package/ed448.d.ts +10 -6
- package/ed448.d.ts.map +1 -1
- package/ed448.js +80 -57
- package/ed448.js.map +1 -1
- package/esm/_shortw_utils.d.ts +7 -5
- package/esm/_shortw_utils.d.ts.map +1 -1
- package/esm/_shortw_utils.js +2 -8
- package/esm/_shortw_utils.js.map +1 -1
- package/esm/abstract/bls.d.ts +60 -24
- package/esm/abstract/bls.d.ts.map +1 -1
- package/esm/abstract/bls.js +158 -109
- package/esm/abstract/bls.js.map +1 -1
- package/esm/abstract/curve.d.ts +44 -9
- package/esm/abstract/curve.d.ts.map +1 -1
- package/esm/abstract/curve.js +83 -8
- package/esm/abstract/curve.js.map +1 -1
- package/esm/abstract/edwards.d.ts +112 -25
- package/esm/abstract/edwards.d.ts.map +1 -1
- package/esm/abstract/edwards.js +138 -104
- package/esm/abstract/edwards.js.map +1 -1
- package/esm/abstract/fft.d.ts +12 -10
- package/esm/abstract/fft.d.ts.map +1 -1
- package/esm/abstract/fft.js +10 -11
- package/esm/abstract/fft.js.map +1 -1
- package/esm/abstract/hash-to-curve.d.ts +25 -11
- package/esm/abstract/hash-to-curve.d.ts.map +1 -1
- package/esm/abstract/hash-to-curve.js +17 -14
- package/esm/abstract/hash-to-curve.js.map +1 -1
- package/esm/abstract/modular.d.ts +24 -11
- package/esm/abstract/modular.d.ts.map +1 -1
- package/esm/abstract/modular.js +48 -19
- package/esm/abstract/modular.js.map +1 -1
- package/esm/abstract/montgomery.d.ts +1 -1
- package/esm/abstract/montgomery.d.ts.map +1 -1
- package/esm/abstract/montgomery.js +5 -4
- package/esm/abstract/montgomery.js.map +1 -1
- package/esm/abstract/poseidon.d.ts +5 -13
- package/esm/abstract/poseidon.d.ts.map +1 -1
- package/esm/abstract/poseidon.js +12 -7
- package/esm/abstract/poseidon.js.map +1 -1
- package/esm/abstract/tower.d.ts +20 -46
- package/esm/abstract/tower.d.ts.map +1 -1
- package/esm/abstract/tower.js +9 -3
- package/esm/abstract/tower.js.map +1 -1
- package/esm/abstract/utils.d.ts +1 -115
- package/esm/abstract/utils.d.ts.map +1 -1
- package/esm/abstract/utils.js +3 -344
- package/esm/abstract/utils.js.map +1 -1
- package/esm/abstract/weierstrass.d.ts +132 -76
- package/esm/abstract/weierstrass.d.ts.map +1 -1
- package/esm/abstract/weierstrass.js +460 -400
- package/esm/abstract/weierstrass.js.map +1 -1
- package/esm/bls12-381.d.ts +2 -0
- package/esm/bls12-381.d.ts.map +1 -1
- package/esm/bls12-381.js +503 -465
- package/esm/bls12-381.js.map +1 -1
- package/esm/bn254.d.ts +2 -0
- package/esm/bn254.d.ts.map +1 -1
- package/esm/bn254.js +41 -29
- package/esm/bn254.js.map +1 -1
- package/esm/ed25519.d.ts +8 -5
- package/esm/ed25519.d.ts.map +1 -1
- package/esm/ed25519.js +62 -49
- package/esm/ed25519.js.map +1 -1
- package/esm/ed448.d.ts +10 -6
- package/esm/ed448.d.ts.map +1 -1
- package/esm/ed448.js +74 -51
- package/esm/ed448.js.map +1 -1
- package/esm/misc.d.ts.map +1 -1
- package/esm/misc.js +31 -26
- package/esm/misc.js.map +1 -1
- package/esm/nist.d.ts +7 -16
- package/esm/nist.d.ts.map +1 -1
- package/esm/nist.js +86 -97
- package/esm/nist.js.map +1 -1
- package/esm/p256.d.ts +3 -3
- package/esm/p384.d.ts +3 -3
- package/esm/p521.d.ts +3 -3
- package/esm/secp256k1.d.ts +6 -6
- package/esm/secp256k1.d.ts.map +1 -1
- package/esm/secp256k1.js +43 -40
- package/esm/secp256k1.js.map +1 -1
- package/esm/utils.d.ts +96 -0
- package/esm/utils.d.ts.map +1 -0
- package/esm/utils.js +279 -0
- package/esm/utils.js.map +1 -0
- package/misc.d.ts.map +1 -1
- package/misc.js +35 -30
- package/misc.js.map +1 -1
- package/nist.d.ts +7 -16
- package/nist.d.ts.map +1 -1
- package/nist.js +86 -97
- package/nist.js.map +1 -1
- package/p256.d.ts +3 -3
- package/p384.d.ts +3 -3
- package/p521.d.ts +3 -3
- package/package.json +14 -5
- package/secp256k1.d.ts +6 -6
- package/secp256k1.d.ts.map +1 -1
- package/secp256k1.js +46 -43
- package/secp256k1.js.map +1 -1
- package/src/_shortw_utils.ts +5 -15
- package/src/abstract/bls.ts +260 -145
- package/src/abstract/curve.ts +115 -13
- package/src/abstract/edwards.ts +279 -138
- package/src/abstract/fft.ts +30 -19
- package/src/abstract/hash-to-curve.ts +51 -27
- package/src/abstract/modular.ts +49 -28
- package/src/abstract/montgomery.ts +9 -7
- package/src/abstract/poseidon.ts +22 -18
- package/src/abstract/tower.ts +36 -67
- package/src/abstract/utils.ts +3 -378
- package/src/abstract/weierstrass.ts +700 -453
- package/src/bls12-381.ts +540 -489
- package/src/bn254.ts +47 -35
- package/src/ed25519.ts +80 -64
- package/src/ed448.ts +129 -92
- package/src/misc.ts +39 -34
- package/src/nist.ts +138 -127
- package/src/p256.ts +3 -3
- package/src/p384.ts +3 -3
- package/src/p521.ts +3 -3
- package/src/secp256k1.ts +58 -46
- package/src/utils.ts +328 -0
- package/utils.d.ts +96 -0
- package/utils.d.ts.map +1 -0
- package/utils.js +313 -0
- package/utils.js.map +1 -0
package/src/abstract/edwards.ts
CHANGED
|
@@ -1,65 +1,61 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Twisted Edwards curve. The formula is: ax² + y² = 1 + dx²y².
|
|
3
3
|
* For design rationale of types / exports, see weierstrass module documentation.
|
|
4
|
+
* Untwisted Edwards curves exist, but they aren't used in real-world protocols.
|
|
4
5
|
* @module
|
|
5
6
|
*/
|
|
6
7
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
7
|
-
// prettier-ignore
|
|
8
8
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
_validateObject,
|
|
10
|
+
abool,
|
|
11
|
+
abytes,
|
|
12
|
+
aInRange,
|
|
13
|
+
bytesToHex,
|
|
14
|
+
bytesToNumberLE,
|
|
15
|
+
concatBytes,
|
|
16
|
+
ensureBytes,
|
|
17
|
+
memoized,
|
|
18
|
+
numberToBytesLE,
|
|
19
|
+
randomBytes,
|
|
20
|
+
type FHash,
|
|
21
|
+
type Hex,
|
|
22
|
+
} from '../utils.ts';
|
|
14
23
|
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
24
|
+
_createCurveFields,
|
|
25
|
+
normalizeZ,
|
|
26
|
+
pippenger,
|
|
27
|
+
wNAF,
|
|
28
|
+
type AffinePoint,
|
|
29
|
+
type BasicCurve,
|
|
30
|
+
type Group,
|
|
31
|
+
type GroupConstructor,
|
|
32
|
+
} from './curve.ts';
|
|
33
|
+
import { Field, type IField, type NLength } from './modular.ts';
|
|
19
34
|
|
|
20
35
|
// Be friendly to bad ECMAScript parsers by not using bigint literals
|
|
21
36
|
// prettier-ignore
|
|
22
37
|
const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _8n = BigInt(8);
|
|
23
38
|
|
|
39
|
+
export type UVRatio = (u: bigint, v: bigint) => { isValid: boolean; value: bigint };
|
|
40
|
+
|
|
24
41
|
/** Edwards curves must declare params a & d. */
|
|
25
42
|
export type CurveType = BasicCurve<bigint> & {
|
|
26
43
|
a: bigint; // curve param a
|
|
27
44
|
d: bigint; // curve param d
|
|
28
45
|
hash: FHash; // Hashing
|
|
29
|
-
randomBytes
|
|
46
|
+
randomBytes?: (bytesLength?: number) => Uint8Array; // CSPRNG
|
|
30
47
|
adjustScalarBytes?: (bytes: Uint8Array) => Uint8Array; // clears bits to get valid field elemtn
|
|
31
48
|
domain?: (data: Uint8Array, ctx: Uint8Array, phflag: boolean) => Uint8Array; // Used for hashing
|
|
32
|
-
uvRatio?:
|
|
49
|
+
uvRatio?: UVRatio; // Ratio √(u/v)
|
|
33
50
|
prehash?: FHash; // RFC 8032 pre-hashing of messages to sign() / verify()
|
|
34
51
|
mapToCurve?: (scalar: bigint[]) => AffinePoint<bigint>; // for hash-to-curve standard
|
|
35
52
|
};
|
|
36
53
|
|
|
37
|
-
export type CurveTypeWithLength = Readonly<CurveType &
|
|
54
|
+
export type CurveTypeWithLength = Readonly<CurveType & Partial<NLength>>;
|
|
38
55
|
|
|
39
56
|
// verification rule is either zip215 or rfc8032 / nist186-5. Consult fromHex:
|
|
40
57
|
const VERIFY_DEFAULT = { zip215: true };
|
|
41
58
|
|
|
42
|
-
function validateOpts(curve: CurveType): CurveTypeWithLength {
|
|
43
|
-
const opts = validateBasic(curve);
|
|
44
|
-
validateObject(
|
|
45
|
-
curve,
|
|
46
|
-
{
|
|
47
|
-
hash: 'function',
|
|
48
|
-
a: 'bigint',
|
|
49
|
-
d: 'bigint',
|
|
50
|
-
randomBytes: 'function',
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
adjustScalarBytes: 'function',
|
|
54
|
-
domain: 'function',
|
|
55
|
-
uvRatio: 'function',
|
|
56
|
-
mapToCurve: 'function',
|
|
57
|
-
}
|
|
58
|
-
);
|
|
59
|
-
// Set defaults
|
|
60
|
-
return Object.freeze({ ...opts } as const);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
59
|
/** Instance of Extended Point with coordinates in X, Y, Z, T. */
|
|
64
60
|
export interface ExtPointType extends Group<ExtPointType> {
|
|
65
61
|
readonly ex: bigint;
|
|
@@ -71,29 +67,115 @@ export interface ExtPointType extends Group<ExtPointType> {
|
|
|
71
67
|
assertValidity(): void;
|
|
72
68
|
multiply(scalar: bigint): ExtPointType;
|
|
73
69
|
multiplyUnsafe(scalar: bigint): ExtPointType;
|
|
70
|
+
is0(): boolean;
|
|
74
71
|
isSmallOrder(): boolean;
|
|
75
72
|
isTorsionFree(): boolean;
|
|
76
73
|
clearCofactor(): ExtPointType;
|
|
77
74
|
toAffine(iz?: bigint): AffinePoint<bigint>;
|
|
78
|
-
|
|
79
|
-
|
|
75
|
+
toBytes(): Uint8Array;
|
|
76
|
+
/** @deprecated use `toBytes` */
|
|
77
|
+
toRawBytes(): Uint8Array;
|
|
78
|
+
toHex(): string;
|
|
79
|
+
precompute(windowSize?: number, isLazy?: boolean): ExtPointType;
|
|
80
|
+
/** @deprecated use `p.precompute(windowSize)` */
|
|
80
81
|
_setWindowSize(windowSize: number): void;
|
|
81
82
|
}
|
|
82
83
|
/** Static methods of Extended Point with coordinates in X, Y, Z, T. */
|
|
83
84
|
export interface ExtPointConstructor extends GroupConstructor<ExtPointType> {
|
|
84
85
|
new (x: bigint, y: bigint, z: bigint, t: bigint): ExtPointType;
|
|
86
|
+
Fp: IField<bigint>;
|
|
87
|
+
Fn: IField<bigint>;
|
|
85
88
|
fromAffine(p: AffinePoint<bigint>): ExtPointType;
|
|
86
|
-
|
|
87
|
-
|
|
89
|
+
fromBytes(bytes: Uint8Array, zip215?: boolean): ExtPointType;
|
|
90
|
+
fromHex(hex: Hex, zip215?: boolean): ExtPointType;
|
|
88
91
|
msm(points: ExtPointType[], scalars: bigint[]): ExtPointType;
|
|
89
92
|
}
|
|
90
93
|
|
|
91
94
|
/**
|
|
92
|
-
* Edwards
|
|
93
|
-
*
|
|
95
|
+
* Twisted Edwards curve options.
|
|
96
|
+
*
|
|
97
|
+
* * a: formula param
|
|
98
|
+
* * d: formula param
|
|
99
|
+
* * p: prime characteristic (order) of finite field, in which arithmetics is done
|
|
100
|
+
* * n: order of prime subgroup a.k.a total amount of valid curve points
|
|
101
|
+
* * h: cofactor. h*n is group order; n is subgroup order
|
|
102
|
+
* * Gx: x coordinate of generator point a.k.a. base point
|
|
103
|
+
* * Gy: y coordinate of generator point
|
|
104
|
+
*/
|
|
105
|
+
export type EdwardsOpts = Readonly<{
|
|
106
|
+
a: bigint;
|
|
107
|
+
d: bigint;
|
|
108
|
+
p: bigint;
|
|
109
|
+
n: bigint;
|
|
110
|
+
h: bigint;
|
|
111
|
+
Gx: bigint;
|
|
112
|
+
Gy: bigint;
|
|
113
|
+
}>;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Extra curve options for Twisted Edwards.
|
|
117
|
+
*
|
|
118
|
+
* * Fp: redefined Field over curve.p
|
|
119
|
+
* * Fn: redefined Field over curve.n
|
|
120
|
+
* * uvRatio: helper function for decompression, calculating √(u/v)
|
|
121
|
+
*/
|
|
122
|
+
export type EdwardsExtraOpts = Partial<{
|
|
123
|
+
Fp: IField<bigint>;
|
|
124
|
+
Fn: IField<bigint>;
|
|
125
|
+
uvRatio: (u: bigint, v: bigint) => { isValid: boolean; value: bigint };
|
|
126
|
+
}>;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* EdDSA (Edwards Digital Signature algorithm) options.
|
|
130
|
+
*
|
|
131
|
+
* * hash: hash function used to hash private keys and messages
|
|
132
|
+
* * adjustScalarBytes: clears bits to get valid field element
|
|
133
|
+
* * domain: Used for hashing
|
|
134
|
+
* * mapToCurve: for hash-to-curve standard
|
|
135
|
+
* * prehash: RFC 8032 pre-hashing of messages to sign() / verify()
|
|
136
|
+
* * randomBytes: function generating random bytes, used for randomPrivateKey
|
|
137
|
+
*/
|
|
138
|
+
export type EdDSAOpts = {
|
|
139
|
+
hash: FHash;
|
|
140
|
+
adjustScalarBytes?: (bytes: Uint8Array) => Uint8Array;
|
|
141
|
+
domain?: (data: Uint8Array, ctx: Uint8Array, phflag: boolean) => Uint8Array;
|
|
142
|
+
mapToCurve?: (scalar: bigint[]) => AffinePoint<bigint>;
|
|
143
|
+
prehash?: FHash;
|
|
144
|
+
randomBytes?: (bytesLength?: number) => Uint8Array;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* EdDSA (Edwards Digital Signature algorithm) interface.
|
|
149
|
+
*
|
|
150
|
+
* Allows to create and verify signatures, create public and private keys.
|
|
94
151
|
*/
|
|
152
|
+
export interface EdDSA {
|
|
153
|
+
getPublicKey: (privateKey: Hex) => Uint8Array;
|
|
154
|
+
sign: (message: Hex, privateKey: Hex, options?: { context?: Hex }) => Uint8Array;
|
|
155
|
+
verify: (
|
|
156
|
+
sig: Hex,
|
|
157
|
+
message: Hex,
|
|
158
|
+
publicKey: Hex,
|
|
159
|
+
options?: { context?: Hex; zip215: boolean }
|
|
160
|
+
) => boolean;
|
|
161
|
+
Point: ExtPointConstructor;
|
|
162
|
+
utils: {
|
|
163
|
+
randomPrivateKey: () => Uint8Array;
|
|
164
|
+
getExtendedPublicKey: (key: Hex) => {
|
|
165
|
+
head: Uint8Array;
|
|
166
|
+
prefix: Uint8Array;
|
|
167
|
+
scalar: bigint;
|
|
168
|
+
point: ExtPointType;
|
|
169
|
+
pointBytes: Uint8Array;
|
|
170
|
+
};
|
|
171
|
+
/** @deprecated use `point.precompute()` */
|
|
172
|
+
precompute: (windowSize?: number, point?: ExtPointType) => ExtPointType;
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Legacy params. TODO: remove
|
|
95
177
|
export type CurveFn = {
|
|
96
|
-
CURVE:
|
|
178
|
+
CURVE: CurveType;
|
|
97
179
|
getPublicKey: (privateKey: Hex) => Uint8Array;
|
|
98
180
|
sign: (message: Hex, privateKey: Hex, options?: { context?: Hex }) => Uint8Array;
|
|
99
181
|
verify: (
|
|
@@ -102,6 +184,8 @@ export type CurveFn = {
|
|
|
102
184
|
publicKey: Hex,
|
|
103
185
|
options?: { context?: Hex; zip215: boolean }
|
|
104
186
|
) => boolean;
|
|
187
|
+
Point: ExtPointConstructor;
|
|
188
|
+
/** @deprecated use `Point` */
|
|
105
189
|
ExtendedPoint: ExtPointConstructor;
|
|
106
190
|
utils: {
|
|
107
191
|
randomPrivateKey: () => Uint8Array;
|
|
@@ -116,67 +200,50 @@ export type CurveFn = {
|
|
|
116
200
|
};
|
|
117
201
|
};
|
|
118
202
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
hash: cHash,
|
|
133
|
-
randomBytes,
|
|
134
|
-
nByteLength,
|
|
135
|
-
h: cofactor,
|
|
136
|
-
} = CURVE;
|
|
203
|
+
function isEdValidXY(Fp: IField<bigint>, CURVE: EdwardsOpts, x: bigint, y: bigint): boolean {
|
|
204
|
+
const x2 = Fp.sqr(x);
|
|
205
|
+
const y2 = Fp.sqr(y);
|
|
206
|
+
const left = Fp.add(Fp.mul(CURVE.a, x2), y2);
|
|
207
|
+
const right = Fp.add(Fp.ONE, Fp.mul(CURVE.d, Fp.mul(x2, y2)));
|
|
208
|
+
return Fp.eql(left, right);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export function edwards(CURVE: EdwardsOpts, curveOpts: EdwardsExtraOpts = {}): ExtPointConstructor {
|
|
212
|
+
const { Fp, Fn } = _createCurveFields('edwards', CURVE, curveOpts);
|
|
213
|
+
const { h: cofactor, n: CURVE_ORDER } = CURVE;
|
|
214
|
+
_validateObject(curveOpts, {}, { uvRatio: 'function' });
|
|
215
|
+
|
|
137
216
|
// Important:
|
|
138
217
|
// There are some places where Fp.BYTES is used instead of nByteLength.
|
|
139
218
|
// So far, everything has been tested with curves of Fp.BYTES == nByteLength.
|
|
140
219
|
// TODO: test and find curves which behave otherwise.
|
|
141
|
-
const MASK = _2n << (BigInt(
|
|
142
|
-
const modP = Fp.create; // Function overrides
|
|
143
|
-
const Fn = Field(CURVE.n, CURVE.nBitLength);
|
|
144
|
-
|
|
145
|
-
function isEdValidXY(x: bigint, y: bigint): boolean {
|
|
146
|
-
const x2 = Fp.sqr(x);
|
|
147
|
-
const y2 = Fp.sqr(y);
|
|
148
|
-
const left = Fp.add(Fp.mul(CURVE.a, x2), y2);
|
|
149
|
-
const right = Fp.add(Fp.ONE, Fp.mul(CURVE.d, Fp.mul(x2, y2)));
|
|
150
|
-
return Fp.eql(left, right);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Validate whether the passed curve params are valid.
|
|
154
|
-
// equation ax² + y² = 1 + dx²y² should work for generator point.
|
|
155
|
-
if (!isEdValidXY(CURVE.Gx, CURVE.Gy)) throw new Error('bad curve params: generator point');
|
|
220
|
+
const MASK = _2n << (BigInt(Fn.BYTES * 8) - _1n);
|
|
221
|
+
const modP = (n: bigint) => Fp.create(n); // Function overrides
|
|
156
222
|
|
|
157
223
|
// sqrt(u/v)
|
|
158
224
|
const uvRatio =
|
|
159
|
-
|
|
225
|
+
curveOpts.uvRatio ||
|
|
160
226
|
((u: bigint, v: bigint) => {
|
|
161
227
|
try {
|
|
162
|
-
return { isValid: true, value: Fp.sqrt(
|
|
228
|
+
return { isValid: true, value: Fp.sqrt(Fp.div(u, v)) };
|
|
163
229
|
} catch (e) {
|
|
164
230
|
return { isValid: false, value: _0n };
|
|
165
231
|
}
|
|
166
232
|
});
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
function
|
|
233
|
+
|
|
234
|
+
// Validate whether the passed curve params are valid.
|
|
235
|
+
// equation ax² + y² = 1 + dx²y² should work for generator point.
|
|
236
|
+
if (!isEdValidXY(Fp, CURVE, CURVE.Gx, CURVE.Gy))
|
|
237
|
+
throw new Error('bad curve params: generator point');
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Asserts coordinate is valid: 0 <= n < MASK.
|
|
241
|
+
* Coordinates >= Fp.ORDER are allowed for zip215.
|
|
242
|
+
*/
|
|
243
|
+
function acoord(title: string, n: bigint, banZero = false) {
|
|
178
244
|
const min = banZero ? _1n : _0n;
|
|
179
245
|
aInRange('coordinate ' + title, n, min, MASK);
|
|
246
|
+
return n;
|
|
180
247
|
}
|
|
181
248
|
|
|
182
249
|
function aextpoint(other: unknown) {
|
|
@@ -223,20 +290,20 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
223
290
|
static readonly BASE = new Point(CURVE.Gx, CURVE.Gy, _1n, modP(CURVE.Gx * CURVE.Gy));
|
|
224
291
|
// zero / infinity / identity point
|
|
225
292
|
static readonly ZERO = new Point(_0n, _1n, _1n, _0n); // 0, 1, 1, 0
|
|
293
|
+
// fields
|
|
294
|
+
static readonly Fp = Fp;
|
|
295
|
+
static readonly Fn = Fn;
|
|
296
|
+
|
|
226
297
|
readonly ex: bigint;
|
|
227
298
|
readonly ey: bigint;
|
|
228
299
|
readonly ez: bigint;
|
|
229
300
|
readonly et: bigint;
|
|
230
301
|
|
|
231
302
|
constructor(ex: bigint, ey: bigint, ez: bigint, et: bigint) {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
this.ex = ex;
|
|
237
|
-
this.ey = ey;
|
|
238
|
-
this.ez = ez;
|
|
239
|
-
this.et = et;
|
|
303
|
+
this.ex = acoord('x', ex);
|
|
304
|
+
this.ey = acoord('y', ey);
|
|
305
|
+
this.ez = acoord('z', ez, true);
|
|
306
|
+
this.et = acoord('t', et);
|
|
240
307
|
Object.freeze(this);
|
|
241
308
|
}
|
|
242
309
|
|
|
@@ -250,16 +317,12 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
250
317
|
static fromAffine(p: AffinePoint<bigint>): Point {
|
|
251
318
|
if (p instanceof Point) throw new Error('extended point not allowed');
|
|
252
319
|
const { x, y } = p || {};
|
|
253
|
-
|
|
254
|
-
|
|
320
|
+
acoord('x', x);
|
|
321
|
+
acoord('y', y);
|
|
255
322
|
return new Point(x, y, _1n, modP(x * y));
|
|
256
323
|
}
|
|
257
324
|
static normalizeZ(points: Point[]): Point[] {
|
|
258
|
-
|
|
259
|
-
Fp,
|
|
260
|
-
points.map((p) => p.ez)
|
|
261
|
-
);
|
|
262
|
-
return points.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
|
|
325
|
+
return normalizeZ(Point, 'ez', points);
|
|
263
326
|
}
|
|
264
327
|
// Multiscalar Multiplication
|
|
265
328
|
static msm(points: Point[], scalars: bigint[]): Point {
|
|
@@ -268,7 +331,12 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
268
331
|
|
|
269
332
|
// "Private method", don't use it directly
|
|
270
333
|
_setWindowSize(windowSize: number) {
|
|
334
|
+
this.precompute(windowSize);
|
|
335
|
+
}
|
|
336
|
+
precompute(windowSize: number = 8, isLazy = true) {
|
|
271
337
|
wnaf.setWindowSize(this, windowSize);
|
|
338
|
+
if (!isLazy) this.multiply(_2n); // random number
|
|
339
|
+
return this;
|
|
272
340
|
}
|
|
273
341
|
// Not required for fromHex(), which always creates valid points.
|
|
274
342
|
// Could be useful for fromAffine().
|
|
@@ -346,15 +414,11 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
346
414
|
return this.add(other.negate());
|
|
347
415
|
}
|
|
348
416
|
|
|
349
|
-
private wNAF(n: bigint): { p: Point; f: Point } {
|
|
350
|
-
return wnaf.wNAFCached(this, n, Point.normalizeZ);
|
|
351
|
-
}
|
|
352
|
-
|
|
353
417
|
// Constant-time multiplication.
|
|
354
418
|
multiply(scalar: bigint): Point {
|
|
355
419
|
const n = scalar;
|
|
356
420
|
aInRange('scalar', n, _1n, CURVE_ORDER); // 1 <= scalar < L
|
|
357
|
-
const { p, f } =
|
|
421
|
+
const { p, f } = wnaf.wNAFCached(this, n, Point.normalizeZ);
|
|
358
422
|
return Point.normalizeZ([p, f])[0];
|
|
359
423
|
}
|
|
360
424
|
|
|
@@ -366,7 +430,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
366
430
|
multiplyUnsafe(scalar: bigint, acc = Point.ZERO): Point {
|
|
367
431
|
const n = scalar;
|
|
368
432
|
aInRange('scalar', n, _0n, CURVE_ORDER); // 0 <= scalar < L
|
|
369
|
-
if (n === _0n) return
|
|
433
|
+
if (n === _0n) return Point.ZERO;
|
|
370
434
|
if (this.is0() || n === _1n) return this;
|
|
371
435
|
return wnaf.wNAFCachedUnsafe(this, n, Point.normalizeZ, acc);
|
|
372
436
|
}
|
|
@@ -382,21 +446,25 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
382
446
|
// Multiplies point by curve order and checks if the result is 0.
|
|
383
447
|
// Returns `false` is the point is dirty.
|
|
384
448
|
isTorsionFree(): boolean {
|
|
385
|
-
return wnaf.
|
|
449
|
+
return wnaf.wNAFCachedUnsafe(this, CURVE_ORDER).is0();
|
|
386
450
|
}
|
|
387
451
|
|
|
388
452
|
// Converts Extended point to default (x, y) coordinates.
|
|
389
453
|
// Can accept precomputed Z^-1 - for example, from invertBatch.
|
|
390
|
-
toAffine(
|
|
391
|
-
return toAffineMemo(this,
|
|
454
|
+
toAffine(invertedZ?: bigint): AffinePoint<bigint> {
|
|
455
|
+
return toAffineMemo(this, invertedZ);
|
|
392
456
|
}
|
|
393
457
|
|
|
394
458
|
clearCofactor(): Point {
|
|
395
|
-
const { h: cofactor } = CURVE;
|
|
396
459
|
if (cofactor === _1n) return this;
|
|
397
460
|
return this.multiplyUnsafe(cofactor);
|
|
398
461
|
}
|
|
399
462
|
|
|
463
|
+
static fromBytes(bytes: Uint8Array, zip215 = false): Point {
|
|
464
|
+
abytes(bytes);
|
|
465
|
+
return this.fromHex(bytes, zip215);
|
|
466
|
+
}
|
|
467
|
+
|
|
400
468
|
// Converts hash string or Uint8Array to Point.
|
|
401
469
|
// Uses algo from RFC8032 5.1.3.
|
|
402
470
|
static fromHex(hex: Hex, zip215 = false): Point {
|
|
@@ -431,28 +499,69 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
431
499
|
if (isLastByteOdd !== isXOdd) x = modP(-x); // if x_0 != x mod 2, set x = p-x
|
|
432
500
|
return Point.fromAffine({ x, y });
|
|
433
501
|
}
|
|
434
|
-
static
|
|
435
|
-
|
|
436
|
-
return G.multiply(scalar); // reduced one call of `toRawBytes`
|
|
502
|
+
static fromPrivateScalar(scalar: bigint): Point {
|
|
503
|
+
return Point.BASE.multiply(scalar);
|
|
437
504
|
}
|
|
438
|
-
|
|
505
|
+
toBytes(): Uint8Array {
|
|
439
506
|
const { x, y } = this.toAffine();
|
|
440
507
|
const bytes = numberToBytesLE(y, Fp.BYTES); // each y has 2 x values (x, -y)
|
|
441
508
|
bytes[bytes.length - 1] |= x & _1n ? 0x80 : 0; // when compressing, it's enough to store y
|
|
442
509
|
return bytes; // and use the last byte to encode sign of x
|
|
443
510
|
}
|
|
511
|
+
/** @deprecated use `toBytes` */
|
|
512
|
+
toRawBytes(): Uint8Array {
|
|
513
|
+
return this.toBytes();
|
|
514
|
+
}
|
|
444
515
|
toHex(): string {
|
|
445
|
-
return bytesToHex(this.
|
|
516
|
+
return bytesToHex(this.toBytes());
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
toString() {
|
|
520
|
+
return `<Point ${this.is0() ? 'ZERO' : this.toHex()}>`;
|
|
446
521
|
}
|
|
447
522
|
}
|
|
448
|
-
const
|
|
449
|
-
|
|
523
|
+
const wnaf = wNAF(Point, Fn.BYTES * 8); // Fn.BITS?
|
|
524
|
+
return Point;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Initializes EdDSA signatures over given Edwards curve.
|
|
529
|
+
*/
|
|
530
|
+
export function eddsa(Point: ExtPointConstructor, eddsaOpts: EdDSAOpts): EdDSA {
|
|
531
|
+
_validateObject(
|
|
532
|
+
eddsaOpts,
|
|
533
|
+
{
|
|
534
|
+
hash: 'function',
|
|
535
|
+
},
|
|
536
|
+
{
|
|
537
|
+
adjustScalarBytes: 'function',
|
|
538
|
+
randomBytes: 'function',
|
|
539
|
+
domain: 'function',
|
|
540
|
+
prehash: 'function',
|
|
541
|
+
mapToCurve: 'function',
|
|
542
|
+
}
|
|
543
|
+
);
|
|
544
|
+
|
|
545
|
+
const { prehash, hash: cHash } = eddsaOpts;
|
|
546
|
+
const { BASE: G, Fp, Fn } = Point;
|
|
547
|
+
const CURVE_ORDER = Fn.ORDER;
|
|
548
|
+
|
|
549
|
+
const randomBytes_ = eddsaOpts.randomBytes || randomBytes;
|
|
550
|
+
const adjustScalarBytes = eddsaOpts.adjustScalarBytes || ((bytes: Uint8Array) => bytes); // NOOP
|
|
551
|
+
const domain =
|
|
552
|
+
eddsaOpts.domain ||
|
|
553
|
+
((data: Uint8Array, ctx: Uint8Array, phflag: boolean) => {
|
|
554
|
+
abool('phflag', phflag);
|
|
555
|
+
if (ctx.length || phflag) throw new Error('Contexts/pre-hash are not supported');
|
|
556
|
+
return data;
|
|
557
|
+
}); // NOOP
|
|
450
558
|
|
|
451
559
|
function modN(a: bigint) {
|
|
452
|
-
return
|
|
560
|
+
return Fn.create(a);
|
|
453
561
|
}
|
|
454
562
|
// Little-endian SHA512 with modulo n
|
|
455
563
|
function modN_LE(hash: Uint8Array): bigint {
|
|
564
|
+
// Not using Fn.fromBytes: hash can be 2*Fn.BYTES
|
|
456
565
|
return modN(bytesToNumberLE(hash));
|
|
457
566
|
}
|
|
458
567
|
|
|
@@ -473,7 +582,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
473
582
|
function getExtendedPublicKey(key: Hex) {
|
|
474
583
|
const { head, prefix, scalar } = getPrivateScalar(key);
|
|
475
584
|
const point = G.multiply(scalar); // Point on Edwards curve aka public key
|
|
476
|
-
const pointBytes = point.
|
|
585
|
+
const pointBytes = point.toBytes();
|
|
477
586
|
return { head, prefix, scalar, point, pointBytes };
|
|
478
587
|
}
|
|
479
588
|
|
|
@@ -494,12 +603,13 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
494
603
|
if (prehash) msg = prehash(msg); // for ed25519ph etc.
|
|
495
604
|
const { prefix, scalar, pointBytes } = getExtendedPublicKey(privKey);
|
|
496
605
|
const r = hashDomainToScalar(options.context, prefix, msg); // r = dom2(F, C) || prefix || PH(M)
|
|
497
|
-
const R = G.multiply(r).
|
|
606
|
+
const R = G.multiply(r).toBytes(); // R = rG
|
|
498
607
|
const k = hashDomainToScalar(options.context, R, pointBytes, msg); // R || A || PH(M)
|
|
499
608
|
const s = modN(r + k * scalar); // S = (r + k * s) mod L
|
|
500
609
|
aInRange('signature.s', s, _0n, CURVE_ORDER); // 0 <= s < l
|
|
501
|
-
const
|
|
502
|
-
|
|
610
|
+
const L = Fp.BYTES;
|
|
611
|
+
const res = concatBytes(R, numberToBytesLE(s, L));
|
|
612
|
+
return ensureBytes('result', res, L * 2); // 64-byte signature
|
|
503
613
|
}
|
|
504
614
|
|
|
505
615
|
const verifyOpts: { context?: Hex; zip215?: boolean } = VERIFY_DEFAULT;
|
|
@@ -531,19 +641,19 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
531
641
|
}
|
|
532
642
|
if (!zip215 && A.isSmallOrder()) return false;
|
|
533
643
|
|
|
534
|
-
const k = hashDomainToScalar(context, R.
|
|
644
|
+
const k = hashDomainToScalar(context, R.toBytes(), A.toBytes(), msg);
|
|
535
645
|
const RkA = R.add(A.multiplyUnsafe(k));
|
|
536
646
|
// Extended group equation
|
|
537
647
|
// [8][S]B = [8]R + [8][k]A'
|
|
538
|
-
return RkA.subtract(SB).clearCofactor().
|
|
648
|
+
return RkA.subtract(SB).clearCofactor().is0();
|
|
539
649
|
}
|
|
540
650
|
|
|
541
|
-
G.
|
|
651
|
+
G.precompute(8); // Enable precomputes. Slows down first publicKey computation by 20ms.
|
|
542
652
|
|
|
543
653
|
const utils = {
|
|
544
654
|
getExtendedPublicKey,
|
|
545
655
|
/** ed25519 priv keys are uniform 32b. No need to check for modulo bias, like in secp256k1. */
|
|
546
|
-
randomPrivateKey: (): Uint8Array =>
|
|
656
|
+
randomPrivateKey: (): Uint8Array => randomBytes_!(Fp.BYTES),
|
|
547
657
|
|
|
548
658
|
/**
|
|
549
659
|
* We're doing scalar multiplication (used in getPublicKey etc) with precomputed BASE_POINT
|
|
@@ -552,18 +662,49 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
552
662
|
* @param windowSize 2, 4, 8, 16
|
|
553
663
|
*/
|
|
554
664
|
precompute(windowSize = 8, point: ExtPointType = Point.BASE): ExtPointType {
|
|
555
|
-
point.
|
|
556
|
-
point.multiply(BigInt(3));
|
|
557
|
-
return point;
|
|
665
|
+
return point.precompute(windowSize, false);
|
|
558
666
|
},
|
|
559
667
|
};
|
|
560
668
|
|
|
561
|
-
return {
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
669
|
+
return { getPublicKey, sign, verify, utils, Point };
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
export type EdComposed = {
|
|
673
|
+
CURVE: EdwardsOpts;
|
|
674
|
+
curveOpts: EdwardsExtraOpts;
|
|
675
|
+
eddsaOpts: EdDSAOpts;
|
|
676
|
+
};
|
|
677
|
+
function _eddsa_legacy_opts_to_new(c: CurveTypeWithLength): EdComposed {
|
|
678
|
+
const CURVE: EdwardsOpts = {
|
|
679
|
+
a: c.a,
|
|
680
|
+
d: c.d,
|
|
681
|
+
p: c.Fp.ORDER,
|
|
682
|
+
n: c.n,
|
|
683
|
+
h: c.h,
|
|
684
|
+
Gx: c.Gx,
|
|
685
|
+
Gy: c.Gy,
|
|
568
686
|
};
|
|
687
|
+
const Fp = c.Fp;
|
|
688
|
+
const Fn = Field(CURVE.n, c.nBitLength, true);
|
|
689
|
+
const curveOpts: EdwardsExtraOpts = { Fp, Fn, uvRatio: c.uvRatio };
|
|
690
|
+
const eddsaOpts: EdDSAOpts = {
|
|
691
|
+
hash: c.hash,
|
|
692
|
+
randomBytes: c.randomBytes,
|
|
693
|
+
adjustScalarBytes: c.adjustScalarBytes,
|
|
694
|
+
domain: c.domain,
|
|
695
|
+
prehash: c.prehash,
|
|
696
|
+
mapToCurve: c.mapToCurve,
|
|
697
|
+
};
|
|
698
|
+
return { CURVE, curveOpts, eddsaOpts };
|
|
699
|
+
}
|
|
700
|
+
function _eddsa_new_output_to_legacy(c: CurveTypeWithLength, eddsa: EdDSA): CurveFn {
|
|
701
|
+
const legacy = Object.assign({}, eddsa, { ExtendedPoint: eddsa.Point, CURVE: c });
|
|
702
|
+
return legacy;
|
|
703
|
+
}
|
|
704
|
+
// TODO: remove. Use eddsa
|
|
705
|
+
export function twistedEdwards(c: CurveTypeWithLength): CurveFn {
|
|
706
|
+
const { CURVE, curveOpts, eddsaOpts } = _eddsa_legacy_opts_to_new(c);
|
|
707
|
+
const Point = edwards(CURVE, curveOpts);
|
|
708
|
+
const EDDSA = eddsa(Point, eddsaOpts);
|
|
709
|
+
return _eddsa_new_output_to_legacy(c, EDDSA);
|
|
569
710
|
}
|