boxrec

package
v0.3.2 Latest Latest
Warning

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

Go to latest
Published: Oct 7, 2026 License: Apache-2.0 Imports: 29 Imported by: 0

Documentation

Overview

Package boxrec is the byte-level contract of bbox: the envelope record an envelope carrier holds, the receipt record a receipt carrier holds, the BRC-169 envelope a record's content is, the office and box name grammars, and the lookup question classes. docs/spec.md is the normative text; this package generates the golden vectors under testdata/vectors.

Every record is canonical CBOR through bcommon's cbor package, so one value has one encoding a reader accepts. Every decoder bounds its input before the CBOR decoder runs, and the CBOR decoder bounds every declared length against the bytes present before it allocates.

Index

Examples

Constants

View Source
const (
	// ProtocolName is the BRC-43 protocol name, security level 1. BRC-43
	// key derivation refuses a name under five characters, so the
	// application name alone ("bbox") cannot be the protocol name.
	ProtocolName = "bbox message"
	// KeyEnvelope locks every carrier's record output (envelopes and
	// receipts), signs its field, and locks the funding-tree outputs a
	// carrier spends.
	KeyEnvelope = "envelope"
	// KeySignature signs the BRC-169 envelope a record's content is.
	KeySignature = "signature"
	// KeyFund is the embedded wallet's funding key.
	KeyFund = "fund"

	// TopicPrefix and LookupService are the overlay names (BRC-87).
	TopicPrefix   = "tm_bbox_"
	LookupService = "ls_bbox"
)

Registry values (docs/frozen.md); frozen once the first record is published to a public host.

View Source
const (
	// MaxSafe is 2^53 - 1.
	MaxSafe = 1<<53 - 1
	// MaxTime is 9999-12-31T23:59:59Z, the last second RFC 3339 can write.
	MaxTime = 253402300799
	// SuffixLen is the length of an office's random suffix.
	SuffixLen = 10
	// MaxOffice is the longest office identifier: BRC-87 caps a name at 50
	// characters and the topic prefix takes 8.
	MaxOffice = 50 - len(TopicPrefix)
	// MaxOfficeName is the longest readable part of an office identifier.
	MaxOfficeName = MaxOffice - 1 - SuffixLen
	// MinOffice is the shortest office identifier.
	MinOffice = 1 + 1 + SuffixLen
	// MaxBox is the longest box name.
	MaxBox = 50
	// MaxContent bounds an envelope's content (key 7), the BRC-169
	// envelope as carried, in bytes.
	MaxContent = 16 << 10
	// MaxEnvelopeRecord bounds an encoded envelope record.
	MaxEnvelopeRecord = MaxContent + 4096
	// MaxAcks bounds the commitments one receipt acknowledges.
	MaxAcks = 64
	// MaxReceiptRecord bounds an encoded receipt record.
	MaxReceiptRecord = 4096
	// MaxKeys bounds the entries of a record map, unknown keys included.
	MaxKeys = 64
)

Bounds. A reader accepts every record within them; a later version may raise a bound but never lower it (docs/frozen.md).

View Source
const (
	EKMagic   = 0
	EKOffice  = 1
	EKTo      = 2
	EKBox     = 3
	EKFrom    = 4
	EKCreated = 5
	EKExpires = 6
	EKContent = 7
)

Envelope record keys.

View Source
const (
	RKMagic   = 0
	RKOffice  = 1
	RKBy      = 2
	RKAcks    = 3
	RKCreated = 4
)

Receipt record keys.

View Source
const (
	MetanetHandles = "1.0"

	MemberVersion   = "metanetHandles"
	MemberRecipient = "recipient"
	MemberSender    = "sender"
	MemberCreated   = "created"
	MemberQuoteID   = "quoteId"
	MemberPayment   = "payment"
	MemberContent   = "content"
	MemberSignature = "signature"
	MemberIdentity  = "identityKey"
)

BRC-169 envelope members and the one version this contract admits.

View Source
const (
	PlainBody    = "body"
	PlainPayment = "payment"
	PlainRefs    = "refs"
)

Plaintext members (docs/spec.md section 4.5).

View Source
const (
	// PaymentMinLife is the least expires - created of an envelope whose
	// payment a recipient takes.
	PaymentMinLife = 7200
	// PaymentMargin is how long before expires a recipient stops
	// internalizing, and after it a sender may reclaim.
	PaymentMargin = 3600
)

