This commit is contained in:
Matthew Fosse 2024-09-04 15:50:56 -07:00
parent 5ec0e264ce
commit 7b5c36e5a7
7 changed files with 185 additions and 128 deletions

View file

@ -1,4 +1,6 @@
import 'package:bech32/bech32.dart';
import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:blockchain_utils/bech32/bech32_base.dart';
import 'package:blockchain_utils/blockchain_utils.dart'; import 'package:blockchain_utils/blockchain_utils.dart';
import 'package:cw_bitcoin/utils.dart'; import 'package:cw_bitcoin/utils.dart';
import 'package:cw_bitcoin/electrum_wallet_addresses.dart'; import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
@ -7,88 +9,91 @@ import 'package:cw_mweb/cw_mweb.dart';
import 'package:cw_mweb/mwebd.pb.dart'; import 'package:cw_mweb/mwebd.pb.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'dart:typed_data'; // import 'dart:typed_data';
import 'package:bech32/bech32.dart'; // import 'package:bech32/bech32.dart';
import 'package:r_crypto/r_crypto.dart'; // import 'package:r_crypto/r_crypto.dart';
part 'litecoin_wallet_addresses.g.dart'; part 'litecoin_wallet_addresses.g.dart';
// class Keychain {
// // ECPrivate scan;
// // ECPrivate? spend;
// ECPrivate scan;
// ECPrivate? spend;
// ECPublic? spendPubKey;
// Keychain({required this.scan, this.spend, this.spendPubKey}) {
// if (this.spend != null) {
// spendPubKey = this.spend!.getPublic();
// }
// }
// static const HashTagAddress = 'A';
class Keychain { // ECPrivate mi(int index) {
final ECPrivate scan; // final input = BytesBuilder();
ECPrivate? spend;
ECPublic? spendPubKey;
// // Write HashTagAddress to the input
// input.addByte(HashTagAddress.codeUnitAt(0));
Keychain({required this.scan, this.spend, this.spendPubKey}) { // // Write index to the input in little endian
if (this.spend != null) { // final indexBytes = Uint8List(4);
spendPubKey = this.spend!.getPublic(); // final byteData = ByteData.view(indexBytes.buffer);
} // byteData.setUint32(0, index, Endian.little);
} // input.add(indexBytes);
// // Write scan to the input
// input.add(scan.prive.raw);
static const HashTagAddress = 'A'; // // Hash the input using Blake3 with a length of 32 bytes
// final hash = rHash.hashString(HashType.blake3(length: 32), input.toString());
ECPrivate mi(int index) { // // Return the hash digest
final input = BytesBuilder(); // var res = Uint8List.fromList(hash);
// return ECPrivate.fromBytes(res);
// }
// Write HashTagAddress to the input // Keychain address(int index) {
input.addByte(HashTagAddress.codeUnitAt(0));
// Write index to the input in little endian // final miPub = this.mi(index).getPublic();
final indexBytes = Uint8List(4); // final Bi = spendPubKey!.pubkeyAdd(miPub);
final byteData = ByteData.view(indexBytes.buffer); // // final Ai = Bi.pubkeyMult(ECPublic.fromBytes(scan.toBytes()));
byteData.setUint32(0, index, Endian.little); // final Ai = Bi.tweakMul(scan.toBigInt());
input.add(indexBytes);
// Write scan to the input // // final miPubKey = ECCurve_secp256k1().G * BigInt.parse(hex.encode(mi), radix: 16);
input.add(scan.prive.raw); // // final Bi = spendPubKey + miPubKey;
// // return Uint8List.fromList(Ai.getEncoded(compressed: true) + Bi.getEncoded(compressed: true));
// final AiPriv = ECPrivate.fromBytes(Ai.toBytes());
// final BiPriv = ECPrivate.fromBytes(Bi.toBytes());
// Hash the input using Blake3 with a length of 32 bytes // return Keychain(scan: AiPriv, spend: BiPriv);
final hash = rHash.hashString(HashType.blake3(length: 32), input.toString()); // }
// Return the hash digest // String addressString(int index) {
var res = Uint8List.fromList(hash); // final address = this.address(index);
return ECPrivate.fromBytes(res); // List<int> bytes = [];
} // bytes.addAll(address.scan.toBytes());
// bytes.addAll(address.spend!.toBytes());
// return encodeMwebAddress(bytes);
// }
Keychain address(int index) { // // Uint8List spendKey(int index) {
// // final mi = this.mi(index);
// // final spendKey = spend + ECCurve_secp256k1().G * BigInt.parse(hex.encode(mi), radix: 16);
// // return spendKey.getEncoded(compressed: true);
// // }
final miPub = this.mi(index).getPublic(); // String encodeMwebAddress(List<int> scriptPubKey) {
final Bi = spendPubKey!.pubkeyAdd(miPub); // return bech32.encode(Bech32("ltcmweb", scriptPubKey));
final Ai = Bi.pubkeyMult(ECPublic.fromBytes(scan.toBytes())); // }
// final miPubKey = ECCurve_secp256k1().G * BigInt.parse(hex.encode(mi), radix: 16);
// final Bi = spendPubKey + miPubKey;
// return Uint8List.fromList(Ai.getEncoded(compressed: true) + Bi.getEncoded(compressed: true));
final AiPriv = ECPrivate.fromBytes(Ai.toBytes());
final BiPriv = ECPrivate.fromBytes(Bi.toBytes());
return Keychain(scan: AiPriv, spend: BiPriv);
}
String addressString(int index) {
final address = this.address(index);
List<int> bytes = [];
bytes.addAll(address.scan.toBytes());
bytes.addAll(address.spend!.toBytes());
return encodeMwebAddress(bytes);
}
// Uint8List spendKey(int index) {
// final mi = this.mi(index);
// final spendKey = spend + ECCurve_secp256k1().G * BigInt.parse(hex.encode(mi), radix: 16);
// return spendKey.getEncoded(compressed: true);
// } // }
String encodeMwebAddress(List<int> scriptPubKey) { String encodeMwebAddress(List<int> scriptPubKey) {
return bech32.encode(Bech32("ltcmweb", scriptPubKey)); return bech32.encode(Bech32("ltcmweb1", scriptPubKey), 250);
} }
}
class LitecoinWalletAddresses = LitecoinWalletAddressesBase with _$LitecoinWalletAddresses; class LitecoinWalletAddresses = LitecoinWalletAddressesBase with _$LitecoinWalletAddresses;
abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with Store { abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with Store {
LitecoinWalletAddressesBase( LitecoinWalletAddressesBase(
WalletInfo walletInfo, { WalletInfo walletInfo, {
@ -119,7 +124,6 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
List<String> mwebAddrs = []; List<String> mwebAddrs = [];
List<String> oldMwebAddrs = []; List<String> oldMwebAddrs = [];
Future<void> topUpMweb(int index) async { Future<void> topUpMweb(int index) async {
final stub = await CwMweb.stub(); final stub = await CwMweb.stub();
while (oldMwebAddrs.length - index < 1000) { while (oldMwebAddrs.length - index < 1000) {
@ -135,16 +139,19 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
} }
} }
// Keychain k = Keychain(scan: ECPrivate.fromBytes(scanSecret), spendPubKey: ECPublic.fromBytes(spendPubkey),);
Keychain k = Keychain(scan: ECPrivate.fromBytes(scanSecret), spendPubKey: ECPublic.fromBytes(spendPubkey),);
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
final address = k.addressString(i + 1000); // final address = k.addressString(i + 1000);
final addressHex =
await CwMweb.address(hex.encode(scanSecret), hex.encode(spendPubkey), index);
// print(addressHex);
// print(hex.decode(addressHex!).length);
// return;
final address = encodeMwebAddress(hex.decode(addressHex!));
mwebAddrs.add(address); mwebAddrs.add(address);
} }
print("old function: ${oldMwebAddrs.first} new function!: ${mwebAddrs.first}"); print("old function: ${oldMwebAddrs.first} new function!: ${mwebAddrs.first}");
} }
@override @override

View file

@ -40,6 +40,12 @@ class CwMwebPlugin: FlutterPlugin, MethodCallHandler {
server = null server = null
port = null port = null
result.success(null) result.success(null)
} else if (call.method == "address") {
val scanSecret: String = call.argument<String>("scanSecret") ?: ""
val spendPub: String = call.argument<String>("spendPub") ?: ""
val index: Int = call.argument<Int>("index") ?: 0
val res = Mwebd.addressIndex(scanSecret, spendPub)
result.success(res)
} else { } else {
result.notImplemented() result.notImplemented()
} }

View file

@ -17,17 +17,28 @@ public class CwMwebPlugin: NSObject, FlutterPlugin {
switch call.method { switch call.method {
case "getPlatformVersion": case "getPlatformVersion":
result("iOS " + UIDevice.current.systemVersion) result("iOS " + UIDevice.current.systemVersion)
break
case "start": case "start":
stopServer() stopServer()
let args = call.arguments as? [String: String] let args = call.arguments as? [String: String]
let dataDir = args?["dataDir"] let dataDir = args?["dataDir"]
CwMwebPlugin.dataDir = dataDir CwMwebPlugin.dataDir = dataDir
startServer(result: result) startServer(result: result)
break
case "stop": case "stop":
stopServer() stopServer()
result(nil) result(nil)
break
case "address":
let args = call.arguments as? [String: String]
let scanSecret = args?["scanSecret"]
let spendPub = args?["spendPub"]
let index = args?["index"]
result(address(scanSecret, spendPub, index))
break
default: default:
result(FlutterMethodNotImplemented) result(FlutterMethodNotImplemented)
break
} }
} }
@ -66,6 +77,15 @@ public class CwMwebPlugin: NSObject, FlutterPlugin {
CwMwebPlugin.port = 0 CwMwebPlugin.port = 0
} }
private func address(_ scanSecret: String?, _ spendPub: String?, _ index: Int?) -> String? {
guard let scanSecret = scanSecret, let spendPub = spendPub, let index = index else {
print("Invalid arguments for address function")
return nil
}
return MwebdAddressIndex(scanSecret, spendPub, UInt32(index))
}
deinit { deinit {
stopServer() stopServer()
} }

