codec.go raw
1 package btcwire
2
3 import (
4 "encoding/binary"
5 "fmt"
6 "io"
7
8 "git.smesh.lol/nostrino/pkg/crypto/chainhash"
9 )
10
11 // Compact size prefixes, as defined by Bitcoin's variable length integer
12 // encoding.
13 const (
14 compactSizeUint16 = 0xfd
15 compactSizeUint32 = 0xfe
16 compactSizeUint64 = 0xff
17 )
18
19 // Encoder appends primitive Bitcoin wire encodings to an internal buffer. The
20 // zero value is ready for use. Encoding never fails except through the
21 // functions that return an error, such as WriteVarBytes.
22 type Encoder struct {
23 buf []byte
24 }
25
26 // Uint8 appends v as a single byte.
27 func (e *Encoder) Uint8(v uint8) {
28 e.buf = append(e.buf, v)
29 }
30
31 // Uint16 appends v as a little-endian uint16.
32 func (e *Encoder) Uint16(v uint16) {
33 e.buf = append(e.buf, byte(v), byte(v>>8))
34 }
35
36 // Uint16BE appends v as a big-endian uint16. Network ports use this encoding
37 // in the version message.
38 func (e *Encoder) Uint16BE(v uint16) {
39 e.buf = append(e.buf, byte(v>>8), byte(v))
40 }
41
42 // Uint32 appends v as a little-endian uint32.
43 func (e *Encoder) Uint32(v uint32) {
44 e.buf = append(e.buf, byte(v), byte(v>>8), byte(v>>16), byte(v>>24))
45 }
46
47 // Uint64 appends v as a little-endian uint64.
48 func (e *Encoder) Uint64(v uint64) {
49 e.buf = append(e.buf,
50 byte(v), byte(v>>8), byte(v>>16), byte(v>>24),
51 byte(v>>32), byte(v>>40), byte(v>>48), byte(v>>56),
52 )
53 }
54
55 // Int32 appends v as a little-endian signed 32-bit integer.
56 func (e *Encoder) Int32(v int32) {
57 e.Uint32(uint32(v))
58 }
59
60 // Int64 appends v as a little-endian signed 64-bit integer.
61 func (e *Encoder) Int64(v int64) {
62 e.Uint64(uint64(v))
63 }
64
65 // CompactSize appends v in Bitcoin's compact size encoding, using the
66 // shortest representation.
67 func (e *Encoder) CompactSize(v uint64) {
68 switch {
69 case v < compactSizeUint16:
70 e.Uint8(uint8(v))
71 case v <= 0xffff:
72 e.Uint8(compactSizeUint16)
73 e.Uint16(uint16(v))
74 case v <= 0xffffffff:
75 e.Uint8(compactSizeUint32)
76 e.Uint32(uint32(v))
77 default:
78 e.Uint8(compactSizeUint64)
79 e.Uint64(v)
80 }
81 }
82
83 // Hash appends h in wire byte order.
84 func (e *Encoder) Hash(h chainhash.Hash) {
85 e.buf = append(e.buf, h[:]...)
86 }
87
88 // Write appends b verbatim.
89 func (e *Encoder) Write(b []byte) {
90 e.buf = append(e.buf, b...)
91 }
92
93 // Bytes returns the encoded bytes. The result aliases the encoder's storage
94 // and is only valid until the next append.
95 func (e *Encoder) Bytes() []byte {
96 return e.buf
97 }
98
99 // Len returns the number of bytes encoded so far.
100 func (e *Encoder) Len() int {
101 return len(e.buf)
102 }
103
104 // Decoder decodes primitive Bitcoin wire types from a byte slice. All methods
105 // return an error rather than panicking when the input is truncated.
106 type Decoder struct {
107 buf []byte
108 off int
109 }
110
111 // NewDecoder returns a Decoder over buf. The Decoder does not copy buf, so
112 // the caller must not modify it while decoding.
113 func NewDecoder(buf []byte) *Decoder {
114 return &Decoder{buf: buf}
115 }
116
117 // Remaining returns the number of undecoded bytes.
118 func (d *Decoder) Remaining() int {
119 return len(d.buf) - d.off
120 }
121
122 // Offset returns the number of bytes decoded so far.
123 func (d *Decoder) Offset() int {
124 return d.off
125 }
126
127 // take returns the next n bytes without copying them.
128 func (d *Decoder) take(n int) ([]byte, error) {
129 if n < 0 {
130 return nil, fmt.Errorf("%w: cannot read %d bytes", ErrInvalidLength, n)
131 }
132 if n > d.Remaining() {
133 return nil, fmt.Errorf(
134 "btcwire: reading %d bytes at offset %d, only %d available: %w",
135 n, d.off, d.Remaining(), io.ErrUnexpectedEOF,
136 )
137 }
138 b := d.buf[d.off : d.off+n]
139 d.off += n
140 return b, nil
141 }
142
143 // Bytes returns the next n bytes. The result aliases the decoder's input.
144 func (d *Decoder) Bytes(n int) ([]byte, error) {
145 return d.take(n)
146 }
147
148 // Uint8 decodes a single byte.
149 func (d *Decoder) Uint8() (uint8, error) {
150 b, err := d.take(1)
151 if err != nil {
152 return 0, err
153 }
154 return b[0], nil
155 }
156
157 // Uint16 decodes a little-endian uint16.
158 func (d *Decoder) Uint16() (uint16, error) {
159 b, err := d.take(2)
160 if err != nil {
161 return 0, err
162 }
163 return binary.LittleEndian.Uint16(b), nil
164 }
165
166 // Uint16BE decodes a big-endian uint16.
167 func (d *Decoder) Uint16BE() (uint16, error) {
168 b, err := d.take(2)
169 if err != nil {
170 return 0, err
171 }
172 return binary.BigEndian.Uint16(b), nil
173 }
174
175 // Uint32 decodes a little-endian uint32.
176 func (d *Decoder) Uint32() (uint32, error) {
177 b, err := d.take(4)
178 if err != nil {
179 return 0, err
180 }
181 return binary.LittleEndian.Uint32(b), nil
182 }
183
184 // Uint64 decodes a little-endian uint64.
185 func (d *Decoder) Uint64() (uint64, error) {
186 b, err := d.take(8)
187 if err != nil {
188 return 0, err
189 }
190 return binary.LittleEndian.Uint64(b), nil
191 }
192
193 // Int32 decodes a little-endian signed 32-bit integer.
194 func (d *Decoder) Int32() (int32, error) {
195 v, err := d.Uint32()
196 if err != nil {
197 return 0, err
198 }
199 return int32(v), nil
200 }
201
202 // Int64 decodes a little-endian signed 64-bit integer.
203 func (d *Decoder) Int64() (int64, error) {
204 v, err := d.Uint64()
205 if err != nil {
206 return 0, err
207 }
208 return int64(v), nil
209 }
210
211 // Hash decodes a chainhash.Hash in wire byte order.
212 func (d *Decoder) Hash() (chainhash.Hash, error) {
213 var h chainhash.Hash
214 b, err := d.take(chainhash.HashSize)
215 if err != nil {
216 return h, err
217 }
218 copy(h[:], b)
219 return h, nil
220 }
221
222 // CompactSize decodes a compact size integer, rejecting non-minimal
223 // encodings.
224 func (d *Decoder) CompactSize() (uint64, error) {
225 prefix, err := d.Uint8()
226 if err != nil {
227 return 0, err
228 }
229 switch prefix {
230 case compactSizeUint16:
231 v, err := d.Uint16()
232 if err != nil {
233 return 0, err
234 }
235 if v < compactSizeUint16 {
236 return 0, fmt.Errorf(
237 "btcwire: compact size %d encoded with 0x%02x prefix: %w",
238 v, compactSizeUint16, ErrNonCanonicalCompactSize,
239 )
240 }
241 return uint64(v), nil
242 case compactSizeUint32:
243 v, err := d.Uint32()
244 if err != nil {
245 return 0, err
246 }
247 if v <= 0xffff {
248 return 0, fmt.Errorf(
249 "btcwire: compact size %d encoded with 0x%02x prefix: %w",
250 v, compactSizeUint32, ErrNonCanonicalCompactSize,
251 )
252 }
253 return uint64(v), nil
254 case compactSizeUint64:
255 v, err := d.Uint64()
256 if err != nil {
257 return 0, err
258 }
259 if v <= 0xffffffff {
260 return 0, fmt.Errorf(
261 "btcwire: compact size %d encoded with 0x%02x prefix: %w",
262 v, compactSizeUint64, ErrNonCanonicalCompactSize,
263 )
264 }
265 return v, nil
266 default:
267 return uint64(prefix), nil
268 }
269 }
270
271 // maxCompactSizeCount is the largest element count that can be safely
272 // converted to an int on every supported platform.
273 const maxCompactSizeCount = 1 << 31
274
275 // count decodes a compact size used as an element count and verifies that it
276 // does not exceed limit. It also rejects counts that cannot fit in memory
277 // given the remaining input, where minItemSize is the smallest encoded size
278 // of one element.
279 func (d *Decoder) count(limit int, minItemSize int, what string) (int, error) {
280 n, err := d.CompactSize()
281 if err != nil {
282 return 0, fmt.Errorf("btcwire: reading %s count: %w", what, err)
283 }
284 if n > maxCompactSizeCount || n > uint64(limit) {
285 return 0, fmt.Errorf(
286 "btcwire: %s count %d exceeds limit %d: %w",
287 what, n, limit, ErrTooManyItems,
288 )
289 }
290 if minItemSize > 0 && n > 0 {
291 need := n * uint64(minItemSize)
292 if need > uint64(d.Remaining()) {
293 return 0, fmt.Errorf(
294 "btcwire: %s count %d needs at least %d bytes, only %d available: %w",
295 what, n, need, d.Remaining(), io.ErrUnexpectedEOF,
296 )
297 }
298 }
299 return int(n), nil
300 }
301
302 // WriteVarBytes appends b to e prefixed by its compact size length. It fails
303 // when b is longer than MaxPayload, since such a field cannot be carried by a
304 // valid frame.
305 func WriteVarBytes(e *Encoder, b []byte) error {
306 if len(b) > MaxPayload {
307 return fmt.Errorf(
308 "btcwire: variable length field of %d bytes exceeds maximum %d: %w",
309 len(b), MaxPayload, ErrVarBytesTooLarge,
310 )
311 }
312 e.CompactSize(uint64(len(b)))
313 e.Write(b)
314 return nil
315 }
316
317 // ReadVarBytes decodes a variable length byte string whose length must not
318 // exceed maxLen. maxLen must be between zero and MaxPayload. The returned
319 // slice aliases the decoder's input.
320 func ReadVarBytes(d *Decoder, maxLen int) ([]byte, error) {
321 if maxLen < 0 || maxLen > MaxPayload {
322 return nil, fmt.Errorf("%w: maximum %d", ErrInvalidLength, maxLen)
323 }
324 n, err := d.CompactSize()
325 if err != nil {
326 return nil, fmt.Errorf("btcwire: reading varbytes length: %w", err)
327 }
328 if n > uint64(maxLen) {
329 return nil, fmt.Errorf(
330 "btcwire: varbytes length %d exceeds maximum %d: %w",
331 n, maxLen, ErrVarBytesTooLarge,
332 )
333 }
334 b, err := d.Bytes(int(n))
335 if err != nil {
336 return nil, fmt.Errorf("btcwire: reading %d byte varbytes: %w", n, err)
337 }
338 return b, nil
339 }
340