Payment timing (docs/spec.md section 10), seconds.

View Source
const (
	QOffice     = "office"
	QTo         = "to"
	QBox        = "box"
	QAfter      = "after"
	QBy         = "by"
	QReceiptFor = "receiptFor"
	QHistory    = "history"
	QFrom       = "from"
	QSpent      = "spent"
)

Query member names.

View Source
const (
	PageEnvelopes = 64
	PageReceipts  = 8
	PageSweeps    = 8
)

Page sizes.

View Source
const BRC78Min = 4 + 33 + 33 + 32 + 32 + 16

BRC78Min is the shortest BRC-78 message: version, sender, recipient, key id, a 32-byte IV and a 16-byte GCM tag around an empty plaintext.

View Source
const DefaultMaxBEEF = 256 << 10

DefaultMaxBEEF is the BEEF bound Admit applies when a host names none: the floor docs/spec.md section 12 sets for a host's own bound.

View Source
const MaxRefs = 32

MaxRefs is the most references a plaintext carries (docs/spec.md section 4.5): 32 references with a key and a locator of a hundred bytes take about 8 KB, which fits the plaintext a 16 KiB content can hold with room for a body.

Variables

View Source
var (
	ErrCarrierShape = errors.New("boxrec: carrier has the wrong shape")
	ErrBEEF         = errors.New("boxrec: BEEF is not exactly the carrier and its proven funding tree")
	ErrMineable     = errors.New("boxrec: carrier is mineable")
	ErrUnlock       = errors.New("boxrec: unlocking script is not in canonical form")
	ErrLock         = errors.New("boxrec: output script is not the canonical one for the owner")
	ErrSignature    = errors.New("boxrec: field signature is not strict or does not verify")
	ErrFunding      = errors.New("boxrec: carrier does not spend a funding output of the owner")
	ErrUnmined      = errors.New("boxrec: sweep has no proof that verifies")
	ErrNotBbox      = errors.New("boxrec: transaction is not for this topic")
)

The transaction refusals of docs/spec.md section 8.1, beside the record and content refusals. A transaction is refused for the first rule it breaks. A carrier whose record names another office than the topic's is refused with ErrOffice, the label of a record whose office breaks the grammar.

View Source
var (
	TagPrefix = []byte("bb")
	// TagFunding is the one field of a funding-tree output.
	TagFunding = []byte{'b', 'b', 0x02}
	// MagicEnvelope is key 0 of an envelope record: "bb", 'e', version 1.
	MagicEnvelope = []byte{'b', 'b', 'e', 0x01}
	// MagicReceipt is key 0 of a receipt record: "bb", 'r', version 1.
	MagicReceipt = []byte{'b', 'b', 'r', 0x01}
)

Tags and magics. The tag prefix "bb" belongs to bbox.

View Source
var (
	Protocol            = wallet.Protocol{SecurityLevel: wallet.SecurityLevelEveryApp, Protocol: ProtocolName}
	EnvelopeDerivation  = pushdrop.Derivation{Protocol: Protocol, KeyID: KeyEnvelope}
	SignatureDerivation = pushdrop.Derivation{Protocol: Protocol, KeyID: KeySignature}
	FundDerivation      = pushdrop.Derivation{Protocol: Protocol, KeyID: KeyFund}
)

Derivations under [1, "bbox message"], each with counterparty anyone, so a reader derives the key from the identity key alone.

View Source
var (
	ErrTooLarge = record.ErrTooLarge
	ErrCBOR     = record.ErrCBOR
	ErrKeyType  = record.ErrKeyType
	ErrMagic    = record.ErrMagic
	ErrMissing  = record.ErrMissing
	ErrType     = record.ErrType
	ErrRange    = record.ErrRange
	ErrIdentity = errors.New("boxrec: identity key is not a canonical compressed key")
	ErrOffice   = errors.New("boxrec: office identifier breaks the grammar")
	ErrBox      = errors.New("boxrec: box name breaks the grammar")
	ErrExpires  = errors.New("boxrec: expires is not zero and not after created")
	ErrAcks     = errors.New("boxrec: acks are not 1 to 64 distinct commitments in ascending order")

	ErrContentJSON      = errors.New("boxrec: content is not a JSON object in the subset")
	ErrContentShape     = errors.New("boxrec: content is not a bbox BRC-169 envelope")
	ErrContentCipher    = errors.New("boxrec: content's encrypted payload does not match the record")
	ErrContentSignature = errors.New("boxrec: content signature does not verify")

	ErrQuery = errors.New("boxrec: question is not one of the defined classes")
)

