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.
|
/// 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
|
/// 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
|
/// PCZT (for example, comfirming that the change amounts are correct) before calling
|
||||||
/// this method.
|
/// this method.
|
||||||
|
@ -179,6 +182,8 @@ impl Signer {
|
||||||
|
|
||||||
/// Signs the Orchard spend at the given index with the given spend authorizing key.
|
/// 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
|
/// 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
|
/// PCZT (for example, comfirming that the change amounts are correct) before calling
|
||||||
/// this method.
|
/// 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
|
- `zcash_transparent::keys::AccountPubKey::derive_pubkey_at_bip32_path` now
|
||||||
returns the correct result for valid paths instead of an error or panic.
|
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
|
## [0.1.0] - 2024-12-16
|
||||||
|
|
||||||
The entries below are relative to the `zcash_primitives` crate as of the tag
|
The entries below are relative to the `zcash_primitives` crate as of the tag
|
||||||
|
|
|
@ -1,19 +1,20 @@
|
||||||
//! Transparent key components.
|
//! Transparent key components.
|
||||||
|
|
||||||
use alloc::string::ToString;
|
use bip32::ChildNumber;
|
||||||
use alloc::vec::Vec;
|
|
||||||
use bip32::{
|
|
||||||
ChildNumber, ExtendedKey, ExtendedKeyAttrs, ExtendedPrivateKey, ExtendedPublicKey, Prefix,
|
|
||||||
};
|
|
||||||
use secp256k1::PublicKey;
|
|
||||||
use sha2::{Digest, Sha256};
|
|
||||||
use subtle::{Choice, ConstantTimeEq};
|
use subtle::{Choice, ConstantTimeEq};
|
||||||
|
|
||||||
use zcash_protocol::consensus::{self, NetworkConstants};
|
#[cfg(feature = "transparent-inputs")]
|
||||||
use zcash_spec::PrfExpand;
|
use {
|
||||||
use zip32::AccountId;
|
crate::address::TransparentAddress,
|
||||||
|
alloc::string::ToString,
|
||||||
use crate::address::TransparentAddress;
|
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.
|
/// 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
|
/// [BIP44]: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
pub struct AccountPrivKey(ExtendedPrivateKey<secp256k1::SecretKey>);
|
pub struct AccountPrivKey(ExtendedPrivateKey<secp256k1::SecretKey>);
|
||||||
|
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
impl AccountPrivKey {
|
impl AccountPrivKey {
|
||||||
/// Performs derivation of the extended private key for the BIP44 path:
|
/// Performs derivation of the extended private key for the BIP44 path:
|
||||||
/// `m/44'/<coin_type>'/<account>'`.
|
/// `m/44'/<coin_type>'/<account>'`.
|
||||||
|
@ -221,9 +224,11 @@ impl AccountPrivKey {
|
||||||
/// full viewing key.
|
/// full viewing key.
|
||||||
///
|
///
|
||||||
/// [BIP44]: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
|
/// [BIP44]: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct AccountPubKey(ExtendedPublicKey<PublicKey>);
|
pub struct AccountPubKey(ExtendedPublicKey<PublicKey>);
|
||||||
|
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
impl AccountPubKey {
|
impl AccountPubKey {
|
||||||
/// Derives the BIP44 public key at the external "change level" path
|
/// Derives the BIP44 public key at the external "change level" path
|
||||||
/// `m/44'/<coin_type>'/<account>'/0`.
|
/// `m/44'/<coin_type>'/<account>'/0`.
|
||||||
|
@ -344,6 +349,7 @@ impl AccountPubKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Derives the P2PKH transparent address corresponding to the given pubkey.
|
/// 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.")]
|
#[deprecated(note = "This function will be removed from the public API in an upcoming refactor.")]
|
||||||
pub fn pubkey_to_address(pubkey: &secp256k1::PublicKey) -> TransparentAddress {
|
pub fn pubkey_to_address(pubkey: &secp256k1::PublicKey) -> TransparentAddress {
|
||||||
TransparentAddress::PublicKeyHash(
|
TransparentAddress::PublicKeyHash(
|
||||||
|
@ -351,6 +357,7 @@ pub fn pubkey_to_address(pubkey: &secp256k1::PublicKey) -> TransparentAddress {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
pub(crate) mod private {
|
pub(crate) mod private {
|
||||||
use super::TransparentKeyScope;
|
use super::TransparentKeyScope;
|
||||||
use bip32::ExtendedPublicKey;
|
use bip32::ExtendedPublicKey;
|
||||||
|
@ -377,6 +384,7 @@ pub(crate) mod private {
|
||||||
///
|
///
|
||||||
/// [BIP32]: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
|
/// [BIP32]: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
|
||||||
/// [BIP44]: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
|
/// [BIP44]: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
pub trait IncomingViewingKey: private::SealedChangeLevelKey + core::marker::Sized {
|
pub trait IncomingViewingKey: private::SealedChangeLevelKey + core::marker::Sized {
|
||||||
/// Derives a transparent address at the provided child index.
|
/// Derives a transparent address at the provided child index.
|
||||||
#[allow(deprecated)]
|
#[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.
|
/// This allows derivation of child addresses that may be provided to external parties.
|
||||||
///
|
///
|
||||||
/// [BIP44]: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
|
/// [BIP44]: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ExternalIvk(ExtendedPublicKey<PublicKey>);
|
pub struct ExternalIvk(ExtendedPublicKey<PublicKey>);
|
||||||
|
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
impl private::SealedChangeLevelKey for ExternalIvk {
|
impl private::SealedChangeLevelKey for ExternalIvk {
|
||||||
const SCOPE: TransparentKeyScope = TransparentKeyScope(0);
|
const SCOPE: TransparentKeyScope = TransparentKeyScope(0);
|
||||||
|
|
||||||
|
@ -453,6 +463,7 @@ impl private::SealedChangeLevelKey for ExternalIvk {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
impl IncomingViewingKey for ExternalIvk {}
|
impl IncomingViewingKey for ExternalIvk {}
|
||||||
|
|
||||||
/// An incoming viewing key at the [BIP44] "internal" path
|
/// An incoming viewing key at the [BIP44] "internal" path
|
||||||
|
@ -462,9 +473,11 @@ impl IncomingViewingKey for ExternalIvk {}
|
||||||
/// not be shared with external parties.
|
/// not be shared with external parties.
|
||||||
///
|
///
|
||||||
/// [BIP44]: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
|
/// [BIP44]: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct InternalIvk(ExtendedPublicKey<PublicKey>);
|
pub struct InternalIvk(ExtendedPublicKey<PublicKey>);
|
||||||
|
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
impl private::SealedChangeLevelKey for InternalIvk {
|
impl private::SealedChangeLevelKey for InternalIvk {
|
||||||
const SCOPE: TransparentKeyScope = TransparentKeyScope(1);
|
const SCOPE: TransparentKeyScope = TransparentKeyScope(1);
|
||||||
|
|
||||||
|
@ -477,12 +490,14 @@ impl private::SealedChangeLevelKey for InternalIvk {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
impl IncomingViewingKey for InternalIvk {}
|
impl IncomingViewingKey for InternalIvk {}
|
||||||
|
|
||||||
/// An incoming viewing key at the "ephemeral" path
|
/// An incoming viewing key at the "ephemeral" path
|
||||||
/// `m/44'/<coin_type>'/<account>'/2`.
|
/// `m/44'/<coin_type>'/<account>'/2`.
|
||||||
///
|
///
|
||||||
/// This allows derivation of ephemeral addresses for use within the wallet.
|
/// This allows derivation of ephemeral addresses for use within the wallet.
|
||||||
|
#[cfg(feature = "transparent-inputs")]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct EphemeralIvk(ExtendedPublicKey<PublicKey>);
|
pub struct EphemeralIvk(ExtendedPublicKey<PublicKey>);
|
||||||
|
|
||||||
|
|
|
@ -9,12 +9,10 @@
|
||||||
pub mod address;
|
pub mod address;
|
||||||
pub mod builder;
|
pub mod builder;
|
||||||
pub mod bundle;
|
pub mod bundle;
|
||||||
|
pub mod keys;
|
||||||
pub mod pczt;
|
pub mod pczt;
|
||||||
pub mod sighash;
|
pub mod sighash;
|
||||||
|
|
||||||
#[cfg(feature = "transparent-inputs")]
|
|
||||||
pub mod keys;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test_vectors;
|
mod test_vectors;
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,11 @@ use bip32::ChildNumber;
|
||||||
use getset::Getters;
|
use getset::Getters;
|
||||||
use zcash_protocol::{value::Zatoshis, TxId};
|
use zcash_protocol::{value::Zatoshis, TxId};
|
||||||
|
|
||||||
use crate::{address::Script, sighash::SighashType};
|
use crate::{
|
||||||
|
address::Script,
|
||||||
|
keys::{NonHardenedChildIndex, TransparentKeyScope},
|
||||||
|
sighash::SighashType,
|
||||||
|
};
|
||||||
|
|
||||||
mod parse;
|
mod parse;
|
||||||
pub use parse::ParseError;
|
pub use parse::ParseError;
|
||||||
|
@ -230,3 +234,43 @@ pub struct Bip32Derivation {
|
||||||
/// The sequence of indices corresponding to the HD path.
|
/// The sequence of indices corresponding to the HD path.
|
||||||
derivation_path: Vec<ChildNumber>,
|
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