go-blockchain/wire/varint.go
Claude 4c0b7f290e
feat: Phase 0 scaffold -- config, types, wire, difficulty
Chain parameters from Lethean C++ source. Base58 address encoding with
Keccak-256 checksum. CryptoNote varint. LWMA difficulty skeleton.

Co-Authored-By: Charon <charon@lethean.io>
2026-02-20 15:10:33 +00:00

75 lines
2.3 KiB
Go

// 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
}