The refusals. A host counts them by Reason.

View Source
var (
	ErrUndecryptable  = errors.New("boxrec: the recipient cannot decrypt the envelope")
	ErrPlaintextJSON  = errors.New("boxrec: plaintext is not a JSON object in the subset")
	ErrPlaintextShape = errors.New("boxrec: plaintext member has the wrong shape")
	ErrPaymentShape   = errors.New("boxrec: payment has the wrong shape")
	ErrPaymentExpires = errors.New("boxrec: payment envelope does not expire at least two hours after it was created")
	ErrPaymentLate    = errors.New("boxrec: payment is past its internalization window")
	ErrPaymentBEEF    = errors.New("boxrec: payment is not an Atomic BEEF that parses")
	ErrPaymentOutput  = errors.New("boxrec: payment output does not pay the recipient what it says")
	ErrPaymentSPV     = errors.New("boxrec: payment does not verify against the recipient's headers")
)

The recipient's refusals of what it decrypts (docs/spec.md sections 4.5, 10 and 13). A host never sees the plaintext, so none of these is a host rule: they are the recipient client's, in the order a client applies them, and a client that refuses a payment shows the message without it.

View Source
var BRC78Version = []byte{0x42, 0x42, 0x10, 0x33}

BRC78Version is the four-byte version a BRC-78 message starts with, as go-sdk v1.5.2's message package writes it.

View Source
var Classes = []Class{
	{"inbox", []string{QOffice, QTo}, true, PageEnvelopes},
	{"inbox-after", []string{QAfter, QOffice, QTo}, true, PageEnvelopes},
	{"box", []string{QBox, QOffice, QTo}, true, PageEnvelopes},
	{"box-after", []string{QAfter, QBox, QOffice, QTo}, true, PageEnvelopes},
	{"sender", []string{QFrom, QOffice, QTo}, true, PageEnvelopes},
	{"sender-after", []string{QAfter, QFrom, QOffice, QTo}, true, PageEnvelopes},
	{"receipt", []string{QBy, QOffice, QReceiptFor}, true, PageReceipts},
	{"sweep", []string{QOffice, QSpent}, true, PageSweeps},
	{"history", []string{QHistory, QOffice}, false, PageEnvelopes},
	{"history-after", []string{QAfter, QHistory, QOffice}, false, PageEnvelopes},
}

Classes is every question class ls_bbox answers, in the spec's order.

View Source
var PaymentProtocol = wallet.Protocol{SecurityLevel: 2, Protocol: "3241645161d8"}

PaymentProtocol is BRC-29's derivation protocol: a payment output is P2PKH to the key derived under it with key id "<prefix> <suffix>".

Functions

func Canonical

func Canonical(v any) ([]byte, error)

Canonical writes v as RFC 8785 serializes it: no white space, object members sorted by the UTF-16 code units of their names, strings escaped as ECMAScript's JSON.stringify escapes them, integers in plain decimal.

func CheckBox

func CheckBox(s string) error

CheckBox applies the box name grammar: 1 to MaxBox bytes of lowercase ASCII letters, digits and single underscores, starting with a letter and ending with a letter or a digit.

func CheckIdentity

func CheckIdentity(k []byte) error

CheckIdentity refuses anything but a canonical compressed secp256k1 key (bcommon guard.ParsePubKey): 33 bytes, prefix 0x02 or 0x03, an x-coordinate below the field prime, and a point on the curve. Accepting an alias would let two byte strings name one sender or recipient.

func CheckOffice

func CheckOffice(s string) error

CheckOffice applies the office identifier grammar: <name>_<suffix>, where name meets CheckOfficeName and suffix is exactly SuffixLen lowercase ASCII letters. TopicPrefix + office is then a BRC-87 topic manager name.

func CheckOfficeName

func CheckOfficeName(name string) error

