Skip to content

Commit eee19d9

Browse files
authored
Merge pull request zcash#1668 from zcash/pczt-improvements
PCZT improvements
2 parents 02d18ec + 2bce3ce commit eee19d9

File tree

5 files changed

+81
-16
lines changed

5 files changed

+81
-16
lines changed

pczt/src/roles/signer/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,9 @@ impl Signer {
139139

140140
/// Signs the Sapling spend at the given index with the given spend authorizing key.
141141
///
142+
/// Requires the spend's `proof_generation_key` field to be set (because the API does
143+
/// not take an FVK).
144+
///
142145
/// It is the caller's responsibility to perform any semantic validity checks on the
143146
/// PCZT (for example, comfirming that the change amounts are correct) before calling
144147
/// this method.
@@ -179,6 +182,8 @@ impl Signer {
179182

180183
/// Signs the Orchard spend at the given index with the given spend authorizing key.
181184
///
185+
/// Requires the spend's `fvk` field to be set (because the API does not take an FVK).
186+
///
182187
/// It is the caller's responsibility to perform any semantic validity checks on the
183188
/// PCZT (for example, comfirming that the change amounts are correct) before calling
184189
/// this method.

zcash_transparent/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ and this library adheres to Rust's notion of
1111
- `zcash_transparent::keys::AccountPubKey::derive_pubkey_at_bip32_path` now
1212
returns the correct result for valid paths instead of an error or panic.
1313

14+
### Added
15+
- `zcash_transparent::pczt::Bip32Derivation::extract_bip_44_fields`
16+
1417
## [0.1.0] - 2024-12-16
1518

1619
The entries below are relative to the `zcash_primitives` crate as of the tag

zcash_transparent/src/keys.rs

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
//! Transparent key components.
22
3-
use alloc::string::ToString;
4-
use alloc::vec::Vec;
5-
use bip32::{
6-
ChildNumber, ExtendedKey, ExtendedKeyAttrs, ExtendedPrivateKey, ExtendedPublicKey, Prefix,
7-
};
8-
use secp256k1::PublicKey;
9-
use sha2::{Digest, Sha256};
3+
use bip32::ChildNumber;
104
use subtle::{Choice, ConstantTimeEq};
115

12-
use zcash_protocol::consensus::{self, NetworkConstants};
13-
use zcash_spec::PrfExpand;
14-
use zip32::AccountId;
15-
16-
use crate::address::TransparentAddress;
6+
#[cfg(feature = "transparent-inputs")]
7+
use {
8+
crate::address::TransparentAddress,
9+
alloc::string::ToString,
10+
alloc::vec::Vec,
11+
bip32::{ExtendedKey, ExtendedKeyAttrs, ExtendedPrivateKey, ExtendedPublicKey, Prefix},
12+
secp256k1::PublicKey,
13+
sha2::{Digest, Sha256},
14+
zcash_protocol::consensus::{self, NetworkConstants},
15+
zcash_spec::PrfExpand,
16+
zip32::AccountId,
17+
};
1718

1819
/// The scope of a transparent key.
1920
///
@@ -123,8 +124,10 @@ impl From<NonHardenedChildIndex> for ChildNumber {
123124
///
124125
/// [BIP44]: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
125126
#[derive(Clone, Debug)]
127+
#[cfg(feature = "transparent-inputs")]
126128
pub struct AccountPrivKey(ExtendedPrivateKey<secp256k1::SecretKey>);
127129

130+
#[cfg(feature = "transparent-inputs")]
128131
impl AccountPrivKey {
129132
/// Performs derivation of the extended private key for the BIP44 path:
130133
/// `m/44'/<coin_type>'/<account>'`.
@@ -221,9 +224,11 @@ impl AccountPrivKey {
221224
/// full viewing key.
222225
///
223226
/// [BIP44]: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
227+
#[cfg(feature = "transparent-inputs")]
224228
#[derive(Clone, Debug)]
225229
pub struct AccountPubKey(ExtendedPublicKey<PublicKey>);
226230

231+
#[cfg(feature = "transparent-inputs")]
227232
impl AccountPubKey {
228233
/// Derives the BIP44 public key at the external "change level" path
229234
/// `m/44'/<coin_type>'/<account>'/0`.
@@ -344,13 +349,15 @@ impl AccountPubKey {
344349
}
345350

346351
/// Derives the P2PKH transparent address corresponding to the given pubkey.
352+
#[cfg(feature = "transparent-inputs")]
347353
#[deprecated(note = "This function will be removed from the public API in an upcoming refactor.")]
348354
pub fn pubkey_to_address(pubkey: &secp256k1::PublicKey) -> TransparentAddress {
349355
TransparentAddress::PublicKeyHash(
350356
*ripemd::Ripemd160::digest(Sha256::digest(pubkey.serialize())).as_ref(),
351357
)
352358
}
353359

360+
#[cfg(feature = "transparent-inputs")]
354361
pub(crate) mod private {
355362
use super::TransparentKeyScope;
356363
use bip32::ExtendedPublicKey;
@@ -377,6 +384,7 @@ pub(crate) mod private {
377384
///
378385
/// [BIP32]: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
379386
/// [BIP44]: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
387+
#[cfg(feature = "transparent-inputs")]
380388
pub trait IncomingViewingKey: private::SealedChangeLevelKey + core::marker::Sized {
381389
/// Derives a transparent address at the provided child index.
382390
#[allow(deprecated)]
@@ -438,9 +446,11 @@ pub trait IncomingViewingKey: private::SealedChangeLevelKey + core::marker::Size
438446
/// This allows derivation of child addresses that may be provided to external parties.
439447
///
440448
/// [BIP44]: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
449+
#[cfg(feature = "transparent-inputs")]
441450
#[derive(Clone, Debug)]
442451
pub struct ExternalIvk(ExtendedPublicKey<PublicKey>);
443452

453+
#[cfg(feature = "transparent-inputs")]
444454
impl private::SealedChangeLevelKey for ExternalIvk {
445455
const SCOPE: TransparentKeyScope = TransparentKeyScope(0);
446456

@@ -453,6 +463,7 @@ impl private::SealedChangeLevelKey for ExternalIvk {
453463
}
454464
}
455465

466+
#[cfg(feature = "transparent-inputs")]
456467
impl IncomingViewingKey for ExternalIvk {}
457468

458469
/// An incoming viewing key at the [BIP44] "internal" path
@@ -462,9 +473,11 @@ impl IncomingViewingKey for ExternalIvk {}
462473
/// not be shared with external parties.
463474
///
464475
/// [BIP44]: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
476+
#[cfg(feature = "transparent-inputs")]
465477
#[derive(Clone, Debug)]
466478
pub struct InternalIvk(ExtendedPublicKey<PublicKey>);
467479

480+
#[cfg(feature = "transparent-inputs")]
468481
impl private::SealedChangeLevelKey for InternalIvk {
469482
const SCOPE: TransparentKeyScope = TransparentKeyScope(1);
470483

@@ -477,12 +490,14 @@ impl private::SealedChangeLevelKey for InternalIvk {
477490
}
478491
}
479492

493+
#[cfg(feature = "transparent-inputs")]
480494
impl IncomingViewingKey for InternalIvk {}
481495

482496
/// An incoming viewing key at the "ephemeral" path
483497
/// `m/44'/<coin_type>'/<account>'/2`.
484498
///
485499
/// This allows derivation of ephemeral addresses for use within the wallet.
500+
#[cfg(feature = "transparent-inputs")]
486501
#[derive(Clone, Debug)]
487502
pub struct EphemeralIvk(ExtendedPublicKey<PublicKey>);
488503

zcash_transparent/src/lib.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,10 @@
99
pub mod address;
1010
pub mod builder;
1111
pub mod bundle;
12+
pub mod keys;
1213
pub mod pczt;
1314
pub mod sighash;
1415

15-
#[cfg(feature = "transparent-inputs")]
16-
pub mod keys;
17-
1816
#[cfg(test)]
1917
mod test_vectors;
2018

zcash_transparent/src/pczt.rs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ use bip32::ChildNumber;
88
use getset::Getters;
99
use zcash_protocol::{value::Zatoshis, TxId};
1010

11-
use crate::{address::Script, sighash::SighashType};
11+
use crate::{
12+
address::Script,
13+
keys::{NonHardenedChildIndex, TransparentKeyScope},
14+
sighash::SighashType,
15+
};
1216

1317
mod parse;
1418
pub use parse::ParseError;
@@ -230,3 +234,43 @@ pub struct Bip32Derivation {
230234
/// The sequence of indices corresponding to the HD path.
231235
derivation_path: Vec<ChildNumber>,
232236
}
237+
238+
impl Bip32Derivation {
239+
/// Extracts the BIP 44 account index, scope, and address index from this derivation
240+
/// path.
241+
///
242+
/// Returns `None` if the seed fingerprints don't match, or if this is a non-standard
243+
/// derivation path.
244+
pub fn extract_bip_44_fields(
245+
&self,
246+
seed_fp: &zip32::fingerprint::SeedFingerprint,
247+
expected_coin_type: ChildNumber,
248+
) -> Option<(zip32::AccountId, TransparentKeyScope, NonHardenedChildIndex)> {
249+
if self.seed_fingerprint == seed_fp.to_bytes() {
250+
match &self.derivation_path[..] {
251+
[purpose, coin_type, account_index, scope, address_index]
252+
if purpose == &ChildNumber(44 | ChildNumber::HARDENED_FLAG)
253+
&& coin_type.is_hardened()
254+
&& coin_type == &expected_coin_type
255+
&& account_index.is_hardened()
256+
&& !scope.is_hardened()
257+
&& !address_index.is_hardened() =>
258+
{
259+
let account_index = zip32::AccountId::try_from(account_index.index())
260+
.expect("account_index is hardened");
261+
262+
let scope =
263+
TransparentKeyScope::custom(scope.index()).expect("scope is not hardened");
264+
265+
let address_index = NonHardenedChildIndex::from_index(address_index.index())
266+
.expect("address_index is not hardened");
267+
268+
Some((account_index, scope, address_index))
269+
}
270+
_ => None,
271+
}
272+
} else {
273+
None
274+
}
275+
}
276+
}

0 commit comments

Comments
 (0)