-
Notifications
You must be signed in to change notification settings - Fork 1
/
rlp.dart
179 lines (147 loc) · 4.78 KB
/
rlp.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// @dart=2.9
// Dart imports:
import 'dart:convert' show utf8;
import 'dart:typed_data';
// Package imports:
import 'package:convert/convert.dart';
// Project imports:
import 'package:idena_lib_dart/util/crypto/bigint.dart';
import 'package:idena_lib_dart/util/crypto/utils_crypto.dart';
class Decoded {
dynamic data;
Uint8List remainder;
Decoded(this.data, this.remainder);
}
Uint8List encodeRlp(dynamic input) {
if (input is List && !(input is Uint8List)) {
final output = <Uint8List>[];
for (var data in input) {
output.add(encodeRlp(data));
}
final data = _concat(output);
return _concat([encodeLength(data.length, 192), data]);
} else {
final data = _toBuffer(input);
if (data.length == 1 && data[0] < 128) {
return data;
} else {
return _concat([encodeLength(data.length, 128), data]);
}
}
}
Uint8List encodeLength(int length, int offset) {
if (length < 56) {
return Uint8List.fromList([length + offset]);
} else {
final hexLen = _intToHex(length);
final lLength = hexLen.length ~/ 2;
return _concat([
Uint8List.fromList([offset + 55 + lLength]),
Uint8List.fromList(hex.decode(hexLen))
]);
}
}
dynamic decodeRlp(Uint8List input, [bool stream = false]) {
if (input == null || input.length == 0) {
return <dynamic>[];
}
Uint8List inputBuffer = _toBuffer(input);
Decoded decoded = _decode(inputBuffer);
if (stream) {
return decoded;
}
if (decoded.remainder.length != 0) {
throw FormatException('invalid remainder');
}
return decoded.data;
}
Decoded _decode(Uint8List input) {
int 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]
int length = firstByte - 0x7f;
// set 0x80 null to 0
Uint8List data =
firstByte == 0x80 ? Uint8List(0) : input.sublist(1, length);
if (length == 2 && data[0] < 0x80) {
throw FormatException('invalid rlp encoding: byte must be less 0x80');
}
return Decoded(data, input.sublist(length));
} else if (firstByte <= 0xbf) {
int llength = firstByte - 0xb6;
int length = safeParseInt(hex.encode(input.sublist(1, llength)), 16);
Uint8List data = input.sublist(llength, length + llength);
if (data.length < length) {
throw FormatException('invalid RLP');
}
return Decoded(data, input.sublist(length + llength));
} else if (firstByte <= 0xf7) {
// a list between 0-55 bytes long
List<dynamic> decoded = <dynamic>[];
int length = firstByte - 0xbf;
Uint8List innerRemainder = input.sublist(1, length);
while (innerRemainder.isNotEmpty) {
Decoded d = _decode(innerRemainder);
decoded.add(d.data);
innerRemainder = d.remainder;
}
return Decoded(decoded, input.sublist(length));
} else {
// a list over 55 bytes long
List<dynamic> decoded = <dynamic>[];
int llength = firstByte - 0xf6;
int length = safeParseInt(hex.encode(input.sublist(1, llength)), 16);
int totalLength = llength + length;
if (totalLength > input.length) {
throw FormatException(
'invalid rlp: total length is larger than the data');
}
Uint8List innerRemainder = input.sublist(llength, totalLength);
if (innerRemainder.isEmpty) {
throw FormatException('invalid rlp, List has a invalid length');
}
while (innerRemainder.isNotEmpty) {
Decoded d = _decode(innerRemainder);
decoded.add(d.data);
innerRemainder = d.remainder;
}
return Decoded(decoded, input.sublist(totalLength));
}
}
int safeParseInt(String v, [int base]) {
if (v.startsWith('00')) {
throw FormatException('invalid RLP: extra zeros');
}
return int.parse(v, radix: base);
}
Uint8List _toBuffer(dynamic data) {
if (data is Uint8List) return data;
if (data is String) {
if (isHexString(data)) {
return Uint8List.fromList(hex.decode(padToEven(stripHexPrefix(data))));
} else {
return Uint8List.fromList(utf8.encode(data));
}
} else if (data is int) {
if (data == 0) return Uint8List(0);
return Uint8List.fromList(intToBuffer(data));
} else if (data is BigInt) {
if (data == BigInt.zero) return Uint8List(0);
return Uint8List.fromList(encodeBigInt(data));
} else if (data is List<int>) {
return Uint8List.fromList(data);
}
throw TypeError();
}
Uint8List _concat(List<Uint8List> lists) {
final list = <int>[];
lists.forEach(list.addAll);
return Uint8List.fromList(list);
}
String _intToHex(int a) {
return hex.encode(_toBuffer(a));
}