CheckOfficeName applies the grammar of an office's readable part: 1 to MaxOfficeName bytes of lowercase ASCII letters and single underscores, starting and ending with a letter.

func CheckPayment

func CheckPayment(ctx context.Context, w KeyGetter, originator string, e *Envelope, p *Payment,
	headers chaintracker.ChainTracker, now uint64) (*transaction.Transaction, error)

CheckPayment is what a recipient checks before it internalizes a payment from envelope e, at its time now, in order: payment-expires (e expires at least PaymentMinLife after it was created), payment-late (now is before expires - PaymentMargin), payment-beef (an Atomic BEEF that parses, with its subject), payment-output (each listed output exists, holds the satoshis listed, and is P2PKH to the key the recipient's wallet derives under BRC-29 for the prefix, the suffix and the sender), payment-spv (the transaction verifies against the recipient's headers, BRC-67). It returns the payment transaction, for the wallet's internalizeAction.

func EncodePlaintext

func EncodePlaintext(doc *Object) ([]byte, error)

EncodePlaintext writes doc as a plaintext: its canonical serialization, held to the recipient's rules (ParsePlaintext) before it is returned, so a sender never seals what the recipient refuses. Members this contract does not define (an application's own, section 4.5) are carried as they are.

Example

An application's own plaintext member rides beside bbox's: written with EncodePlaintext, read back with Extension, its members as the sender wrote them.

package main

import (
	"fmt"

	"github.com/lightwebinc/bbox/boxrec"
)

func main() {
	app := &boxrec.Object{}
	app.Set("v", boxrec.Int(1))
	app.Set("kind", "dm")
	app.Set("seq", boxrec.Int(1))

	doc := &boxrec.Object{}
	doc.Set(boxrec.PlainBody, "hello")
	doc.Set("app", app)
	plain, err := boxrec.EncodePlaintext(doc)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(plain))

	p, err := boxrec.ParsePlaintext(plain)
	if err != nil {
		panic(err)
	}
	m, _ := p.Extension("app")
	kind, _ := m.Get("kind")
	seq, _ := m.Get("seq")
	fmt.Println(*p.Body, kind, seq)

	// A plaintext the recipient would refuse is not written.
	bad := &boxrec.Object{}
	bad.Set(boxrec.PlainBody, boxrec.Int(7))
	_, err = boxrec.EncodePlaintext(bad)
	fmt.Println(boxrec.Reason(err))
}
Output:
{"app":{"kind":"dm","seq":1,"v":1},"body":"hello"}
hello dm 1
plaintext-shape

func FundingScript

func FundingScript(key *ec.PublicKey) []byte

FundingScript is a funding-tree output locked to key: <key> OP_CHECKSIG <62 62 02> OP_DROP.

func IsEnvelope

func IsEnvelope(payload []byte) bool

IsEnvelope reports whether a PushDrop's first field claims to be an envelope record.

func IsFundingShape

func IsFundingShape(s []byte) bool

IsFundingShape reports whether s is a well-formed funding output under some canonical compressed key: exactly the funding script rebuilt from its own key. Whose key it is cannot be read from the script (the derivation is one way); a carrier's funding rule compares with the owner's, and a sweep takes any.

func IsReceipt

func IsReceipt(payload []byte) bool

IsReceipt reports whether a PushDrop's first field claims to be a receipt record.

func Mined

Mined reports whether tx carries a proof that verifies against the headers. No headers means nothing is mined.

func MinimalPath

func MinimalPath(mp *transaction.MerklePath, txid *chainhash.Hash) (*transaction.MerklePath, error)

MinimalPath is mp cut to the proof of txid alone (spec section 8.1 rule 2): at the lowest level txid, flagged as the txid, and its sibling; above that the one sibling each level needs, computed from the leaves below when mp holds only those. A node may answer a proof that carries more of its block than one transaction needs, and a host refuses a carrier whose funding tree's proof does. The result proves the same root.

func NewOffice

func NewOffice(name string, r io.Reader) (string, error)

NewOffice creates an office identifier for name: name, an underscore, and SuffixLen letters drawn uniformly at random from a to z by r (crypto/rand.Reader when r is nil). Whoever creates the office calls it once and keeps the result for the office's life.

func Open

func Open(ctx context.Context, w Decrypter, originator string, c *Content, from []byte) ([]byte, error)

