// Copyright (c) 2017-2026 Lethean (https://lt.hn) // // Licensed under the European Union Public Licence (EUPL) version 1.2. // You may obtain a copy of the licence at: // // https://joinup.ec.europa.eu/software/page/eupl/licence-eupl // // SPDX-License-Identifier: EUPL-1.2 // Package wire provides binary serialisation primitives for the CryptoNote // wire protocol. All encoding is consensus-critical and must be bit-identical // to the C++ reference implementation. package wire import ( "errors" ) // MaxVarintLen is the maximum number of bytes a CryptoNote varint can occupy. // A uint64 requires at most 10 bytes of 7-bit encoding (64 bits / 7 = ~9.14, // so values above 2^63-1 need a 10th byte). const MaxVarintLen = 10 // ErrVarintOverflow is returned when a varint exceeds the maximum allowed // length of 10 bytes. var ErrVarintOverflow = errors.New("wire: varint overflow (exceeds 10 bytes)") // ErrVarintEmpty is returned when attempting to decode a varint from an // empty byte slice. var ErrVarintEmpty = errors.New("wire: cannot decode varint from empty data") // EncodeVarint encodes a uint64 value as a CryptoNote variable-length integer. // // The encoding uses 7 bits per byte, with the most significant bit (MSB) set // to 1 to indicate that more bytes follow. This is the same scheme as protobuf // varints but limited to 9 bytes maximum for uint64 values. func EncodeVarint(v uint64) []byte { if v == 0 { return []byte{0x00} } var buf [MaxVarintLen]byte n := 0 for v > 0 { buf[n] = byte(v & 0x7f) v >>= 7 if v > 0 { buf[n] |= 0x80 } n++ } return append([]byte(nil), buf[:n]...) } // DecodeVarint decodes a CryptoNote variable-length integer from the given // byte slice. It returns the decoded value, the number of bytes consumed, // and any error encountered. func DecodeVarint(data []byte) (uint64, int, error) { if len(data) == 0 { return 0, 0, ErrVarintEmpty } var v uint64 for i := 0; i < len(data) && i < MaxVarintLen; i++ { v |= uint64(data[i]&0x7f) << (7 * uint(i)) if data[i]&0x80 == 0 { return v, i + 1, nil } } // If we read MaxVarintLen bytes and the last one still has the // continuation bit set, or if we ran out of data with the continuation // bit still set, that is an overflow. if len(data) >= MaxVarintLen { return 0, 0, ErrVarintOverflow } return 0, 0, ErrVarintOverflow }