monblob

package module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 30, 2026 License: MIT Imports: 4 Imported by: 0

README

go-monblob

go-monblob logo

Go Version License Go Report Card

go-monblob is a pure Go, zero-dependency library for parsing and serializing Monero transaction binary blobs (tx_blob). It follows CNS003 and Monero v0.18+ specifications, adopting a strategy of “precise prefix parsing + raw signature retention” to support all transaction versions (V1/V2) and all RingCT types (0–5).


Features

  • Zero external dependencies – only uses the Go standard library (with golang.org/x/crypto/sha3 for Keccak-256, but that’s an official Go extension).
  • Full parsing – supports parsing and serialization of Transaction and its prefix (TransactionPrefix).
  • Flexible storage – signature blocks (including RingCT) are kept as raw bytes, enabling lossless round‑trips.
  • High performance – parses 100,000+ typical transactions (~2KB) per second on a single core.
  • Production‑ready security – built‑in recursion depth, slice size, and memory limits to prevent DoS attacks.
  • Fuzz testing – native Go fuzz tests to continuously verify robustness.

Architecture Overview

The diagram below illustrates the parsing flow: from raw []byteTransaction struct, and the reverse serialization.

Architecture diagram

Installation

go get github.com/cexpepe/go-monblob

Usage Example

package main

import (
    "encoding/hex"
    "fmt"
    "log"

    "github.com/cexpepe/go-monblob"
)

func main() {
    // Hex blob obtained from RPC or file
    hexBlob := "020002020010c0b2d122f183e30386f332b1bc01..." // truncated

    data, err := hex.DecodeString(hexBlob)
    if err != nil {
        log.Fatal(err)
    }

    // Parse full transaction
    tx, err := monblob.Parse(data)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Version: %d\n", tx.Prefix.Version)
    fmt.Printf("Inputs: %d\n", len(tx.Prefix.Inputs))
    fmt.Printf("Outputs: %d\n", len(tx.Prefix.Outputs))

    // Compute transaction ID (Keccak-256 of prefix)
    txid := tx.Hash()
    fmt.Printf("Transaction ID: %x\n", txid)

    // Parse only the prefix (lightweight inspection)
    prefix, _ := monblob.ParsePrefix(data)
    // ... use prefix

    // Serialize back to blob (lossless round-trip)
    reborn, _ := monblob.Serialize(tx)
    if len(reborn) == len(data) {
        fmt.Println("Round-trip successful")
    }
}

For more examples, see blob_test.go.


API Reference

Function Description
Parse(data []byte) (*Transaction, error) Parses a full transaction from a binary blob
Serialize(tx *Transaction) ([]byte, error) Serializes a transaction back to binary blob
ParsePrefix(data []byte) (*TransactionPrefix, error) Parses only the transaction prefix (without signatures)
SerializePrefix(prefix *TransactionPrefix) ([]byte, error) Serializes only the transaction prefix
ParseFromReader(r io.Reader) (*Transaction, error) Stream‑based parsing
SerializeToWriter(tx *Transaction, w io.Writer) error Stream‑based serialization
tx.Hash() [32]byte Computes the transaction ID (Keccak‑256 of the prefix)
HashPrefix(prefix *TransactionPrefix) [32]byte Computes the hash directly from a prefix

Testing

# Unit tests + vector tests (requires a real transaction in testdata/transaction.bin)
go test -v

# Fuzz testing (30 seconds)
go test -fuzz=^FuzzParse$ -fuzztime=30s
go test -fuzz=^FuzzParsePrefix$ -fuzztime=30s

# Benchmarks
go test -bench=. -benchmem

To prepare test data, place any Monero transaction binary as testdata/transaction.bin (you can export one using monero-blockchain-export or via the RPC get_transactions endpoint).


Contributing

Issues and pull requests are welcome. Please ensure all tests pass and maintain the zero‑dependency principle.


License

MIT


Version v1.0.0

First stable release, supporting:

  • V1/V2 transactions
  • RingCT types 0–5 (signatures stored as raw bytes)
  • Tagged outputs (v0.18+)
  • Complete round‑trip serialization

Documentation

Overview

Package monblob provides Monero transaction binary blob parsing and serialization. It follows CNS003 and Monero v0.18+ specifications with zero external dependencies.

