external

package
v0.12.1 Latest Latest
Warning

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

Go to latest
Published: Jul 30, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package external fetches supplementary data from third-party public sources (Stellar Horizon, Bitcoin block explorers, the NIST Randomness Beacon) to corroborate proofs against real-world public records, and fetches the Truestamp keyring for the E.17 key-binding step.

Index

Constants

This section is empty.

Variables

View Source
var (
	BlockstreamMainnetURL = "https://blockstream.info/api"
	BlockstreamTestnetURL = "https://blockstream.info/testnet/api"
)

BlockstreamMainnetURL / BlockstreamTestnetURL are the Blockstream API endpoints consulted by VerifyBitcoinBlock. Exposed as vars so tests can redirect them; do not mutate in production code.

View Source
var (
	HorizonPublicURL  = "https://horizon.stellar.org"
	HorizonTestnetURL = "https://horizon-testnet.stellar.org"
)

HorizonPublicURL / HorizonTestnetURL are the Stellar Horizon endpoints consulted by VerifyStellar. Exposed as vars so tests can point them at an httptest server; do not mutate in production code.

View Source
var NISTBeaconURL = "https://beacon.nist.gov/beacon/2.0"

NISTBeaconURL is the NIST Randomness Beacon v2.0 base URL. Exposed as a var so tests can redirect it; do not mutate in production code.

Functions

func BitcoinNetworkSkipReason added in v0.12.0

func BitcoinNetworkSkipReason(network string) string

BitcoinNetworkSkipReason explains why a `net` value yields no networked Bitcoin lookup, so a report can state the reason it actually has instead of asserting that a name it does not recognise is a Bitcoin network that happens to lack a public API. It returns "" for a network that IS looked up.

The grading is settled by E.5: `net` is optional, and "E.19 names no default endpoint, and a verifier MUST NOT guess a Bitcoin network from an absent `net`: if it cannot determine which chain to query it has no networked lookup available, which is already one of E.19's stated `skip` conditions for the binding step." Absent, regtest and unrecognised all land there.

Known consequence: `net` is not in the 0x61 signature payload, so this is an unauthenticated downgrade lever — a bundle whose header is genuinely absent from mainnet can have `net` rewritten and the definitive on-chain refutation becomes a skip. It cannot be closed by grading: regtest is a legitimate Truestamp network with no public API, and E.5 forbids guessing a chain. What a verifier can do is refuse to dress the skip up as a statement about a chain it never consulted.

func IsDefaultedNetwork added in v0.12.0

func IsDefaultedNetwork(network string) bool

IsDefaultedNetwork reports whether the entry named no Horizon instance, so the lookup fell through to E.18's default. A 404 from a defaulted lookup is not a definitive absence from the chain: the transaction may simply live on the network the entry failed to name.

func NetworkLabel added in v0.12.0

func NetworkLabel(network string) string

NetworkLabel names the Horizon instance actually queried, so a report says which chain answered rather than echoing an empty `net`.

func VerifyKeyring

func VerifyKeyring(signingKeys map[string]string, keyringURL string) error

VerifyKeyring checks that all signing keys in the proof match the published keyring.

Trust model: the keyring's authenticity is rooted entirely in the TLS chain presented by keyringURL. There is no in-band signature over the keyring payload itself, so every key in the returned document is only as trustworthy as the URL you configured. In particular:

  • Use https:// with a host whose certificate chain you trust (an attacker able to mint a valid cert for the host — via DNS/BGP hijack, a rogue CA, or a compromised certificate — can substitute signing keys and every downstream signature will validate against their key).
  • The keyring URL is derived from --base-url (or TRUESTAMP_BASE_URL, or base_url in config.toml); set that origin from a source you trust — e.g. official Truestamp docs — not from a bundle authored by the same party whose proof you are verifying.
  • The CLI enforces TLS chain validation (InsecureSkipVerify is never set) and refuses any redirect that downgrades https to http, so a server cannot talk the fetch out of TLS mid-chain (httpclient.ErrRedirectDowngrade). Cross-host redirects that stay on https ARE followed — they remain authenticated by the CA chain, and banning them would break the GitHub-asset fetch in internal/selfupgrade, which shares this client.

