diff --git a/crates/deadcat-client/tests/simplicity_budget.rs b/crates/deadcat-client/tests/simplicity_budget.rs index ba3ba1f..818415b 100644 --- a/crates/deadcat-client/tests/simplicity_budget.rs +++ b/crates/deadcat-client/tests/simplicity_budget.rs @@ -25,7 +25,7 @@ use elements::{AssetId, LockTime, OutPoint, Script, Sequence, TxOut, TxOutWitnes use serde::Serialize; use simplex::simplicityhl::simplicity::Cost; -// Rounded CI ceilings with headroom above the typed-action maxima of 3,633,302 +// Rounded CI ceilings with headroom above the oracle-precomputed maxima of 3,633,302 // mw, 72,462 cells, 62 frames, 4,339 stack bytes, 13,624 transaction bytes, // 15,574 WU, and 3,894 vB. The exact measurements are emitted by the test. const MAX_MARKET_COVENANT_COST_MILLIWEIGHT: u64 = 4_000_000; @@ -1401,6 +1401,34 @@ fn market_coordinator_rejects_adversarial_solvency_and_authorization_mutations() "coordinator accepted a valid NO attestation with a YES continuation" ); + let (no_resolution_plan, _, no_resolution) = finalized_market_fixture( + &compiled, + active, + resolve_no, + RtSide::A, + input_base, + output_base, + ); + let yes_signature_for_no = direct_market_witness( + &no_resolution_plan, + resolve_no, + resolution_attestation, + coordinator, + output_base, + ); + assert!( + compiled + .execute( + coordinator, + &no_resolution, + &yes_signature_for_no.build_witness(), + input_base, + &network, + ) + .is_err(), + "coordinator accepted a valid YES signature for the NO message" + ); + let mut wrong_resolution_collateral = resolution.clone(); wrong_resolution_collateral.outputs_mut()[output_base + 2].amount = Some(601); assert_rejected( diff --git a/crates/deadcat-contracts/simplicityhl/README.md b/crates/deadcat-contracts/simplicityhl/README.md index c28f355..1673f51 100644 --- a/crates/deadcat-contracts/simplicityhl/README.md +++ b/crates/deadcat-contracts/simplicityhl/README.md @@ -154,6 +154,8 @@ static instance facts such as: - valid and distinct collateral, outcome-token, and RT asset identities; - a valid oracle public key; +- correct derivation of both oracle messages from the outcome-token identities + and the protocol domain; - correct derivation of the public RT commitments from the RT asset IDs; - a positive base payout whose per-pair collateral is representable; and - an expiry value with the advertised block-height semantics. diff --git a/crates/deadcat-contracts/simplicityhl/binary_market.simf b/crates/deadcat-contracts/simplicityhl/binary_market.simf index 8b980c0..8e4c460 100644 --- a/crates/deadcat-contracts/simplicityhl/binary_market.simf +++ b/crates/deadcat-contracts/simplicityhl/binary_market.simf @@ -410,29 +410,14 @@ fn ensure_rt_burn( // Oracle authorization // ----------------------------------------------------------------------------- -fn compute_market_id() -> u256 { - let ctx: Ctx8 = jet::sha_256_ctx_8_init(); - let ctx: Ctx8 = jet::sha_256_ctx_8_add_32(ctx, param::YES_TOKEN_ASSET_ID); - let ctx: Ctx8 = jet::sha_256_ctx_8_add_32(ctx, param::NO_TOKEN_ASSET_ID); - jet::sha_256_ctx_8_finalize(ctx) -} - -fn oracle_domain() -> u256 { - // SHA256("deadcat/oracle_attestation") - 0x8b96c12d4ff2c6dba7c14f5491b04200c86acf64283662940f700ad3b8b83c39 -} - fn verify_oracle(outcome_yes: bool, signature: Signature) { - let outcome: u8 = match outcome_yes { - true => 1, - false => 0, + // These messages are derived by the compiler from the canonical outcome + // asset IDs and oracle domain; they are not independently selectable + // public market parameters. + let message: u256 = match outcome_yes { + true => param::ORACLE_MESSAGE_YES, + false => param::ORACLE_MESSAGE_NO, }; - let ctx: Ctx8 = jet::sha_256_ctx_8_init(); - let ctx: Ctx8 = jet::sha_256_ctx_8_add_32(ctx, oracle_domain()); - let ctx: Ctx8 = jet::sha_256_ctx_8_add_32(ctx, oracle_domain()); - let ctx: Ctx8 = jet::sha_256_ctx_8_add_32(ctx, compute_market_id()); - let ctx: Ctx8 = jet::sha_256_ctx_8_add_1(ctx, outcome); - let message: u256 = jet::sha_256_ctx_8_finalize(ctx); jet::bip_0340_verify((param::ORACLE_PUBLIC_KEY, message), signature); } diff --git a/crates/deadcat-contracts/src/binary_market/compiled.rs b/crates/deadcat-contracts/src/binary_market/compiled.rs index a508a76..fa0fc1d 100644 --- a/crates/deadcat-contracts/src/binary_market/compiled.rs +++ b/crates/deadcat-contracts/src/binary_market/compiled.rs @@ -27,6 +27,7 @@ use thiserror::Error; use super::{BinaryMarketEconomics, BinaryMarketParams, BinaryMarketSlot}; use crate::artifacts::binary_market::{BinaryMarketProgram, derived_binary_market}; use crate::finalized_spend::{FinalizedSimplicitySpend, FinalizedSimplicitySpendError}; +use crate::market_crypto::{BinaryOutcome as OracleOutcome, oracle_message}; use crate::rt::{RtCommitmentError, RtLeg, RtSide, commitments, factors}; const NUMS_INTERNAL_KEY: [u8; 32] = [ @@ -439,8 +440,20 @@ fn contract_arguments( ) -> Result { let yes = rt_commitment_arguments(params.yes_reissuance_token_id, RtLeg::Yes)?; let no = rt_commitment_arguments(params.no_reissuance_token_id, RtLeg::No)?; + let oracle_message_yes = oracle_message( + params.yes_token_asset_id, + params.no_token_asset_id, + OracleOutcome::Yes, + ); + let oracle_message_no = oracle_message( + params.yes_token_asset_id, + params.no_token_asset_id, + OracleOutcome::No, + ); Ok(derived_binary_market::BinaryMarketArguments { oracle_public_key: params.oracle_public_key, + oracle_message_yes, + oracle_message_no, collateral_asset_id: params.collateral_asset_id.into_inner().to_byte_array(), yes_token_asset_id: params.yes_token_asset_id.into_inner().to_byte_array(), no_token_asset_id: params.no_token_asset_id.into_inner().to_byte_array(), @@ -900,6 +913,22 @@ mod tests { compiled.arguments.oracle_public_key, params.oracle_public_key ); + assert_eq!( + compiled.arguments.oracle_message_yes, + oracle_message( + params.yes_token_asset_id, + params.no_token_asset_id, + OracleOutcome::Yes, + ) + ); + assert_eq!( + compiled.arguments.oracle_message_no, + oracle_message( + params.yes_token_asset_id, + params.no_token_asset_id, + OracleOutcome::No, + ) + ); assert_eq!( compiled.arguments.collateral_asset_id, params.collateral_asset_id.into_inner().to_byte_array() @@ -1014,9 +1043,9 @@ mod tests { assert_eq!( first.cmr(), [ - 0xe8, 0x91, 0x2f, 0x8e, 0x5d, 0xeb, 0x3c, 0x04, 0xba, 0x47, 0xea, 0xac, 0xac, 0xc8, - 0xd1, 0x94, 0xae, 0x04, 0x73, 0xe3, 0x5c, 0xee, 0x9e, 0x17, 0x1b, 0x8a, 0x71, 0xe3, - 0x51, 0x3a, 0xbc, 0xa0, + 0x70, 0x2f, 0x5d, 0x04, 0xf1, 0x5b, 0xcd, 0xec, 0x3f, 0xa1, 0x07, 0x05, 0x40, 0xbf, + 0x2f, 0x68, 0xc0, 0xec, 0xdc, 0xf4, 0x0b, 0xc8, 0xaa, 0x80, 0x24, 0xe1, 0xe7, 0x7e, + 0xf1, 0x9c, 0xd5, 0xee, ] ); diff --git a/crates/deadcat-contracts/tests/fixtures/binary_market_abi.txt b/crates/deadcat-contracts/tests/fixtures/binary_market_abi.txt index 45cdccb..9f7767d 100644 --- a/crates/deadcat-contracts/tests/fixtures/binary_market_abi.txt +++ b/crates/deadcat-contracts/tests/fixtures/binary_market_abi.txt @@ -10,6 +10,8 @@ NO_RT_ASSET_B_X: u256 NO_RT_VALUE_PARITY: bool NO_RT_VALUE_X: u256 NO_TOKEN_ASSET_ID: u256 +ORACLE_MESSAGE_NO: u256 +ORACLE_MESSAGE_YES: u256 ORACLE_PUBLIC_KEY: u256 YES_REISSUANCE_TOKEN_ID: u256 YES_RT_ASSET_A_PARITY: bool diff --git a/crates/deadcat-contracts/tests/golden_vectors.rs b/crates/deadcat-contracts/tests/golden_vectors.rs index 4deae7c..e8f4936 100644 --- a/crates/deadcat-contracts/tests/golden_vectors.rs +++ b/crates/deadcat-contracts/tests/golden_vectors.rs @@ -3,6 +3,7 @@ use std::fmt::Write as _; use deadcat_contracts::binary_market::{ BinaryMarketProgram, BinaryMarketSlot, CompiledBinaryMarket, }; +use deadcat_contracts::market_crypto::{BinaryOutcome as OracleOutcome, oracle_message}; use deadcat_contracts::rt::{ABF_A, ABF_B, RtLeg, RtSide, YES_CBF, commitments, factors, no_cbf}; use deadcat_types::BinaryMarketParams; use elements::AssetId; @@ -73,10 +74,27 @@ fn nonuniform_contract_arguments_compile_to_stable_cmr() { // Every asset byte is position-sensitive. This golden therefore changes if // `contract_arguments` accidentally substitutes display order for consensus // byte order before compiling the parameterized program. - let compiled = CompiledBinaryMarket::new(nonuniform_params()).expect("compile market"); + let params = nonuniform_params(); + assert_eq!( + hex(&oracle_message( + params.yes_token_asset_id, + params.no_token_asset_id, + OracleOutcome::Yes, + )), + "0091d6c79a16ced37737ac34a7a461359d93ce1eebebca50eefd9197a1bc0876" + ); + assert_eq!( + hex(&oracle_message( + params.yes_token_asset_id, + params.no_token_asset_id, + OracleOutcome::No, + )), + "10c3d52c18c0a9d2d1d9cd90dc1ae4537ad53cf2e2a4e980b5dd4f04b5f1263e" + ); + let compiled = CompiledBinaryMarket::new(params).expect("compile market"); assert_eq!( hex(&compiled.cmr()), - "2d350901b53cfeb3204f97e7708980fd62bf24914bf8e4aafb6530ce025dbb7f" + "090548f91e2f07d2e691216336b578bf15fcdbde96f2e4255e4e70c60e4c1931" ); } @@ -225,40 +243,40 @@ fn sample_binary_market_consensus_vectors_are_stable() { let compiled = CompiledBinaryMarket::new(params).expect("compile market"); assert_eq!( hex(&compiled.cmr()), - "e8912f8e5deb3c04ba47eaacacc8d194ae0473e35cee9e171b8a71e3513abca0" + "702f5d04f15bcdec3fa1070540bf2f68c0ecdcf40bc8aa8024e1e77ef19cd5ee" ); let expected_slots = [ ( - "51203fbf4e0e02df806affc1f0c66180a2d49b2ec03e1848a5ab326700157a7a15bd", + "512001d36e8c57cfcd1f3c2f17fb588985f8dcd5834e9938c4f7d35e3ef2a4e5acf7", "be50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac03491a3e42d2db13335d900b3cbadcb0d5088b4eb9073869ff309910862294069", ), ( - "51206126a2324335d42fe5b9998579b9187b2b6af2a1ffa3e9e10042fc856ebc708c", - "be50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac09c44e27f20b80c93313762a6f4e71fc82db38469d90f902bc1720755b61660f3", + "5120d33c3880d2a6c1fb3a95b359fd7d602a793a10e2af5da30806685bb2c50c8390", + "bf50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac09c44e27f20b80c93313762a6f4e71fc82db38469d90f902bc1720755b61660f3", ), ( - "5120a252a8b117ebdd1bf207f98a6c2034344119d492f84d03e7052c103c1dfad71b", + "51208e9a829d1fb7d7c0cb19d524cb469dbe4e248744304f60c1bb487676ba660de5", "be50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac04bbdde171ae4fa8cfe1c7790ec1d737b4044251c647103b3e2c320a25a8b61e2", ), ( - "51207bea2e337f0bb4f7235a16a61b8aa2935fcbc011d423ebcda8c3f0f7d4456d35", + "5120a4e68ecf6a94a73272c75e2023f9ab3cd3fd1ce0e86e5556540ce33bec5739b1", "bf50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac013169a5cae722314cc26e3f278b4f9d087affe9b0dab437d6d8c2b28ace343d0", ), ( - "5120b1920be3d3c368dd49067dd3958bd1c5c79af3166ba5534d34ddf2a6e087e68a", + "51208745d41c870ac38b4aa9d9c9bf345f160a9e82f1691daa50216a79a224b6b7ea", "be50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac04b7b02768d8d3b9339bfd3417355db78cada99eb21f1e32873b3ab77065ee015", ), ( - "5120fccd0ab4351768ecf55fbf7cbe2bb65591845bdc13978e8b5832de33f87afa74", - "be50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac094c17910e4ec9a08d1a445308fd4b66ee01cc818d1772a8deff59dd38b649bee", + "512098e5b0dc5969b4f0716f179507d882026857b84f507692da10d258081ff979f1", + "bf50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac094c17910e4ec9a08d1a445308fd4b66ee01cc818d1772a8deff59dd38b649bee", ), ( - "51206b247f70cbae80525455896174fb5d3129d417b224418650bd7d6e444dd8a4c7", - "be50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0838594e38820be8487ed62ea7663c1d3ce2f20b3f0c7d8075b1bd3f436239d25", + "5120ba9e2e04ae3c5b62b8a2eba46eddb764d7d2038f2640a6db0654ee9d52e793ac", + "bf50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0838594e38820be8487ed62ea7663c1d3ce2f20b3f0c7d8075b1bd3f436239d25", ), ( - "51208e44c81c10c744ea9d5ab30469e1c1510e5a67c08c42a10db2973c9f876f91bb", - "be50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac03efb3634a85ea11aa3a246775edf9406ff088af069350d5b8a4ef7a9f862ae0c", + "51200a566889ec9ce31dea29985827ae10915373de02c609285b4d735b04880d7338", + "bf50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac03efb3634a85ea11aa3a246775edf9406ff088af069350d5b8a4ef7a9f862ae0c", ), ]; for (slot, (script, control_block)) in BinaryMarketSlot::ALL.into_iter().zip(expected_slots) { diff --git a/docs/acceptance/binary-market-ab-v1.md b/docs/acceptance/binary-market-ab-v1.md index a40ae5f..8765a30 100644 --- a/docs/acceptance/binary-market-ab-v1.md +++ b/docs/acceptance/binary-market-ab-v1.md @@ -2,7 +2,7 @@ - Status: Engineering candidate complete; protocol-owner approved; focused external review pending - Prepared: 2026-07-13; strict coordinator hardening updated 2026-07-22; - typed-action ABI candidate updated 2026-07-31 + typed-action ABI and oracle-precomputed candidates updated 2026-07-31 - Protocol-owner approval: Tommy Volk; 2026-07-14 - Decision record: [ADR 0005](../adr/0005-rt-blinding-schedule.md) - Protocol specification: [Deadcat protocol v1](../protocol-v1.md) @@ -27,9 +27,15 @@ The still-undeployed v1 covenant was subsequently simplified to a typed five-operation `ACTION` sum plus authenticated `SLOT`. Path variants, burn quantity, redemption side, and dummy oracle fields are derived from the slot, semantic action, and mandatory transaction outputs. The exact branch-pruned -decoder and current identity are recorded in the +decoder and historical typed-action identity are recorded in the [PR3 witness conformance note](../binary-market-witness-conformance-pr3.md). +The compiler subsequently moved the two fixed oracle-message derivations to +compile time. The signed bytes and public market parameters are unchanged; the +covenant selects the derived YES or NO digest before BIP340 verification. The +exact vectors and measurements are recorded in the +[oracle-precomputation note](../binary-market-oracle-precomputation.md). + ADR 0005 remains Proposed until a focused reviewer records a conclusion. Tommy Volk approved every protocol-owner choice below on 2026-07-14 against the candidate implementation commit. Reviewer checkboxes remain for the independent @@ -41,7 +47,7 @@ For the golden fixture in `deadcat-contracts/tests/golden_vectors.rs`, the parameterized binary-market CMR is: ```text -e8912f8e5deb3c04ba47eaacacc8d194ae0473e35cee9e171b8a71e3513abca0 +702f5d04f15bcdec3fa1070540bf2f68c0ecdcf40bc8aa8024e1e77ef19cd5ee ``` The v1 consensus scalars are big-endian 32-byte integers: @@ -61,7 +67,9 @@ IDs so an accidental Elements display-order reversal cannot pass unnoticed. The CMR above is not universal across market parameters. The prior strict coordinator/follower implementation compiled this fixture to `ebbd8f3001141120edb0880c8e14f40d2054018116627624fc31c1bcf73af473`; -that value remains historical evidence rather than the current candidate. +the typed-action implementation then compiled it to +`e8912f8e5deb3c04ba47eaacacc8d194ae0473e35cee9e171b8a71e3513abca0`. +Those values remain historical evidence rather than the current candidate. ## Engineering evidence @@ -75,6 +83,7 @@ that value remains historical evidence rather than the current candidate. | Input-side reissuance nonce | Complete | Covenant/builder/interpreter adversarial tests and live A/B issuances inspect the exact nonce | | Every lifecycle shape | Complete | All 18 builder/BitMachine/interpreter shapes execute; every RT-consuming shape executes on both A and B, every sibling, with sufficient Simplicity budget; direct mutation tests cover solvency, issuance authority, terminal burns, oracle/expiry, redemption arithmetic, wrong slots, and follower source-witness independence | | Typed semantic action ABI | Complete | Golden source ABI contains only `SLOT` and the five-branch `ACTION`; checked Rust facades prevent invalid role/action layouts; exact finalized decoding rejects missing, duplicate, unexpected, or near-miss structural values without width scans or candidate search | +| Static oracle-message derivation | Complete | The canonical compiler derives both digests from the outcome asset IDs; literal nonuniform vectors freeze byte order and outcome tags; active/dormant YES/NO execution plus corrupt and cross-outcome signatures exercise selection and verification | | Elements consensus and policy | Complete | Three full-contract chains, 15 market transactions plus one setup-funding transaction confirmed; every valid stage through `testmempoolaccept`, broadcast, mining, and confirmation; strict rerun adds a divergent-follower-stack transaction and rejects follower stacks transplanted into the coordinator input | | Confidential proofs | Complete | Creation/continuation/burn rangeproofs and complete-domain surjection proofs accepted live; missing and parseable-corrupt proofs rejected | | Golden integration identity | Complete | Constants, six fixture commitments, six independently derived nonuniform-ID commitments, CMR, eight scripts, and eight control blocks are literal regression vectors | @@ -83,8 +92,8 @@ that value remains historical evidence rather than the current candidate. | Composition/orchestration | Complete for v1 gate | Live confidential wallet input/change composition and deterministic synthetic two-market atomic indexing; the mandatory multi-contract liquidregtest gate mines and atomically indexes a real market-plus-two-orders transaction | | Full-market before/after measurements | Captured with provenance limitation | A/B reporter is reproducible; exact rolling rows are a preserved capture from temporary baseline instrumentation whose patch was not committed; the strict live rerun passed locally but its per-transaction raw JSON is not committed; isolated rolling/A-B study remains reproducible | | Rolling retirement | Complete | No rolling implementation, compatibility mode, study crate, or schema migration remains in the candidate tree | -| Clean pinned-Nix CI | Passed on 2026-07-13, 2026-07-22, and typed-action candidate on 2026-07-31 | `nix develop .#default --command just ci-checks` passes formatting, strict Clippy, 211 workspace tests, doc tests, and WASM; `just regtest-market-ab` passes the production-shaped live lifecycle | -| Independent implementation review | Complete for A/B vectors and pre-strict CMR; current typed-action identity is regression-tested | Plain-integer scalar arithmetic, direct C libsecp256k1-zkp commitments, and isolated pinned-compiler CMR reproduction all matched on 2026-07-13; current CMRs and all eight scripts/control blocks are covered by committed golden vectors | +| Clean pinned-Nix CI | Passed on 2026-07-13, 2026-07-22, and the typed-action and oracle-precomputed candidates on 2026-07-31 | `nix develop .#default --command just ci` passes formatting, strict Clippy, 211 workspace tests, doc tests, WASM, the complete market lifecycle, multi-market indexing/reorg/rebuild, backend equivalence, and daemon/CLI process-boundary gates | +| Independent implementation review | Complete for A/B vectors and pre-strict CMR; current oracle-precomputed identity is regression-tested | Plain-integer scalar arithmetic, direct C libsecp256k1-zkp commitments, and isolated pinned-compiler CMR reproduction all matched on 2026-07-13; current message digests, CMRs, and all eight scripts/control blocks are covered by committed golden vectors | | Focused external human review | Pending | Reviewer record below | | Protocol-owner approval | Complete | Tommy Volk; 2026-07-14; candidate implementation commit below | @@ -138,14 +147,20 @@ contract on 2026-07-22: all 16 transactions confirmed, both malformed-proof variants were rejected, and a coordinator/follower pruning negative was rejected. Transaction identifiers are intentionally treated as run-local. The preserved measurement file records that strict-covenant run; the typed-action candidate's -current CMR and resource maxima are recorded in the golden vectors and PR3 -conformance note. +historical CMR and witness ABI are recorded in the PR3 conformance note. The gate was rerun again against the typed-action candidate on 2026-07-31. All 16 transactions confirmed across the three lifecycle chains, both malformed proofs were rejected, and transplanting a follower stack into the coordinator was rejected. +The complete `just ci` gate was rerun after oracle-message precomputation on +2026-07-31. The same 16-transaction lifecycle and three negative cases passed; +the multi-market indexing/reorg/rebuild, Elements/Esplora equivalence, and +daemon/CLI process-boundary gates also passed. Current CMRs, oracle vectors, and +resource measurements are recorded in the +[oracle-precomputation note](../binary-market-oracle-precomputation.md). + | Chain | Stage | Side | Height | Txid | |---|---|---|---:|---| | YES resolution | creation | start A | 105 | `00741193071a30d409403fcfc50b86e1feae971ba29515db5cf03ecad633c3c6` | @@ -256,8 +271,17 @@ The external reviewer should work from the recorded implementation commit: with Elements serialization and proof APIs. - [ ] Confirm Rust builder/interpreter, node registration, and independent client replay fail closed on the same commitment/side shapes. -- [ ] Reproduce the CMR and review the covenant/witness diff from - `ed6de4c4c8a177b4a4ba92c2bac17f55b324781f`. +- [ ] Independently derive the YES and NO oracle digests from nonuniform outcome + asset IDs, including consensus byte order, the domain tag, and `0x01`/`0x00` + outcome bytes. Confirm the canonical host compiler binds exactly those + digests and the covenant selects the matching digest before BIP340 + verification. +- [ ] Reproduce the current CMR and review the covenant/witness diff from + `ed6de4c4c8a177b4a4ba92c2bac17f55b324781f`, including the typed-action CMR + `e8912f8e5deb3c04ba47eaacacc8d194ae0473e35cee9e171b8a71e3513abca0` + to oracle-precomputed CMR + `702f5d04f15bcdec3fa1070540bf2f68c0ecdcf40bc8aa8024e1e77ef19cd5ee` + transition. - [ ] Reproduce the current A/B full-market rows. If acceptance depends on the exact rolling full-market percentages, reconstruct and review equivalent instrumentation at `ed6de4c...`; otherwise record acceptance of the preserved @@ -279,14 +303,14 @@ for the focused human review above. | Field | Value | |---|---| | Independent vector method/result | Python big integers reproduced all CBF/VBF arithmetic; standalone C using upstream libsecp256k1-zkp reproduced the fixture and nonuniform-asset-ID commitment sets; isolated Simplex 0.0.6 build reproduced the pre-strict CMR; all matched on 2026-07-13 | -| Automated implementation audit | No production A/B findings on 2026-07-13; no strict-contract production findings on 2026-07-22; typed-action ABI/domain/interpreter review completed on 2026-07-31 with exact-decoder, adversarial BitMachine, and live-regtest coverage | +| Automated implementation audit | No production A/B findings on 2026-07-13; no strict-contract production findings on 2026-07-22; typed-action ABI/domain/interpreter and oracle-precomputation reviews completed on 2026-07-31 with exact-decoder, digest-vector, adversarial BitMachine, and complete live-regtest coverage | | External reviewer | `` | | Commit reviewed | `` | | Review date | `` | | Findings and dispositions | `` | | Reviewer conclusion | `` | -- [x] Clean pinned-Nix CI is recorded against the candidate and strict contract commits. +- [x] Clean pinned-Nix CI is recorded through the oracle-precomputed candidate. - [ ] Every focused-review finding has a disposition. - [x] Every protocol-owner checkbox is checked. - [ ] ADR 0005 is changed from Proposed to Accepted only after those reviews. @@ -295,6 +319,7 @@ for the focused human review above. |---|---|---|---|---| | Implementation owner | Codex candidate | 2026-07-13 | `7ed20b8b81306eaf81ee49b80b4ea65b49804871` | Engineering-complete | | Implementation owner | Codex strict hardening review | 2026-07-22 | `044fdf07d92217df7ad794ff2a9dff0fc9ae62b2` | Engineering-complete; external review still pending | +| Implementation owner | Codex oracle precomputation | 2026-07-31 | This pull request head | Engineering-complete; external review still pending | | External reviewer | `` | `` | `` | `` | | Protocol owner | Tommy Volk | 2026-07-14 | `7ed20b8b81306eaf81ee49b80b4ea65b49804871` | Approved | diff --git a/docs/adr/0005-rt-blinding-schedule.md b/docs/adr/0005-rt-blinding-schedule.md index b25de37..5cf77a3 100644 --- a/docs/adr/0005-rt-blinding-schedule.md +++ b/docs/adr/0005-rt-blinding-schedule.md @@ -79,6 +79,15 @@ changes the current parameterized golden CMR to The exact source and finalized witness shapes are recorded in the [PR3 conformance note](../binary-market-witness-conformance-pr3.md). +Later on 2026-07-31, the canonical compiler began deriving and binding the YES +and NO oracle messages from the outcome asset IDs. The covenant now selects one +of those messages before BIP340 verification instead of rebuilding the market +ID and tagged hash during every resolution spend. This preserves the oracle +protocol and A/B decision while changing the current parameterized golden CMR +to `702f5d04f15bcdec3fa1070540bf2f68c0ecdcf40bc8aa8024e1e77ef19cd5ee`. +The exact derived-message vectors and resource bounds are recorded in the +[oracle-precomputation note](../binary-market-oracle-precomputation.md). + ## Candidate schedule Let `n` be the secp256k1 group order. Use these fixed, valid, nonzero scalars: @@ -161,6 +170,11 @@ market parameters. Clients and nodes recompile them from the RT asset IDs and the constants above. Prebinding removes runtime curve generation and outpoint hashing while preserving the normal CMR/script verification trust model. +The compiler likewise derives and binds the two possible oracle messages from +the outcome asset IDs and fixed oracle domain. Clients and nodes independently +derive the same messages during recompilation; the covenant merely selects the +outcome-specific digest and verifies the supplied signature. + Off-chain code exposes typed `RtLeg` and `RtSide` values and derives factors from them. A live RT is accepted only after its raw `TxOut` matches one exact side; a node-provided side is at most a convenience hint. Reissuance uses diff --git a/docs/binary-market-oracle-precomputation.md b/docs/binary-market-oracle-precomputation.md new file mode 100644 index 0000000..bbd948d --- /dev/null +++ b/docs/binary-market-oracle-precomputation.md @@ -0,0 +1,70 @@ +# Binary-market oracle-message precomputation + +The canonical binary-market compiler derives the two possible oracle messages +from the YES and NO token asset IDs and binds both digests into the instantiated +Simplicity program. The covenant selects the bound digest from the authenticated +outcome bit and performs only BIP340 verification at spend time. + +This is an implementation-boundary change, not an oracle-protocol change. The +message remains: + +```text +market_id = SHA256(yes_token_asset_id_bytes || no_token_asset_id_bytes) +message = tagged_hash("deadcat/oracle_attestation", market_id || outcome_byte) +``` + +`outcome_byte` remains `0x01` for YES and `0x00` for NO. The compiler-derived +messages are not independently selectable market parameters. Independent +clients derive them from the public outcome asset IDs, recompile the covenant, +and verify the resulting script as before. + +## Golden identity + +For the canonical golden fixture, the precomputed program has CMR: + +```text +702f5d04f15bcdec3fa1070540bf2f68c0ecdcf40bc8aa8024e1e77ef19cd5ee +``` + +The position-sensitive nonuniform-asset fixture has CMR: + +```text +090548f91e2f07d2e691216336b578bf15fcdbde96f2e4255e4e70c60e4c1931 +``` + +Its independently frozen oracle digests are: + +```text +YES = 0091d6c79a16ced37737ac34a7a461359d93ce1eebebca50eefd9197a1bc0876 +NO = 10c3d52c18c0a9d2d1d9cd90dc1ae4537ad53cf2e2a4e980b5dd4f04b5f1263e +``` + +The golden-vector suite also freezes all eight resulting Taproot scripts and +control blocks. + +## Resource measurements + +The all-path, both-RT-side finalized corpus measured the following worst +resolution rows after precomputation. Each covenant value is aggregated over +all market inputs in that transaction. + +| Resolution shape | Cost (mw) | Program bytes | Stack bytes | Transaction bytes | vB | +|---|---:|---:|---:|---:|---:| +| Active | 3,127,815 | 3,733 | 4,117 | 13,188 | 3,624 | +| Dormant | 1,457,852 | 2,362 | 2,641 | 11,588 | 3,135 | + +The overall corpus maxima remain determined by non-resolution paths: + +| Resource | Maximum | +|---|---:| +| Covenant cost | 3,633,302 milliweight | +| Extra cells | 72,462 | +| Extra frames | 62 | +| Finalized covenant stack | 4,339 bytes | +| Transaction size | 13,624 bytes | +| Transaction weight | 15,574 WU | +| Transaction vsize | 3,894 vB | + +The corpus executes active and dormant YES and NO resolution, both RT input +sides, corrupt signatures, and cross-outcome signatures. The parameter ABI, +both CMRs, scripts, and control blocks are committed golden vectors. diff --git a/docs/binary-market-witness-conformance-pr3.md b/docs/binary-market-witness-conformance-pr3.md index dcf665d..52ca941 100644 --- a/docs/binary-market-witness-conformance-pr3.md +++ b/docs/binary-market-witness-conformance-pr3.md @@ -91,12 +91,16 @@ output-base selection and independently invalid transaction shapes. ## Candidate identity and resource bounds -For the canonical golden parameter fixture, this refactor produces CMR +For the canonical golden parameter fixture, this refactor originally produced CMR `e8912f8e5deb3c04ba47eaacacc8d194ae0473e35cee9e171b8a71e3513abca0`. -The nonuniform-asset fixture produces +The nonuniform-asset fixture originally produced `2d350901b53cfeb3204f97e7708980fd62bf24914bf8e4aafb6530ce025dbb7f`. -The golden-vector suite pins both CMRs, the source ABI, and all eight resulting -Taproot script/control-block pairs. +A later semantic-preserving compiler change precomputed the two oracle messages, +changing the current CMRs while retaining this witness ABI. The current identity +and derived-message vectors are recorded in the +[oracle-precomputation note](binary-market-oracle-precomputation.md). The +golden-vector suite pins both current CMRs, the source ABI, and all eight +resulting Taproot script/control-block pairs. The all-path, both-RT-side budget corpus records these current maxima: @@ -110,5 +114,6 @@ The all-path, both-RT-side budget corpus records these current maxima: | Transaction weight | 15,574 WU | | Transaction vsize | 3,894 vB | -CI uses rounded ceilings above these measurements and fails if a later compiler -or covenant change crosses them. +These overall maxima remain current after oracle-message precomputation because +non-resolution paths determine them. CI uses rounded ceilings above the +measurements and fails if a later compiler or covenant change crosses them. diff --git a/docs/protocol-v1.md b/docs/protocol-v1.md index eed203e..ebe8c8f 100644 --- a/docs/protocol-v1.md +++ b/docs/protocol-v1.md @@ -479,6 +479,12 @@ outcome_byte = 0x01 for YES outcome_byte = 0x00 for NO ``` +The canonical compiler derives both possible messages from the outcome asset +IDs and binds them as internal program arguments. They are not independently +selectable market parameters. At resolution, the covenant selects the bound +digest from `outcome_yes` and verifies the BIP340 signature; this preserves the +message format above while avoiding repeated SHA work at spend time. + The oracle supplies a BIP-340 signature under `oracle_public_key`. ### Fixed A/B RT construction