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