mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-17 05:41:29 +02:00
* feat: add support for Trezor hardware wallet integration Restore Wallets * feat: add Trezor hardware wallet support, implement RLP decoding utility, and update transaction signing logic * feat: add bitcoin trezor signing * chore: update Trezor Connect dependency to specific commit hash in pubspec_base.yaml * feat: add trezor support for litecoin * feat: add colorFilter for device manufacturer icons to align with theme styles * refactor: optimize Trezor callback handling * feat: add BitBox and Trezor support for Bitcoin and Litecoin, update transaction signing logic, and improve modularity in hardware wallet services * refactor: simplify constructor assertions in `BaseBottomSheetWidget` and cleanup Trezor chainId handling logic * feat: conditionally render device manufacturers based on platform and hide SeedSigner for now
102 lines
3.2 KiB
Dart
102 lines
3.2 KiB
Dart
import 'dart:typed_data';
|
|
|
|
import 'package:web3dart/crypto.dart';
|
|
|
|
/// RLP Decode
|
|
///
|
|
/// Adapted from https://github.com/ethereumjs/ethereumjs-monorepo/tree/master/packages/rlp
|
|
|
|
class _Decoded {
|
|
Uint8List remainder;
|
|
List data;
|
|
|
|
_Decoded(this.data, this.remainder);
|
|
}
|
|
|
|
int _decodeLength(Uint8List v) {
|
|
if (v[0] == 0) throw Exception('invalid RLP: extra zeros');
|
|
return int.parse(bytesToHex(v), radix: 16);
|
|
}
|
|
|
|
_Decoded _decode(Uint8List input) {
|
|
final firstByte = input[0];
|
|
|
|
if (firstByte <= 0x7f) {
|
|
// a single byte whose value is in the [0x00, 0x7f] range, that byte is its own RLP encoding.
|
|
return _Decoded(input.sublist(0, 1), input.sublist(1));
|
|
} else if (firstByte <= 0xb7) {
|
|
// string is 0-55 bytes long. A single byte with value 0x80 plus the length of the string followed by the string
|
|
// The range of the first byte is [0x80, 0xb7]
|
|
final length = firstByte - 0x7f;
|
|
|
|
// set 0x80 null to 0
|
|
final data = firstByte == 0x80 ? Uint8List(0) : input.sublist(1, length);
|
|
|
|
if (length == 2 && data[0] < 0x80) {
|
|
throw Exception('invalid RLP encoding: invalid prefix, single byte < 0x80 are not prefixed');
|
|
}
|
|
|
|
return _Decoded(data, input.sublist(length));
|
|
} else if (firstByte <= 0xbf) {
|
|
// string is greater than 55 bytes long. A single byte with the value (0xb7 plus the length of the length),
|
|
// followed by the length, followed by the string
|
|
final lLength = firstByte - 0xb6;
|
|
if (input.length - 1 < lLength) {
|
|
throw Exception('invalid RLP: not enough bytes for string length');
|
|
}
|
|
|
|
final length = _decodeLength(input.sublist(1, lLength));
|
|
if (length <= 55) {
|
|
throw Exception('invalid RLP: expected string length to be greater than 55');
|
|
}
|
|
|
|
final data = input.sublist(lLength, length + lLength);
|
|
return _Decoded(data, input.sublist(length + lLength));
|
|
} else if (firstByte <= 0xf7) {
|
|
// a list between 0-55 bytes long
|
|
final length = firstByte - 0xbf;
|
|
var innerRemainder = input.sublist(1, length);
|
|
|
|
final decoded = [];
|
|
while (innerRemainder.isNotEmpty) {
|
|
final d = _decode(innerRemainder);
|
|
decoded.add(d.data);
|
|
innerRemainder = d.remainder;
|
|
}
|
|
|
|
return _Decoded(decoded, input.sublist(length));
|
|
} else {
|
|
// a list over 55 bytes long
|
|
final lLength = firstByte - 0xf6;
|
|
|
|
final length = _decodeLength(input.sublist(1, lLength));
|
|
if (length < 56) {
|
|
throw Exception('invalid RLP: encoded list too short');
|
|
}
|
|
|
|
final totalLength = lLength + length;
|
|
if (totalLength > input.length) {
|
|
throw Exception('invalid RLP: total length is larger than the data');
|
|
}
|
|
|
|
var innerRemainder = input.sublist(lLength, totalLength);
|
|
final decoded = [];
|
|
while (innerRemainder.isNotEmpty) {
|
|
final d = _decode(innerRemainder);
|
|
decoded.add(d.data);
|
|
innerRemainder = d.remainder;
|
|
}
|
|
|
|
return _Decoded(decoded, input.sublist(totalLength));
|
|
}
|
|
}
|
|
|
|
/// RLP Decoding based on https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp/
|
|
List decode(Uint8List input) {
|
|
final decoded = _decode(input);
|
|
|
|
if (decoded.remainder.isNotEmpty) throw Exception('invalid RLP: remainder must be zero');
|
|
|
|
return decoded.data;
|
|
}
|