Line data Source code
1 : import 'dart:typed_data';
2 : import 'package:dart_bech32/dart_bech32.dart';
3 : import 'package:pointycastle/digests/ripemd160.dart';
4 : import 'package:pointycastle/digests/sha256.dart';
5 : import 'package:walletkit_dart/src/utils/base32.dart';
6 : import 'package:convert/convert.dart' show hex;
7 : import 'package:bs58check/bs58check.dart' as bs58check;
8 : import 'package:walletkit_dart/src/utils/base58.dart';
9 : import 'package:walletkit_dart/walletkit_dart.dart';
10 :
11 3 : String pubKeyHexToAddress(
12 : String pubKeyHex,
13 : AddressType addressType,
14 : UTXONetworkType networkType,
15 : ) {
16 6 : final pubKey = Uint8List.fromList(hex.decode(pubKeyHex));
17 3 : return pubKeyToAddress(pubKey, addressType, networkType);
18 : }
19 :
20 10 : String pubKeyToAddress(
21 : Uint8List pubKey,
22 : AddressType addressType,
23 : UTXONetworkType networkType,
24 : ) {
25 10 : final pubKeyHash = ripmed160Sha256Hash(pubKey);
26 :
27 : return switch (addressType) {
28 16 : AddressType.segwit => pubKeyHashToSegwitAddress(
29 : pubKeyHash,
30 6 : networkType.bech32,
31 6 : networkType.pubKeyHashPrefix,
32 : ),
33 11 : AddressType.compatibility => pubKeyHashToP2SHAddress(
34 : pubKey,
35 1 : networkType.scriptHashPrefix,
36 : ),
37 18 : AddressType.legacy => pubKeyHashToLegacyAddress(
38 : pubKeyHash,
39 9 : networkType.pubKeyHashPrefix,
40 : ),
41 6 : AddressType.cashaddr => bchAddrEncode(
42 3 : hrp: networkType.bech32,
43 : data: pubKeyHash,
44 3 : witnessVersion: networkType.pubKeyHashPrefix,
45 : ),
46 0 : _ => throw UnsupportedError("Address type not supported: $addressType")
47 : };
48 : }
49 :
50 8 : String pubKeyHashToAddress(
51 : Uint8List pubKeyHash,
52 : AddressType addressType,
53 : UTXONetworkType networkType,
54 : ) {
55 : return switch (addressType) {
56 12 : AddressType.segwit => pubKeyHashToSegwitAddress(
57 : pubKeyHash,
58 4 : networkType.bech32,
59 4 : networkType.pubKeyHashPrefix,
60 : ),
61 16 : AddressType.legacy => pubKeyHashToLegacyAddress(
62 : pubKeyHash,
63 8 : networkType.pubKeyHashPrefix,
64 : ),
65 6 : AddressType.cashaddr => bchAddrEncode(
66 3 : hrp: networkType.bech32,
67 : data: pubKeyHash,
68 3 : witnessVersion: networkType.pubKeyHashPrefix,
69 : ),
70 0 : _ => throw UnsupportedError("Address type not supported: $addressType")
71 : };
72 : }
73 :
74 : ///
75 : /// Legacy Address (Base58)
76 : ///
77 9 : String pubKeyHashToLegacyAddress(Uint8List pubKeyHash, int witnessVersion) {
78 27 : final data = Uint8List.fromList([witnessVersion, ...pubKeyHash]);
79 :
80 9 : return bs58check.encode(data);
81 : }
82 :
83 : ///
84 : /// Segwit Address (Bech32)
85 : ///
86 6 : String pubKeyHashToSegwitAddress(
87 : Uint8List pubKeyHash,
88 : String bech32Prefix,
89 : int witnessVersion,
90 : ) {
91 6 : final words = bech32.toWords(pubKeyHash);
92 :
93 18 : final wordsWithVersion = Uint8List.fromList([0, ...words]);
94 :
95 6 : final decoded = Decoded(prefix: bech32Prefix, words: wordsWithVersion);
96 :
97 : try {
98 6 : bech32.encode(decoded);
99 : } catch (e) {
100 0 : print(e);
101 : }
102 :
103 6 : return bech32.encode(decoded);
104 : }
105 :
106 : ///
107 : /// P2SH Address (Base58)
108 : ///
109 5 : String pubKeyHashToP2SHAddress(Uint8List pubKeyHash, int scriptHashPrefix) {
110 15 : final prefixedHash = Uint8List.fromList([scriptHashPrefix, ...pubKeyHash]);
111 :
112 10 : final checkSum = sha256Sha256Hash(prefixedHash).sublist(0, 4);
113 :
114 5 : final prefixedHashWithChecksum = Uint8List.fromList(
115 10 : [...prefixedHash, ...checkSum],
116 : );
117 :
118 5 : return base58Encode(prefixedHashWithChecksum);
119 : }
120 :
121 : ///
122 : /// Ripmed160 Hash of Sha256 Hash
123 : ///
124 10 : Uint8List ripmed160Sha256Hash(Uint8List buffer) {
125 10 : final ripmed160 = RIPEMD160Digest();
126 10 : final sha256 = SHA256Digest();
127 20 : return ripmed160.process(sha256.process(buffer));
128 : }
129 :
130 : ///
131 : /// Sha256 Hash of Sha256 Hash
132 : ///
133 8 : Uint8List sha256Sha256Hash(Uint8List buffer) {
134 8 : final sha256 = SHA256Digest();
135 16 : return sha256.process(sha256.process(buffer));
136 : }
137 :
138 : ///
139 : /// Sha256 Hash
140 : ///
141 12 : Uint8List sha256Hash(Uint8List buffer) {
142 12 : final sha256 = SHA256Digest();
143 12 : return sha256.process(buffer);
144 : }
145 :
146 : ///
147 : /// BCH CashAddr
148 : ///
149 :
150 3 : BigInt _polymod(List<int> data) {
151 3 : List<BigInt> GENERATOR = [
152 3 : BigInt.from(0x98f2bc8e61),
153 3 : BigInt.from(0x79b76d99e2),
154 3 : BigInt.from(0xf33e5fb3c4),
155 3 : BigInt.from(0xae2eabe2a8),
156 3 : BigInt.from(0x1e4f43e470),
157 : ];
158 :
159 3 : BigInt checksum = BigInt.from(1);
160 :
161 9 : for (int i = 0; i < data.length; ++i) {
162 3 : int value = data[i];
163 3 : BigInt topBits = checksum >> 35;
164 : checksum =
165 15 : ((checksum & BigInt.from(0x07ffffffff)) << 5) ^ BigInt.from(value);
166 :
167 9 : for (int j = 0; j < GENERATOR.length; ++j) {
168 15 : if ((topBits >> j) & BigInt.from(1) == BigInt.from(1)) {
169 6 : checksum = checksum ^ GENERATOR[j];
170 : }
171 : }
172 : }
173 :
174 6 : return checksum ^ BigInt.from(1);
175 : }
176 :
177 3 : String bchAddrEncode({
178 : required String hrp,
179 : required int witnessVersion,
180 : required List<int> data,
181 : }) {
182 12 : final prefixData = [..._prefixToUint5Array(hrp), 0].toUint8List;
183 :
184 12 : final payloadData = bech32.toWords([witnessVersion, ...data].toUint8List);
185 :
186 3 : final checksumData = [
187 : ...prefixData,
188 3 : ...payloadData,
189 3 : ...[0, 0, 0, 0, 0, 0, 0, 0]
190 3 : ].toUint8List;
191 :
192 : final checksumUint5List =
193 9 : _checksumToUint5List(_polymod(checksumData).toInt());
194 :
195 9 : final payload = [...payloadData, ...checksumUint5List].toUint8List;
196 :
197 6 : final base32Encoded = Base32().encode(payload);
198 :
199 3 : return "$hrp:$base32Encoded";
200 : }
201 :
202 3 : Uint8List _checksumToUint5List(int checksum) {
203 3 : final result = Uint8List(8);
204 6 : for (var i = 0; i < 8; ++i) {
205 9 : result[7 - i] = checksum & 31;
206 3 : checksum = checksum >> 5;
207 : }
208 : return result;
209 : }
210 :
211 3 : Uint8List _prefixToUint5Array(String prefix) {
212 6 : var result = new Uint8List(prefix.length);
213 9 : for (var i = 0; i < prefix.length; ++i) {
214 12 : result[i] = prefix[i].codeUnitAt(0) & 31;
215 : }
216 : return result;
217 : }
|