Help us shape the future of Go! Take the 2026 Go Developer Survey

verify

package
v0.25.0 Latest Latest
Warning

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

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

Documentation

Overview

Package verify is a dependency-light, standalone verifier for Bide audit proofs. It depends on nothing but the Go standard library (crypto/sha256, crypto/ed25519, crypto/mldsa, encoding/binary, bytes, container/list, math/big, math/bits, strings, sync), deliberately NOT the agent core or gsm, so a third party (an auditor, a regulator) can verify a proof without importing the SDK, or reimplement this file from RFC 6962 and check us against it. That is what "verifiable without trusting the vendor" means in practice.

It operates on canonical LEAF BYTES, not typed records, precisely so it needs no domain types. A leaf's bytes are a versioned tag naming its kind followed by its content: JournalLeaf builds a journal record's leaf from the bytes a store persists for it (a proof's record_bytes, the record's random salt included), KeyLeaf an absence key's, EventLeaf an event's (its random salt included), and AnchorLeaf an anchor entry's. TreeHead checks a signed tree head under any of the four schemes (ed25519, ecdsa-p256, ml-dsa-65, and the ed25519+ml-dsa-65 hybrid), with a Verifier from NewVerifier. The algorithms mirror the audit package exactly and are cross-checked against it in the tests, so the intentional duplication cannot drift.

This mirror is verification-only, by design: it can check a proof, never mint one.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AnchorLeaf added in v0.7.0

func AnchorLeaf(entry []byte) []byte

AnchorLeaf returns the leaf bytes of an anchor log entry from its JSON: "bide.audit.anchor-leaf.v1\x00" || entry.

func Consistency

func Consistency(first, size int, path [][]byte, firstRoot, laterRoot []byte) bool

Consistency runs the RFC 6962 §2.1.2 consistency-proof algorithm: reports whether firstRoot (over the first `first` leaves) is an append-only prefix of laterRoot (over `size` leaves).

func EventLeaf added in v0.7.0

func EventLeaf(event []byte) []byte

EventLeaf returns the leaf bytes of an event from its canonical JSON, the event's salt included ({"kind":...,"event":...,"salt":...}, with a snake_case kind and event, and the salt the event's proof discloses in base64): "bide.audit.event-leaf.v3\x00" || event.

func Inclusion

func Inclusion(root, leaf []byte, index, size int, path [][]byte) bool

Inclusion runs the RFC 6962 §2.1.1 inclusion-proof algorithm: leaf is the canonical leaf bytes (JournalLeaf, KeyLeaf, EventLeaf, or AnchorLeaf of the content), index/size locate it in the tree, path is the sibling hashes leaf-to-root, and root is the committed Merkle root (an STH's Root). Reports whether leaf is provably at index in a size-leaf tree committed by root.

func JournalLeaf added in v0.7.0

func JournalLeaf(record []byte) []byte

JournalLeaf returns the leaf bytes of a journal record from the bytes a store persists for it (a proof's record_bytes, verbatim, including its "salt"): "bide.audit.journal-leaf.v1\x00" || record. The bytes are hashed as they are, never decoded, so a record with fields this verifier does not know verifies all the same.

func KeyLeaf added in v0.7.0

func KeyLeaf(key string) []byte

KeyLeaf returns the leaf bytes of an absence key: "bide.audit.key-leaf.v1\x00" || key.

func TreeHead

func TreeHead(h Head, sig []byte, v Verifier) bool

TreeHead reports whether sig is a valid signature, under v, of the signed tree head h. h.Alg must be v's scheme: the scheme is part of the signed bytes, and a signature is never checked under another. The canonical encoding is domain-separated and length-prefixed, byte-identical to the audit package's (format bide.audit.sth.v5):

"bide.audit.sth.v5\x00" || field(alg) || field(kind) || field(run_id) || u64(size) ||
field(root) || u64(timestamp_nanos) || (0x00 | 0x01 || u64(journal.size) || field(journal.root))

where field(x) is u64(len(x)) || x and u64 is 8 bytes big-endian. So an STH signed by the SDK verifies here and vice versa. The caller checks that kind and runID are the tree it expects.

A weak pub (not canonically encoded, small order, or outside the prime-order subgroup) verifies nothing: crypto/ed25519 alone accepts forged signatures under a small-order key.

Like audit, it refuses a head whose shape no commitment has, whatever its signature: a "journal" or "events" head that names a source journal, an "absence/<set>" head that names none, and a head of any other kind.

Types

type Head struct {
	Alg            string   // "ed25519", "ml-dsa-65", or "ed25519+ml-dsa-65"
	Kind           string   // "journal", "events", or an "absence/..." key set
	RunID          string   // the run the tree is about
	Size           int      // number of leaves
	Root           []byte   // RFC 6962 root over them
	TimestampNanos int64    // when the head was signed, Unix nanoseconds
	Journal        *TreeRef // the source journal tree of an absence key-set head; nil otherwise
}

Head is the content of a signed tree head (the "sth" of a proof): the scheme it is signed under, the tree's kind and run, its size and root, when it was signed, and, for an absence key-set head, the source journal tree.

type TreeRef added in v0.7.0

type TreeRef struct {
	Size int    `json:"size"`
	Root []byte `json:"root"`
}

TreeRef names one tree by its size and root: the source journal of an absence key-set head.

type Verifier added in v0.9.0

type Verifier interface {
	// Alg names the scheme: "ed25519", "ecdsa-p256", "ml-dsa-65", or "ed25519+ml-dsa-65".
	Alg() string
	// Verify reports whether sig is a valid signature over message.
	Verify(message, sig []byte) bool
}

Verifier checks signatures under one scheme with one public key. NewVerifier builds one for each scheme the audit package signs with.

func NewVerifier added in v0.9.0

func NewVerifier(alg string, pub []byte) (Verifier, error)

NewVerifier returns the verifier of scheme alg for the encoded public key pub, with the encodings the audit package uses: ed25519, the 32-byte key; ecdsa-p256, the 65-byte SEC1 uncompressed point (0x04 || X || Y), whose signatures are 64-byte low-S r||s over SHA-256 of the message; ml-dsa-65, the 1952-byte ML-DSA-65 public key; ed25519+ml-dsa-65, a 4-byte big-endian length of the Ed25519 key, the Ed25519 key, then the ML-DSA-65 key. A weak Ed25519 key is refused, as audit.NewVerifier refuses it.

The schemes are the audit package's: ML-DSA-65 signs with the context "bide.audit.mldsa65.v1", and a hybrid signature is len32(ed) || ed || mldsa, where the Ed25519 component signs "bide.hybrid.ed25519.v1\x00" || message and the ML-DSA-65 component signs "bide.hybrid.mldsa65.v1\x00" || message, and both must verify.

Jump to

Keyboard shortcuts

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