fix formatting

This commit is contained in:
julian 2023-07-27 11:33:39 -06:00
parent 9b4c1abf35
commit aa2ab89f73
11 changed files with 785 additions and 923 deletions

View file

@ -1,12 +1,12 @@
import 'util.dart';
import 'connection.dart';
import 'fusion.dart';
import 'fusion.pb.dart';
import 'dart:io';
import 'dart:async';
import 'dart:io';
import 'package:protobuf/protobuf.dart';
import 'socketwrapper.dart';
import 'package:stackwallet/services/cashfusion/connection.dart';
import 'package:stackwallet/services/cashfusion/fusion.dart';
import 'package:stackwallet/services/cashfusion/fusion.pb.dart';
import 'package:stackwallet/services/cashfusion/socketwrapper.dart';
import 'package:stackwallet/services/cashfusion/util.dart';
typedef PbCreateFunc = GeneratedMessage Function();
@ -43,13 +43,11 @@ Map<Type, PbCreateFunc> pbClassCreators = {
ServerMessage: () => ServerMessage(),
CovertMessage: () => CovertMessage(),
CovertResponse: () => CovertResponse()
};
Future<void> sendPb(Connection connection, Type pbClass, GeneratedMessage subMsg, {Duration? timeout}) async {
Future<void> sendPb(
Connection connection, Type pbClass, GeneratedMessage subMsg,
{Duration? timeout}) async {
// Construct the outer message with the submessage.
if (pbClassCreators[pbClass] == null) {
@ -70,11 +68,9 @@ Future<void> sendPb(Connection connection, Type pbClass, GeneratedMessage subMsg
}
}
Future<void> sendPb2(SocketWrapper socketwrapper, Connection connection, Type pbClass, GeneratedMessage subMsg, {Duration? timeout}) async {
Future<void> sendPb2(SocketWrapper socketwrapper, Connection connection,
Type pbClass, GeneratedMessage subMsg,
{Duration? timeout}) async {
// Construct the outer message with the submessage.
if (pbClassCreators[pbClass] == null) {
@ -85,7 +81,8 @@ Future<void> sendPb2(SocketWrapper socketwrapper, Connection connection, Type pb
var pbMessage = pbClassCreators[pbClass]!()..mergeFromMessage(subMsg);
final msgBytes = pbMessage.writeToBuffer();
try {
await connection.sendMessageWithSocketWrapper(socketwrapper, msgBytes, timeout: timeout);
await connection.sendMessageWithSocketWrapper(socketwrapper, msgBytes,
timeout: timeout);
} on SocketException {
throw FusionError('Connection closed by remote');
} on TimeoutException {
@ -95,13 +92,12 @@ Future<void> sendPb2(SocketWrapper socketwrapper, Connection connection, Type pb
}
}
Future<Tuple<GeneratedMessage, String>> recvPb2(SocketWrapper socketwrapper, Connection connection, Type pbClass, List<String> expectedFieldNames, {Duration? timeout}) async {
Future<Tuple<GeneratedMessage, String>> recvPb2(SocketWrapper socketwrapper,
Connection connection, Type pbClass, List<String> expectedFieldNames,
{Duration? timeout}) async {
try {
List<int> blob = await connection.recv_message2(socketwrapper, timeout: timeout);
List<int> blob =
await connection.recv_message2(socketwrapper, timeout: timeout);
var pbMessage = pbClassCreators[pbClass]!()..mergeFromBuffer(blob);
@ -121,8 +117,8 @@ Future<Tuple<GeneratedMessage, String>> recvPb2(SocketWrapper socketwrapper, Con
}
}
throw FusionError('None of the expected fields found in the received message');
throw FusionError(
'None of the expected fields found in the received message');
} catch (e) {
// Handle different exceptions here
if (e is SocketException) {
@ -134,15 +130,16 @@ Future<Tuple<GeneratedMessage, String>> recvPb2(SocketWrapper socketwrapper, Con
} else if (e is OSError && e.errorCode == 9) {
throw FusionError('Connection closed by local');
} else {
throw FusionError('Communications error: ${e.runtimeType}: ${e.toString()}');
throw FusionError(
'Communications error: ${e.runtimeType}: ${e.toString()}');
}
}
}
Future<Tuple<GeneratedMessage, String>> recvPb(Connection connection, Type pbClass, List<String> expectedFieldNames, {Duration? timeout}) async {
Future<Tuple<GeneratedMessage, String>> recvPb(
Connection connection, Type pbClass, List<String> expectedFieldNames,
{Duration? timeout}) async {
try {
List<int> blob = await connection.recv_message(timeout: timeout);
var pbMessage = pbClassCreators[pbClass]!()..mergeFromBuffer(blob);
@ -163,8 +160,8 @@ Future<Tuple<GeneratedMessage, String>> recvPb(Connection connection, Type pbCla
}
}
throw FusionError('None of the expected fields found in the received message');
throw FusionError(
'None of the expected fields found in the received message');
} catch (e) {
// Handle different exceptions here
if (e is SocketException) {
@ -176,8 +173,8 @@ Future<Tuple<GeneratedMessage, String>> recvPb(Connection connection, Type pbCla
} else if (e is OSError && e.errorCode == 9) {
throw FusionError('Connection closed by local');
} else {
throw FusionError('Communications error: ${e.runtimeType}: ${e.toString()}');
throw FusionError(
'Communications error: ${e.runtimeType}: ${e.toString()}');
}
}
}

View file

@ -1,10 +1,10 @@
import 'socketwrapper.dart';
import 'dart:io';
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:convert/convert.dart';
import 'package:collection/collection.dart';
import 'package:convert/convert.dart';
import 'package:stackwallet/services/cashfusion/socketwrapper.dart';
/*
This file might need some fixing up because each time we call fillBuf, we're trying to
@ -22,14 +22,14 @@ class BadFrameError extends Error {
String toString() => message;
}
Future<Connection> openConnection(String host, int port,
{double connTimeout = 5.0,
Future<Connection> openConnection(
String host,
int port, {
double connTimeout = 5.0,
double defaultTimeout = 5.0,
bool ssl = false,
dynamic socksOpts}) async {
dynamic socksOpts,
}) async {
try {
// Dart's Socket class handles connection timeout internally.
Socket socket = await Socket.connect(host, port);
@ -38,25 +38,27 @@ Future<Connection> openConnection(String host, int port,
socket = await SecureSocket.secure(socket);
}
return Connection(socket: socket, timeout: Duration(seconds: defaultTimeout.toInt()));
return Connection(
socket: socket, timeout: Duration(seconds: defaultTimeout.toInt()));
} catch (e) {
throw 'Failed to open connection: $e';
}
}
class Connection {
Duration timeout = Duration(seconds: 1);
Socket? socket;
static const int MAX_MSG_LENGTH = 200 * 1024;
static final Uint8List magic = Uint8List.fromList([0x76, 0x5b, 0xe8, 0xb4, 0xe4, 0x39, 0x6d, 0xcf]);
static final Uint8List magic =
Uint8List.fromList([0x76, 0x5b, 0xe8, 0xb4, 0xe4, 0x39, 0x6d, 0xcf]);
final Uint8List recvbuf = Uint8List(0);
Connection({required this.socket, this.timeout = const Duration(seconds: 1)});
Connection.withoutSocket({this.timeout = const Duration(seconds: 1)});
Future<void> sendMessageWithSocketWrapper(SocketWrapper socketwrapper, List<int> msg, {Duration? timeout}) async {
Future<void> sendMessageWithSocketWrapper(
SocketWrapper socketwrapper, List<int> msg,
{Duration? timeout}) async {
timeout ??= this.timeout;
print("DEBUG sendmessage msg sending ");
print(msg);
@ -76,10 +78,7 @@ class Connection {
}
}
Future<void> sendMessage(List<int> msg, {Duration? timeout}) async {
timeout ??= this.timeout;
final lengthBytes = Uint8List(4);
@ -93,7 +92,6 @@ class Connection {
..addAll(msg);
try {
StreamController<List<int>> controller = StreamController();
controller.stream.listen((data) {
@ -109,19 +107,18 @@ class Connection {
} finally {
controller.close();
}
} on SocketException catch (e) {
throw TimeoutException('Socket write timed out', timeout);
}
}
void close() {
socket?.close();
}
Future<List<int>> fillBuf2(SocketWrapper socketwrapper, List<int> recvBuf, int n, {Duration? timeout}) async {
Future<List<int>> fillBuf2(
SocketWrapper socketwrapper, List<int> recvBuf, int n,
{Duration? timeout}) async {
final maxTime = timeout != null ? DateTime.now().add(timeout) : null;
await for (var data in socketwrapper.socket!.cast<List<int>>()) {
@ -139,7 +136,8 @@ class Connection {
}
recvBuf.addAll(data);
print("DEBUG fillBuf2 2 - data added to recvBuf, new length: ${recvBuf.length}");
print(
"DEBUG fillBuf2 2 - data added to recvBuf, new length: ${recvBuf.length}");
if (recvBuf.length >= n) {
print("DEBUG fillBuf2 3 - breaking loop, recvBuf is big enough");
@ -163,8 +161,6 @@ class Connection {
});
return recvBuf;
StreamSubscription<List<int>>? subscription; // Declaration moved here
subscription = socket!.listen(
(List<int> data) {
@ -180,7 +176,8 @@ class Connection {
onDone: () {
print("DEBUG ON DONE");
if (recvBuf.length < n) {
throw SocketException('Connection closed before enough data was received');
throw SocketException(
'Connection closed before enough data was received');
}
},
);
@ -197,8 +194,8 @@ class Connection {
return recvBuf;
}
Future<List<int>> recv_message2(SocketWrapper socketwrapper, {Duration? timeout}) async {
Future<List<int>> recv_message2(SocketWrapper socketwrapper,
{Duration? timeout}) async {
if (timeout == null) {
timeout = this.timeout;
}
@ -237,14 +234,17 @@ class Connection {
throw BadFrameError('Bad magic in frame: ${hex.encode(magic)}');
}
final byteData = ByteData.view(Uint8List.fromList(recvBuf.sublist(8, 12)).buffer);
final byteData =
ByteData.view(Uint8List.fromList(recvBuf.sublist(8, 12)).buffer);
final messageLength = byteData.getUint32(0, Endian.big);
if (messageLength > MAX_MSG_LENGTH) {
throw BadFrameError('Got a frame with msg_length=$messageLength > $MAX_MSG_LENGTH (max)');
throw BadFrameError(
'Got a frame with msg_length=$messageLength > $MAX_MSG_LENGTH (max)');
}
print("DEBUG recv_message2 3 - about to read the message body, messageLength: $messageLength");
print(
"DEBUG recv_message2 3 - about to read the message body, messageLength: $messageLength");
print("DEBUG recvfbuf len is ");
print(recvBuf.length);
@ -255,13 +255,15 @@ class Connection {
if (recvBuf.length == bytesRead && bytesRead == 12 + messageLength) {
final message = recvBuf.sublist(12, 12 + messageLength);
print("DEBUG recv_message2 4 - message received, length: ${message.length}");
print(
"DEBUG recv_message2 4 - message received, length: ${message.length}");
print("DEBUG recv_message2 5 - message content: $message");
return message;
} else {
// Throwing exception if the length doesn't match
throw Exception('Message length mismatch: expected ${12 + messageLength} bytes, received ${recvBuf.length} bytes.');
throw Exception(
'Message length mismatch: expected ${12 + messageLength} bytes, received ${recvBuf.length} bytes.');
}
}
}
@ -273,13 +275,8 @@ class Connection {
return [];
}
Future<List<int>> recv_message({Duration? timeout}) async {
// DEPRECATED
return [];
}
} // END OF CLASS

View file

@ -1,17 +1,18 @@
import 'dart:math';
import 'dart:async';
import 'dart:io';
import 'dart:collection';
import 'connection.dart';
import 'package:protobuf/protobuf.dart' as pb;
import 'comms.dart';
import 'fusion.pb.dart';
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:protobuf/protobuf.dart' as pb;
import 'comms.dart';
import 'connection.dart';
import 'fusion.pb.dart';
const int TOR_COOLDOWN_TIME = 660;
const int TIMEOUT_INACTIVE_CONNECTION = 120;
class FusionError implements Exception {
String cause;
FusionError(this.cause);
@ -21,15 +22,14 @@ class Unrecoverable extends FusionError {
Unrecoverable(String cause) : super(cause);
}
Future<bool> isTorPort(String host, int port) async {
if (port < 0 || port > 65535) {
return false;
}
try {
Socket sock = await Socket.connect(host, port, timeout: Duration(milliseconds: 100));
Socket sock =
await Socket.connect(host, port, timeout: Duration(milliseconds: 100));
sock.write("GET\n");
List<int> data = await sock.first;
sock.destroy();
@ -43,8 +43,6 @@ Future<bool> isTorPort(String host, int port) async {
return false;
}
class TorLimiter {
Queue<DateTime> deque = Queue<DateTime>();
int lifetime;
@ -65,7 +63,6 @@ class TorLimiter {
TorLimiter limiter = TorLimiter(TOR_COOLDOWN_TIME);
double randTrap(Random rng) {
final sixth = 1.0 / 6;
final f = rng.nextDouble();
@ -80,8 +77,6 @@ double randTrap(Random rng) {
}
}
class CovertConnection {
Connection? connection; // replace dynamic with the type of your connection
int? slotNum;
@ -124,7 +119,8 @@ class CovertSlot {
int submitTimeout;
pb.GeneratedMessage? subMsg; // The work to be done.
bool done; // Whether last work requested is done.
CovertConnection? covConn; // which CovertConnection is assigned to work on this slot
CovertConnection?
covConn; // which CovertConnection is assigned to work on this slot
CovertSlot(this.submitTimeout) : done = true;
DateTime? t_submit;
@ -138,25 +134,21 @@ class CovertSlot {
throw Unrecoverable('connection is null');
}
await sendPb(connection, CovertMessage, subMsg!, timeout: Duration(seconds: submitTimeout));
var result = await recvPb(connection, CovertResponse, ['ok', 'error'], timeout: Duration(seconds: submitTimeout));
await sendPb(connection, CovertMessage, subMsg!,
timeout: Duration(seconds: submitTimeout));
var result = await recvPb(connection, CovertResponse, ['ok', 'error'],
timeout: Duration(seconds: submitTimeout));
if (result.item1 == 'error') {
throw Unrecoverable('error from server: ${result.item2}');
}
done = true;
t_submit = DateTime.fromMillisecondsSinceEpoch(0);
covConn?.tPing = DateTime.fromMillisecondsSinceEpoch(0); // if a submission is done, no ping is needed.
covConn?.tPing = DateTime.fromMillisecondsSinceEpoch(
0); // if a submission is done, no ping is needed.
}
}
class PrintError {
// Declare properties here
}
@ -194,12 +186,11 @@ class CovertSubmitter extends PrintError {
this.num_slots,
double randSpan, // changed from int to double
double submit_timeout) // changed from int to double
: slots = List<CovertSlot>.generate(num_slots, (index) => CovertSlot(submit_timeout.toInt())) {
: slots = List<CovertSlot>.generate(
num_slots, (index) => CovertSlot(submit_timeout.toInt())) {
// constructor body...
}
void wakeAll() {
for (var s in slots) {
if (s.covConn != null) {
@ -218,7 +209,6 @@ class CovertSubmitter extends PrintError {
}
}
void stop([Exception? exception]) {
if (this.stopping) {
// already requested!
@ -226,13 +216,16 @@ class CovertSubmitter extends PrintError {
}
this.failureException = exception?.toString();
this.stopping = true;
var timeRemaining = this.stopTStart?.difference(DateTime.now()).inSeconds ?? 0;
print("Stopping; connections will close in approximately $timeRemaining seconds");
var timeRemaining =
this.stopTStart?.difference(DateTime.now()).inSeconds ?? 0;
print(
"Stopping; connections will close in approximately $timeRemaining seconds");
this.wakeAll();
}
// PYTHON USES MULTITHREADING, WHICH ISNT IMPLEMENTED HERE YET
void scheduleConnections(DateTime tStart, Duration tSpan, {int numSpares = 0, int connectTimeout = 10}) {
void scheduleConnections(DateTime tStart, Duration tSpan,
{int numSpares = 0, int connectTimeout = 10}) {
var newConns = <CovertConnection>[];
for (var sNum = 0; sNum < this.slots.length; sNum++) {
@ -244,8 +237,6 @@ class CovertSubmitter extends PrintError {
if (myCovConn != null) {
newConns.add(myCovConn);
}
}
}
@ -258,16 +249,15 @@ class CovertSubmitter extends PrintError {
for (var covConn in newConns) {
covConn.connNumber = this.countAttempted;
this.countAttempted++;
var connTime = tStart.add(Duration(seconds: (tSpan.inSeconds * randTrap(this.rng)).round()));
var connTime = tStart.add(
Duration(seconds: (tSpan.inSeconds * randTrap(this.rng)).round()));
var randDelay = (this.randSpan ?? 0) * randTrap(this.rng);
runConnection(covConn, connTime.millisecondsSinceEpoch, randDelay, connectTimeout);
runConnection(
covConn, connTime.millisecondsSinceEpoch, randDelay, connectTimeout);
}
}
void scheduleSubmit(int slotNum, DateTime tStart, dynamic subMsg) {
var slot = slots[slotNum];
@ -282,7 +272,6 @@ class CovertSubmitter extends PrintError {
}
}
void scheduleSubmissions(DateTime tStart, List<dynamic> slotMessages) {
// Convert to list (Dart does not have tuples)
slotMessages = List.from(slotMessages);
@ -317,11 +306,11 @@ class CovertSubmitter extends PrintError {
}
}
Future runConnection(
CovertConnection covConn, int connTime, double randDelay, int connectTimeout) async {
Future runConnection(CovertConnection covConn, int connTime, double randDelay,
int connectTimeout) async {
// Main loop for connection thread
DateTime connDateTime = DateTime.fromMillisecondsSinceEpoch(connTime * 1000);
DateTime connDateTime =
DateTime.fromMillisecondsSinceEpoch(connTime * 1000);
while (await covConn.waitWakeupOrTime(connDateTime)) {
// if we are woken up before connection and stopping is happening, then just don't make a connection at all
if (this.stopping) {
@ -350,11 +339,11 @@ class CovertSubmitter extends PrintError {
try {
final connection = await openConnection(
this.destAddr!, this.destPort!,
connTimeout: connectTimeout.toDouble(), ssl: this.ssl, socksOpts: proxyOpts);
connTimeout: connectTimeout.toDouble(),
ssl: this.ssl,
socksOpts: proxyOpts);
covConn.connection = connection;
}
catch (e) {
} catch (e) {
this.countFailed++;
final tEnd = DateTime.now().millisecondsSinceEpoch;
@ -364,7 +353,6 @@ class CovertSubmitter extends PrintError {
rethrow;
}
this.countEstablished++;
final tEnd = DateTime.now().millisecondsSinceEpoch;
@ -372,7 +360,6 @@ class CovertSubmitter extends PrintError {
print(
'[${covConn.connNumber}] connection established after ${((tEnd - tBegin) / 1000).toStringAsFixed(3)}s');
covConn.delay = (randTrap(this.rng) ?? 0) * (this.randSpan ?? 0);
var lastActionTime = DateTime.now().millisecondsSinceEpoch;
@ -396,7 +383,8 @@ class CovertSubmitter extends PrintError {
}
// Last preference: wait doing nothing
if (nextTime == null) {
nextTime = DateTime.now().add(Duration(seconds: TIMEOUT_INACTIVE_CONNECTION));
nextTime = DateTime.now()
.add(Duration(seconds: TIMEOUT_INACTIVE_CONNECTION));
action = covConn.inactive;
}
@ -423,7 +411,9 @@ class CovertSubmitter extends PrintError {
// STATE 3 - stopping
while (true) {
final stopTime = this.stopTStart?.add(Duration(seconds: randDelay.toInt())) ?? DateTime.now();
final stopTime =
this.stopTStart?.add(Duration(seconds: randDelay.toInt())) ??
DateTime.now();
if (!(await covConn.waitWakeupOrTime(stopTime))) {
break;
@ -442,7 +432,8 @@ class CovertSubmitter extends PrintError {
// Found a spare.
this.slots[slotNum].covConn = spare;
spare.slotNum = slotNum;
spare.wakeup.complete(); // python code is using set, possibly dealing wiht multi thread...double check this is ok.
spare.wakeup
.complete(); // python code is using set, possibly dealing wiht multi thread...double check this is ok.
covConn.slotNum = null;
} catch (e) {
@ -453,7 +444,6 @@ class CovertSubmitter extends PrintError {
} else {
// Handle the case where the exception is not an instance of Exception
}
}
}
} finally {
@ -462,7 +452,6 @@ class CovertSubmitter extends PrintError {
}
}
void checkOk() {
// Implement checkOk logic here
var e = this.failure_exception;
@ -474,26 +463,21 @@ class CovertSubmitter extends PrintError {
void checkConnected() {
// Implement checkConnected logic here
this.checkOk();
var numMissing = this.slots
.where((s) => s.covConn?.connection == null)
.length;
var numMissing =
this.slots.where((s) => s.covConn?.connection == null).length;
if (numMissing > 0) {
throw FusionError(
"Covert connections were too slow ($numMissing incomplete out of ${this
.slots.length}).");
"Covert connections were too slow ($numMissing incomplete out of ${this.slots.length}).");
}
}
void checkDone() {
// Implement checkDone logic here
this.checkOk();
var numMissing = this.slots
.where((s) => !s.done)
.length;
var numMissing = this.slots.where((s) => !s.done).length;
if (numMissing > 0) {
throw FusionError(
"Covert submissions were too slow ($numMissing incomplete out of ${this
.slots.length}).");
"Covert submissions were too slow ($numMissing incomplete out of ${this.slots.length}).");
}
}
}

View file

@ -1,17 +1,20 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:pointycastle/pointycastle.dart' hide Mac;
import 'package:crypto/crypto.dart' as crypto;
import 'package:cryptography/cryptography.dart';
import 'package:pointycastle/pointycastle.dart' hide Mac;
import 'util.dart';
final ECDomainParameters params = ECDomainParameters('secp256k1');
final BigInt order = params.n;
class EncryptionFailed implements Exception {}
class DecryptionFailed implements Exception {}
Future<Uint8List> encrypt(Uint8List message, ECPoint pubkey, {int? padToLength}) async {
Future<Uint8List> encrypt(Uint8List message, ECPoint pubkey,
{int? padToLength}) async {
ECPoint pubpoint;
try {
pubpoint = Util.ser_to_point(pubkey.getEncoded(true), params);
@ -27,22 +30,27 @@ Future<Uint8List> encrypt(Uint8List message, ECPoint pubkey, {int? padToLength})
var pubpoint_times_nonceSec = pubpoint * nonceSec;
if (pubpoint_times_nonceSec == null) {
throw Exception('Multiplication of pubpoint with nonceSec resulted in null');
throw Exception(
'Multiplication of pubpoint with nonceSec resulted in null');
}
var key = crypto.sha256.convert(Util.point_to_ser(pubpoint_times_nonceSec, true)).bytes;
var key = crypto.sha256
.convert(Util.point_to_ser(pubpoint_times_nonceSec, true))
.bytes;
var plaintext = Uint8List(4 + message.length)..buffer.asByteData().setUint32(0, message.length, Endian.big)..setRange(4, 4 + message.length, message);
var plaintext = Uint8List(4 + message.length)
..buffer.asByteData().setUint32(0, message.length, Endian.big)
..setRange(4, 4 + message.length, message);
if (padToLength == null) {
padToLength = ((plaintext.length + 15) ~/ 16) * 16; // round up to nearest 16
padToLength =
((plaintext.length + 15) ~/ 16) * 16; // round up to nearest 16
} else if (padToLength % 16 != 0) {
throw ArgumentError('$padToLength not multiple of 16');
}
if (padToLength < plaintext.length) {
throw ArgumentError('$padToLength < ${plaintext.length}');
}
plaintext = Uint8List(padToLength)..setRange(0, message.length + 4, plaintext);
plaintext = Uint8List(padToLength)
..setRange(0, message.length + 4, plaintext);
final secretKey = SecretKey(key);
@ -50,16 +58,20 @@ Future<Uint8List> encrypt(Uint8List message, ECPoint pubkey, {int? padToLength})
final cipher = AesCbc.with128bits(macAlgorithm: macAlgorithm);
final nonce = Uint8List(16); // Random nonce
final secretBox = await cipher.encrypt(plaintext, secretKey: secretKey, nonce: nonce);
final secretBox =
await cipher.encrypt(plaintext, secretKey: secretKey, nonce: nonce);
final ciphertext = secretBox.cipherText;
return Uint8List(noncePub.length + ciphertext.length + secretBox.mac.bytes.length)
return Uint8List(
noncePub.length + ciphertext.length + secretBox.mac.bytes.length)
..setRange(0, noncePub.length, noncePub)
..setRange(noncePub.length, noncePub.length + ciphertext.length, ciphertext)
..setRange(noncePub.length + ciphertext.length, noncePub.length + ciphertext.length + secretBox.mac.bytes.length, secretBox.mac.bytes);
..setRange(
noncePub.length + ciphertext.length,
noncePub.length + ciphertext.length + secretBox.mac.bytes.length,
secretBox.mac.bytes);
}
Future<Uint8List> decryptWithSymmkey(Uint8List data, Uint8List key) async {
@ -75,7 +87,8 @@ Future<Uint8List> decryptWithSymmkey(Uint8List data, Uint8List key) async {
final cipher = AesCbc.with128bits(macAlgorithm: Hmac.sha256());
final nonce = Uint8List(16); // Random nonce
final secretBox = SecretBox(ciphertext, mac: Mac(data.sublist(data.length - 16)), nonce: nonce);
final secretBox = SecretBox(ciphertext,
mac: Mac(data.sublist(data.length - 16)), nonce: nonce);
final plaintext = await cipher.decrypt(secretBox, secretKey: secretKey);
if (plaintext.length < 4) {
@ -86,15 +99,14 @@ Future<Uint8List> decryptWithSymmkey(Uint8List data, Uint8List key) async {
ByteData byteData = ByteData.sublistView(uint8list);
var msgLength = byteData.getUint32(0, Endian.big);
if (msgLength + 4 > plaintext.length) {
throw DecryptionFailed();
}
return Uint8List.fromList(plaintext.sublist(4, 4 + msgLength));
}
Future<Tuple<Uint8List, Uint8List>> decrypt(Uint8List data, ECPrivateKey privkey) async {
Future<Tuple<Uint8List, Uint8List>> decrypt(
Uint8List data, ECPrivateKey privkey) async {
if (data.length < 33 + 16 + 16) {
throw DecryptionFailed();
}
@ -122,4 +134,3 @@ Future<Tuple<Uint8List, Uint8List>> decrypt(Uint8List data, ECPrivateKey privkey
var decryptedData = await decryptWithSymmkey(data, Uint8List.fromList(key));
return Tuple(decryptedData, Uint8List.fromList(key));
}

File diff suppressed because it is too large Load diff

View file

@ -1,122 +0,0 @@
import 'package:flutter/material.dart';
import 'fusion.dart';
import 'pedersen.dart';
import 'encrypt.dart';
import 'validation.dart';
void main() {
Fusion.foo();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
}
@override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
// Column is also a layout widget. It takes a list of children and
// arranges them vertically. By default, it sizes itself to fit its
// children horizontally, and tries to be as tall as its parent.
//
// Invoke "debug painting" (press "p" in the console, choose the
// "Toggle Debug Paint" action from the Flutter Inspector in Android
// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
// to see the wireframe for each widget.
//
// Column has various properties to control how it sizes itself and
// how it positions its children. Here we use mainAxisAlignment to
// center the children vertically; the main axis here is the vertical
// axis because Columns are vertical (the cross axis would be
// horizontal).
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}

View file

@ -1,8 +1,8 @@
import 'package:pointycastle/ecc/api.dart';
import 'util.dart';
import 'dart:math';
import 'dart:typed_data';
import 'package:pointycastle/ecc/api.dart';
import 'package:stackwallet/services/cashfusion/util.dart';
ECDomainParameters getDefaultParams() {
return ECDomainParameters("secp256k1");
}
@ -11,10 +11,10 @@ class NullPointError implements Exception {
String errMsg() => 'NullPointError: Either Hpoint or HGpoint is null.';
}
class NonceRangeError implements Exception {
final String message;
NonceRangeError([this.message = "Nonce value must be in the range 0 < nonce < order"]);
NonceRangeError(
[this.message = "Nonce value must be in the range 0 < nonce < order"]);
String toString() => "NonceRangeError: $message";
}
@ -26,12 +26,12 @@ class ResultAtInfinity implements Exception {
class InsecureHPoint implements Exception {
final String message;
InsecureHPoint([this.message = "The H point has a known discrete logarithm, which means the commitment setup is broken"]);
InsecureHPoint(
[this.message =
"The H point has a known discrete logarithm, which means the commitment setup is broken"]);
String toString() => "InsecureHPoint: $message";
}
class PedersenSetup {
late ECPoint _H;
late ECPoint _HG;
@ -53,7 +53,6 @@ class PedersenSetup {
Commitment commit(BigInt amount, {BigInt? nonce, Uint8List? PUncompressed}) {
return Commitment(this, amount, nonce: nonce, PUncompressed: PUncompressed);
}
}
class Commitment {
@ -62,8 +61,8 @@ class Commitment {
late BigInt nonce;
late Uint8List PUncompressed;
Commitment(this.setup, BigInt amount, {BigInt? nonce, Uint8List? PUncompressed}) {
Commitment(this.setup, BigInt amount,
{BigInt? nonce, Uint8List? PUncompressed}) {
this.nonce = nonce ?? Util.secureRandomBigInt(setup.params.n.bitLength);
amountMod = amount % setup.params.n;
@ -84,13 +83,16 @@ class Commitment {
ECPoint? HpointMultiplied = Hpoint * multiplier1;
ECPoint? HGpointMultiplied = HGpoint * multiplier2;
ECPoint? Ppoint = HpointMultiplied != null && HGpointMultiplied != null ? HpointMultiplied + HGpointMultiplied : null;
ECPoint? Ppoint = HpointMultiplied != null && HGpointMultiplied != null
? HpointMultiplied + HGpointMultiplied
: null;
if (Ppoint == setup.params.curve.infinity) {
throw ResultAtInfinity();
}
this.PUncompressed = PUncompressed ?? Ppoint?.getEncoded(false) ?? Uint8List(0);
this.PUncompressed =
PUncompressed ?? Ppoint?.getEncoded(false) ?? Uint8List(0);
}
void calcInitial(PedersenSetup setup, BigInt amount) {
@ -114,7 +116,9 @@ class Commitment {
ECPoint? HpointMultiplied = Hpoint * multiplier1;
ECPoint? HGpointMultiplied = HGpoint * multiplier2;
ECPoint? Ppoint = HpointMultiplied != null && HGpointMultiplied != null ? HpointMultiplied + HGpointMultiplied : null;
ECPoint? Ppoint = HpointMultiplied != null && HGpointMultiplied != null
? HpointMultiplied + HGpointMultiplied
: null;
if (Ppoint == setup.params.curve.infinity) {
throw ResultAtInfinity();
@ -124,14 +128,17 @@ class Commitment {
}
static Uint8List add_points(Iterable<Uint8List> pointsIterable) {
ECDomainParameters params = getDefaultParams(); // Using helper function here
var pointList = pointsIterable.map((pser) => Util.ser_to_point(pser, params)).toList();
ECDomainParameters params =
getDefaultParams(); // Using helper function here
var pointList =
pointsIterable.map((pser) => Util.ser_to_point(pser, params)).toList();
if (pointList.isEmpty) {
throw ArgumentError('Empty list');
}
ECPoint pSum = pointList.first; // Initialize pSum with the first point in the list
ECPoint pSum =
pointList.first; // Initialize pSum with the first point in the list
for (var i = 1; i < pointList.length; i++) {
pSum = (pSum + pointList[i])!;
@ -144,7 +151,6 @@ class Commitment {
return Util.point_to_ser(pSum, false);
}
Commitment addCommitments(Iterable<Commitment> commitmentIterable) {
BigInt ktotal = BigInt.zero; // Changed to BigInt from int
BigInt atotal = BigInt.zero; // Changed to BigInt from int
@ -168,7 +174,8 @@ class Commitment {
ktotal = ktotal % setup.params.n; // Changed order to setup.params.n
if (ktotal == BigInt.zero) { // Changed comparison from 0 to BigInt.zero
if (ktotal == BigInt.zero) {
// Changed comparison from 0 to BigInt.zero
throw Exception('Nonce range error');
}
@ -182,6 +189,7 @@ class Commitment {
} else {
PUncompressed = null;
}
return Commitment(setup, atotal, nonce: ktotal, PUncompressed: PUncompressed);
return Commitment(setup, atotal,
nonce: ktotal, PUncompressed: PUncompressed);
}
}

View file

@ -1,11 +1,8 @@
class Protocol {
static const VERSION = 'alpha13';
static const FUSE_ID = 'FUZ\x00';
// Safety limits to prevent loss of funds / limit fees:
//(Note that if we enter multiply into the same fusion, our limits apply
//separately for each "player".)
@ -56,4 +53,3 @@ class Protocol {
static const STANDARD_TIMEOUT = 3.0;
static const BLAME_VERIFY_TIME = 5.0;
}

View file

@ -5,16 +5,19 @@ class SocketWrapper {
final String serverIP;
final int serverPort;
late Stream<List<int>> _receiveStream; // create a field for the broadcast stream
late Stream<List<int>>
_receiveStream; // create a field for the broadcast stream
SocketWrapper(this.serverIP, this.serverPort);
Socket get socket => _socket;
Stream<List<int>> get receiveStream => _receiveStream; // expose the stream with a getter
Stream<List<int>> get receiveStream =>
_receiveStream; // expose the stream with a getter
Future<void> connect() async {
_socket = await Socket.connect(serverIP, serverPort);
_receiveStream = _socket.asBroadcastStream(); // initialize the broadcast stream
_receiveStream =
_socket.asBroadcastStream(); // initialize the broadcast stream
_socket.done.then((_) {
print('......Socket has been closed');
});
@ -25,7 +28,8 @@ class SocketWrapper {
void status() {
if (_socket != null) {
print("Socket connected to ${_socket.remoteAddress.address}:${_socket.remotePort}");
print(
"Socket connected to ${_socket.remoteAddress.address}:${_socket.remotePort}");
} else {
print("Socket is not connected");
}

View file

@ -1,18 +1,18 @@
import 'package:stackwallet/services/cashfusion/fusion.dart';
import 'package:pointycastle/ecc/api.dart';
import 'dart:convert';
import 'dart:math';
import 'dart:typed_data';
import 'dart:convert';
import 'package:crypto/crypto.dart' as crypto;
import 'protocol.dart';
import 'package:pointycastle/ecc/api.dart';
import 'fusion.pb.dart';
import 'dart:convert';
import 'protocol.dart';
class Address {
String addr = "";
Address({required this.addr}); // Constructor updated to accept addr as a named parameter
Address(
{required this.addr}); // Constructor updated to accept addr as a named parameter
Address._create({required this.addr});
@ -32,7 +32,6 @@ class Address {
}
}
class Tuple<T1, T2> {
T1 item1;
T2 item2;
@ -49,8 +48,6 @@ class Tuple<T1, T2> {
}
class Util {
static Uint8List hexToBytes(String hex) {
var result = new Uint8List(hex.length ~/ 2);
for (var i = 0; i < hex.length; i += 2) {
@ -65,7 +62,6 @@ class Util {
//
}
static int randPosition(Uint8List seed, int numPositions, int counter) {
// counter to bytes
var counterBytes = Uint8List(4);
@ -77,7 +73,8 @@ class Util {
// take the first 8 bytes
var first8Bytes = digest.bytes.take(8).toList();
var int64 = ByteData.sublistView(Uint8List.fromList(first8Bytes)).getUint64(0, Endian.big);
var int64 = ByteData.sublistView(Uint8List.fromList(first8Bytes))
.getUint64(0, Endian.big);
// perform the modulo operation
return ((int64 * numPositions) >> 64).toInt();
@ -93,7 +90,6 @@ class Util {
return 500;
}
static Address getAddressFromOutputScript(Uint8List scriptpubkey) {
// Dummy implementation...
@ -102,19 +98,18 @@ class Util {
return Address.fromString('dummy_address');
}
static bool schnorrVerify(ECPoint pubkey, List<int> signature, Uint8List messageHash) {
static bool schnorrVerify(
ECPoint pubkey, List<int> signature, Uint8List messageHash) {
// Implementation needed: actual Schnorr signature verification
return true;
}
static String formatSatoshis(sats, {int numZeros = 8}) {
// To implement
return "";
}
static void updateWalletLabel(String txid, String label) {
static void updateWalletLabel(String txid, String label) {
// Call the wallet layer.
}
@ -132,12 +127,13 @@ static List<List<T>> zip<T>(List<T> list1, List<T> list2) {
return List<List<T>>.generate(length, (i) => [list1[i], list2[i]]);
}
static List<int> calcInitialHash(int tier, Uint8List covertDomainB, int covertPort, bool covertSsl, double beginTime) {
static List<int> calcInitialHash(int tier, Uint8List covertDomainB,
int covertPort, bool covertSsl, double beginTime) {
// Converting int to bytes in BigEndian order
var tierBytes = ByteData(8)..setInt64(0, tier, Endian.big);
var covertPortBytes = ByteData(4)..setInt32(0, covertPort, Endian.big);
var beginTimeBytes = ByteData(8)..setInt64(0, beginTime.toInt(), Endian.big);
var beginTimeBytes = ByteData(8)
..setInt64(0, beginTime.toInt(), Endian.big);
// Define constants
const version = Protocol.VERSION;
@ -159,7 +155,12 @@ static List<List<T>> zip<T>(List<T> list1, List<T> list2) {
return digest.bytes;
}
static List<int> calcRoundHash(List<int> lastHash, List<int> roundPubkey, int roundTime, List<List<int>> allCommitments, List<List<int>> allComponents) {
static List<int> calcRoundHash(
List<int> lastHash,
List<int> roundPubkey,
int roundTime,
List<List<int>> allCommitments,
List<List<int>> allComponents) {
return listHash([
utf8.encode('Cash Fusion Round'),
lastHash,
@ -179,12 +180,11 @@ static List<int> calcRoundHash(List<int> lastHash, List<int> roundPubkey, int ro
bytes.addAll(x);
}
return crypto.sha256.convert(bytes).bytes;
}
static Uint8List get_current_genesis_hash() {
var GENESIS = "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f";
var GENESIS =
"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f";
var _lastGenesisHash = hexToBytes(GENESIS).reversed.toList();
return Uint8List.fromList(_lastGenesisHash);
}
@ -194,7 +194,6 @@ static List<int> calcRoundHash(List<int> lastHash, List<int> roundPubkey, int ro
return [];
}
static List<Address> reserve_change_addresses(int number_addresses) {
//implement later based on wallet.
return [];
@ -206,7 +205,8 @@ static List<int> calcRoundHash(List<int> lastHash, List<int> roundPubkey, int ro
}
static Uint8List bigIntToBytes(BigInt bigInt) {
return Uint8List.fromList(bigInt.toRadixString(16).padLeft(32, '0').codeUnits);
return Uint8List.fromList(
bigInt.toRadixString(16).padLeft(32, '0').codeUnits);
}
static Tuple<Uint8List, Uint8List> genKeypair() {
@ -224,8 +224,6 @@ static Tuple<Uint8List, Uint8List> genKeypair() {
return Tuple(privKey, pubKey);
}
// Generates a cryptographically secure private key
static BigInt _generatePrivateKey(int bitLength) {
final random = Random.secure();
@ -236,7 +234,9 @@ static Tuple<Uint8List, Uint8List> genKeypair() {
List<int> rnd = List<int>.generate(bytes, (_) => random.nextInt(256));
var rndBit = random.nextInt(1 << remBit);
rnd.add(rndBit);
var privateKey = BigInt.parse(rnd.map((x) => x.toRadixString(16).padLeft(2, '0')).join(), radix: 16);
var privateKey = BigInt.parse(
rnd.map((x) => x.toRadixString(16).padLeft(2, '0')).join(),
radix: 16);
return privateKey;
}
@ -251,15 +251,16 @@ static Tuple<Uint8List, Uint8List> genKeypair() {
return BigInt.parse(hexString, radix: 16);
}
static Uint8List sha256(Uint8List bytes) {
crypto.Digest digest = crypto.sha256.convert(bytes);
return Uint8List.fromList(digest.bytes);
}
static Uint8List tokenBytes([int nbytes = 32]) {
final Random _random = Random.secure();
return Uint8List.fromList(List<int>.generate(nbytes, (i) => _random.nextInt(256)));
return Uint8List.fromList(
List<int>.generate(nbytes, (i) => _random.nextInt(256)));
}
static int componentFee(int size, int feerate) {
@ -269,8 +270,8 @@ static Tuple<Uint8List, Uint8List> genKeypair() {
return ((size * feerate) + 999) ~/ 1000;
}
static ECPoint ser_to_point(Uint8List serializedPoint, ECDomainParameters params) {
static ECPoint ser_to_point(
Uint8List serializedPoint, ECDomainParameters params) {
var point = params.curve.decodePoint(serializedPoint);
if (point == null) {
throw FormatException('Point decoding failed');
@ -282,7 +283,6 @@ static Tuple<Uint8List, Uint8List> genKeypair() {
return point.getEncoded(compress);
}
static BigInt secureRandomBigInt(int bitLength) {
final random = Random.secure();
final bytes = (bitLength + 7) ~/ 8; // ceil division
@ -292,9 +292,12 @@ static Tuple<Uint8List, Uint8List> genKeypair() {
randomBytes[i] = random.nextInt(256);
}
BigInt randomNumber = BigInt.parse(randomBytes.map((e) => e.toRadixString(16).padLeft(2, '0')).join(), radix: 16);
BigInt randomNumber = BigInt.parse(
randomBytes.map((e) => e.toRadixString(16).padLeft(2, '0')).join(),
radix: 16);
return randomNumber;
}
static ECPoint combinePubKeys(List<ECPoint> pubKeys) {
if (pubKeys.isEmpty) throw ArgumentError('pubKeys cannot be empty');
@ -323,8 +326,4 @@ static Tuple<Uint8List, Uint8List> genKeypair() {
// Check if the point is on the curve
return left == right;
}
} // END OF CLASS

View file

@ -1,14 +1,12 @@
import 'package:protobuf/protobuf.dart';
import 'dart:typed_data';
import 'package:pointycastle/export.dart';
import 'encrypt.dart' as Encrypt;
import 'fusion.dart';
import 'fusion.pb.dart' as pb;
import 'pedersen.dart';
import 'util.dart';
import 'encrypt.dart' as Encrypt;
import 'protocol.dart';
import 'fusion.dart';
import 'dart:typed_data';
import 'package:pointycastle/export.dart';
import 'package:convert/convert.dart';
import 'pedersen.dart';
class ValidationError implements Exception {
final String message;
@ -31,13 +29,12 @@ int componentContrib(pb.Component component, int feerate) {
}
}
void check(bool condition, String failMessage) {
if (!condition) {
throw ValidationError(failMessage);
}
}
dynamic protoStrictParse(dynamic msg, List<int> blob) {
try {
if (msg.mergeFromBuffer(blob) != blob.length) {
@ -63,21 +60,22 @@ dynamic protoStrictParse(dynamic msg, List<int> blob) {
return msg;
}
List<pb.InitialCommitment> checkPlayerCommit(pb.PlayerCommit msg,
int minExcessFee, int maxExcessFee, int numComponents) {
check(msg.initialCommitments.length == numComponents,
"wrong number of component commitments");
check(msg.blindSigRequests.length == numComponents,
"wrong number of blind sig requests");
List<pb.InitialCommitment> checkPlayerCommit(
pb.PlayerCommit msg,
int minExcessFee,
int maxExcessFee,
int numComponents
) {
check(msg.initialCommitments.length == numComponents, "wrong number of component commitments");
check(msg.blindSigRequests.length == numComponents, "wrong number of blind sig requests");
check(minExcessFee <= msg.excessFee.toInt() && msg.excessFee.toInt() <= maxExcessFee, "bad excess fee");
check(
minExcessFee <= msg.excessFee.toInt() &&
msg.excessFee.toInt() <= maxExcessFee,
"bad excess fee");
check(msg.randomNumberCommitment.length == 32, "bad random commit");
check(msg.pedersenTotalNonce.length == 32, "bad nonce");
check(msg.blindSigRequests.every((r) => r.length == 32), "bad blind sig request");
check(msg.blindSigRequests.every((r) => r.length == 32),
"bad blind sig request");
List<pb.InitialCommitment> commitMessages = [];
for (var cblob in msg.initialCommitments) {
@ -85,11 +83,15 @@ List<pb.InitialCommitment> checkPlayerCommit(
check(cmsg.saltedComponentHash.length == 32, "bad salted hash");
var P = cmsg.amountCommitment;
check(P.length == 65 && P[0] == 4, "bad commitment point");
check(cmsg.communicationKey.length == 33 && (cmsg.communicationKey[0] == 2 || cmsg.communicationKey[0] == 3), "bad communication key");
check(
cmsg.communicationKey.length == 33 &&
(cmsg.communicationKey[0] == 2 || cmsg.communicationKey[0] == 3),
"bad communication key");
commitMessages.add(cmsg);
}
Uint8List HBytes = Uint8List.fromList([0x02] + 'CashFusion gives us fungibility.'.codeUnits);
Uint8List HBytes =
Uint8List.fromList([0x02] + 'CashFusion gives us fungibility.'.codeUnits);
ECDomainParameters params = ECDomainParameters('secp256k1');
ECPoint? HMaybe = params.curve.decodePoint(HBytes);
if (HMaybe == null) {
@ -102,26 +104,28 @@ List<pb.InitialCommitment> checkPlayerCommit(
var pointsum;
// Verify pedersen commitment
try {
pointsum = Commitment.add_points(commitMessages.map((m) => Uint8List.fromList(m.amountCommitment)).toList());
claimedCommit = setup.commit(BigInt.from(msg.excessFee.toInt()), nonce: Util.bytesToBigInt(Uint8List.fromList(msg.pedersenTotalNonce)));
pointsum = Commitment.add_points(commitMessages
.map((m) => Uint8List.fromList(m.amountCommitment))
.toList());
claimedCommit = setup.commit(BigInt.from(msg.excessFee.toInt()),
nonce: Util.bytesToBigInt(Uint8List.fromList(msg.pedersenTotalNonce)));
check(pointsum == claimedCommit.PUncompressed, "pedersen commitment mismatch");
check(pointsum == claimedCommit.PUncompressed,
"pedersen commitment mismatch");
} catch (e) {
throw ValidationError("pedersen commitment verification error");
}
check(pointsum == claimedCommit.PUncompressed, "pedersen commitment mismatch");
check(
pointsum == claimedCommit.PUncompressed, "pedersen commitment mismatch");
return commitMessages;
}
Tuple<String, int> checkCovertComponent(
pb.CovertComponent msg, ECPoint roundPubkey, int componentFeerate) {
var messageHash = Util.sha256(Uint8List.fromList(msg.component));
check(msg.signature.length == 64, "bad message signature");
check(
Util.schnorrVerify(
roundPubkey, msg.signature, messageHash),
check(Util.schnorrVerify(roundPubkey, msg.signature, messageHash),
"bad message signature");
var cmsg = protoStrictParse(pb.Component(), msg.component);
@ -133,7 +137,8 @@ Tuple<String, int> checkCovertComponent(
var inp = cmsg.input;
check(inp.prevTxid.length == 32, "bad txid");
check(
(inp.pubkey.length == 33 && (inp.pubkey[0] == 2 || inp.pubkey[0] == 3)) ||
(inp.pubkey.length == 33 &&
(inp.pubkey[0] == 2 || inp.pubkey[0] == 3)) ||
(inp.pubkey.length == 65 && inp.pubkey[0] == 4),
"bad pubkey");
sortKey = 'i' +
@ -146,8 +151,7 @@ Tuple<String, int> checkCovertComponent(
// Basically just checks if its ok address. should throw error if not.
addr = Util.getAddressFromOutputScript(out.scriptpubkey);
check(
out.amount >= Util.dustLimit(out.scriptpubkey.length), "dust output");
check(out.amount >= Util.dustLimit(out.scriptpubkey.length), "dust output");
sortKey = 'o' +
out.amount.toString() +
String.fromCharCodes(out.scriptpubkey) +
@ -168,8 +172,8 @@ pb.InputComponent? validateProofInternal(
List<int> badComponents,
int componentFeerate,
) {
Uint8List HBytes = Uint8List.fromList([0x02] + 'CashFusion gives us fungibility.'.codeUnits);
Uint8List HBytes =
Uint8List.fromList([0x02] + 'CashFusion gives us fungibility.'.codeUnits);
ECDomainParameters params = ECDomainParameters('secp256k1');
ECPoint? HMaybe = params.curve.decodePoint(HBytes);
if (HMaybe == null) {
@ -246,8 +250,10 @@ Future<dynamic> validateBlame(
if (decrypter == pb.Blames_BlameProof_Decrypter.privkey) {
var privkey = Uint8List.fromList(blame.privkey);
check(privkey.length == 32, 'bad blame privkey');
var privkeyHexStr = Util.bytesToHex(privkey); // Convert bytes to hex string.
var privkeyBigInt = BigInt.parse(privkeyHexStr, radix: 16); // Convert hex string to BigInt.
var privkeyHexStr =
Util.bytesToHex(privkey); // Convert bytes to hex string.
var privkeyBigInt =
BigInt.parse(privkeyHexStr, radix: 16); // Convert hex string to BigInt.
var privateKey = ECPrivateKey(privkeyBigInt, params); // Create ECPrivateKey
var pubkeys = Util.pubkeysFromPrivkey(privkeyHexStr);
check(destCommit.communicationKey == pubkeys[1], 'bad blame privkey');
@ -282,11 +288,13 @@ Future<dynamic> validateBlame(
}
if (!blame.needLookupBlockchain) {
throw ValidationError('blame indicated internal inconsistency, none found!');
throw ValidationError(
'blame indicated internal inconsistency, none found!');
}
if (inpComp == null) {
throw ValidationError('blame indicated blockchain error on a non-input component');
throw ValidationError(
'blame indicated blockchain error on a non-input component');
}
return inpComp;