Open decrypts an envelope's BRC-78 message through the recipient's wallet: protocol [2, "message encryption"], the message's key id in base64, counterparty the sender. A failure is ErrUndecryptable, which a reader shows as such, never as an empty message.

func P2PKH

func P2PKH(key *ec.PublicKey) []byte

P2PKH is the pay-to-public-key-hash locking script of key.

func Params

func Params() carrier.Params

Params are the bcommon carrier parameters of a bbox carrier: the record output and funding outputs under [1, "bbox message"] key id envelope, the funding tag, and a payload validator that takes an envelope or a receipt record. A sender mints with carrier.Mint and sweeps with carrier.Sweep under them.

func ParseAfter

func ParseAfter(s string) (uint64, string, bool)

ParseAfter parses a page cursor: the decimal created (1 to MaxTime, no leading zero), a colon, and 64 lowercase hex digits of a txid in display order.

func ParseJSON

func ParseJSON(b []byte) (any, error)

ParseJSON parses b as one value of the subset: valid UTF-8, no byte order mark, objects with unique member names, strings with no lone surrogate, integers only (no fraction, exponent, leading zero or minus zero, magnitude at most 2^53 - 1), nesting at most 16, and nothing but white space after the value.

func ParseOutpoint

func ParseOutpoint(s string) (string, uint32, bool)

ParseOutpoint parses an outpoint as the engine writes one: 64 lowercase hex digits of a txid in display order, a dot, and the output index in decimal (0 to 4294967295, no leading zero).

func PushDropScript

func PushDropScript(key *ec.PublicKey, fields [][]byte, sig []byte) []byte

PushDropScript is the one canonical lock-before PushDrop for key, fields and an optional field signature (bcommon pushdrop.Script).

func RFC3339

func RFC3339(t uint64) string

RFC3339 writes t as the one form this contract admits for created: YYYY-MM-DDTHH:MM:SSZ.

func Reason

func Reason(err error) string

Reason is the fixed label a host counts a refusal by.

func Seal

func Seal(ctx context.Context, w Signer, originator string, doc *Object, brc78 []byte) ([]byte, error)

Seal completes a BRC-169 envelope for the sender: it sets payment to null, the content member to the BRC-78 message in standard base64, and the signature member to the wallet's signature, under the sender's key for [1, "bbox message"] and key id "signature", over SHA-256 of the RFC 8785 serialization without content and signature. It returns the carried bytes: the canonical serialization of the whole envelope.

func SealEnvelope

func SealEnvelope(ctx context.Context, w Sealer, originator string, from, to, plaintext []byte, created uint64) ([]byte, error)

SealEnvelope encrypts the plaintext to the recipient under BRC-78 through the sender's wallet (protocol [2, "message encryption"], a random key id) and completes and signs the BRC-169 envelope (spec section 4). from is the sender's identity key, the wallet's own, and to the recipient's. It returns the content an envelope record carries (key 7).

Example

An envelope from sealing to opening: the sender seals the plaintext into the content, the record carries it, and the recipient checks the content against the record, decrypts it and applies the plaintext's rules.

package main

import (
	"bytes"
	"context"
	"fmt"

	ec "github.com/bsv-blockchain/go-sdk/primitives/ec"
	"github.com/bsv-blockchain/go-sdk/wallet"

	"github.com/lightwebinc/bbox/boxrec"
)

func main() {
	ctx := context.Background()
	senderKey, _ := ec.NewPrivateKey()
	recipientKey, _ := ec.NewPrivateKey()
	sender, _ := wallet.NewCompletedProtoWallet(senderKey)
	recipient, _ := wallet.NewCompletedProtoWallet(recipientKey)
	from, to := senderKey.PubKey().Compressed(), recipientKey.PubKey().Compressed()

	doc := &boxrec.Object{}
	doc.Set(boxrec.PlainBody, "hello")
	plain, err := boxrec.EncodePlaintext(doc)
	if err != nil {
		panic(err)
	}
	const created = 1700000000
	content, err := boxrec.SealEnvelope(ctx, sender, "example", from, to, plain, created)
	if err != nil {
		panic(err)
	}
	env := &boxrec.Envelope{Office: "example_abcdefghij", To: to, Box: "inbox", From: from, Created: created, Content: content}
	record, err := env.Encode()
	if err != nil {
		panic(err)
	}

	got, err := boxrec.DecodeEnvelope(record)
	if err != nil {
		panic(err)
	}
	c, err := boxrec.CheckContent(got)
	if err != nil {
		panic(err)
	}
	opened, err := boxrec.Open(ctx, recipient, "example", c, got.From)
	if err != nil {
		panic(err)
	}
	p, err := boxrec.ParsePlaintext(opened)
	if err != nil {
		panic(err)
	}
	fmt.Println(got.Box, bytes.Equal(got.From, from), *p.Body)
}
Output:
inbox true hello

