@@ -62,50 +62,215 @@ fn decode_shelley_payment_address(params: ¶ms::Params, address: &str) -> Res
62
62
Ok ( data)
63
63
}
64
64
65
+ /// CBOR major type for unsigned integers (major type 0).
66
+ /// See [RFC 7049 §2.1](https://www.rfc-editor.org/rfc/rfc7049#section-2.1).
67
+ const MAJOR_TYPE_UNSIGNED : u8 = 0x00 ; // 0x00..0x1b
68
+
69
+ /// CBOR major type for byte strings (major type 2).
70
+ /// See [RFC 7049 §2.1](https://www.rfc-editor.org/rfc/rfc7049#section-2.1).
71
+ const MAJOR_TYPE_BYTES : u8 = 0x40 ; // 0x40..0x5b
72
+
73
+ /// CBOR major type for arrays (major type 4).
74
+ /// See [RFC 7049 §2.1](https://www.rfc-editor.org/rfc/rfc7049#section-2.1).
75
+ const MAJOR_TYPE_ARRAY : u8 = 0x80 ; // 0x80..0x9b
76
+
77
+ /// CBOR major type for maps (major type 5).
78
+ /// See [RFC 7049 §2.1](https://www.rfc-editor.org/rfc/rfc7049#section-2.1).
79
+ const MAJOR_TYPE_MAP : u8 = 0xa0 ; // 0xa0..0xbb
80
+
81
+ /// CBOR major type for tags (major type 6).
82
+ /// See [RFC 7049 §2.1](https://www.rfc-editor.org/rfc/rfc7049#section-2.1).
83
+ const MAJOR_TYPE_TAG : u8 = 0xc0 ; // 0xc0..0xdb
84
+
85
+ // We use a custom CborReader instead of the minicbor library as it saves almost 3kB of binary
86
+ // space.
87
+ struct CborReader < ' a > {
88
+ buf : & ' a [ u8 ] ,
89
+ }
90
+
91
+ impl < ' a > CborReader < ' a > {
92
+ fn new ( buf : & ' a [ u8 ] ) -> Self {
93
+ Self { buf }
94
+ }
95
+
96
+ /// Reads the next byte from the internal buffer.
97
+ /// Returns an error if the buffer is empty.
98
+ fn read_u8 ( & mut self ) -> Result < u8 , ( ) > {
99
+ if self . buf . is_empty ( ) {
100
+ return Err ( ( ) ) ;
101
+ }
102
+ let b = self . buf [ 0 ] ;
103
+ self . buf = & self . buf [ 1 ..] ;
104
+ Ok ( b)
105
+ }
106
+
107
+ /// Reads a CBOR unsigned integer, interpreting the `initial` byte's lower 5 bits
108
+ /// to determine how many additional bytes to consume.
109
+ /// See [RFC 7049 §2.1](https://www.rfc-editor.org/rfc/rfc7049#section-2.1) for details.
110
+ fn read_uint ( & mut self , initial : u8 ) -> Result < u64 , ( ) > {
111
+ let additional = initial & 0x1f ;
112
+ match additional {
113
+ n @ 0 ..=23 => Ok ( n as u64 ) ,
114
+ 24 => {
115
+ let b = self . read_u8 ( ) ? as u64 ;
116
+ Ok ( b)
117
+ }
118
+ 25 => {
119
+ if self . buf . len ( ) < 2 {
120
+ return Err ( ( ) ) ;
121
+ }
122
+ let val = u16:: from_be_bytes ( [ self . buf [ 0 ] , self . buf [ 1 ] ] ) as u64 ;
123
+ self . buf = & self . buf [ 2 ..] ;
124
+ Ok ( val)
125
+ }
126
+ 26 => {
127
+ if self . buf . len ( ) < 4 {
128
+ return Err ( ( ) ) ;
129
+ }
130
+ let val =
131
+ u32:: from_be_bytes ( [ self . buf [ 0 ] , self . buf [ 1 ] , self . buf [ 2 ] , self . buf [ 3 ] ] ) as u64 ;
132
+ self . buf = & self . buf [ 4 ..] ;
133
+ Ok ( val)
134
+ }
135
+ 27 => {
136
+ if self . buf . len ( ) < 8 {
137
+ return Err ( ( ) ) ;
138
+ }
139
+ let val = u64:: from_be_bytes ( [
140
+ self . buf [ 0 ] ,
141
+ self . buf [ 1 ] ,
142
+ self . buf [ 2 ] ,
143
+ self . buf [ 3 ] ,
144
+ self . buf [ 4 ] ,
145
+ self . buf [ 5 ] ,
146
+ self . buf [ 6 ] ,
147
+ self . buf [ 7 ] ,
148
+ ] ) ;
149
+ self . buf = & self . buf [ 8 ..] ;
150
+ Ok ( val)
151
+ }
152
+ _ => Err ( ( ) ) ,
153
+ }
154
+ }
155
+
156
+ /// Reads and returns a CBOR tag (major type 6) as a `u64`.
157
+ /// See [RFC 7049 §2.4](https://www.rfc-editor.org/rfc/rfc7049#section-2.4).
158
+ fn read_tag ( & mut self ) -> Result < u64 , ( ) > {
159
+ let b = self . read_u8 ( ) ?;
160
+ if ( b & 0xe0 ) != MAJOR_TYPE_TAG {
161
+ return Err ( ( ) ) ;
162
+ }
163
+ self . read_uint ( b)
164
+ }
165
+
166
+ /// Reads and returns a byte string (major type 2). Returns a slice of the
167
+ /// requested length, advancing the reader.
168
+ /// See [RFC 7049 §2.1](https://www.rfc-editor.org/rfc/rfc7049#section-2.1).
169
+ fn read_bytes ( & mut self ) -> Result < & ' a [ u8 ] , ( ) > {
170
+ let b = self . read_u8 ( ) ?;
171
+ if ( b & 0xe0 ) != MAJOR_TYPE_BYTES {
172
+ return Err ( ( ) ) ;
173
+ }
174
+ let len = self . read_uint ( b) ? as usize ;
175
+ if self . buf . len ( ) < len {
176
+ return Err ( ( ) ) ;
177
+ }
178
+ let out = & self . buf [ ..len] ;
179
+ self . buf = & self . buf [ len..] ;
180
+ Ok ( out)
181
+ }
182
+
183
+ /// Reads and returns the length of an array (major type 4).
184
+ /// See [RFC 7049 §2.1](https://www.rfc-editor.org/rfc/rfc7049#section-2.1).
185
+ fn read_array_len ( & mut self ) -> Result < usize , ( ) > {
186
+ let b = self . read_u8 ( ) ?;
187
+ if ( b & 0xe0 ) != MAJOR_TYPE_ARRAY {
188
+ return Err ( ( ) ) ;
189
+ }
190
+ let len = self . read_uint ( b) ? as usize ;
191
+ Ok ( len)
192
+ }
193
+
194
+ /// Reads and returns the length of a map (major type 5).
195
+ /// See [RFC 7049 §2.1](https://www.rfc-editor.org/rfc/rfc7049#section-2.1).
196
+ fn read_map_len ( & mut self ) -> Result < usize , ( ) > {
197
+ let b = self . read_u8 ( ) ?;
198
+ if ( b & 0xe0 ) != MAJOR_TYPE_MAP {
199
+ return Err ( ( ) ) ;
200
+ }
201
+ let len = self . read_uint ( b) ? as usize ;
202
+ Ok ( len)
203
+ }
204
+
205
+ /// Reads a 32-bit unsigned integer from the buffer,
206
+ /// expecting a CBOR major type 0 (unsigned integer).
207
+ fn read_u32 ( & mut self ) -> Result < u32 , ( ) > {
208
+ let b = self . read_u8 ( ) ?;
209
+ if ( b & 0xe0 ) != MAJOR_TYPE_UNSIGNED {
210
+ return Err ( ( ) ) ;
211
+ }
212
+ let val = self . read_uint ( b) ?;
213
+ if val > u32:: MAX as u64 {
214
+ return Err ( ( ) ) ;
215
+ }
216
+ Ok ( val as u32 )
217
+ }
218
+ }
219
+
220
+ fn decode_u32_from_cbor_bytes ( data : & [ u8 ] ) -> Result < u32 , ( ) > {
221
+ let mut r = CborReader :: new ( data) ;
222
+ r. read_u32 ( )
223
+ }
224
+
65
225
/// Decode a base58-encoded Byron payment address, validate it's checksum and that it was encoded for the right network.
66
226
///
67
227
/// A byron address is cbor encoded data: https://raw.githubusercontent.com/cardano-foundation/CIPs/0081c890995ff94618145ae5beb7f288c029a86a/CIP-0019/CIP-0019-byron-addresses.cddl
68
228
///
69
229
/// See also:
70
230
/// - https://github.com/input-output-hk/cardano-ledger/blob/d0aa86ded0b973b09b629e5aa62aa1e71364d088/eras/alonzo/test-suite/cddl-files/alonzo.cddl#L134-L135
71
231
/// - https://github.com/input-output-hk/technical-docs/blob/8d4f08bc05ec611f3943cdc09a4ae18e72a0eb3c/cardano-components/cardano-wallet/doc/About-Address-Format---Byron.md
72
- fn decode_byron_payment_address ( params : & params:: Params , address : & str ) -> Result < Vec < u8 > , ( ) > {
232
+ pub fn decode_byron_payment_address ( params : & params:: Params , address : & str ) -> Result < Vec < u8 > , ( ) > {
73
233
let base58_decoded = bitcoin:: base58:: decode ( address) . or ( Err ( ( ) ) ) ?;
74
- let payload = {
75
- let mut decoder = minicbor:: Decoder :: new ( & base58_decoded) ;
76
- if decoder. array ( ) . or ( Err ( ( ) ) ) ?. ok_or ( ( ) ) ? != 2 {
77
- return Err ( ( ) ) ;
78
- }
79
- if decoder. tag ( ) . or ( Err ( ( ) ) ) ? != minicbor:: data:: IanaTag :: Cbor . tag ( ) {
80
- return Err ( ( ) ) ;
81
- }
82
- let payload = decoder. bytes ( ) . or ( Err ( ( ) ) ) ?;
83
- let address_crc = decoder. u32 ( ) . or ( Err ( ( ) ) ) ?;
84
- if crc:: Crc :: < u32 > :: new ( & crc:: CRC_32_ISO_HDLC ) . checksum ( payload) != address_crc {
85
- return Err ( ( ) ) ;
86
- }
87
- payload
88
- } ;
234
+ let mut top = CborReader :: new ( & base58_decoded) ;
235
+
236
+ // Top-level array: [ (tag=24) bytes, crc_u32 ]
237
+ if top. read_array_len ( ) ? != 2 {
238
+ return Err ( ( ) ) ;
239
+ }
240
+
241
+ let tag = top. read_tag ( ) ?;
242
+ if tag != 24 {
243
+ return Err ( ( ) ) ;
244
+ }
245
+
246
+ let payload_slice = top. read_bytes ( ) ?;
247
+ let address_crc = top. read_u32 ( ) ?;
89
248
90
- let mut decoder = minicbor:: Decoder :: new ( payload) ;
91
- // Array with three elements.
92
- if decoder. array ( ) . or ( Err ( ( ) ) ) ?. ok_or ( ( ) ) ? != 3 {
249
+ if crc:: Crc :: < u32 > :: new ( & crc:: CRC_32_ISO_HDLC ) . checksum ( payload_slice) != address_crc {
93
250
return Err ( ( ) ) ;
94
251
}
252
+
253
+ let mut p = CborReader :: new ( payload_slice) ;
254
+ // payload: [rootDigest: bytes(28), attributes: map, type: u32]
255
+ if p. read_array_len ( ) ? != 3 {
256
+ return Err ( ( ) ) ;
257
+ }
258
+
95
259
// First element: address root digest.
96
- if decoder . bytes ( ) . or ( Err ( ( ) ) ) ?. len ( ) != 28 {
260
+ if p . read_bytes ( ) ?. len ( ) != 28 {
97
261
return Err ( ( ) ) ;
98
262
}
263
+
99
264
// Second element: address attributes map. Item with key 2 is the network magic. If absent, it
100
265
// is mainnet. If present, must not be mainnet.
266
+ let map_len = p. read_map_len ( ) ?;
101
267
let mut magic: Option < u32 > = None ;
102
- for item in decoder
103
- . map_iter :: < u32 , minicbor:: bytes:: ByteVec > ( )
104
- . or ( Err ( ( ) ) ) ?
105
- {
106
- let ( key, value) = item. or ( Err ( ( ) ) ) ?;
268
+ for _ in 0 ..map_len {
269
+ let key = p. read_u32 ( ) ?;
270
+ let val = p. read_bytes ( ) ?;
107
271
if key == 2 {
108
- magic = Some ( minicbor:: decode ( & value) . or ( Err ( ( ) ) ) ?) ;
272
+ let m = decode_u32_from_cbor_bytes ( val) ?;
273
+ magic = Some ( m) ;
109
274
break ;
110
275
}
111
276
}
@@ -123,15 +288,17 @@ fn decode_byron_payment_address(params: ¶ms::Params, address: &str) -> Resul
123
288
}
124
289
}
125
290
}
291
+
126
292
// Third element: address type
127
- let typ = decoder . u32 ( ) . or ( Err ( ( ) ) ) ?;
293
+ let typ = p . read_u32 ( ) ?;
128
294
if typ != 0 && typ != 2 {
129
295
return Err ( ( ) ) ;
130
296
}
131
297
Ok ( base58_decoded)
132
298
}
133
299
134
- /// Decode a Byron or Shelley payment address string and check that it was encoded for the right network.
300
+ /// Decode a Byron or Shelley payment address string and check that it was encoded for the right
301
+ /// network.
135
302
pub fn decode_payment_address ( params : & params:: Params , address : & str ) -> Result < Vec < u8 > , Error > {
136
303
if let Ok ( address) = decode_shelley_payment_address ( params, address) {
137
304
return Ok ( address) ;
0 commit comments