Skip to content

Commit

Permalink
Merge pull request #1635 from zcash/feature/wallet_pczt_support
Browse files Browse the repository at this point in the history
zcash_client_backend PCZT support
  • Loading branch information
nuttycom authored Dec 9, 2024
2 parents 01ba1d2 + 0f4e01c commit 67fe5f8
Show file tree
Hide file tree
Showing 34 changed files with 1,843 additions and 269 deletions.
11 changes: 8 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,12 @@ zcash_keys = { version = "0.5", path = "zcash_keys" }
zcash_protocol = { version = "0.4.1", path = "components/zcash_protocol" }
zip321 = { version = "0.2", path = "components/zip321" }

zcash_note_encryption = "0.4"
zcash_note_encryption = "0.4.1"
zcash_primitives = { version = "0.20", path = "zcash_primitives", default-features = false }
zcash_proofs = { version = "0.20", path = "zcash_proofs", default-features = false }

pczt = { version = "0.0", path = "pczt" }

# Shielded protocols
bellman = { version = "0.14", default-features = false, features = ["groth16"] }
ff = "0.13"
Expand Down Expand Up @@ -95,6 +97,7 @@ bs58 = { version = "0.5", features = ["check"] }
byteorder = "1"
hex = "0.4"
percent-encoding = "2.1.0"
postcard = { version = "1", features = ["alloc"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"

Expand Down Expand Up @@ -188,4 +191,4 @@ unexpected_cfgs = { level = "warn", check-cfg = ['cfg(zcash_unstable, values("zf

[patch.crates-io]
orchard = { git = "https://github.com/zcash/orchard.git", rev = "bcd08e1d23e70c42a338f3e3f79d6f4c0c219805" }
sapling-crypto = { git = "https://github.com/zcash/sapling-crypto.git", rev = "f228f52542749ea89f4a7cffbc0682ed9ea4b8d1" }
sapling-crypto = { git = "https://github.com/zcash/sapling-crypto.git", rev = "29cff9683cdf2f0c522ff3224081dfb4fbc80248" }
3 changes: 3 additions & 0 deletions components/zcash_address/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ and this library adheres to Rust's notion of
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- `impl serde::{Serialize, Deserialize} for zcash_address::ZcashAddress` behind
the `serde` feature flag.

## [0.6.0] - 2024-10-02
### Changed
Expand Down
2 changes: 2 additions & 0 deletions components/zcash_address/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@ f4jumble = { version = "0.1", path = "../f4jumble" }
zcash_protocol.workspace = true
zcash_encoding.workspace = true
proptest = { workspace = true, optional = true }
serde = { workspace = true, optional = true }

[dev-dependencies]
assert_matches.workspace = true
proptest.workspace = true

[features]
test-dependencies = ["dep:proptest"]
serde = ["dep:serde"]

[lib]
bench = false
43 changes: 43 additions & 0 deletions components/zcash_address/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,49 @@ pub struct ZcashAddress {
kind: AddressKind,
}

#[cfg(feature = "serde")]
impl serde::Serialize for ZcashAddress {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&self.encode())
}
}

#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for ZcashAddress {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use std::fmt;
struct AddrVisitor;

impl<'de> serde::de::Visitor<'de> for AddrVisitor {
type Value = ZcashAddress;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a valid Zcash address string")
}

fn visit_str<E>(self, value: &str) -> Result<ZcashAddress, E>
where
E: serde::de::Error,
{
ZcashAddress::try_from_encoded(value).map_err(|_| {
serde::de::Error::invalid_value(
serde::de::Unexpected::Str(value),
&"a valid Zcash address string",
)
})
}
}

deserializer.deserialize_str(AddrVisitor)
}
}

/// Known kinds of Zcash addresses.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
enum AddressKind {
Expand Down
2 changes: 2 additions & 0 deletions pczt/src/roles/creator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ impl Creator {
| zcash_primitives::transaction::TxVersion::Overwinter => None,
zcash_primitives::transaction::TxVersion::Sapling => Some(SAPLING_TX_VERSION),
zcash_primitives::transaction::TxVersion::Zip225 => Some(V5_TX_VERSION),
#[cfg(zcash_unstable = "zfuture")]
zcash_primitives::transaction::TxVersion::ZFuture => None,
}?;

// Spends and outputs not modifiable.
Expand Down
2 changes: 2 additions & 0 deletions pczt/src/roles/signer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,8 @@ impl Authorization for EffectsOnly {
type TransparentAuth = transparent::EffectsOnly;
type SaplingAuth = sapling::bundle::EffectsOnly;
type OrchardAuth = orchard::bundle::EffectsOnly;
#[cfg(zcash_unstable = "zfuture")]
type TzeAuth = std::convert::Infallible;
}

/// Errors that can occur while creating signatures for a PCZT.
Expand Down
4 changes: 4 additions & 0 deletions pczt/src/roles/tx_extractor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ impl<'a> TransactionExtractor<'a> {
})
.transpose()
},
#[cfg(zcash_unstable = "zfuture")]
|_| unimplemented!("PCZT support for TZEs is not implemented."),
)?;

let tx = tx_data.freeze().expect("v5 tx can't fail here");
Expand All @@ -152,6 +154,8 @@ impl Authorization for Unbound {
type TransparentAuth = zcash_primitives::transaction::components::transparent::pczt::Unbound;
type SaplingAuth = ::sapling::pczt::Unbound;
type OrchardAuth = ::orchard::pczt::Unbound;
#[cfg(zcash_unstable = "zfuture")]
type TzeAuth = std::convert::Infallible;
}