func SplitOffice

func SplitOffice(s string) (name, suffix string, err error)

SplitOffice returns an office identifier's readable part and suffix. The readable part alone never identifies an office.

func StrictSignature

func StrictSignature(der []byte) bool

StrictSignature reports whether der is a strict DER ECDSA signature (BIP 66) with R in [1, n-1] and S in [1, n/2]: the one encoding of a signature a host accepts, so nobody can re-encode it into another byte string that still verifies.

func Topic

func Topic(office string) (string, error)

Topic is the topic manager name of an office identifier.

Types

type Admission

type Admission struct {
	Kind TxKind
	// Txid is the transaction's txid, hash byte order.
	Txid [32]byte
	// Outputs are the output indices admitted.
	Outputs []int
	// Retain are the input indices that spend an output the topic holds:
	// every one is retained, so no admitted output is deleted when
	// something spends it.
	Retain []int
	// Carrier is set for TxEnvelope and TxReceipt.
	Carrier *Carrier
	// Spent is, for TxSweep, every outpoint the sweep's inputs spend.
	Spent []transaction.Outpoint
}

Admission is what a host admits from one transaction: the outputs to admit and the held inputs to retain (BRC-22's admittance instructions), and what the lookup service records.

func Admit

func Admit(ctx context.Context, beef []byte, held []int, h Host) (*Admission, error)

Admit applies docs/spec.md section 8.1 to one submission: the BEEF as it arrived, and held, the indices of its subject's inputs that spend an output the topic holds (BRC-22's previous coins, as the engine hands them to the topic manager). A carrier's funding output is read from the carrier's own BEEF; no other verdict reads anything but the transaction, its BEEF and the headers, except that a transaction claiming nothing that is not a sweep is accepted only when held names an input. SPV of the BEEF is the engine's and is assumed to have run.

Every refusal is an error: a topic manager raises it rather than answer with empty instructions, so the engine records nothing for the txid.

type Carrier

type Carrier struct {
	// Envelope and Content are set for an envelope carrier, Receipt for a
	// receipt carrier.
	Envelope *Envelope
	Content  *Content
	Receipt  *Receipt
	// Owner is the record's from or by, the key the carrier is bound to.
	Owner []byte
	// Record is the record exactly as carried.
	Record []byte
	// Commitment is C = txid(K), hash byte order.
	Commitment [32]byte
	// Funding is the outpoint the carrier spends; a mined spend of it by
	// another transaction retracts the carrier.
	Funding transaction.Outpoint
}

Carrier is an admitted envelope or receipt carrier.

type Class

type Class struct {
	Name    string
	Members []string // sorted
	// Free classes are answered at no price on every conforming host.
	Free bool
	// Page is the most outputs one answer holds.
	Page int
}

Class is one ls_bbox question class: a set of query member names.

type Content

type Content struct {
	Doc *Object
	// Signed is what the signature covers the SHA-256 of: the RFC 8785
	// serialization of Doc without content and signature (BRC-169 section
	// 7.2 rule 2).
	Signed []byte
	// Cipher is the BRC-78 message the content member carries.
	Cipher []byte
	// Signature is the DER signature the signature member carries.
	Signature []byte
}

Content is an envelope record's content, parsed and checked against the record.

func CheckContent

func CheckContent(e *Envelope) (*Content, error)

CheckContent applies every content rule in order: ParseContent, then VerifySignature.

func ParseContent

func ParseContent(e *Envelope) (*Content, error)

ParseContent applies the content rules short of the signature, in their order: content-json (the bytes are exactly the canonical serialization of a JSON object in the subset), content-shape (the BRC-169 members and their agreement with the record), content-cipher (the BRC-78 message's header names the record's sender and recipient). The record must already have passed DecodeEnvelope or Validate.

