Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zcash_client_backend PCZT support #1635

Merged
merged 14 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@
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())

Check warning on line 161 in components/zcash_address/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

components/zcash_address/src/lib.rs#L161

Added line #L161 was not covered by tests
}
}

#[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 {

Check warning on line 174 in components/zcash_address/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

components/zcash_address/src/lib.rs#L174

Added line #L174 was not covered by tests
type Value = ZcashAddress;

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

Check warning on line 178 in components/zcash_address/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

components/zcash_address/src/lib.rs#L177-L178

Added lines #L177 - L178 were not covered by tests
}

fn visit_str<E>(self, value: &str) -> Result<ZcashAddress, E>

Check warning on line 181 in components/zcash_address/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

components/zcash_address/src/lib.rs#L181

Added line #L181 was not covered by tests
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",

Check warning on line 188 in components/zcash_address/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

components/zcash_address/src/lib.rs#L185-L188

Added lines #L185 - L188 were not covered by tests
)
})
}
}

deserializer.deserialize_str(AddrVisitor)

Check warning on line 194 in components/zcash_address/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

components/zcash_address/src/lib.rs#L194

Added line #L194 was not covered by tests
}
}

/// Known kinds of Zcash addresses.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
enum AddressKind {
Expand Down
6 changes: 2 additions & 4 deletions devtools/src/bin/inspect/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use zcash_address::{
unified::{self, Encoding},
ToAddress, ZcashAddress,
};
use zcash_keys::keys::{UnifiedAddressRequest, UnifiedFullViewingKey};
use zcash_keys::keys::UnifiedFullViewingKey;
use zcash_primitives::{
legacy::{
keys::{AccountPrivKey, IncomingViewingKey},
Expand Down Expand Up @@ -220,9 +220,7 @@ pub(crate) fn inspect_sapling_extsk(
};
eprintln!("- UFVK: {encoded_ufvk}");

let (default_ua, _) = ufvk
.default_address(UnifiedAddressRequest::unsafe_new(false, true, false))
.expect("should exist");
let (default_ua, _) = ufvk.default_address(None).expect("should exist");
let encoded_ua = match network {
NetworkType::Main => default_ua.encode(&Network::MainNetwork),
NetworkType::Test => default_ua.encode(&Network::TestNetwork),
Expand Down
6 changes: 2 additions & 4 deletions devtools/src/bin/inspect/keys/view.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use bech32::{FromBase32, ToBase32};
use zcash_address::unified::{self, Container, Encoding};
use zcash_keys::keys::{UnifiedAddressRequest, UnifiedFullViewingKey};
use zcash_keys::keys::UnifiedFullViewingKey;
use zcash_protocol::{
consensus::{Network, NetworkConstants, NetworkType},
local_consensus::LocalNetwork,
Expand Down Expand Up @@ -138,9 +138,7 @@ pub(crate) fn inspect_sapling_extfvk(
};
eprintln!("- Equivalent UFVK: {encoded_ufvk}");

let (default_ua, _) = ufvk
.default_address(UnifiedAddressRequest::unsafe_new(false, true, false))
.expect("should exist");
let (default_ua, _) = ufvk.default_address(None).expect("should exist");
let encoded_ua = match network {
NetworkType::Main => default_ua.encode(&Network::MainNetwork),
NetworkType::Test => default_ua.encode(&Network::TestNetwork),
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 @@
| 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,

Check warning on line 117 in pczt/src/roles/creator/mod.rs

View check run for this annotation

Codecov / codecov/patch

pczt/src/roles/creator/mod.rs#L117

Added line #L117 was not covered by tests
daira marked this conversation as resolved.
Show resolved Hide resolved
}?;

// 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 @@
})
.transpose()
},
#[cfg(zcash_unstable = "zfuture")]
|_| unimplemented!("PCZT support for TZEs is not implemented."),

Check warning on line 130 in pczt/src/roles/tx_extractor/mod.rs

View check run for this annotation

Codecov / codecov/patch

pczt/src/roles/tx_extractor/mod.rs#L129-L130

Added lines #L129 - L130 were not covered by tests
)?;

let tx = tx_data.freeze().expect("v5 tx can't fail here");
Expand All @@ -152,6 +154,8 @@
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
12 changes: 11 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 @@ -26,8 +31,13 @@ and this library adheres to Rust's notion of
additional `key_source` field that is used to convey application-specific
key source metadata.
- The `Copy` impl for this type has been removed.
- 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
Loading
Loading