Skip to content

Commit 2bacef5

Browse files
authored
Bugfix: Inconsistent EDPoint representation (#28)
This branch fixes 2 issues related to EDPoint representation. First and foremost, it addresses an issue with the modulo P operations missing in some cases and, as a result, the parameter T being inconsistently calculated. Secondly, deriving an ED25519PublicKey from an ED25519PrivateKey now ensures the underlying EDPoint is scaled to affine coordinates, allowing us to easily compare any actually derived ED25519PublicKey with the expected results of EDPoint.fromBytes(). List of changes: - updated ed25519_private_key.dart, so that publicKey getter always constructs the public key from an EDPoint scaled to affine coordinates, ensuring consistency with the EDPoint form produced by EDPoint.fromBytes() - updated ed_point.dart, adding modulo P operations where they were missing, which also ensures consistency of the fromBytes() default constructor with the EDPoint form produced by scaleToAffineCoordinates(), as well as fixing an incorrect value for the parameter T in * operator - unrelated with the domain: fixed solana-specific ed25519_derivator_test.dart using Ethereum derivation path in tests
1 parent 3602993 commit 2bacef5

7 files changed

Lines changed: 58 additions & 79 deletions

File tree

lib/src/cdsa/eddsa/ed25519/ed25519_private_key.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class ED25519PrivateKey extends ABip32PrivateKey {
2727
@override
2828
ED25519PublicKey get publicKey {
2929
return ED25519PublicKey(
30-
edPublicKey: edPrivateKey.edPublicKey,
30+
edPublicKey: EDPublicKey(edPrivateKey.edPublicKey.A.scaleToAffineCoordinates()),
3131
metadata: metadata,
3232
);
3333
}

lib/src/cdsa/eddsa/ed_point.dart

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class EDPoint extends Equatable {
7575
}) : x = x ?? BigInt.zero,
7676
y = y ?? BigInt.zero,
7777
z = z ?? BigInt.zero,
78-
t = t ?? ((x ?? BigInt.zero) * (y ?? BigInt.zero));
78+
t = t ?? ((x ?? BigInt.zero) * (y ?? BigInt.zero)) % curve.p;
7979

8080
/// Constructs an instance of EDPoint from a byte array.
8181
factory EDPoint.fromBytes(EDPoint generator, Uint8List bytes) {
@@ -91,15 +91,15 @@ class EDPoint extends Equatable {
9191
int x0 = (editableBytes[expLen - 1] & 0x80) >> 7;
9292
editableBytes[expLen - 1] &= 0x80 - 1;
9393

94-
BigInt y = BigIntUtils.decode(editableBytes, order: Endian.little);
94+
BigInt y = BigIntUtils.decode(editableBytes, order: Endian.little) % p;
9595

96-
BigInt x2 = (y * y - BigInt.from(1)) * (curve.d * y * y - curve.a).modInverse(p) % p;
96+
BigInt x2 = (((y * y) % p - BigInt.one) % p) * (((curve.d * ((y * y) % p)) % p - curve.a) % p).modInverse(p) % p;
9797
BigInt x = ED25519Utils.findModularSquareRoot(a: x2, p: p);
9898
if (x.isOdd != (x0 == 1)) {
9999
x = (-x) % p;
100100
}
101101

102-
return EDPoint(curve: curve, n: generator.n, x: x, y: y, z: BigInt.one, t: x * y);
102+
return EDPoint(curve: curve, n: generator.n, x: x, y: y, z: BigInt.one, t: (x * y) % p);
103103
}
104104

105105
/// Constructs an instance of [EDPoint] representing the point at infinity.
@@ -143,10 +143,10 @@ class EDPoint extends Equatable {
143143
BigInt b = (y * other.y) % curve.p;
144144
BigInt c = (z * other.t) % curve.p;
145145
BigInt d = (t * other.z) % curve.p;
146-
BigInt e = d + c;
146+
BigInt e = (d + c) % curve.p;
147147
BigInt f = (((x - y) * (other.x + other.y)) + b - A) % curve.p;
148-
BigInt g = b + (curve.a * A);
149-
BigInt h = d - c;
148+
BigInt g = (b + (curve.a * A)) % curve.p;
149+
BigInt h = (d - c) % curve.p;
150150

151151
if (h == BigInt.zero) {
152152
return _double();
@@ -188,7 +188,7 @@ class EDPoint extends Equatable {
188188
x: BigInt.zero,
189189
y: BigInt.one,
190190
z: BigInt.one,
191-
t: BigInt.one,
191+
t: BigInt.zero,
192192
);
193193

194194
List<BigInt> nafList = BigIntUtils.computeNAF(modScalar).reversed.toList();
@@ -245,9 +245,9 @@ class EDPoint extends Equatable {
245245
BigInt C = (z * z * BigInt.two) % curve.p;
246246
BigInt D = (curve.a * A) % curve.p;
247247
BigInt E = (((x + y) * (x + y)) - A - B) % curve.p;
248-
BigInt G = D + B;
249-
BigInt F = G - C;
250-
BigInt H = D - B;
248+
BigInt G = (D + B) % curve.p;
249+
BigInt F = (G - C) % curve.p;
250+
BigInt H = (D - B) % curve.p;
251251
BigInt x3 = (E * F) % curve.p;
252252
BigInt y3 = (G * H) % curve.p;
253253
BigInt t3 = (E * H) % curve.p;

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: cryptography_utils
22
description: "Dart package containing utility methods for common cryptographic and blockchain-specific operations"
33
publish_to: none
4-
version: 0.0.27
4+
version: 0.0.28
55

66
environment:
77
sdk: ">=3.2.6"

test/bip/bip32/derivators/legacy_derivators/ed25519_derivator_test.dart

Lines changed: 36 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -54,106 +54,85 @@ void main() {
5454
expect(actualED25519PrivateKey, expectedED25519PrivateKey);
5555
});
5656

57-
test("Should [return ED25519PrivateKey] constructed from mnemonic and derivation path (m/44'/60'/)", () async {
57+
test("Should [return ED25519PrivateKey] constructed from mnemonic and derivation path (m/44'/501'/)", () async {
5858
// Act
59-
LegacyDerivationPath actualLegacyDerivationPath = LegacyDerivationPath.parse("m/44'/60'/");
59+
LegacyDerivationPath actualLegacyDerivationPath = LegacyDerivationPath.parse("m/44'/501'/");
6060
ED25519PrivateKey actualED25519PrivateKey = await actualED25519Derivator.derivePath(actualMnemonic, actualLegacyDerivationPath);
6161

6262
// Assert
6363
ED25519PrivateKey expectedED25519PrivateKey = ED25519PrivateKey(
6464
metadata: Bip32KeyMetadata(
6565
depth: 2,
66-
shiftedIndex: 2147483708,
67-
chainCode: base64Decode('AlYCSjYOCo//7XisF+s9f+4uREPjJlQ3lZVRypceTI0='),
68-
fingerprint: BigInt.parse('4278372777'),
66+
shiftedIndex: 2147484149,
67+
chainCode: base64Decode('N8hqS/GQMbS0QaVEk75FmKA6yPFRa2XC5x+MWTMYSsg='),
68+
fingerprint: BigInt.parse('4036075356'),
6969
parentFingerprint: BigInt.parse('2330465125'),
7070
masterFingerprint: BigInt.parse('3578578273'),
7171
),
72-
edPrivateKey: EDPrivateKey.fromBytes(base64Decode('dZiZCf9yd0YSUxbInwyamtkndKTTRj6j+G6xmj928vY=')),
72+
edPrivateKey: EDPrivateKey.fromBytes(base64Decode('/TWsTCOLvsuX0xrFMzD3yXZSjCQViIGf6hWaevc1vOY=')),
7373
);
7474

7575
expect(actualED25519PrivateKey, expectedED25519PrivateKey);
7676
});
7777

78-
test("Should [return ED25519PrivateKey] constructed from mnemonic and derivation path (m/44'/60'/0'/)", () async {
78+
test("Should [return ED25519PrivateKey] constructed from mnemonic and derivation path (m/44'/501'/0'/)", () async {
7979
// Act
80-
LegacyDerivationPath actualLegacyDerivationPath = LegacyDerivationPath.parse("m/44'/60'/0'/");
80+
LegacyDerivationPath actualLegacyDerivationPath = LegacyDerivationPath.parse("m/44'/501'/0'/");
8181
ED25519PrivateKey actualED25519PrivateKey = await actualED25519Derivator.derivePath(actualMnemonic, actualLegacyDerivationPath);
8282

8383
// Assert
8484
ED25519PrivateKey expectedED25519PrivateKey = ED25519PrivateKey(
8585
metadata: Bip32KeyMetadata(
8686
depth: 3,
8787
shiftedIndex: 2147483648,
88-
chainCode: base64Decode('XJIq3dw+4wLO363ghHmYr8iBf0sSpDC1SsJGbG6BMxM='),
89-
fingerprint: BigInt.parse('4237045580'),
90-
parentFingerprint: BigInt.parse('4278372777'),
88+
chainCode: base64Decode('LxPIxnNe9YXF9o6sstwDQavHXPdE7WUF2cKUqxS+MTc='),
89+
fingerprint: BigInt.parse('753771646'),
90+
parentFingerprint: BigInt.parse('4036075356'),
9191
masterFingerprint: BigInt.parse('3578578273'),
9292
),
93-
edPrivateKey: EDPrivateKey.fromBytes(base64Decode('dnfNSsX9wTWBvMXva/SUqWt3iRaK+oH68fM9Feg/SIs=')),
93+
edPrivateKey: EDPrivateKey.fromBytes(base64Decode('T3WAkMPu1mLHuRW+Dra0RFDDclbr6L6zJw6wPkpPJYA=')),
9494
);
9595

9696
expect(actualED25519PrivateKey, expectedED25519PrivateKey);
9797
});
9898

99-
test("Should [return ED25519PrivateKey] constructed from mnemonic and derivation path (m/44'/60'/0'/0'/)", () async {
99+
test("Should [return ED25519PrivateKey] constructed from mnemonic and derivation path (m/44'/501'/0'/0'/)", () async {
100100
// Act
101-
LegacyDerivationPath actualLegacyDerivationPath = LegacyDerivationPath.parse("m/44'/60'/0'/0'/");
101+
LegacyDerivationPath actualLegacyDerivationPath = LegacyDerivationPath.parse("m/44'/501'/0'/0'/");
102102
ED25519PrivateKey actualED25519PrivateKey = await actualED25519Derivator.derivePath(actualMnemonic, actualLegacyDerivationPath);
103103

104104
// Assert
105105
ED25519PrivateKey expectedED25519PrivateKey = ED25519PrivateKey(
106106
metadata: Bip32KeyMetadata(
107107
depth: 4,
108108
shiftedIndex: 2147483648,
109-
chainCode: base64Decode('7VKKNJkj9ZEp7SX+GveAvvcZhi+8NJNrSG98+BNgjxY='),
110-
fingerprint: BigInt.parse('2130523803'),
111-
parentFingerprint: BigInt.parse('4237045580'),
109+
chainCode: base64Decode('bJz0NEJLEZUTTobbklJ8hYb9gCS+4J7UGPMtDyO+IDY='),
110+
fingerprint: BigInt.parse('635615273'),
111+
parentFingerprint: BigInt.parse('753771646'),
112112
masterFingerprint: BigInt.parse('3578578273'),
113113
),
114-
edPrivateKey: EDPrivateKey.fromBytes(base64Decode('Dy1S7AO7gPWC+vO7mV/cwTi9sjJ56abeYtD8s3qRTAk=')),
114+
edPrivateKey: EDPrivateKey.fromBytes(base64Decode('iGjr84MoC1+WAY4cnAFqETc5KjMEtZ7CfAYvxkd877M=')),
115115
);
116116

117117
expect(actualED25519PrivateKey, expectedED25519PrivateKey);
118118
});
119119

120-
test("Should [return ED25519PrivateKey] constructed from mnemonic and derivation path (m/44'/60'/0'/0'/0')", () async {
120+
test("Should [return ED25519PrivateKey] constructed from mnemonic and derivation path (m/44'/501'/1'/0'/)", () async {
121121
// Act
122-
LegacyDerivationPath actualLegacyDerivationPath = LegacyDerivationPath.parse("m/44'/60'/0'/0'/0'");
122+
LegacyDerivationPath actualLegacyDerivationPath = LegacyDerivationPath.parse("m/44'/501'/1'/0'/");
123123
ED25519PrivateKey actualED25519PrivateKey = await actualED25519Derivator.derivePath(actualMnemonic, actualLegacyDerivationPath);
124124

125125
// Assert
126126
ED25519PrivateKey expectedED25519PrivateKey = ED25519PrivateKey(
127127
metadata: Bip32KeyMetadata(
128-
depth: 5,
128+
depth: 4,
129129
shiftedIndex: 2147483648,
130-
chainCode: base64Decode('hz6ve3vISMyVDK7ZD0zQoV2v4K1ota1QJ9kY1xakFR4='),
131-
fingerprint: BigInt.parse('3808761756'),
132-
parentFingerprint: BigInt.parse('2130523803'),
130+
chainCode: base64Decode('pdvuHGZNYfgdrW/BAMpsBlNcM2xCYGKsT7j4ZymApJA='),
131+
fingerprint: BigInt.parse('1931527399'),
132+
parentFingerprint: BigInt.parse('429089605'),
133133
masterFingerprint: BigInt.parse('3578578273'),
134134
),
135-
edPrivateKey: EDPrivateKey.fromBytes(base64Decode('fbrqtRb364ZjYonX89pDhtlKE+4jFrxmpHGU2kmQaGs=')),
136-
);
137-
138-
expect(actualED25519PrivateKey, expectedED25519PrivateKey);
139-
});
140-
141-
test("Should [return ED25519PrivateKey] constructed from mnemonic and derivation path (m/44'/60'/0'/0'/1')", () async {
142-
// Act
143-
LegacyDerivationPath actualLegacyDerivationPath = LegacyDerivationPath.parse("m/44'/60'/0'/0'/1'");
144-
ED25519PrivateKey actualED25519PrivateKey = await actualED25519Derivator.derivePath(actualMnemonic, actualLegacyDerivationPath);
145-
146-
// Assert
147-
ED25519PrivateKey expectedED25519PrivateKey = ED25519PrivateKey(
148-
metadata: Bip32KeyMetadata(
149-
depth: 5,
150-
shiftedIndex: 2147483649,
151-
chainCode: base64Decode('l1JlMYKoERbLwsNQIZbHugLvqyxktb1J+O+zU5jue+k='),
152-
fingerprint: BigInt.parse('2573384385'),
153-
parentFingerprint: BigInt.parse('2130523803'),
154-
masterFingerprint: BigInt.parse('3578578273'),
155-
),
156-
edPrivateKey: EDPrivateKey.fromBytes(base64Decode('AVPH3U7LPhJ6E3PFI9S+Ek+vUM59I5RBk5uRG1nMIBw=')),
135+
edPrivateKey: EDPrivateKey.fromBytes(base64Decode('2fcDuvPOTai9vU+A3d9xto81C5nkpEtawFntHXhyrts=')),
157136
);
158137

159138
expect(actualED25519PrivateKey, expectedED25519PrivateKey);
@@ -215,19 +194,19 @@ void main() {
215194
expect(actualDerivedED25519PrivateKey, expectedDerivedED25519PrivateKey);
216195
});
217196

218-
test("Should [return ED25519PrivateKey] derived from ED25519PrivateKey (m/44'/ -> m/44'/60'/)", () async {
197+
test("Should [return ED25519PrivateKey] derived from ED25519PrivateKey (m/44'/ -> m/44'/501'/)", () async {
219198
// Arrange
220-
LegacyDerivationPathElement actualDerivationPathElement = LegacyDerivationPathElement.parse("60'");
199+
LegacyDerivationPathElement actualDerivationPathElement = LegacyDerivationPathElement.parse("501'");
221200
ED25519PrivateKey actualED25519PrivateKey = ED25519PrivateKey(
222201
metadata: Bip32KeyMetadata(
223202
depth: 1,
224203
shiftedIndex: 2147483692,
225-
chainCode: base64Decode('oVTP3c7E2KeoquJttMLqsSV7zyzEbvACvVcFTjW2Cz4='),
204+
chainCode: base64Decode('N8hqS/GQMbS0QaVEk75FmKA6yPFRa2XC5x+MWTMYSsg='),
226205
fingerprint: BigInt.parse('2330465125'),
227206
parentFingerprint: BigInt.parse('3578578273'),
228207
masterFingerprint: BigInt.parse('3578578273'),
229208
),
230-
edPrivateKey: EDPrivateKey.fromBytes(base64Decode('MinQRVP+LSjLX9pmmkDLcm01pJP8IVaKrlVAGlNXUbs=')),
209+
edPrivateKey: EDPrivateKey.fromBytes(base64Decode('/TWsTCOLvsuX0xrFMzD3yXZSjCQViIGf6hWaevc1vOY=')),
231210
);
232211

233212
// Act
@@ -237,19 +216,19 @@ void main() {
237216
ED25519PrivateKey expectedDerivedED25519PrivateKey = ED25519PrivateKey(
238217
metadata: Bip32KeyMetadata(
239218
depth: 2,
240-
shiftedIndex: 2147483708,
241-
chainCode: base64Decode('AlYCSjYOCo//7XisF+s9f+4uREPjJlQ3lZVRypceTI0='),
242-
fingerprint: BigInt.parse('4278372777'),
219+
shiftedIndex: 2147484149,
220+
chainCode: base64Decode('nVpoaXRJzBmqw/3/DHi9EjRrEWOUiEilp5fbkw8aaTk='),
221+
fingerprint: BigInt.parse('3862087306'),
243222
parentFingerprint: BigInt.parse('2330465125'),
244223
masterFingerprint: BigInt.parse('3578578273'),
245224
),
246-
edPrivateKey: EDPrivateKey.fromBytes(base64Decode('dZiZCf9yd0YSUxbInwyamtkndKTTRj6j+G6xmj928vY=')),
225+
edPrivateKey: EDPrivateKey.fromBytes(base64Decode('/Fcp11uAxg7VyMEvkW5IPYuGDrk2bcxS8tZ8QvZgqaQ=')),
247226
);
248227

249228
expect(actualDerivedED25519PrivateKey, expectedDerivedED25519PrivateKey);
250229
});
251230

252-
test("Should [return ED25519PrivateKey] derived from ED25519PrivateKey (m/44'/60'/ -> m/44'/60'/0'/)", () async {
231+
test("Should [return ED25519PrivateKey] derived from ED25519PrivateKey (m/44'/501'/ -> m/44'/501'/0'/)", () async {
253232
// Arrange
254233
LegacyDerivationPathElement actualDerivationPathElement = LegacyDerivationPathElement.parse("0'");
255234
ED25519PrivateKey actualED25519PrivateKey = ED25519PrivateKey(
@@ -283,7 +262,7 @@ void main() {
283262
expect(actualDerivedED25519PrivateKey, expectedDerivedED25519PrivateKey);
284263
});
285264

286-
test("Should [return ED25519PrivateKey] derived from ED25519PrivateKey (m/44'/60'/0'/ -> m/44'/60'/0'/0'/)", () async {
265+
test("Should [return ED25519PrivateKey] derived from ED25519PrivateKey (m/44'/501'/0'/ -> m/44'/501'/0'/0'/)", () async {
287266
// Arrange
288267
LegacyDerivationPathElement actualDerivationPathElement = LegacyDerivationPathElement.parse("0'");
289268
ED25519PrivateKey actualED25519PrivateKey = ED25519PrivateKey(
@@ -317,7 +296,7 @@ void main() {
317296
expect(actualDerivedED25519PrivateKey, expectedDerivedED25519PrivateKey);
318297
});
319298

320-
test("Should [return ED25519PrivateKey] derived from ED25519PrivateKey (m/44'/60'/0'/0'/ -> m/44'/60'/0'/0'/0'/)", () async {
299+
test("Should [return ED25519PrivateKey] derived from ED25519PrivateKey (m/44'/501'/0'/0'/ -> m/44'/501'/0'/0'/0'/)", () async {
321300
// Arrange
322301
LegacyDerivationPathElement actualDerivationPathElement = LegacyDerivationPathElement.parse("0'");
323302
ED25519PrivateKey actualED25519PrivateKey = ED25519PrivateKey(

test/bip/bip32/hd_wallet/legacy_hd_wallet_test.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -321,10 +321,10 @@ void main() {
321321
EDPoint(
322322
curve: Curves.ed25519,
323323
n: BigInt.parse('7237005577332262213973186563042994240857116359379907606001950938285454250989'),
324-
x: BigInt.parse('44770412612249132879508693710199042699271465674024261288602292914024751467771'),
325-
y: BigInt.parse('9071192539003680880021133333155815940615935403600658841594844653366853384648'),
326-
z: BigInt.parse('215655415489707601689906281986627164961686488479408878249048443374796070278'),
327-
t: BigInt.parse('55926202586167076010672118601058589559146741453778469146658296279768153697900'),
324+
x: BigInt.parse('2897232476953985954279425303677103468775948810819257722110548651944397154000'),
325+
y: BigInt.parse('55864704347926684278745305761095583792533035912294806089133322461286120966785'),
326+
z: BigInt.parse('1'),
327+
t: BigInt.parse('22729427263460374807531776853364223631806892420209994431342720698762552415126'),
328328
),
329329
),
330330
),

test/cdsa/eddsa/ed25519/ed25519_private_key_test.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,10 @@ void main() {
119119
EDPoint(
120120
curve: Curves.ed25519,
121121
n: BigInt.parse('7237005577332262213973186563042994240857116359379907606001950938285454250989'),
122-
x: BigInt.parse('19793122580953396643657614893737675412715271732516190437477497872396293476517'),
123-
y: BigInt.parse('11043535616153659670420426046812415327322207260394876224747641236324749531277'),
124-
z: BigInt.parse('52307325976996590356746334614254516249809358280279038039749391123110162041889'),
125-
t: BigInt.parse('18663140037355883143136513717086037971900193259991003799674694468591719114115'),
122+
x: BigInt.parse('54065565874754690464541746979170565753169877194888053393545030920551520745988'),
123+
y: BigInt.parse('3341297077934518673457142734077350879420471371059900657313532910747302736079'),
124+
z: BigInt.parse('1'),
125+
t: BigInt.parse('17889545404307743854678190178496636156195764849150499252736625982701909100111'),
126126
),
127127
),
128128
);

test/cdsa/eddsa/ed_point_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ void main() {
2121
y: BigInt.parse('21722763853247575927517928451216332729805032358530396811928860500080504648297'),
2222
z: BigInt.one,
2323
t: BigInt.parse(
24-
'788462136826487035517522181628529984945326118901391734773631962347443138612680071187232142979650154875261951270767071733362165107888869070753013137283114'),
24+
'35199835903149059728846105492536262642237786856927316283699659281752607508541'),
2525
);
2626

2727
expect(actualEDPoint, expectedEDPoint);

0 commit comments

Comments
 (0)