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 ¶
- Variables
- func BitcoinNetworkSkipReason(network string) string
- func IsDefaultedNetwork(network string) bool
- func NetworkLabel(network string) string
- func VerifyKeyring(signingKeys map[string]string, keyringURL string) error
- type BadInputError
- type BitcoinBlockHeader
- type BitcoinResult
- type KeyBindingError
- type KeyringKey
- type KeyringResponse
- type MalformedResponseError
- type MismatchError
- type NISTPulse
- type Outcome
- type StellarLedger
- type StellarResult
Constants ¶
This section is empty.
Variables ¶
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.
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.
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
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
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
NetworkLabel names the Horizon instance actually queried, so a report says which chain answered rather than echoing an empty `net`.
func VerifyKeyring ¶
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
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
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
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
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
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
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 // 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 )
type StellarLedger ¶ added in v0.6.0
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.