View file

@ -53,6 +53,15 @@ class CwMweb {
await cleanup(); await cleanup();
} }
static Future<String?> address(String scanSecret, String spendPub, int index) async {
// try {
// return (await CwMwebPlatform.instance.address(scan, spendPub, index))!;
// } catch (e) {
// print("error generating address!: $e");
// }
return CwMwebPlatform.instance.address(scanSecret, spendPub, index);
}
static Future<void> cleanup() async { static Future<void> cleanup() async {
await _clientChannel?.terminate(); await _clientChannel?.terminate();
_rpcClient = null; _rpcClient = null;

View file

@ -19,4 +19,14 @@ class MethodChannelCwMweb extends CwMwebPlatform {
Future<void> stop() async { Future<void> stop() async {
await methodChannel.invokeMethod<void>('stop'); await methodChannel.invokeMethod<void>('stop');
} }
@override
Future<String?> address(String scanSecret, String spendPub, int index) async {
final result = await methodChannel.invokeMethod<String>('address', {
'scanSecret': scanSecret,
'spendPub': spendPub,
'index': index,
});
return result;
}
} }

View file

@ -30,4 +30,8 @@ abstract class CwMwebPlatform extends PlatformInterface {
Future<void> stop() { Future<void> stop() {
throw UnimplementedError('stop() has not been implemented.'); throw UnimplementedError('stop() has not been implemented.');
} }
Future<String?> address(String scanSecret, String spendPub, int index) {
throw UnimplementedError('address(int) has not been implemented.');
}
} }

View file

@ -136,6 +136,7 @@ dependency_overrides:
git: git:
url: https://github.com/cake-tech/bitcoin_base url: https://github.com/cake-tech/bitcoin_base
ref: cake-update-v6 ref: cake-update-v6
ffi: 2.1.0
flutter_icons: flutter_icons:
image_path: "assets/images/app_logo.png" image_path: "assets/images/app_logo.png"