A future revision may add pinning of the keyring payload's hash or a cosign/Sigstore signature over the keyring document itself. Until then, treat the configured base URL as a root of trust that deserves the same care as a CA root.

Types

type BadInputError added in v0.12.0

type BadInputError struct {
	Field  string
	Detail string
}

BadInputError reports that a field taken from the bundle is unusable, so no lookup was attempted.

func (*BadInputError) Error added in v0.12.0

func (e *BadInputError) Error() string

type BitcoinBlockHeader added in v0.6.0

type BitcoinBlockHeader struct {
	Hash       string
	Height     int
	Time       int64
	MerkleRoot string
}

BitcoinBlockHeader is the CLI-facing return shape for GetBitcoinBlockHeader.

func GetBitcoinBlockHeader added in v0.6.0

func GetBitcoinBlockHeader(blockHash, network string) (*BitcoinBlockHeader, bool, error)

GetBitcoinBlockHeader fetches a Bitcoin block header from Blockstream by block hash. Returns (nil, skipped=true, nil) when `net` resolves to no public Blockstream endpoint — regtest, an absent net, or an unrecognised name (see BitcoinNetworkSkipReason). Errors are typed for Classify.

type BitcoinResult

type BitcoinResult struct {
	Height    int
	Timestamp string // ISO 8601 block timestamp from Blockstream
}

BitcoinResult holds the verification result from the Blockstream API.

func VerifyBitcoinBlock

func VerifyBitcoinBlock(blockHash, network string) (*BitcoinResult, bool, error)

VerifyBitcoinBlock runs E.19(b)'s networked binding lookup: it asks a public Blockstream instance for the block named by blockHash and returns that block's height and timestamp. Returns a skip indicator when `net` resolves to no public endpoint (see BitcoinNetworkSkipReason). Errors are typed for Classify.

type KeyBindingError added in v0.12.0

type KeyBindingError struct {
	KeyID  string
	Reason string
}

KeyBindingError reports that the keyring answered and does not vouch for the key: either it is absent, or it is published with different bytes. Both are substantive disagreements, so both grade as OutcomeMismatch.

func (*KeyBindingError) Error added in v0.12.0

func (e *KeyBindingError) Error() string

type KeyringKey

type KeyringKey struct {
	KeyID     string `json:"key_id"`
	PublicKey string `json:"public_key"`
	Sequence  int    `json:"sequence"`
	Active    bool   `json:"active"`
}

KeyringKey is a single entry in the keyring.

type KeyringResponse

type KeyringResponse struct {
	Version string       `json:"version"`
	Keys    []KeyringKey `json:"keys"`
}

KeyringResponse is the shape of /.well-known/keyring.json.

type MalformedResponseError added in v0.12.0

type MalformedResponseError struct {
	Source string
	Detail string
	Err    error
}

MalformedResponseError reports a 2xx response this client could not interpret: unparseable, or missing the field the comparison needs.

func (*MalformedResponseError) Error added in v0.12.0

func (e *MalformedResponseError) Error() string

func (*MalformedResponseError) Unwrap added in v0.12.0

func (e *MalformedResponseError) Unwrap() error

type MismatchError added in v0.12.0

type MismatchError struct {
	Field    string
	Expected string
	Got      string
}

MismatchError reports that the source answered and the value it returned disagrees with the bundle.

func (*MismatchError) Error added in v0.12.0

func (e *MismatchError) Error() string

type NISTPulse added in v0.6.0

type NISTPulse struct {
	ChainIndex  int    `json:"chainIndex"`
	PulseIndex  int    `json:"pulseIndex"`
	OutputValue string `json:"outputValue"`
	TimeStamp   string `json:"timeStamp"`
	Version     string `json:"version"`
}

