./SEMANTIC_CONTRACT.md defines what a normalized sender or receiver result looks like.
This document defines the execution bridge that real implementations use to produce that result from a case format v2 input without each implementation having to parse the repository's binary test fixture format on its own.
The intent is:
tests/vectors/bip352/derived/v2/*.hexremains the canonical corpus.- The runner parses those bytes once into a stable JSON request.
- Adapters consume that JSON request and emit a semantic result matching
./SEMANTIC_CONTRACT.md. - The runner compares the adapter result to the vendored oracle expectations.
The semantic adapter contract is transport-neutral.
The default command transport is:
- Input: UTF-8 JSON on
stdin - Output: UTF-8 JSON on
stdout - Success exit code:
0 - Failure exit code: nonzero
The same request/response JSON can also be transported through the compiled semantic worker ABI defined in ../ffi/sp_differ_semantic.h.
Adapters must not print non-JSON material to stdout.
Top-level fields:
semantic_adapter_request_version: integer, currently1case_format_version: integer, currently2kind:"send"or"receive"network: currently"mainnet","testnet","regtest", or"signet"silent_payment_version: integer, currently0seed: copied from the v2 case header for provenance/debuggingflags: copied from the v2 case header for provenance/debuggingsource: the exactsourceobject that must be echoed back in the semantic resultinputs: array of parsed input objectsexpectation_hints: optional non-semantic execution hints supplied by the runner
Each inputs[] item contains:
outpoint_txid: 32-byte txid hex in normal display orderoutpoint_vout: integerinput_type: one ofp2wpkh,p2tr,p2sh-p2wpkh,p2pkhprevout_script_pubkey: hex ornullscript_sig: hex ornulltxinwitness: serialized witness-stack hex ornulltxinwitness_stack: decoded witness stack as an array of hex stringsprivkey: hex ornullpubkey: hex ornull
send requests additionally contain:
recipient_groups: array of{scan_pubkey, spend_pubkey, count}
receive requests additionally contain:
outputs_to_scan: array of x-only output pubkeys as 32-byte hexreceiver_keys:{scan_privkey, spend_privkey}labels: array of integers
Current expectation_hints fields:
detailed_outputs_required: boolean used only for receiver-side execution
This hint is intentionally narrow. It tells an adapter whether the current harness requires exact found_outputs material or only found_output_count. It does not include expected outputs, tweaks, or secrets.
The adapter response is a semantic result object validated by ./SEMANTIC_CONTRACT.md.
That means adapters must emit:
- the same
source - the same
kind case_format_version = 2semantic_contract_version = 1
and then the normalized sender or receiver fields required by the semantic contract.
The runner uses the same comparison rules as the oracle path:
- sender adapters may return one or more acceptable output sets, as long as every returned set is allowed by the expected contract
- receiver adapters must match
found_output_count - receiver adapters may return detailed outputs even when the official expectation is count-only
adapters/reference/semantic_adapter.py: wraps the vendored upstream BIP352 reference bundle through this contractadapters/spdk_rust/: Rust adapter backed by the publicsilentpaymentscrate, exposed as both a command adapter and a semantic worker shared libraryadapters/silent_payments_rust/: Rust adapter backed by the publicsilent-paymentscrate, exposed as both a command adapter and a semantic worker shared libraryadapters/bip352_rust/: Rust adapter backed by the publicbip352crate, exposed as both a command adapter and a semantic worker shared libraryadapters/go_bip352/: Go-backed adapter, exposed as both a command adapter and a semantic worker shared libraryadapters/bdk_sp_rust/: Rust adapter backed bybdk-sp, currently exposed as a command adapter
The existing compiled worker ABI in ../ffi/sp_differ.h is still the minimal v1 byte-buffer interface used by the C++ and Rust byte-worker surfaces.
The repo now also defines a separate semantic worker ABI in ../ffi/sp_differ_semantic.h for compiled execution of this same request/response contract.
The semantic adapter contract is deliberately higher level:
- it lets real implementations integrate now
- it keeps the semantic shape stable across command and shared-library transports
- it keeps the repository's binary corpus and the implementation-facing execution surface decoupled