Package monblob provides binary encoding and decoding for Monero transactions.

Package monblob provides Keccak-256 hashing for transaction IDs.

Package monblob defines all data structures for Monero transaction parsing. Types follow CNS003 and Monero v0.18+ specifications.

Package monblob provides Monero varint encoding/decoding. Monero uses a 7-bit-per-byte varint with MSB as continuation flag.

Index

Constants

View Source
const (
	MaxInputs         = 4096
	MaxOutputs        = 4096
	MaxKeyOffsets     = 4096
	MaxSignatureSize  = 10 * 1024 * 1024
	MaxRecursionDepth = 32
	MaxVarBytesSize   = 10 * 1024 * 1024
)

Security limits

View Source
const (
	TxInTypeGen         = 0xFF
	TxInTypeToKey       = 0x01
	TxInTypeToKeyTagged = 0x02
)

TxIn type constants.

View Source
const (
	TxOutTypeToKey       = 0x01
	TxOutTypeToKeyTagged = 0x02
)

TxOut type constants.

View Source
const (
	ExtraTagPadding           = 0x00 // Padding bytes, skipped entirely
	ExtraTagPublicKey         = 0x01 // 32-byte public key (tx_public_key)
	ExtraTagExtraNonce        = 0x02 // Variable length extra nonce: [length][data]
	ExtraTagMergeMining       = 0x03 // Deprecated merge mining info
	ExtraTagAdditionalPubKeys = 0x04 // [count][pubkey1][pubkey2]... (additional public keys)
	ExtraTagMinerGate         = 0xDE // Miner gate tag (reserved)
)

Extra tag constants as defined in Monero specifications.

View Source
const (
	ExtraNonceTagPaymentID          = 0x00 // 32-byte plain payment ID (deprecated since v0.15)
	ExtraNonceTagEncryptedPaymentID = 0x01 // 8-byte encrypted payment ID
)

ExtraNonce sub-tags used inside ExtraTagExtraNonce.

Variables

View Source
var (
	ErrUnexpectedEOF    = errors.New("unexpected end of data")
	ErrUnknownTxInType  = errors.New("unknown transaction input type")
	ErrUnknownTxOutType = errors.New("unknown transaction output type")
	ErrVarintOverflow   = errors.New("varint overflow")
	ErrMaxSliceSize     = errors.New("slice size exceeds maximum allowed")
	ErrRecursionDepth   = errors.New("maximum recursion depth exceeded")
)

Error definitions

View Source
var ErrOverflow = errors.New("varint overflow")

ErrOverflow indicates that the varint value exceeds 64 bits.

View Source
var ErrTrailingData = errors.New("trailing data after transaction")

ErrTrailingData indicates that extra bytes remain after fully parsing a transaction.

Functions

func DecodeVarint

func DecodeVarint(data []byte) (uint64, int, error)

DecodeVarint decodes a Monero-style varint from the beginning of data. Returns the value, the number of bytes consumed, and any error.

func DecodeVarintFromReader

func DecodeVarintFromReader(r io.Reader) (uint64, error)

DecodeVarintFromReader reads a Monero-style varint from r and returns the decoded value.

func EncodeVarint

func EncodeVarint(val uint64) []byte

EncodeVarint encodes a uint64 as a Monero-style varint and returns the byte slice.

func EncodeVarintToWriter

func EncodeVarintToWriter(w io.Writer, val uint64) error

EncodeVarintToWriter encodes a uint64 as a Monero-style varint and writes it to w. Each byte uses 7 bits for data, with the MSB set to 1 for continuation.

func HashPrefix

func HashPrefix(prefix *TransactionPrefix) [32]byte

HashPrefix computes the transaction ID directly from a TransactionPrefix.

func Keccak256

func Keccak256(data []byte) [32]byte

Keccak256 computes the Keccak-256 hash of the input data.

func Serialize

func Serialize(tx *Transaction) ([]byte, error)

Serialize serializes a complete transaction back into its binary blob representation. The output is a concatenation of the prefix and all signatures.

func SerializePrefix

func SerializePrefix(prefix *TransactionPrefix) ([]byte, error)

SerializePrefix serializes only the transaction prefix. The result is suitable for hashing to obtain the transaction ID.