NISTPulse holds the minimum set of NIST Beacon pulse fields the CLI byte-compares against entropy subject data. Signature-chain verification is not performed: the Truestamp service stores only these five fields, so the entropy subject hash it signed is already over the same slice of data we compare here.

func GetNISTPulse added in v0.6.0

func GetNISTPulse(chainIndex, pulseIndex int) (*NISTPulse, error)

GetNISTPulse fetches a specific pulse from the NIST Randomness Beacon v2.0 API at /chain/{chainIndex}/pulse/{pulseIndex}.

NIST Beacon reliability caveat (per truestamp-v2 docs): during US federal shutdowns the beacon may stop publishing new pulses and repeat the last pulse indefinitely. Callers that care about freshness should apply their own staleness policy on top of this fetch. Errors are typed for Classify so the caller can tell an unusable bundle field from an unreachable beacon.

type Outcome added in v0.12.0

type Outcome int

Outcome grades what an external lookup actually established, so a caller can report the right verification status. Whitepaper Appendix E.22 is unambiguous that "a skipped external check MUST NOT fail a proof": without this distinction an unreachable Horizon and a transaction that is genuinely absent from the chain are the same opaque error, and the verifier fails a sound proof for want of a network.

const (
	// OutcomeOK means the lookup succeeded and agreed with the bundle.
	OutcomeOK Outcome = iota
	// OutcomeMismatch means the source answered and substantively
	// disagreed with the bundle. This is the only networked outcome
	// that may fail a step.
	OutcomeMismatch
	// OutcomeNotFound means the source answered HTTP 404: a definitive
	// "no such record here". Whether that is a failure is a per-step
	// decision (E.18 grades it against the commitment; E.21 does not).
	OutcomeNotFound
	// OutcomeUnavailable means no answer was obtained: transport
	// failure, DNS, TLS, timeout, cancellation, 429, 5xx, or any other
	// non-2xx status.
	OutcomeUnavailable
	// OutcomeMalformed means a 2xx response whose body this client
	// cannot interpret. It is an upstream property, not a bundle
	// property.
	OutcomeMalformed
	// OutcomeBadInput means the bundle's own field is unusable, so
	// there was nothing to look up.
	OutcomeBadInput
)

func Classify added in v0.12.0

func Classify(err error) Outcome

Classify maps any error returned by this package's lookups onto an Outcome, unwrapping through %w chains. The default is OutcomeUnavailable on purpose: an unrecognized error must skip a step, never fail one (E.22).

func (Outcome) String added in v0.12.0

func (o Outcome) String() string

type StellarLedger added in v0.6.0

type StellarLedger struct {
	Sequence int
	Hash     string
	ClosedAt string
}

StellarLedger is the CLI-facing return shape for GetStellarLedger.

func GetStellarLedger added in v0.6.0

func GetStellarLedger(sequence int, network string) (*StellarLedger, error)

GetStellarLedger fetches a specific ledger from Stellar Horizon at /ledgers/{sequence}. The caller compares returned hash + closed_at against the entropy subject data. Endpoint selection follows E.18's rule (see [horizonBaseURL]), so an entry that names no network is still looked up against the testnet instance.

type StellarResult

type StellarResult struct {
	Ledger    int
	Timestamp string // ISO 8601 ledger close timestamp from Horizon
}

StellarResult holds the verification result from the Stellar Horizon API.

func VerifyStellar

func VerifyStellar(transactionHash, expectedMemoHash, network string, expectedLedger int) (*StellarResult, error)

VerifyStellar checks the Stellar Horizon API to confirm the transaction exists, the memo matches, and the ledger number matches the expected value. Returns the ledger number, the transaction timestamp, or an error. Errors are typed for Classify: the caller decides which outcomes fail the step and which only leave it unconfirmed.

Jump to

Keyboard shortcuts

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