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

PCZT improvements #1668

Merged
merged 2 commits into from
Dec 19, 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
5 changes: 5 additions & 0 deletions pczt/src/roles/signer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@ impl Signer {

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

/// Signs the Orchard spend at the given index with the given spend authorizing key.
///
/// Requires the spend's `fvk` field to be set (because the API does not take an FVK).
///
/// It is the caller's responsibility to perform any semantic validity checks on the
/// PCZT (for example, comfirming that the change amounts are correct) before calling
/// this method.
Expand Down
3 changes: 3 additions & 0 deletions zcash_transparent/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ and this library adheres to Rust's notion of
- `zcash_transparent::keys::AccountPubKey::derive_pubkey_at_bip32_path` now
returns the correct result for valid paths instead of an error or panic.

### Added
- `zcash_transparent::pczt::Bip32Derivation::extract_bip_44_fields`

## [0.1.0] - 2024-12-16

The entries below are relative to the `zcash_primitives` crate as of the tag
Expand Down
39 changes: 27 additions & 12 deletions zcash_transparent/src/keys.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
//! Transparent key components.

use alloc::string::ToString;
use alloc::vec::Vec;
use bip32::{
ChildNumber, ExtendedKey, ExtendedKeyAttrs, ExtendedPrivateKey, ExtendedPublicKey, Prefix,
};
use secp256k1::PublicKey;
use sha2::{Digest, Sha256};
use bip32::ChildNumber;
use subtle::{Choice, ConstantTimeEq};

use zcash_protocol::consensus::{self, NetworkConstants};
use zcash_spec::PrfExpand;
use zip32::AccountId;

use crate::address::TransparentAddress;
#[cfg(feature = "transparent-inputs")]
use {
crate::address::TransparentAddress,
alloc::string::ToString,
alloc::vec::Vec,
bip32::{ExtendedKey, ExtendedKeyAttrs, ExtendedPrivateKey, ExtendedPublicKey, Prefix},
secp256k1::PublicKey,
sha2::{Digest, Sha256},
zcash_protocol::consensus::{self, NetworkConstants},
zcash_spec::PrfExpand,
zip32::AccountId,
};

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

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

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

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

#[cfg(feature = "transparent-inputs")]
pub(crate) mod private {
use super::TransparentKeyScope;
use bip32::ExtendedPublicKey;
Expand All @@ -377,6 +384,7 @@ pub(crate) mod private {
///
/// [BIP32]: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
/// [BIP44]: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
#[cfg(feature = "transparent-inputs")]
pub trait IncomingViewingKey: private::SealedChangeLevelKey + core::marker::Sized {
/// Derives a transparent address at the provided child index.
#[allow(deprecated)]
Expand Down Expand Up @@ -438,9 +446,11 @@ pub trait IncomingViewingKey: private::SealedChangeLevelKey + core::marker::Size
/// This allows derivation of child addresses that may be provided to external parties.
///
/// [BIP44]: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
#[cfg(feature = "transparent-inputs")]
#[derive(Clone, Debug)]
pub struct ExternalIvk(ExtendedPublicKey<PublicKey>);

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

Expand All @@ -453,6 +463,7 @@ impl private::SealedChangeLevelKey for ExternalIvk {
}
}

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

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

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

Expand All @@ -477,12 +490,14 @@ impl private::SealedChangeLevelKey for InternalIvk {
}
}

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

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

Expand Down
4 changes: 1 addition & 3 deletions zcash_transparent/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@
pub mod address;
pub mod builder;
pub mod bundle;
pub mod keys;
pub mod pczt;
pub mod sighash;

#[cfg(feature = "transparent-inputs")]
pub mod keys;

#[cfg(test)]
mod test_vectors;

Expand Down
46 changes: 45 additions & 1 deletion zcash_transparent/src/pczt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@
use getset::Getters;
use zcash_protocol::{value::Zatoshis, TxId};

use crate::{address::Script, sighash::SighashType};
use crate::{
address::Script,
keys::{NonHardenedChildIndex, TransparentKeyScope},
sighash::SighashType,
};

mod parse;
pub use parse::ParseError;
Expand Down Expand Up @@ -230,3 +234,43 @@
/// The sequence of indices corresponding to the HD path.
derivation_path: Vec<ChildNumber>,
}

impl Bip32Derivation {
/// Extracts the BIP 44 account index, scope, and address index from this derivation
/// path.
///
/// Returns `None` if the seed fingerprints don't match, or if this is a non-standard
/// derivation path.
pub fn extract_bip_44_fields(

Check warning on line 244 in zcash_transparent/src/pczt.rs

View check run for this annotation

Codecov / codecov/patch

zcash_transparent/src/pczt.rs#L244

Added line #L244 was not covered by tests
&self,
seed_fp: &zip32::fingerprint::SeedFingerprint,
expected_coin_type: ChildNumber,
) -> Option<(zip32::AccountId, TransparentKeyScope, NonHardenedChildIndex)> {
if self.seed_fingerprint == seed_fp.to_bytes() {
match &self.derivation_path[..] {
[purpose, coin_type, account_index, scope, address_index]
if purpose == &ChildNumber(44 | ChildNumber::HARDENED_FLAG)
&& coin_type.is_hardened()
&& coin_type == &expected_coin_type
&& account_index.is_hardened()
&& !scope.is_hardened()
&& !address_index.is_hardened() =>

Check warning on line 257 in zcash_transparent/src/pczt.rs

View check run for this annotation

Codecov / codecov/patch

zcash_transparent/src/pczt.rs#L249-L257

Added lines #L249 - L257 were not covered by tests
{
let account_index = zip32::AccountId::try_from(account_index.index())

Check warning on line 259 in zcash_transparent/src/pczt.rs

View check run for this annotation

Codecov / codecov/patch

zcash_transparent/src/pczt.rs#L259

Added line #L259 was not covered by tests
.expect("account_index is hardened");

let scope =
TransparentKeyScope::custom(scope.index()).expect("scope is not hardened");

Check warning on line 263 in zcash_transparent/src/pczt.rs

View check run for this annotation

Codecov / codecov/patch

zcash_transparent/src/pczt.rs#L262-L263

Added lines #L262 - L263 were not covered by tests

let address_index = NonHardenedChildIndex::from_index(address_index.index())

Check warning on line 265 in zcash_transparent/src/pczt.rs

View check run for this annotation

Codecov / codecov/patch

zcash_transparent/src/pczt.rs#L265

Added line #L265 was not covered by tests
.expect("address_index is not hardened");

Some((account_index, scope, address_index))

Check warning on line 268 in zcash_transparent/src/pczt.rs

View check run for this annotation

Codecov / codecov/patch

zcash_transparent/src/pczt.rs#L268

Added line #L268 was not covered by tests
}
_ => None,

Check warning on line 270 in zcash_transparent/src/pczt.rs

View check run for this annotation

Codecov / codecov/patch

zcash_transparent/src/pczt.rs#L270

Added line #L270 was not covered by tests
}
} else {
None

Check warning on line 273 in zcash_transparent/src/pczt.rs

View check run for this annotation

Codecov / codecov/patch

zcash_transparent/src/pczt.rs#L273

Added line #L273 was not covered by tests
}
}
}
Loading