Skip to content

feat: add Zcash chain support with PCZT signing and unified addresses#204

Open
Kenbak wants to merge 1 commit intoopen-wallet-standard:mainfrom
Kenbak:feat/zcash-support
Open

feat: add Zcash chain support with PCZT signing and unified addresses#204
Kenbak wants to merge 1 commit intoopen-wallet-standard:mainfrom
Kenbak:feat/zcash-support

Conversation

@Kenbak
Copy link
Copy Markdown

@Kenbak Kenbak commented Apr 14, 2026

Summary

Adds full Zcash support to OWS, including:

  • ZIP-32 key derivation — Zcash uses its own HD derivation standard (ZIP-32) instead of BIP-44. The ChainSigner trait gains needs_raw_seed() and derive_address_from_seed() methods so Zcash can derive keys from the raw BIP-39 seed.
  • Unified addresses — Wallet creation derives u1… unified addresses containing Orchard + Sapling receivers (privacy-by-default, transparent omitted).
  • PCZT signing — Implements the Signer role of the Partially Created Zcash Transaction workflow. OWS signs PCZTs that have already been through Creator and Prover stages, applying spend authorization signatures for Orchard, Sapling, and transparent pools.
  • lightwalletd broadcastsign send-tx finalizes the signed PCZT and broadcasts the raw transaction to Zcash's lightwalletd via gRPC.
  • Feature-gated — All shielded dependencies (librustzcash, pczt, orchard, sapling-crypto) are behind a zcash-shielded feature flag, so builds that don't need Zcash stay lean.

What changed

Area Files What
Core chain.rs, config.rs ChainType::Zcash, CAIP-2 namespace zcash, zcash:mainnet in known chains
Signer zcash.rs (new, 638 lines) ZcashSigner with ZIP-32 derivation, unified address generation, PCZT signing, message signing. 15+ unit tests.
Signer traits traits.rs needs_raw_seed(), derive_address_from_seed()
Library ops.rs, lwd_grpc.rs (new) Zcash-aware wallet creation, sign_and_broadcast_zcash pipeline, lightwalletd gRPC client. 12 integration tests.
CLI derive.rs, sign_transaction.rs, send_transaction.rs Zcash routing for address derivation, PCZT signing, and broadcast
Docs zcash-guide.md (new), 07-supported-chains.md, CONTRIBUTING.md Developer guide, updated chain table, build instructions

PCZT pipeline

External tool          OWS (this PR)
─────────────          ─────────────
Creator ─┐
          ├─ PCZT ──▶  Signer ──▶ Finalize ──▶ Broadcast
Prover  ──┘                                      (lightwalletd gRPC)

OWS receives a proved PCZT, signs all pool inputs with the ZIP-32 spending key, extracts the finalized transaction, and broadcasts it. This matches OWS's existing model where the wallet is a signing primitive — transaction construction is the caller's responsibility.

Tested on mainnet

End-to-end verified: PCZT created externally → signed by OWS → broadcast via lightwalletd → confirmed on-chain.

c0a16bbf385dd6d17cbc29b07c998c73a7eba6b3fc12e8051eaa52044b79e29f

Test plan

  • cargo test --workspace — all 465 tests pass
  • cargo test --features zcash-shielded — all 12 Zcash integration tests pass
  • cargo build --release without zcash-shielded — clean build, no Zcash deps pulled
  • Mainnet transaction broadcast and confirmed

Note

High Risk
High risk because it adds new chain support that touches key derivation/signing paths and introduces a new broadcast transport (lightwalletd gRPC) plus substantial new crypto dependencies behind feature flags.

Overview
Adds first-class Zcash support across core, signer, library, and CLI, including ChainType::Zcash, CAIP-2 IDs/aliases, and default RPC endpoints for zcash:mainnet/zcash:testnet.

Introduces feature-gated shielded functionality (zcash-shielded) with ZIP-32 raw-seed derivation via new ChainSigner hooks (needs_raw_seed, derive_address_from_seed) and a new ZcashSigner that derives unified addresses and signs PCZTs (transparent + Sapling + Orchard).

Extends signing and send flows to route Zcash transactions through PCZT signing/finalization and broadcast via lightwalletd gRPC (lwd_grpc), updates CLI behavior accordingly (including disallowing message signing for shielded Zcash), and adds extensive Zcash-focused tests and documentation.

