Skip to content

Commit 79ecf70

Browse files
committed
V5.0.0
- Ported the Bitcoin secp256k1 cryptographic library to Dart. - Enhanced security: all private key implementations (except secp256r1) now use constant-time techniques for public key generation. - Improved signing safety: all signer classes (except secp256r1) now use constant-time signing methods. <sub>Note: I'm not an expert in constant-time or side-channel attack mitigation. Feedback is welcome to help improve the safety of this package.</sub>
1 parent 8527d80 commit 79ecf70

128 files changed

Lines changed: 40407 additions & 2125 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
## 5.0.0
2+
3+
- Ported the Bitcoin secp256k1 cryptographic library to Dart.
4+
- Enhanced security: all private key implementations (except secp256r1) now use constant-time techniques for public key generation.
5+
- Improved signing safety: all signer classes (except secp256r1) now use constant-time signing methods.
6+
<sub>Note: I'm not an expert in constant-time or side-channel attack mitigation. Feedback is welcome to help improve the safety of this package.</sub>
7+
8+
19
## 4.4.0
210
- Added support for BCH schnor signig and verifying
311
- Fix schnorr signature validation

lib/bip/address/ada/ada_shelley_addr.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'dart:typed_data';
22
import 'package:blockchain_utils/bech32/bech32_base.dart';
3+
import 'package:blockchain_utils/helper/helper.dart';
34
import 'package:blockchain_utils/utils/utils.dart';
45
import 'package:blockchain_utils/bip/address/addr_dec_utils.dart';
56
import 'package:blockchain_utils/bip/address/addr_key_validator.dart';
@@ -57,7 +58,7 @@ class AdaStakeCredential {
5758
final AdaStakeCredType type;
5859
final List<int> hash;
5960
AdaStakeCredential._(this.type, List<int> hash)
60-
: hash = BytesUtils.toBytes(hash, unmodifiable: true);
61+
: hash = hash.asImmutableBytes;
6162

6263
factory AdaStakeCredential(
6364
{required List<int> hash, required AdaStakeCredType type}) {

lib/bip/address/ada/gneric_addr_decoder.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'package:blockchain_utils/bip/address/addr_dec_utils.dart';
66
import 'package:blockchain_utils/bip/address/decoder.dart';
77
import 'package:blockchain_utils/bip/address/exception/exception.dart';
88
import 'package:blockchain_utils/crypto/quick_crypto.dart';
9+
import 'package:blockchain_utils/helper/extensions/extensions.dart';
910
import 'package:blockchain_utils/utils/utils.dart';
1011

1112
import 'ada_addres_type.dart';
@@ -21,8 +22,8 @@ class AdaGenericAddrDecoderResult {
2122
this.stakeHashBytes,
2223
this.pointer,
2324
this.byronAddrPayload})
24-
: addressBytes = BytesUtils.toBytes(addressBytes, unmodifiable: true),
25-
prefixBytes = BytesUtils.tryToBytes(prefixBytes, unmodifiable: true);
25+
: addressBytes = addressBytes.asImmutableBytes,
26+
prefixBytes = prefixBytes?.asImmutableBytes;
2627
final ADAAddressType type;
2728
final List<int> addressBytes;
2829
final AdaStakeCredential? baseHashBytes;

lib/bip/address/ton_addr.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import 'package:blockchain_utils/bip/address/addr_key_validator.dart';
2525
import 'package:blockchain_utils/bip/address/decoder.dart';
2626
import 'package:blockchain_utils/bip/address/encoder.dart';
2727
import 'package:blockchain_utils/crypto/crypto/crc16/crc16.dart';
28+
import 'package:blockchain_utils/helper/helper.dart';
2829
import 'package:blockchain_utils/utils/utils.dart';
2930
import 'exception/exception.dart';
3031

@@ -184,7 +185,7 @@ class TonAddressUtils {
184185
"length": bytes.length
185186
});
186187
}
187-
return BytesUtils.toBytes(bytes, unmodifiable: true);
188+
return bytes.asImmutableBytes;
188189
}
189190
}
190191