func (*Content) VerifySignature

func (c *Content) VerifySignature(from []byte) error

VerifySignature is the content-signature rule: the signature member is lowercase hex of a strict low-S DER signature over SHA-256(Signed) that verifies under the sender's key for [1, "bbox message"], key id "signature", counterparty anyone.

type Decrypter

type Decrypter interface {
	Decrypt(ctx context.Context, args wallet.DecryptArgs, originator string) (*wallet.DecryptResult, error)
}

Decrypter is the wallet method Open needs; every wallet.Interface has it.

type Envelope

type Envelope struct {
	Office  string // key 1, the office identifier <name>_<suffix>
	To      []byte // key 2, the recipient's identity key
	Box     string // key 3, the box name
	From    []byte // key 4, the sender's identity key
	Created uint64 // key 5, Unix seconds, the sender's clock
	Expires uint64 // key 6, Unix seconds; 0 means none
	Content []byte // key 7, the BRC-169 envelope, JSON, as carried
	// Extra holds integer keys above 7, preserved verbatim and ignored.
	Extra cbor.Map
}

Envelope is one envelope record: the payload of one envelope carrier.

func DecodeEnvelope

func DecodeEnvelope(p []byte) (*Envelope, error)

DecodeEnvelope parses an envelope record in the refusal order: the bound, canonical CBOR and the map's shape, the key types, the magic, then each defined key in ascending order (missing, type, the key's own rule), then the rule across fields.

func (*Envelope) Encode

func (e *Envelope) Encode() ([]byte, error)

Encode writes the envelope record in canonical CBOR.

func (*Envelope) Validate

func (e *Envelope) Validate() error

Validate applies every rule that needs only the record itself, in the refusal order (steps 6 and 7). Encode runs it, so a sender cannot write what a reader refuses. The content's own rules are CheckContent's.

type Host

type Host struct {
	Office  string
	Headers chaintracker.ChainTracker
	MaxBEEF int
}

Host is what admission needs from the host beyond the object: the topic's office, a chain tracker over the host's own block headers, and the host's BEEF bound (DefaultMaxBEEF when zero).

type Int

type Int int64

Int is an integer in the subset, from -(2^53 - 1) to 2^53 - 1.

type KeyGetter

type KeyGetter interface {
	GetPublicKey(ctx context.Context, args wallet.GetPublicKeyArgs, originator string) (*wallet.GetPublicKeyResult, error)
}

KeyGetter is the wallet method CheckPayment needs; every wallet.Interface has it.

type Kind

type Kind int

Kind is what a locking script claims to carry.

const (
	KindNone Kind = iota
	KindEnvelope
	KindReceipt
)

The kinds.

func ClaimOf

func ClaimOf(s []byte) Kind

ClaimOf is the admission classifier over raw locking-script bytes (docs/spec.md section 8.1): a script claims a record when it starts with a 33-byte push (0x21 and 33 bytes), then OP_CHECKSIG (0xac), then one push whose data the record's claim prefix begins. Nothing else about the script is read here; the lock rule compares the whole script later.

func ClaimOfField

func ClaimOfField(p []byte) Kind

ClaimOfField is what a PushDrop's first field claims to be: an envelope or a receipt record when it starts with a CBOR definite-length map head, key 0 and that record's magic.

func (Kind) String

func (k Kind) String() string

type Member

type Member struct {
	Name  string
	Value any // *Object, []any, string, Int, bool, or nil
}

Member is one name and value.

type Object

type Object struct {
	Members []Member
}

Object is a JSON object whose member names are unique. Members keep the order they were parsed or added in; serialization sorts them.

func (*Object) Get

func (o *Object) Get(name string) (any, bool)

Get returns a member's value and whether it is present.

func (*Object) Set

func (o *Object) Set(name string, v any)

Set replaces a member's value, or appends the member.

func (*Object) Without

func (o *Object) Without(names ...string) *Object

Without returns a shallow copy without the named members.

type Payment

type Payment struct {
	// BEEF is the payment transaction as Atomic BEEF (BRC-95).
	BEEF             []byte
	DerivationPrefix string
	Outputs          []PaymentOutput
}

Payment is a BRC-29 payment made as BRC-169 section 6.1 describes.

type PaymentOutput