Reviewed by Cursor Bugbot for commit ede3e58. Bugbot is set up for automated code reviews on this repo. Configure here.

@Kenbak Kenbak requested a review from njdawn as a code owner April 14, 2026 06:13
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 14, 2026

@Kenbak is attempting to deploy a commit to the MoonPay Team on Vercel.

A member of the Team first needs to authorize it.

Comment thread ows/crates/ows-cli/src/commands/send_transaction.rs
Comment thread ows/crates/ows-lib/src/ops.rs
Comment thread ows/crates/ows-lib/src/lwd_grpc.rs Outdated
@Kenbak Kenbak force-pushed the feat/zcash-support branch from bf90b48 to ed4e72c Compare April 14, 2026 06:24
Comment thread ows/crates/ows-signer/src/chains/zcash.rs
Comment thread ows/crates/ows-signer/src/chains/zcash.rs
@Kenbak Kenbak force-pushed the feat/zcash-support branch from ed4e72c to 5aa40d7 Compare April 14, 2026 06:32
Comment thread ows/crates/ows-lib/src/ops.rs Outdated
)));
}
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Transparent PCZT signing only handles address index zero

Low Severity

In sign_pczt, transparent input signing always derives the secret key at NonHardenedChildIndex::ZERO. Transparent inputs belonging to the same account but at a higher address index (analogous to Bitcoin change addresses) will be silently skipped by the TransparentSign error handler, producing a partially-signed PCZT that fails during finalization.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 5aa40d7. Configure here.

@Kenbak Kenbak force-pushed the feat/zcash-support branch from 5aa40d7 to 806fe01 Compare April 14, 2026 06:55
Comment thread ows/crates/ows-signer/src/chains/zcash.rs
Comment thread ows/crates/ows-lib/src/lib.rs
@Kenbak Kenbak force-pushed the feat/zcash-support branch from 806fe01 to 0466199 Compare April 14, 2026 07:09
Comment thread ows/crates/ows-lib/src/ops.rs
Add Zcash as the first privacy-preserving chain in OWS, with full
shielded transaction support via the PCZT format.

Chain registration:
- ChainType::Zcash with CAIP-2 namespace, coin type 133
- Default lightwalletd endpoints (zec.rocks mainnet/testnet)

Wallet creation (ows wallet create):
- ZIP-32 key derivation from BIP-39 seed (needs_raw_seed trait extension)
- Unified address with Orchard + Sapling receivers, shielded by default

PCZT signing (ows sign tx --chain zcash):
- Orchard spend authorization (RedPallas)
- Sapling spend authorization (Jubjub)
- Transparent spend authorization (secp256k1)
- Skips non-matching/dummy actions per standard Orchard builder behavior
- Key material zeroized after use

Sign + broadcast (ows sign send-tx --chain zcash):
- PCZT finalization via TransactionExtractor
- Broadcast via lightwalletd gRPC with TLS

Feature-gated behind zcash-shielded (enabled by default in CLI).
Without the feature, falls back to transparent-only t-address support.

Dependencies: zcash_keys, pczt, orchard, sapling-crypto, zcash_transparent,
zcash_protocol, zcash_primitives (all from librustzcash, maintained by ZODL).

Tests: 27 Zcash-specific tests (15 signer unit tests + 12 library
integration tests). All 465 workspace tests pass.

Docs: zcash-guide.md covering wallet creation, PCZT pipeline, security
model, configuration, and end-to-end workflow.
@Kenbak Kenbak force-pushed the feat/zcash-support branch from 0466199 to ede3e58 Compare April 14, 2026 07:23
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ede3e58. Configure here.

buf.push(0xFF);
buf.extend_from_slice(&(n as u64).to_le_bytes());
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicated encode_compact_size function across signers

Low Severity

The encode_compact_size function in zcash.rs is an exact copy of the one in bitcoin.rs. This duplicated logic increases the risk of inconsistent bug fixes if the varint encoding ever needs to change. It belongs in a shared utility module.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit ede3e58. Configure here.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intentional — both signers are standalone modules with no shared dependency between them. Extracting a common utility crate for a single 10-line function would add coupling without meaningful benefit. Each chain signer should remain self-contained so it can be enabled/disabled independently via feature flags.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant