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 ¶
- func AnchorLeaf(entry []byte) []byte
- func Consistency(first, size int, path [][]byte, firstRoot, laterRoot []byte) bool
- func EventLeaf(event []byte) []byte
- func Inclusion(root, leaf []byte, index, size int, path [][]byte) bool
- func JournalLeaf(record []byte) []byte
- func KeyLeaf(key string) []byte
- func TreeHead(h Head, sig []byte, v Verifier) bool
- type Head
- type TreeRef
- type Verifier
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AnchorLeaf ¶ added in v0.7.0
AnchorLeaf returns the leaf bytes of an anchor log entry from its JSON: "bide.audit.anchor-leaf.v1\x00" || entry.
func Consistency ¶
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
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 ¶
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
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
KeyLeaf returns the leaf bytes of an absence key: "bide.audit.key-leaf.v1\x00" || key.
func TreeHead ¶
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 ¶ added in v0.9.0
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
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
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.