@noble/curves 1.9.0 → 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 +78 -34
- 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 +99 -11
- 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 +141 -92
- package/abstract/edwards.js.map +1 -1
- package/abstract/fft.d.ts +122 -0
- package/abstract/fft.d.ts.map +1 -0
- package/abstract/fft.js +438 -0
- package/abstract/fft.js.map +1 -0
- 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 +28 -17
- package/abstract/modular.d.ts.map +1 -1
- package/abstract/modular.js +156 -139
- package/abstract/modular.js.map +1 -1
- package/abstract/montgomery.d.ts +3 -8
- package/abstract/montgomery.d.ts.map +1 -1
- package/abstract/montgomery.js +73 -93
- 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 +10 -4
- 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 +152 -73
- package/abstract/weierstrass.d.ts.map +1 -1
- package/abstract/weierstrass.js +487 -404
- 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 -480
- 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 +25 -9
- package/ed25519.d.ts.map +1 -1
- package/ed25519.js +89 -65
- package/ed25519.js.map +1 -1
- package/ed448.d.ts +29 -10
- package/ed448.d.ts.map +1 -1
- package/ed448.js +116 -81
- 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 +96 -12
- 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 +141 -94
- package/esm/abstract/edwards.js.map +1 -1
- package/esm/abstract/fft.d.ts +122 -0
- package/esm/abstract/fft.d.ts.map +1 -0
- package/esm/abstract/fft.js +425 -0
- package/esm/abstract/fft.js.map +1 -0
- 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 +28 -17
- package/esm/abstract/modular.d.ts.map +1 -1
- package/esm/abstract/modular.js +155 -138
- package/esm/abstract/modular.js.map +1 -1
- package/esm/abstract/montgomery.d.ts +3 -8
- package/esm/abstract/montgomery.d.ts.map +1 -1
- package/esm/abstract/montgomery.js +74 -94
- 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 +10 -4
- 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 +152 -73
- package/esm/abstract/weierstrass.d.ts.map +1 -1
- package/esm/abstract/weierstrass.js +485 -406
- 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 -479
- 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 +25 -9
- package/esm/ed25519.d.ts.map +1 -1
- package/esm/ed25519.js +84 -60
- package/esm/ed25519.js.map +1 -1
- package/esm/ed448.d.ts +29 -10
- package/esm/ed448.d.ts.map +1 -1
- package/esm/ed448.js +113 -78
- package/esm/ed448.js.map +1 -1
- package/esm/jubjub.d.ts +4 -0
- package/esm/jubjub.d.ts.map +1 -1
- package/esm/jubjub.js +4 -0
- package/esm/jubjub.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 +8 -16
- package/esm/nist.d.ts.map +1 -1
- package/esm/nist.js +87 -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/pasta.d.ts +4 -0
- package/esm/pasta.d.ts.map +1 -1
- package/esm/pasta.js +4 -0
- package/esm/pasta.js.map +1 -1
- package/esm/secp256k1.d.ts +6 -6
- package/esm/secp256k1.d.ts.map +1 -1
- package/esm/secp256k1.js +44 -41
- 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/jubjub.d.ts +4 -0
- package/jubjub.d.ts.map +1 -1
- package/jubjub.js +4 -0
- package/jubjub.js.map +1 -1
- package/misc.d.ts.map +1 -1
- package/misc.js +35 -30
- package/misc.js.map +1 -1
- package/nist.d.ts +8 -16
- package/nist.d.ts.map +1 -1
- package/nist.js +87 -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 +26 -8
- package/pasta.d.ts +4 -0
- package/pasta.d.ts.map +1 -1
- package/pasta.js +4 -0
- package/pasta.js.map +1 -1
- package/secp256k1.d.ts +6 -6
- package/secp256k1.d.ts.map +1 -1
- package/secp256k1.js +47 -44
- 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 +125 -18
- package/src/abstract/edwards.ts +282 -127
- package/src/abstract/fft.ts +519 -0
- package/src/abstract/hash-to-curve.ts +51 -27
- package/src/abstract/modular.ts +156 -143
- package/src/abstract/montgomery.ts +81 -111
- package/src/abstract/poseidon.ts +22 -18
- package/src/abstract/tower.ts +37 -68
- package/src/abstract/utils.ts +3 -378
- package/src/abstract/weierstrass.ts +752 -461
- package/src/bls12-381.ts +542 -507
- package/src/bn254.ts +47 -35
- package/src/ed25519.ts +104 -76
- package/src/ed448.ts +156 -105
- package/src/jubjub.ts +4 -0
- package/src/misc.ts +39 -34
- package/src/nist.ts +138 -126
- package/src/p256.ts +3 -3
- package/src/p384.ts +3 -3
- package/src/p521.ts +3 -3
- package/src/pasta.ts +5 -1
- package/src/secp256k1.ts +59 -47
- 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)
|
|
94
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.
|
|
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,55 +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);
|
|
220
|
+
const MASK = _2n << (BigInt(Fn.BYTES * 8) - _1n);
|
|
221
|
+
const modP = (n: bigint) => Fp.create(n); // Function overrides
|
|
144
222
|
|
|
145
223
|
// sqrt(u/v)
|
|
146
224
|
const uvRatio =
|
|
147
|
-
|
|
225
|
+
curveOpts.uvRatio ||
|
|
148
226
|
((u: bigint, v: bigint) => {
|
|
149
227
|
try {
|
|
150
|
-
return { isValid: true, value: Fp.sqrt(
|
|
228
|
+
return { isValid: true, value: Fp.sqrt(Fp.div(u, v)) };
|
|
151
229
|
} catch (e) {
|
|
152
230
|
return { isValid: false, value: _0n };
|
|
153
231
|
}
|
|
154
232
|
});
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
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) {
|
|
166
244
|
const min = banZero ? _1n : _0n;
|
|
167
245
|
aInRange('coordinate ' + title, n, min, MASK);
|
|
246
|
+
return n;
|
|
168
247
|
}
|
|
169
248
|
|
|
170
249
|
function aextpoint(other: unknown) {
|
|
@@ -204,25 +283,27 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
204
283
|
return true;
|
|
205
284
|
});
|
|
206
285
|
|
|
207
|
-
// Extended Point works in extended coordinates: (
|
|
286
|
+
// Extended Point works in extended coordinates: (X, Y, Z, T) ∋ (x=X/Z, y=Y/Z, T=xy).
|
|
208
287
|
// https://en.wikipedia.org/wiki/Twisted_Edwards_curve#Extended_coordinates
|
|
209
288
|
class Point implements ExtPointType {
|
|
289
|
+
// base / generator point
|
|
210
290
|
static readonly BASE = new Point(CURVE.Gx, CURVE.Gy, _1n, modP(CURVE.Gx * CURVE.Gy));
|
|
291
|
+
// zero / infinity / identity point
|
|
211
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
|
+
|
|
212
297
|
readonly ex: bigint;
|
|
213
298
|
readonly ey: bigint;
|
|
214
299
|
readonly ez: bigint;
|
|
215
300
|
readonly et: bigint;
|
|
216
301
|
|
|
217
302
|
constructor(ex: bigint, ey: bigint, ez: bigint, et: bigint) {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
this.ex = ex;
|
|
223
|
-
this.ey = ey;
|
|
224
|
-
this.ez = ez;
|
|
225
|
-
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);
|
|
226
307
|
Object.freeze(this);
|
|
227
308
|
}
|
|
228
309
|
|
|
@@ -236,16 +317,12 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
236
317
|
static fromAffine(p: AffinePoint<bigint>): Point {
|
|
237
318
|
if (p instanceof Point) throw new Error('extended point not allowed');
|
|
238
319
|
const { x, y } = p || {};
|
|
239
|
-
|
|
240
|
-
|
|
320
|
+
acoord('x', x);
|
|
321
|
+
acoord('y', y);
|
|
241
322
|
return new Point(x, y, _1n, modP(x * y));
|
|
242
323
|
}
|
|
243
324
|
static normalizeZ(points: Point[]): Point[] {
|
|
244
|
-
|
|
245
|
-
Fp,
|
|
246
|
-
points.map((p) => p.ez)
|
|
247
|
-
);
|
|
248
|
-
return points.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
|
|
325
|
+
return normalizeZ(Point, 'ez', points);
|
|
249
326
|
}
|
|
250
327
|
// Multiscalar Multiplication
|
|
251
328
|
static msm(points: Point[], scalars: bigint[]): Point {
|
|
@@ -254,7 +331,12 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
254
331
|
|
|
255
332
|
// "Private method", don't use it directly
|
|
256
333
|
_setWindowSize(windowSize: number) {
|
|
334
|
+
this.precompute(windowSize);
|
|
335
|
+
}
|
|
336
|
+
precompute(windowSize: number = 8, isLazy = true) {
|
|
257
337
|
wnaf.setWindowSize(this, windowSize);
|
|
338
|
+
if (!isLazy) this.multiply(_2n); // random number
|
|
339
|
+
return this;
|
|
258
340
|
}
|
|
259
341
|
// Not required for fromHex(), which always creates valid points.
|
|
260
342
|
// Could be useful for fromAffine().
|
|
@@ -332,15 +414,11 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
332
414
|
return this.add(other.negate());
|
|
333
415
|
}
|
|
334
416
|
|
|
335
|
-
private wNAF(n: bigint): { p: Point; f: Point } {
|
|
336
|
-
return wnaf.wNAFCached(this, n, Point.normalizeZ);
|
|
337
|
-
}
|
|
338
|
-
|
|
339
417
|
// Constant-time multiplication.
|
|
340
418
|
multiply(scalar: bigint): Point {
|
|
341
419
|
const n = scalar;
|
|
342
420
|
aInRange('scalar', n, _1n, CURVE_ORDER); // 1 <= scalar < L
|
|
343
|
-
const { p, f } =
|
|
421
|
+
const { p, f } = wnaf.wNAFCached(this, n, Point.normalizeZ);
|
|
344
422
|
return Point.normalizeZ([p, f])[0];
|
|
345
423
|
}
|
|
346
424
|
|
|
@@ -352,7 +430,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
352
430
|
multiplyUnsafe(scalar: bigint, acc = Point.ZERO): Point {
|
|
353
431
|
const n = scalar;
|
|
354
432
|
aInRange('scalar', n, _0n, CURVE_ORDER); // 0 <= scalar < L
|
|
355
|
-
if (n === _0n) return
|
|
433
|
+
if (n === _0n) return Point.ZERO;
|
|
356
434
|
if (this.is0() || n === _1n) return this;
|
|
357
435
|
return wnaf.wNAFCachedUnsafe(this, n, Point.normalizeZ, acc);
|
|
358
436
|
}
|
|
@@ -368,21 +446,25 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
368
446
|
// Multiplies point by curve order and checks if the result is 0.
|
|
369
447
|
// Returns `false` is the point is dirty.
|
|
370
448
|
isTorsionFree(): boolean {
|
|
371
|
-
return wnaf.
|
|
449
|
+
return wnaf.wNAFCachedUnsafe(this, CURVE_ORDER).is0();
|
|
372
450
|
}
|
|
373
451
|
|
|
374
452
|
// Converts Extended point to default (x, y) coordinates.
|
|
375
453
|
// Can accept precomputed Z^-1 - for example, from invertBatch.
|
|
376
|
-
toAffine(
|
|
377
|
-
return toAffineMemo(this,
|
|
454
|
+
toAffine(invertedZ?: bigint): AffinePoint<bigint> {
|
|
455
|
+
return toAffineMemo(this, invertedZ);
|
|
378
456
|
}
|
|
379
457
|
|
|
380
458
|
clearCofactor(): Point {
|
|
381
|
-
const { h: cofactor } = CURVE;
|
|
382
459
|
if (cofactor === _1n) return this;
|
|
383
460
|
return this.multiplyUnsafe(cofactor);
|
|
384
461
|
}
|
|
385
462
|
|
|
463
|
+
static fromBytes(bytes: Uint8Array, zip215 = false): Point {
|
|
464
|
+
abytes(bytes);
|
|
465
|
+
return this.fromHex(bytes, zip215);
|
|
466
|
+
}
|
|
467
|
+
|
|
386
468
|
// Converts hash string or Uint8Array to Point.
|
|
387
469
|
// Uses algo from RFC8032 5.1.3.
|
|
388
470
|
static fromHex(hex: Hex, zip215 = false): Point {
|
|
@@ -417,28 +499,69 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
417
499
|
if (isLastByteOdd !== isXOdd) x = modP(-x); // if x_0 != x mod 2, set x = p-x
|
|
418
500
|
return Point.fromAffine({ x, y });
|
|
419
501
|
}
|
|
420
|
-
static
|
|
421
|
-
|
|
422
|
-
return G.multiply(scalar); // reduced one call of `toRawBytes`
|
|
502
|
+
static fromPrivateScalar(scalar: bigint): Point {
|
|
503
|
+
return Point.BASE.multiply(scalar);
|
|
423
504
|
}
|
|
424
|
-
|
|
505
|
+
toBytes(): Uint8Array {
|
|
425
506
|
const { x, y } = this.toAffine();
|
|
426
507
|
const bytes = numberToBytesLE(y, Fp.BYTES); // each y has 2 x values (x, -y)
|
|
427
508
|
bytes[bytes.length - 1] |= x & _1n ? 0x80 : 0; // when compressing, it's enough to store y
|
|
428
509
|
return bytes; // and use the last byte to encode sign of x
|
|
429
510
|
}
|
|
511
|
+
/** @deprecated use `toBytes` */
|
|
512
|
+
toRawBytes(): Uint8Array {
|
|
513
|
+
return this.toBytes();
|
|
514
|
+
}
|
|
430
515
|
toHex(): string {
|
|
431
|
-
return bytesToHex(this.
|
|
516
|
+
return bytesToHex(this.toBytes());
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
toString() {
|
|
520
|
+
return `<Point ${this.is0() ? 'ZERO' : this.toHex()}>`;
|
|
432
521
|
}
|
|
433
522
|
}
|
|
434
|
-
const
|
|
435
|
-
|
|
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
|
|
436
558
|
|
|
437
559
|
function modN(a: bigint) {
|
|
438
|
-
return
|
|
560
|
+
return Fn.create(a);
|
|
439
561
|
}
|
|
440
562
|
// Little-endian SHA512 with modulo n
|
|
441
563
|
function modN_LE(hash: Uint8Array): bigint {
|
|
564
|
+
// Not using Fn.fromBytes: hash can be 2*Fn.BYTES
|
|
442
565
|
return modN(bytesToNumberLE(hash));
|
|
443
566
|
}
|
|
444
567
|
|
|
@@ -459,7 +582,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
459
582
|
function getExtendedPublicKey(key: Hex) {
|
|
460
583
|
const { head, prefix, scalar } = getPrivateScalar(key);
|
|
461
584
|
const point = G.multiply(scalar); // Point on Edwards curve aka public key
|
|
462
|
-
const pointBytes = point.
|
|
585
|
+
const pointBytes = point.toBytes();
|
|
463
586
|
return { head, prefix, scalar, point, pointBytes };
|
|
464
587
|
}
|
|
465
588
|
|
|
@@ -480,12 +603,13 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
480
603
|
if (prehash) msg = prehash(msg); // for ed25519ph etc.
|
|
481
604
|
const { prefix, scalar, pointBytes } = getExtendedPublicKey(privKey);
|
|
482
605
|
const r = hashDomainToScalar(options.context, prefix, msg); // r = dom2(F, C) || prefix || PH(M)
|
|
483
|
-
const R = G.multiply(r).
|
|
606
|
+
const R = G.multiply(r).toBytes(); // R = rG
|
|
484
607
|
const k = hashDomainToScalar(options.context, R, pointBytes, msg); // R || A || PH(M)
|
|
485
608
|
const s = modN(r + k * scalar); // S = (r + k * s) mod L
|
|
486
609
|
aInRange('signature.s', s, _0n, CURVE_ORDER); // 0 <= s < l
|
|
487
|
-
const
|
|
488
|
-
|
|
610
|
+
const L = Fp.BYTES;
|
|
611
|
+
const res = concatBytes(R, numberToBytesLE(s, L));
|
|
612
|
+
return ensureBytes('result', res, L * 2); // 64-byte signature
|
|
489
613
|
}
|
|
490
614
|
|
|
491
615
|
const verifyOpts: { context?: Hex; zip215?: boolean } = VERIFY_DEFAULT;
|
|
@@ -517,19 +641,19 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
517
641
|
}
|
|
518
642
|
if (!zip215 && A.isSmallOrder()) return false;
|
|
519
643
|
|
|
520
|
-
const k = hashDomainToScalar(context, R.
|
|
644
|
+
const k = hashDomainToScalar(context, R.toBytes(), A.toBytes(), msg);
|
|
521
645
|
const RkA = R.add(A.multiplyUnsafe(k));
|
|
522
646
|
// Extended group equation
|
|
523
647
|
// [8][S]B = [8]R + [8][k]A'
|
|
524
|
-
return RkA.subtract(SB).clearCofactor().
|
|
648
|
+
return RkA.subtract(SB).clearCofactor().is0();
|
|
525
649
|
}
|
|
526
650
|
|
|
527
|
-
G.
|
|
651
|
+
G.precompute(8); // Enable precomputes. Slows down first publicKey computation by 20ms.
|
|
528
652
|
|
|
529
653
|
const utils = {
|
|
530
654
|
getExtendedPublicKey,
|
|
531
655
|
/** ed25519 priv keys are uniform 32b. No need to check for modulo bias, like in secp256k1. */
|
|
532
|
-
randomPrivateKey: (): Uint8Array =>
|
|
656
|
+
randomPrivateKey: (): Uint8Array => randomBytes_!(Fp.BYTES),
|
|
533
657
|
|
|
534
658
|
/**
|
|
535
659
|
* We're doing scalar multiplication (used in getPublicKey etc) with precomputed BASE_POINT
|
|
@@ -538,18 +662,49 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
538
662
|
* @param windowSize 2, 4, 8, 16
|
|
539
663
|
*/
|
|
540
664
|
precompute(windowSize = 8, point: ExtPointType = Point.BASE): ExtPointType {
|
|
541
|
-
point.
|
|
542
|
-
point.multiply(BigInt(3));
|
|
543
|
-
return point;
|
|
665
|
+
return point.precompute(windowSize, false);
|
|
544
666
|
},
|
|
545
667
|
};
|
|
546
668
|
|
|
547
|
-
return {
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
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,
|
|
554
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);
|
|
555
710
|
}
|