type PaymentOutput struct {
	OutputIndex      uint32
	DerivationSuffix string
	Satoshis         uint64
}

PaymentOutput is one output paid to the recipient.

type Plaintext

type Plaintext struct {
	Doc     *Object
	Body    *string
	Payment *Payment
	Refs    []Ref
}

Plaintext is what the recipient decrypts: a canonical JSON object in the subset whose members of section 4.5 have their shapes. Doc keeps every member, unknown ones included.

func ParsePlaintext

func ParsePlaintext(b []byte) (*Plaintext, error)

ParsePlaintext applies the plaintext's rules in order: plaintext-json (the bytes are the canonical serialization of a JSON object in the subset), plaintext-shape (body a string; refs an array of at most MaxRefs well-formed references), payment-shape (payment an object with beef, derivationPrefix and a non-empty outputs array of distinct output indices). Unknown members are kept in Doc and ignored.

func (*Plaintext) Extension

func (p *Plaintext) Extension(name string) (*Object, bool)

Extension is a member of the plaintext this contract does not define, when it is present and an object: an application's own member, which bbox carries and ignores (section 4.5). Its own members, unknown ones included, are as the sender wrote them.

type Question

type Question struct {
	Class  Class
	Office string
	// Key is the identity key the question is about: to, by or history.
	Key []byte
	// From is the sender a sender question is about.
	From []byte
	Box  string
	// After is the page cursor: created and a txid, display order.
	AfterCreated uint64
	AfterTxid    string
	// ReceiptFor is an envelope's txid, display order.
	ReceiptFor string
	// SpentTxid and SpentVout are the outpoint a sweep question is about,
	// txid in display order.
	SpentTxid string
	SpentVout uint32
}

Question is a validated question.

func ParseQuery

func ParseQuery(q map[string]any) (*Question, error)

ParseQuery validates a BRC-24 query object as parsed (a member given twice has already taken its last value). It must carry exactly the members of one class, each a string meeting its rule; anything else is refused, never answered empty and never ignored.

type Receipt

type Receipt struct {
	Office  string     // key 1
	By      []byte     // key 2, the acknowledging recipient's identity key
	Acks    [][32]byte // key 3, envelope commitments, hash byte order, ascending
	Created uint64     // key 4, Unix seconds, the recipient's clock
	// Extra holds integer keys above 4, preserved verbatim and ignored.
	Extra cbor.Map
}

Receipt is one receipt record: the payload of one receipt carrier. It acknowledges envelopes by their commitments.

func DecodeReceipt

func DecodeReceipt(p []byte) (*Receipt, error)

DecodeReceipt parses a receipt record in the refusal order.

func (*Receipt) Encode

func (r *Receipt) Encode() ([]byte, error)

Encode writes the receipt record in canonical CBOR.

func (*Receipt) Validate

func (r *Receipt) Validate() error

Validate applies every rule that needs only the record itself.

type Ref

type Ref struct {
	URL    string
	SHA256 [32]byte
	Length uint64
	// Key is the AES-256 key the referenced bytes are encrypted under, or
	// nil when they are not.
	Key []byte
}

Ref is a reference to content larger than the bound.

type Sealer

type Sealer interface {
	Signer
	Encrypt(ctx context.Context, args wallet.EncryptArgs, originator string) (*wallet.EncryptResult, error)
}

Sealer is the two wallet methods SealEnvelope needs; every wallet.Interface has them.

type Signer

type Signer interface {
	CreateSignature(ctx context.Context, args wallet.CreateSignatureArgs, originator string) (*wallet.CreateSignatureResult, error)
}

Signer is the one wallet method Seal needs; every wallet.Interface has it.

type TxKind

type TxKind int

TxKind is what an admitted transaction is to the topic.

const (
	// TxEnvelope is an envelope carrier: output 0 is admitted.
	TxEnvelope TxKind = iota + 1
	// TxReceipt is a receipt carrier: output 0 is admitted.
	TxReceipt
	// TxSweep is a mined sweep, or a published funding tree: output 0 is
	// admitted and every input's outpoint is recorded.
	TxSweep
	// TxSpend admits nothing and retains the held outputs it spends.
	TxSpend
)

The kinds of admitted transaction.

func (TxKind) String

func (k TxKind) String() string

Jump to

Keyboard shortcuts

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