feat(zcash-wasm): PCZT producer + extractor + redactor + UR fountain decoder#6
Open
hitchho wants to merge 3 commits into
Open
feat(zcash-wasm): PCZT producer + extractor + redactor + UR fountain decoder#6hitchho wants to merge 3 commits into
hitchho wants to merge 3 commits into
Conversation
…decoder Adds the cold-signer signing pipeline that pairs zafu with any UR/PCZT-compatible hardware (zigner, Keystone, zashi). The producer-side wasm previously emitted a [sighash][alphas][summary] simple format that decouples the displayed plan from the signed bytes — a compromised hot wallet could lie about what's being signed. The PCZT path closes that gap: the cold device recomputes the sighash from the PCZT contents itself, so display and signed bytes are bound by construction. What lands: - build_unsigned_pczt: canonical pipeline Builder::build_for_pczt → Creator → Prover (Halo 2) → IoFinalizer (sighash-stamping) → redactor → serialize. - extract_signed_tx_from_pczt_bytes (+ wasm wrapper): TransactionExtractor over a fully-signed PCZT, returns broadcast-ready v5 hex. - redact_pczt_for_signer: strips fields the cold device doesn't need (witness, zip32_derivation, dummy_sk, proprietary) while preserving everything the signer reconstructs the sighash from. Saves QR frames; matters for Keystone-class hardware whose RAM budget assumes redacted form. - ur_decode_frames: BC-UR multipart fountain decoder for the receive path. Dep alignment: bumped zcash_primitives 0.21 → 0.26, zcash_keys/zcash_address/ zcash_protocol/zcash_transparent to git rev 5333c01b (matches zigner). Pulled sapling-crypto 0.6 with circuit feature — required by pczt's prover/io-finalizer even though zafu doesn't use sapling. Added pczt with all roles needed for the producer side (zcp-builder, prover, io-finalizer, signer, spend-finalizer, tx-extractor). Tests: - pczt_redactor_smoke: source-grep guard that build_unsigned_pczt invokes the redactor in the right pipeline order (finalize_io < redact < serialize). - pczt_redactor_property: 4 behavioral tests on a synthetic transparent → orchard PCZT — round-trip stability, size shrinks under redaction, Signer::new still accepts the redacted PCZT (kept fields intact), and crucially the shielded sighash is invariant under redaction (the security property the whole migration delivers). - extract_signed_tx: full prove + sign + extract end-to-end with structural validation of the v5 tx bytes (header words, version_group_id, vin/vout/orchard shape, re-parses via Transaction::read). - zashi_interop_snapshot: scaffold for #[ignore]'d external-fixture test; drop a real zashi/keystone-emitted ur:zcash-pczt byte stream into tests/fixtures/ to activate. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6 tasks
# Conflicts: # crates/zcash-wasm/Cargo.toml
… errors Two review findings from the 8-persona PR audit. validate_ufvk (security + redshiftzero, BLOCKING): Structural-only UFVK validation in @repo/wallet let a structurally-plausible but cryptographically-bogus UFVK reach the wallet store, failing only at first-send and poisoning FVK-equality dedup. Add a single authoritative decoder export — `UnifiedFullViewingKey::decode(...).is_ok()`, the *same* decoder the signing path uses. Deliberately not a second hand-rolled bech32m/checksum validator (a divergent implementation at the trust boundary is worse than none). The zafu persistence boundary (wallet-entries.ts) calls this before writing a record; @repo/wallet keeps its cheap structural pre-screen and stays wasm-free. merkle filter_map -> precise errors (release-mgmt, QA): `auth_path.iter().filter_map(MerkleHashOrchard::from_bytes).collect()` then `len() != 32` collapsed a non-canonical sibling into a generic "invalid merkle path hashes" — erasing which sibling and why, exactly when debugging an anchor mismatch on hardware. Not a silent-corruption hole (a wrong path is still caught downstream by orchard has_matching_anchor → AnchorMismatch) but undiagnosable. Both sites now decode positionally and error with `merkle sibling i/j is not a canonical Pallas base element: <hex>`. zcli tests green (pczt_redactor_property 4/4, extract_signed_tx 1/1, pczt_redactor_smoke 1/1). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
Author
Review round (8-persona audit) + correctionsAn 8-reviewer audit was run. Walking back overstated claims and recording what changed. Claims corrected:
Fixed this round (commit 2038eb6):
Disposition: keep as Draft. Merge after a behavioral merkle-rejection test lands (now testable post-fix) and the companion zafu anchor-depth fix is hardware-validated. Reciprocal note: rotkonetworks/zafu#11 vendors wasm built from this branch — see its BUILD_PROVENANCE.md pinning the exact rev. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
What lands
build_unsigned_pcztpczt::Pczt::serialize()bytes.extract_signed_tx_from_pczt(_bytes)redact_pczt_for_signerur_decode_framesTests
pczt_redactor_smoke— source-grep guard thatbuild_unsigned_pcztinvokes the redactor in the right pipeline order.pczt_redactor_property— 4 behavioral tests on a synthetic transparent → orchard PCZT: round-trip stability, size shrinks under redaction,Signer::newstill accepts redacted PCZT (kept fields intact), shielded sighash is invariant under redaction (the security property the migration delivers).extract_signed_tx— full prove + sign + extract end-to-end with structural validation of the v5 tx bytes (header words, version_group_id, vin/vout/orchard shape, re-parses viaTransaction::read).zashi_interop_snapshot— scaffold for#[ignore]'d external-fixture test; drop a real zashi/keystone-emittedur:zcash-pcztbyte stream intotests/fixtures/to activate.Test plan
cargo test --release --test pczt_redactor_smoke --test pczt_redactor_property --test extract_signed_tx --test zashi_interop_snapshot— 6 passing, 1 ignored (pending external fixture).wasm-pack build --release --target web --no-default-features— clean.RUSTFLAGS='-C target-feature=+atomics,+bulk-memory,+mutable-globals,+simd128' cargo +nightly build -Z build-std=panic_abort,std --features parallel— clean.🤖 Generated with Claude Code