lib/bip/address/xlm_addr.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import 'package:blockchain_utils/bip/address/addr_key_validator.dart';
44
import 'package:blockchain_utils/bip/address/decoder.dart';
55
import 'package:blockchain_utils/bip/ecc/keys/ed25519_keys.dart';
66
import 'package:blockchain_utils/crypto/crypto/x_modem_crc/x_modem_crc.dart';
7+
import 'package:blockchain_utils/helper/helper.dart';
78
import 'package:blockchain_utils/utils/binary/binary_operation.dart';
8-
import 'package:blockchain_utils/utils/binary/utils.dart';
99
import 'package:blockchain_utils/utils/numbers/numbers.dart';
1010
import 'exception/exception.dart';
1111
import 'encoder.dart';
@@ -98,7 +98,7 @@ class XlmAddrDecoderResult {
9898
required List<int> pubKeyBytes,
9999
required this.baseAddress,
100100
required this.accountId})
101-
: pubKeyBytes = BytesUtils.toBytes(pubKeyBytes, unmodifiable: true);
101+
: pubKeyBytes = pubKeyBytes.asImmutableBytes;
102102
@override
103103
String toString() {
104104
return baseAddress;

lib/bip/address/xrp_addr.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:blockchain_utils/base58/base58.dart';
2+
import 'package:blockchain_utils/helper/helper.dart';
23
import 'package:blockchain_utils/utils/utils.dart';
34
import 'package:blockchain_utils/bip/address/addr_dec_utils.dart';
45
import 'package:blockchain_utils/bip/address/addr_key_validator.dart';
@@ -31,7 +32,7 @@ class XRPXAddressDecodeResult {
3132
final bool isTestnet;
3233
XRPXAddressDecodeResult(
3334
{required List<int> bytes, required this.tag, required this.isTestnet})
34-
: bytes = BytesUtils.toBytes(bytes, unmodifiable: true);
35+
: bytes = bytes.asImmutableBytes;
3536
}
3637

3738
class XRPAddressUtils {

lib/bip/bip/bip32/khalow/bip32_kholaw_ed25519_key_derivator.dart

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'dart:typed_data';
22

3+
import 'package:blockchain_utils/crypto/crypto/crypto.dart';
34
import 'package:blockchain_utils/utils/utils.dart';
45
import 'package:blockchain_utils/bip/bip/bip32/bip32_ex.dart';
56
import 'package:blockchain_utils/bip/bip/bip32/bip32_key_data.dart';
@@ -8,7 +9,6 @@ import 'package:blockchain_utils/bip/bip/bip32/khalow/bip32_kholaw_key_derivator
89
import 'package:blockchain_utils/bip/ecc/curve/elliptic_curve_getter.dart';
910
import 'package:blockchain_utils/bip/ecc/curve/elliptic_curve_types.dart';
1011
import 'package:blockchain_utils/bip/ecc/keys/ed25519_kholaw_keys.dart';
11-
import 'package:blockchain_utils/crypto/crypto/cdsa/point/edwards.dart';
1212

1313
/// Define a class, 'Bip32KholawEd25519KeyDerivator', that extends 'Bip32KholawEd25519KeyDerivatorBase'
1414
/// for Ed25519 key derivation.
@@ -43,16 +43,16 @@ class Bip32KholawEd25519KeyDerivator
4343
final BigInt klInt =
4444
BigintUtils.fromBytes(klBytes, byteOrder: Endian.little);
4545

46-
final EDPoint generator =
47-
EllipticCurveGetter.generatorFromType(curve) as EDPoint;
4846
final BigInt prvlInt = (zlInt * BigInt.from(8)) + klInt;
49-
if (prvlInt % generator.order! == BigInt.zero) {
50-
throw const Bip32KeyError(
51-
'Computed child key is not valid, very unlucky index');
52-
}
5347
final tobytes = BigintUtils.toBytes(prvlInt,
5448
order: Endian.little,
5549
length: Ed25519KholawKeysConst.privKeyByteLen ~/ 2);
50+
final sc = Ed25519Utils.scalarReduceConst(tobytes);
51+
if (BytesUtils.bytesEqual(sc, CryptoOpsConst.zero)) {
52+
throw const Bip32KeyError(
53+
'Computed child key is not valid, very unlucky index');
54+
}
55+
5656
return tobytes;
5757
}
5858

lib/bip/bip/bip32/slip10/bip32_slip10_key_derivator.dart

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import 'dart:typed_data';
2-
2+
import 'package:blockchain_utils/crypto/crypto/cdsa/secp256k1/secp256k1.dart';
33
import 'package:blockchain_utils/utils/utils.dart';
44
import 'package:blockchain_utils/bip/bip/bip32/base/ibip32_key_derivator.dart';
55
import 'package:blockchain_utils/bip/bip/bip32/bip32_key_data.dart';
@@ -57,16 +57,45 @@ class Bip32Slip10EcdsaDerivator implements IBip32KeyDerivator {
5757

5858
final ilBytes = hmacHalves.item1;
5959
final irBytes = hmacHalves.item2;
60-
final ilInt = BigintUtils.fromBytes(ilBytes);
61-
final privKeyInt = BigintUtils.fromBytes(privKeyBytes);
62-
final generator = EllipticCurveGetter.generatorFromType(type);
63-
final scalar = (ilInt + privKeyInt) % generator.order!;
60+
final scalar =
61+
_addScalar(privKeyBytes: privKeyBytes, newScalar: ilBytes, type: type);
6462
final newPrivKeyBytes = BigintUtils.toBytes(scalar,
6563
order: Endian.big, length: privKey.privKey.length);
6664

6765
return Tuple(newPrivKeyBytes, irBytes);
6866
}
6967

68+
BigInt _addScalar(
69+
{required List<int> privKeyBytes,
70+
required List<int> newScalar,
71+
required EllipticCurveTypes type}) {
72+
switch (type) {
73+
case EllipticCurveTypes.secp256k1:
74+
Secp256k1Scalar privKeyScalar = Secp256k1Scalar();
75+
Secp256k1.secp256k1ScalarSetB32(privKeyScalar, privKeyBytes);
76+
Secp256k1Scalar newSc = Secp256k1Scalar();
77+
Secp256k1.secp256k1ScalarSetB32(newSc, newScalar);
78+
Secp256k1Scalar result = Secp256k1Scalar();
79+
Secp256k1.secp256k1ScalarAdd(result, privKeyScalar, newSc);
80+
final scBytes = List<int>.filled(32, 0);
81+
Secp256k1.secp256k1ScalarGetB32(scBytes, result);
82+
final nd = BigintUtils.fromBytes(scBytes);
83+
84+
final ilInt = BigintUtils.fromBytes(newScalar);
85+
final privKeyInt = BigintUtils.fromBytes(privKeyBytes);
86+
final generator = EllipticCurveGetter.generatorFromType(type);
87+
final newScalarBig = (ilInt + privKeyInt) % generator.order!;
88+
assert(newScalarBig == nd);
89+
return nd;
90+
91+
default:
92+
final ilInt = BigintUtils.fromBytes(newScalar);
93+
final privKeyInt = BigintUtils.fromBytes(privKeyBytes);
94+
final generator = EllipticCurveGetter.generatorFromType(type);
95+
return (ilInt + privKeyInt) % generator.order!;
96+
}
97+
}
98+
7099
/// Derive a child public key from the given parent public key using the provided
71100
/// index and elliptic curve type.
72101
///

lib/bip/bip/bip32/slip10/bip32_slip10_mst_key_generator.dart

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,7 @@ class _Bip32Slip10MstKeyGenerator {
109109
hmacData = hmac;
110110
}
111111
}
112-
return Tuple(
113-
hmac.sublist(0, hmacHalfLen),
114-
hmac.sublist(hmacHalfLen),
115-
);
112+
return Tuple(hmac.sublist(0, hmacHalfLen), hmac.sublist(hmacHalfLen));
116113
}
117114
}
118115