func SerializeToWriter

func SerializeToWriter(tx *Transaction, w io.Writer) error

SerializeToWriter serializes a transaction and writes the binary blob to the given io.Writer. This avoids holding the entire blob in memory when writing to a stream.

Types

type ExtraAdditionalPubKeys

type ExtraAdditionalPubKeys struct {
	Count uint8
	Keys  [][32]byte
}

ExtraAdditionalPubKeys holds the parsed additional public keys from ExtraTagAdditionalPubKeys.

type ExtraField

type ExtraField struct {
	Tag  uint8  // 0x00=padding, 0x01=pubkey, 0x02=nonce, 0x04=additional_pubkeys
	Data []byte // Raw data excluding the tag byte
}

ExtraField represents a single field in the transaction extra section. The extra section is a TLV (Tag-Length-Value) structure, but the length and format depend on the tag. This struct stores the raw data for flexibility.

type ExtraNonce

type ExtraNonce struct {
	Tag  uint8  // Sub-tag (e.g., ExtraNonceTagPaymentID)
	Data []byte // Raw data corresponding to the sub-tag
}

ExtraNonce holds the parsed extra nonce data.

type ExtraPublicKey

type ExtraPublicKey [32]byte

ExtraPublicKey is a convenience type for a 32-byte public key.

type TaggedKey

type TaggedKey struct {
	ViewTag   uint32
	PublicKey [32]byte
}

TaggedKey represents a view-tagged output public key.

type Transaction

type Transaction struct {
	Prefix     TransactionPrefix
	Signatures [][]byte // Each input contributes one signature group (ring signature or generation signature)
}

Transaction represents a complete Monero transaction with its prefix and signatures.

func Parse

func Parse(data []byte) (*Transaction, error)

Parse parses a complete transaction from a binary blob. It automatically splits the prefix and signature sections.

func ParseFromReader

func ParseFromReader(r io.Reader) (*Transaction, error)

ParseFromReader reads all data from an io.Reader and parses a complete transaction. This is suitable for streaming large blobs or reading from network connections.

func (*Transaction) Hash

func (tx *Transaction) Hash() [32]byte

Hash computes the transaction ID for a complete Transaction.

type TransactionPrefix

type TransactionPrefix struct {
	Version    uint64 // Current version is 2
	UnlockTime uint64 // 0 means immediate unlock (block height or timestamp otherwise)
	Inputs     []TxIn
	Outputs    []TxOut
	Extra      []byte
}

TransactionPrefix holds the non-signature part of a transaction. This is the portion hashed to compute the transaction ID.

func ParsePrefix

func ParsePrefix(data []byte) (*TransactionPrefix, error)

ParsePrefix parses only the transaction prefix (without signatures). This is useful for computing transaction IDs or inspecting transaction structure without processing potentially large signature data.

type TxIn

type TxIn struct {
	Type  uint8      // 0xFF=Gen, 0x01=ToKey, 0x02=ToKeyTagged
	Gen   *TxInGen   // Used when Type == TxInTypeGen
	ToKey *TxInToKey // Used when Type == TxInTypeToKey or TxInTypeToKeyTagged
}

TxIn represents a transaction input with a type tag. The actual input data is stored in either Gen or ToKey based on Type.

type TxInGen

type TxInGen struct {
	Height uint64 // Block height at which this coinbase was generated
}

TxInGen represents a coinbase (miner) transaction input.

type TxInToKey

type TxInToKey struct {
	Amount     uint64   // Always 0 in Monero (amounts are hidden)
	KeyOffsets []uint64 // Ring member indices as offsets from the global output index
	KeyImage   [32]byte // Key image to prevent double-spending
}

TxInToKey represents a standard transaction input referencing outputs in the ring.

type TxOut

type TxOut struct {
	Amount uint64 // Always 0 in Monero
	Target TxOutTarget
}

TxOut represents a transaction output.

type TxOutTarget

type TxOutTarget struct {
	Type   uint8      // 0x01=ToKey, 0x02=ToKeyTagged
	ToKey  *[32]byte  // Standard output public key
	Tagged *TaggedKey // Tagged output (v0.18+)
}

TxOutTarget is a union of output target types.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL