Merge pull request #1668 from zcash/pczt-improvements
PCZT improvements
This commit is contained in:
commit
eee19d90c3
|
@ -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.
|
||||
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
@ -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>'`.
|
||||
|
@ -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`.
|
||||
|
@ -344,6 +349,7 @@ 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(
|
||||
|
@ -351,6 +357,7 @@ pub fn pubkey_to_address(pubkey: &secp256k1::PublicKey) -> TransparentAddress {
|
|||
)
|
||||
}
|
||||
|
||||
#[cfg(feature = "transparent-inputs")]
|
||||
pub(crate) mod private {
|
||||
use super::TransparentKeyScope;
|
||||
use bip32::ExtendedPublicKey;
|
||||
|
@ -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)]
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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>);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -8,7 +8,11 @@ use bip32::ChildNumber;
|
|||
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;
|
||||
|
@ -230,3 +234,43 @@ pub struct Bip32Derivation {
|
|||
/// 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(
|
||||
&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() =>
|
||||
{
|
||||
let account_index = zip32::AccountId::try_from(account_index.index())
|
||||
.expect("account_index is hardened");
|
||||
|
||||
let scope =
|
||||
TransparentKeyScope::custom(scope.index()).expect("scope is not hardened");
|
||||
|
||||
let address_index = NonHardenedChildIndex::from_index(address_index.index())
|
||||
.expect("address_index is not hardened");
|
||||
|
||||
Some((account_index, scope, address_index))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue