Documentation
¶
Overview ¶
Package proof parses, downloads, and generates Truestamp proof bundles in both JSON and CBOR wire formats. Proofs are the self-contained artefacts consumers receive from the API; this package handles only serialization and I/O — cryptographic verification lives in internal/verify.
Index ¶
- Constants
- func Download(rawURL string) ([]byte, error)
- func DownloadCtx(ctx context.Context, rawURL string) ([]byte, error)
- func FileSize(filename string) int64
- func FileSizeFromData(data []byte) int64
- func Generate(apiURL, team, id, subjectType, format string) ([]byte, error)
- func GenerateCtx(ctx context.Context, apiURL, team, id, subjectType, format string) ([]byte, error)
- func HasCBORTag(data []byte) bool
- func IsCBORProof(data []byte) bool
- func RejectionCode(err error) string
- type Block
- type ExternalCommit
- type IDType
- type ProofBundle
- type RejectionError
- type Subject
Constants ¶
const ( CodeNotAJSONObject = "not_a_json_object" CodeMissingTypeCode = "missing_type_code" CodeInvalidSubjectTypeCode = "invalid_subject_type_code" CodeMissingBlock = "missing_block" CodeNoExternalCommitments = "no_external_commitments" CodeInvalidExternalCommitmentEntry = "invalid_external_commitment_entry" CodeUnexpectedSubjectFieldsForBlockLike = "unexpected_subject_fields_for_block_like" CodeMissingSubject = "missing_subject" CodeMissingInclusionProof = "missing_inclusion_proof" // CodeInvalidSubjectData covers a CBOR `s.d` value that has no JSON // counterpart (E.3). E.23 names no identifier for this class; this one // is taken verbatim from the Elixir reference verifier // (truestamp-v2 lib/truestamp/proof/binary.ex) so both implementations // report the same word for the same rejection. CodeInvalidSubjectData = "invalid_subject_data" )
Hard-rejection identifiers from the whitepaper's error taxonomy (E.23). A hard rejection aborts before any report exists (E.6) — independent verifiers are required to agree on this vocabulary so their outcomes are comparable, which is only possible if the identifier travels with the error rather than living in prose.
Variables ¶
This section is empty.
Functions ¶
func Download ¶
Download fetches a proof bundle from a URL using context.Background. Prefer DownloadCtx when a cancellable context is available.
func DownloadCtx ¶ added in v0.3.0
DownloadCtx is the context-aware variant of Download. Honours ctx for cancellation (e.g. Ctrl-C while a proof is streaming).
func FileSizeFromData ¶
FileSizeFromData returns the byte length of proof data.
func Generate ¶
Generate calls GenerateCtx with context.Background.
func GenerateCtx ¶ added in v0.3.0
GenerateCtx requests a proof bundle from the Truestamp API for the given subject ID. subjectType MUST be one of the six canonical values on the server's /proof/generate type enum (empty string omits the field, which the server rejects under the post-cutover schema — callers should always pass an explicit value):
item | entropy_nist | entropy_stellar | entropy_bitcoin | block | beacon
"auto" and bare "entropy" were removed when the server cut over to the strict enum alongside t=11 beacon support. Use the matching subtype.
format is "json" or "cbor". Returns raw bytes ready to write to a file (pretty JSON or decoded CBOR binary). ctx cancels the in-flight request. The credential is applied by the process-wide auth.Authorizer.
func HasCBORTag ¶ added in v0.12.0
HasCBORTag reports whether data begins with the RFC 8949 self-describing tag 55799 (0xd9 0xd9 0xf7).
func IsCBORProof ¶
IsCBORProof reports whether data is a CBOR proof bundle. E.3 requires a verifier to accept CBOR both wrapped in the self-describing tag 55799 and as a bare map, so a bare CBOR map — major type 5, first byte 0xa0-0xbf, definite or indefinite length — counts too. Those bytes are UTF-8 continuation bytes and can never open a valid JSON document, so widening the check cannot steal input from the JSON path.
func RejectionCode ¶ added in v0.12.0
RejectionCode returns the E.23 identifier carried by err, or "" when err is not a hard rejection. Callers use it to distinguish "this bundle was refused at the structural layer" from "verification produced a report".
Types ¶
type Block ¶
type Block struct {
ID string `json:"id"`
PreviousBlockHash string `json:"ph"`
MerkleRoot string `json:"mr"`
MetadataHash string `json:"mh"`
SigningKeyID string `json:"kid"`
}
Block represents the single block in the proof.
type ExternalCommit ¶
type ExternalCommit struct {
Type ptype.Code `json:"t"`
Network string `json:"net"` // Stellar: "testnet"|"public" ; Bitcoin: "regtest"|"testnet"|"mainnet"
// Epoch Merkle proof (base64url compact binary)
EpochProof string `json:"ep"`
// Stellar fields
TransactionHash string `json:"tx,omitempty"`
MemoHash string `json:"memo,omitempty"`
Ledger int `json:"l,omitempty"`
Timestamp string `json:"ts,omitempty"`
// Bitcoin fields
OpReturn string `json:"op,omitempty"`
RawTxHex string `json:"rtx,omitempty"`
TxoutproofHex string `json:"txp,omitempty"`
BlockMerkleRoot string `json:"bmr,omitempty"`
BlockHeight int `json:"h,omitempty"`
}
ExternalCommit represents a commitment entry in the proof bundle. Type is an integer code from ptype (CommitmentStellar=40, CommitmentBitcoin=41). Each commitment carries an epoch Merkle proof (ep) linking the block hash to the committed value (Stellar: memo, Bitcoin: OP_RETURN payload).
func (ExternalCommit) MarshalJSON ¶ added in v0.12.0
func (c ExternalCommit) MarshalJSON() ([]byte, error)
MarshalJSON emits a commitment entry, always carrying `ep` and the chain-specific epoch-root key (`memo` for t=40, `op` for t=41) even when empty. E.6 hard-rejects an entry missing either, so letting `omitempty` drop an empty value would make the CLI emit a bundle its own parser refuses to read back.
type IDType ¶
type IDType string
IDType is the syntactic shape of a subject id. It is NOT the subject's semantic kind (item / entropy / block / beacon): /proof/generate requires an explicit `type` from the caller — there is no server-side auto detection (see cmd/download.go's id-shape smart default). The authoritative label for a bundle in hand is its own signed `t`, readable only after ParseBytes / ParseCBOR. Use DetectIDType for pre-flight validation and for sanity-checking positional args.
func DetectIDType ¶
DetectIDType returns the syntactic shape of id. Returns an error for values that are neither a valid ULID nor a parseable UUID.
type ProofBundle ¶
type ProofBundle struct {
Version int `json:"v"`
T ptype.Code `json:"t"`
Timestamp string `json:"ts"`
PublicKey string `json:"pk"`
Signature string `json:"sig"`
// Subject is nil for block-like subjects (t ∈ {10, 11}). For all other
// subject types it is non-nil after a successful parse.
Subject *Subject `json:"-"`
Block Block `json:"-"`
Commitments []ExternalCommit `json:"-"`
// InclusionProof is "" for block-like subjects and non-empty otherwise.
InclusionProof string `json:"-"` // base64url compact Merkle proof
// RawData is the subject-data JSON preserved byte-for-byte for JCS.
// Empty for block-like subjects.
RawData json.RawMessage `json:"-"`
}
ProofBundle is the top-level compact Truestamp proof structure (bundle version `v` is 1). Normative reference: Appendix E of `truestamp-v2/whitepaper/whitepaper.typ`; the wire shape is also described in `truestamp-v2/kb/verification/proof-bundle-format.md`.
The top-level integer field `t` discriminates subject types:
10 block (no Subject, no InclusionProof) 11 beacon (no Subject, no InclusionProof — same shape as block) 20 item 30 entropy_nist 31 entropy_stellar 32 entropy_bitcoin
func Parse ¶
func Parse(filename string) (*ProofBundle, error)
Parse reads and parses a proof JSON file, preserving raw JSON for JCS.
func ParseBytes ¶
func ParseBytes(data []byte) (*ProofBundle, error)
ParseBytes parses a proof from raw bytes, dispatching to ParseCBOR for CBOR input and parsing JSON otherwise.
Only the hard rejections E.6 enumerates abort here; everything else is a step failure the report has to surface. In particular a missing or wrong `v`, a missing or malformed `pk` / `sig`, and missing or wrong-sized hash / kid fields all parse cleanly so the pipeline can grade them. Every abort returns a RejectionError carrying its E.23 identifier.
func ParseCBOR ¶
func ParseCBOR(data []byte) (*ProofBundle, error)
ParseCBOR decodes a CBOR proof bundle into a ProofBundle. The output is structurally identical to what ParseBytes produces from JSON, and the two paths agree on the verdict for the same logical bundle: E.6's rejections are enforced from the same helpers, and every CBOR-only value-space class (E.3) is refused here rather than coerced into a JSON counterpart.
The two do not always agree on the *kind* of refusal. A duplicate `s.d` key is a hard rejection on this path, because RFC 8949 section 5.6 makes the document invalid CBOR, while the JSON path reaches it as a failing JCS step. Both refuse the bundle; only the stage differs.
func (*ProofBundle) IsBlockLike ¶ added in v0.6.0
func (b *ProofBundle) IsBlockLike() bool
IsBlockLike returns true if this bundle is either a block (t=10) or a beacon (t=11). Use this in verification-pipeline guards that skip subject / inclusion-proof / subject-hash-derivation steps — those are shape concerns and beacon proofs have the same shape as block proofs.
func (*ProofBundle) IsEntropy ¶
func (b *ProofBundle) IsEntropy() bool
IsEntropy returns true if this bundle is an entropy subject (t in {30,31,32}).
func (*ProofBundle) IsItem ¶ added in v0.6.0
func (b *ProofBundle) IsItem() bool
IsItem returns true if this bundle is an item subject (t=20).
func (*ProofBundle) MarshalCBOR ¶ added in v0.5.0
func (b *ProofBundle) MarshalCBOR() ([]byte, error)
MarshalCBOR produces the canonical CBOR representation of the proof bundle. Byte-valued fields (`pk`, `sig`, hashes) are emitted as CBOR major-type-2 byte strings; identifier fields (ULID, UUIDv7, timestamps) and the E.3 text-string fields `rtx` / `txp` remain text. The subject data (`s.d`) is decoded back from its preserved raw JSON and encoded as a nested CBOR structure. `t` is emitted as a CBOR integer at the top level and per commitment entry.
`ip` and `ep` are emitted as byte strings even though E.3's table lists them as text: that table governs what a verifier MUST accept on decode, and byte strings are what the backend puts on the wire. The decoder accepts both forms.
Round-trip guarantee: `cbor → Parse → MarshalCBOR` is byte-stable for inputs that are themselves deterministically encoded. Non-deterministic source CBOR is normalized on the first round trip.
func (*ProofBundle) MarshalJSON ¶
func (b *ProofBundle) MarshalJSON() ([]byte, error)
MarshalJSON produces the compact JSON wire format from a parsed ProofBundle. Subject and InclusionProof are omitted for block-like subjects (t ∈ {10, 11}). Used when sending a CBOR-decoded proof to the API as JSON.
type RejectionError ¶ added in v0.12.0
RejectionError is a structural hard rejection: the bundle is malformed in a way E.6 says MUST abort before any step runs, so no Report is produced. Code is the E.23 identifier; Detail is the human-facing explanation.
func (*RejectionError) Error ¶ added in v0.12.0
func (e *RejectionError) Error() string
type Subject ¶
type Subject struct {
ID string `json:"id"`
Data json.RawMessage `json:"d"`
MetadataHash string `json:"mh"`
SigningKeyID string `json:"kid"`
}
Subject represents the unified subject within a non-block proof bundle. For item proofs (T=20), Data contains the claims map. For entropy subjects (T in {30,31,32}), Data contains the entropy observation. The source is carried in the top-level ProofBundle.T field; no per- subject `src` discriminator is emitted.