/// Errors that can occur while extracting a transaction from a PCZT.
Expand Down
23 changes: 18 additions & 5 deletions pczt/tests/end_to_end.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use pczt::{
roles::{
combiner::Combiner, creator::Creator, io_finalizer::IoFinalizer, prover::Prover,
signer::Signer, spend_finalizer::SpendFinalizer, tx_extractor::TransactionExtractor,
updater::Updater,
},
Pczt,
};
Expand Down Expand Up @@ -49,6 +50,8 @@ fn transparent_to_orchard() {
let transparent_sk = transparent_account_sk
.derive_external_secret_key(address_index)
.unwrap();
let secp = secp256k1::Secp256k1::signing_only();
let transparent_pubkey = transparent_sk.public_key(&secp);

// Create an Orchard account to receive funds.
let orchard_sk = orchard::keys::SpendingKey::from_bytes([0; 32]).unwrap();
Expand All @@ -73,7 +76,7 @@ fn transparent_to_orchard() {
},
);
builder
.add_transparent_input(transparent_sk, utxo, coin)
.add_transparent_input(transparent_pubkey, utxo, coin)
.unwrap();
builder
.add_orchard_output::<zip317::FeeRule>(
Expand Down Expand Up @@ -157,7 +160,7 @@ fn sapling_to_orchard() {
.add_output(None, sapling_recipient, value, None)
.unwrap();
let (bundle, meta) = sapling_builder
.build::<LocalTxProver, LocalTxProver, _, i64>(&mut rng)
.build::<LocalTxProver, LocalTxProver, _, i64>(&[], &mut rng)
.unwrap()
.unwrap();
let output = bundle
Expand Down Expand Up @@ -201,7 +204,7 @@ fn sapling_to_orchard() {
},
);
builder
.add_sapling_spend::<zip317::FeeRule>(&sapling_extsk, note, merkle_path)
.add_sapling_spend::<zip317::FeeRule>(sapling_dfvk.fvk().clone(), note, merkle_path)
.unwrap();
builder
.add_orchard_output::<zip317::FeeRule>(
Expand Down Expand Up @@ -235,6 +238,17 @@ fn sapling_to_orchard() {
let pczt = IoFinalizer::new(pczt).finalize_io().unwrap();
check_round_trip(&pczt);

// Update the Sapling bundle with its proof generation key.
let index = sapling_meta.spend_index(0).unwrap();
let pczt = Updater::new(pczt)
.update_sapling_with(|mut updater| {
updater.update_spend_with(index, |mut spend_updater| {
spend_updater.set_proof_generation_key(sapling_extsk.expsk.proof_generation_key())
})
})
.unwrap()
.finish();

// To test the Combiner, we will create the Sapling proofs, Sapling signatures, and
// Orchard proof "in parallel".

Expand All @@ -258,7 +272,6 @@ fn sapling_to_orchard() {
let pczt = Pczt::parse(&pczt.serialize()).unwrap();

// Apply signatures.
let index = sapling_meta.spend_index(0).unwrap();
let mut signer = Signer::new(pczt).unwrap();
signer
.sign_sapling(index, &sapling_extsk.expsk.ask)
Expand Down Expand Up @@ -350,7 +363,7 @@ fn orchard_to_orchard() {
},
);
builder
.add_orchard_spend::<zip317::FeeRule>(&orchard_sk, note, merkle_path)
.add_orchard_spend::<zip317::FeeRule>(orchard_fvk.clone(), note, merkle_path)
.unwrap();
builder
.add_orchard_output::<zip317::FeeRule>(
Expand Down
6 changes: 6 additions & 0 deletions supply-chain/audits.toml
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,12 @@ who = "Kris Nuttycombe <[email protected]>"
criteria = "safe-to-deploy"
delta = "0.2.0 -> 0.3.0"

[[audits.zcash_note_encryption]]
who = "Kris Nuttycombe <[email protected]>"
criteria = "safe-to-deploy"
version = "0.4.1"
notes = "Additive-only change that exposes the ability to decrypt by pk_d and esk. No functional changes."

[[audits.zcash_primitives]]
who = "Kris Nuttycombe <[email protected]>"
criteria = "safe-to-deploy"
Expand Down
14 changes: 0 additions & 14 deletions supply-chain/imports.lock
Original file line number Diff line number Diff line change
Expand Up @@ -62,20 +62,6 @@ user-id = 169181
user-login = "nuttycom"
user-name = "Kris Nuttycombe"

[[publisher.orchard]]
version = "0.10.0"
when = "2024-10-02"
user-id = 169181
user-login = "nuttycom"
user-name = "Kris Nuttycombe"

[[publisher.sapling-crypto]]
version = "0.3.0"
when = "2024-10-02"
user-id = 169181
user-login = "nuttycom"
user-name = "Kris Nuttycombe"

[[publisher.schemerz]]
version = "0.2.0"
when = "2024-10-16"
Expand Down
11 changes: 10 additions & 1 deletion zcash_client_backend/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ and this library adheres to Rust's notion of
## [Unreleased]

### Added
- `zcash_client_backend::data_api::AccountSource::key_derivation`
- `zcash_client_backend::data_api`
- `AccountSource::key_derivation`
- `error::PcztError`
- `wallet::ExtractErrT`
- `wallet::create_pczt_from_proposal`
- `wallet::extract_and_store_transaction_from_pczt`

### Changed
- `zcash_client_backend::data_api::AccountBalance`: Refactored to use `Balance`
Expand All @@ -29,6 +34,10 @@ and this library adheres to Rust's notion of
- The `request` argument to `WalletRead::get_next_available_address` is now optional.
- `zcash_client_backend::data_api::Account` has an additional `name` method
that returns the human-readable name of the account, if any.
- `zcash_client_backend::data_api::error::Error` has new variants:
- `AccountIdNotRecognized`
- `AccountCannotSpend`
- `Pczt`

### Deprecated
- `AccountBalance::unshielded`. Instead use `unshielded_balance` which
Expand Down
18 changes: 18 additions & 0 deletions zcash_client_backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ zcash_primitives.workspace = true
zcash_protocol.workspace = true
zip32.workspace = true
zip321.workspace = true
pczt = { workspace = true, optional = true }

# Dependencies exposed in a public API:
# (Breaking upgrades to these require a breaking upgrade to this crate.)
Expand All @@ -47,6 +48,7 @@ rand_core.workspace = true
base64.workspace = true
bech32.workspace = true
bs58.workspace = true
postcard = { workspace = true, optional = true }

# - Errors
bip32 = { workspace = true, optional = true }
Expand Down Expand Up @@ -170,6 +172,22 @@ transparent-inputs = [
## Enables receiving and spending Orchard funds.
orchard = ["dep:orchard", "dep:pasta_curves", "zcash_keys/orchard"]

## Enables creating partially-constructed transactions for use in hardware wallet and multisig scenarios.
pczt = [
"orchard",
"transparent-inputs",
"pczt/zcp-builder",
"pczt/io-finalizer",
"pczt/prover",
"pczt/signer",
"pczt/spend-finalizer",
"pczt/tx-extractor",
"pczt/zcp-builder",
"dep:postcard",
"dep:serde",
"zcash_address/serde",
]

## Exposes a wallet synchronization function that implements the necessary state machine.
sync = [
"lightwalletd-tonic",
Expand Down
Loading

0 comments on commit 67fe5f8

Please sign in to comment.