@@ -128,10 +125,9 @@ class Bip32Slip10Ed25519MstKeyGenerator implements IBip32MstKeyGenerator {
128125
@override
129126
Tuple<List<int>, List<int>> generateFromSeed(List<int> seedBytes) {
130127
return _Bip32Slip10MstKeyGenerator.generateFromSeed(
131-
seedBytes,
132-
List<int>.from(Bip32Slip10MstKeyGeneratorConst.hmacKeyEd25519Bytes),
133-
EllipticCurveTypes.ed25519,
134-
);
128+
seedBytes,
129+
List<int>.from(Bip32Slip10MstKeyGeneratorConst.hmacKeyEd25519Bytes),
130+
EllipticCurveTypes.ed25519);
135131
}
136132
}
137133

@@ -147,10 +143,9 @@ class Bip32Slip10Nist256p1MstKeyGenerator implements IBip32MstKeyGenerator {
147143
@override
148144
Tuple<List<int>, List<int>> generateFromSeed(List<int> seedBytes) {
149145
return _Bip32Slip10MstKeyGenerator.generateFromSeed(
150-
seedBytes,
151-
List<int>.from(Bip32Slip10MstKeyGeneratorConst.hmacKeyNist256p1Bytes),
152-
EllipticCurveTypes.nist256p1,
153-
);
146+
seedBytes,
147+
List<int>.from(Bip32Slip10MstKeyGeneratorConst.hmacKeyNist256p1Bytes),
148+
EllipticCurveTypes.nist256p1);
154149
}
155150
}
156151

lib/bip/bip/bip38/bip38_ec.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ class Bip38EcKeysGenerator {
292292
final magic = intPassphraseBytes.sublist(0, 8);
293293
final ownerEntropy = intPassphraseBytes.sublist(8, 16);
294294
final passpoint =
295-
Secp256k1PublicKeyEcdsa.fromBytes(intPassphraseBytes.sublist(16));
295+
Secp256k1PublicKey.fromBytes(intPassphraseBytes.sublist(16));
296296

297297
/// Check if the magic number is valid.
298298
if (!BytesUtils.bytesEqual(magic, Bip38EcConst.intPassMagicNoLotSeq) &&
@@ -442,7 +442,7 @@ class Bip38EcDecrypter {
442442
final privateKeyBytes = _computePrivateKey(passfactor, factorb);
443443

444444
/// Create a public key from the private key and calculate address hash.
445-
final toPub = Secp256k1PrivateKeyEcdsa.fromBytes(privateKeyBytes);
445+
final toPub = Secp256k1PrivateKey.fromBytes(privateKeyBytes);
446446
final addressHashGot = Bip38Addr.addressHash(
447447
toPub.publicKey.point.toBytes(), flagOptions.item1);
448448

0 commit comments

Comments
 (0)