Merge pull request #1043 from zcash/zip32-refactor

Refactor ZIP 32 code
This commit is contained in:
str4d 2023-11-28 03:18:36 +00:00 committed by GitHub
commit 2f2401d144
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 490 additions and 560 deletions

View File

@ -9,6 +9,7 @@ use zcash_primitives::{
self,
note_encryption::{try_sapling_note_decryption, PreparedIncomingViewingKey},
prover::{OutputProver, SpendProver},
zip32::{DiversifiableFullViewingKey, ExtendedSpendingKey},
Node,
},
transaction::{
@ -17,7 +18,7 @@ use zcash_primitives::{
fees::{zip317::FeeError as Zip317FeeError, FeeRule, StandardFeeRule},
Transaction, TxId,
},
zip32::{sapling::DiversifiableFullViewingKey, sapling::ExtendedSpendingKey, AccountId, Scope},
zip32::{AccountId, Scope},
};
use crate::{

View File

@ -28,7 +28,7 @@ use {
};
pub mod sapling {
pub use zcash_primitives::zip32::sapling::{
pub use zcash_primitives::sapling::zip32::{
DiversifiableFullViewingKey, ExtendedFullViewingKey, ExtendedSpendingKey,
};
use zcash_primitives::zip32::{AccountId, ChildIndex};
@ -62,9 +62,9 @@ pub mod sapling {
ExtendedSpendingKey::from_path(
&ExtendedSpendingKey::master(seed),
&[
ChildIndex::Hardened(32),
ChildIndex::Hardened(coin_type),
ChildIndex::Hardened(account.into()),
ChildIndex::hardened(32),
ChildIndex::hardened(coin_type),
account.into(),
],
)
}

View File

@ -13,9 +13,10 @@ use zcash_primitives::{
sapling::{
self,
note_encryption::{CompactOutputDescription, PreparedIncomingViewingKey, SaplingDomain},
zip32::DiversifiableFullViewingKey,
SaplingIvk,
},
zip32::{sapling::DiversifiableFullViewingKey, AccountId, Scope},
zip32::{AccountId, Scope},
};
use crate::data_api::{BlockMetadata, ScannedBlock, ShieldedProtocol};

View File

@ -49,6 +49,7 @@ use zcash_primitives::{
note_encryption::{sapling_note_encryption, SaplingDomain},
util::generate_random_rseed,
value::NoteValue,
zip32::DiversifiableFullViewingKey,
Note, Nullifier, PaymentAddress,
},
transaction::{
@ -56,7 +57,7 @@ use zcash_primitives::{
fees::{zip317::FeeError as Zip317FeeError, FeeRule, StandardFeeRule},
Transaction, TxId,
},
zip32::{sapling::DiversifiableFullViewingKey, DiversifierIndex},
zip32::DiversifierIndex,
};
use crate::{

View File

@ -176,8 +176,9 @@ mod tests {
use zcash_primitives::{
consensus::{self, BlockHeight, BranchId, Network, NetworkUpgrade, Parameters},
sapling::zip32::ExtendedFullViewingKey,
transaction::{TransactionData, TxVersion},
zip32::{sapling::ExtendedFullViewingKey, AccountId},
zip32::AccountId,
};
use crate::{testing::TestBuilder, wallet::scanning::priority_code, WalletDb};

View File

@ -429,6 +429,7 @@ pub(crate) mod tests {
sapling::{
note_encryption::try_sapling_output_recovery,
prover::{OutputProver, SpendProver},
zip32::ExtendedSpendingKey,
Node, Note, PaymentAddress,
},
transaction::{
@ -438,7 +439,7 @@ pub(crate) mod tests {
},
Transaction,
},
zip32::{sapling::ExtendedSpendingKey, Scope},
zip32::Scope,
};
use zcash_client_backend::{

View File

@ -54,6 +54,7 @@ and this library adheres to Rust's notion of
- `ValueCommitTrapdoor::from_bytes`
- `impl Sub<TrapdoorSum> for TrapdoorSum`
- `impl Sub<CommitmentSum> for CommitmentSum`
- `zip32` module (moved from `zcash_primitives::zip32::sapling`).
- `impl Debug for keys::{ExpandedSpendingKey, ProofGenerationKey}`
- `zcash_primitives::transaction`:
- `builder::get_fee`
@ -71,6 +72,12 @@ and this library adheres to Rust's notion of
- `GRACE_ACTIONS`
- `P2PKH_STANDARD_INPUT_SIZE`
- `P2PKH_STANDARD_OUTPUT_SIZE`
- `zcash_primitives::zip32`:
- `ChildIndex::hardened`
- `ChildIndex::index`
- `ChainCode::new`
- `ChainCode::as_bytes`
- `impl From<AccountId> for ChildIndex`
- Test helpers, behind the `test-dependencies` feature flag:
- `zcash_primitives::sapling::prover::mock::{MockSpendProver, MockOutputProver}`
- Additions related to `zcash_primitive::components::amount::Amount`
@ -120,6 +127,7 @@ and this library adheres to Rust's notion of
- `bundle::MapAuth` trait methods now take `&mut self` instead of `&self`.
- `circuit::ValueCommitmentOpening::value` is now represented as a `NoteValue`
instead of as a bare `u64`.
- `keys::DecodingError` has a new variant `UnsupportedChildIndex`.
- `note_encryption`:
- `SaplingDomain` no longer has a `P: consensus::Parameters` type parameter.
- The following methods now take a `Zip212Enforcement` argument instead of a
@ -154,6 +162,9 @@ and this library adheres to Rust's notion of
- `fees::fixed::FeeRule::fixed_fee`
- `fees::zip317::FeeRule::marginal_fee`
- `sighash::TransparentAuthorizingContext::input_amounts`
- `zcash_primitives::zip32`:
- `ChildIndex` has been changed from an enum to an opaque struct, and no
longer supports non-hardened indices.
### Removed
- `zcash_primitives::constants`:
@ -187,6 +198,11 @@ and this library adheres to Rust's notion of
- `Bundle::<Unauthorized>::apply_signatures` (use
`Bundle::<InProgress<Proven, Unsigned>>::apply_signatures` instead).
- `impl From<zcash_primitive::components::transaction::Amount> for u64`
- `zcash_primitives::zip32`:
- `sapling` module (moved from `zcash_primitives::sapling::zip32`).
- `ChildIndex::Hardened` (use `ChildIndex::hardened` instead).
- `ChildIndex::NonHardened`
- `sapling::ExtendedFullViewingKey::derive_child`
## [0.13.0] - 2023-09-25
### Added

View File

@ -17,6 +17,7 @@ mod tree;
pub mod util;
pub mod value;
mod verifier;
pub mod zip32;
use group::GroupEncoding;
use rand_core::{CryptoRng, RngCore};

View File

@ -865,17 +865,15 @@ pub mod testing {
use proptest::prelude::*;
use rand::{rngs::StdRng, SeedableRng};
use crate::{
sapling::{
bundle::{Authorized, Bundle},
note_encryption::Zip212Enforcement,
prover::mock::{MockOutputProver, MockSpendProver},
redjubjub::PrivateKey,
testing::{arb_node, arb_note},
value::testing::arb_positive_note_value,
Diversifier,
},
zip32::sapling::testing::arb_extended_spending_key,
use crate::sapling::{
bundle::{Authorized, Bundle},
note_encryption::Zip212Enforcement,
prover::mock::{MockOutputProver, MockSpendProver},
redjubjub::PrivateKey,
testing::{arb_node, arb_note},
value::testing::arb_positive_note_value,
zip32::testing::arb_extended_spending_key,
Diversifier,
};
use incrementalmerkletree::{
frontier::testing::arb_commitment_tree, witness::IncrementalWitness,

View File

@ -33,6 +33,9 @@ pub enum DecodingError {
InvalidAsk,
/// Could not decode the `nsk` bytes to a jubjub field element.
InvalidNsk,
/// An extended spending key had an unsupported child index: either a non-hardened
/// index, or a non-zero index at depth 0.
UnsupportedChildIndex,
}
/// An outgoing viewing key
@ -101,7 +104,9 @@ impl ExpandedSpendingKey {
DecodingError::InvalidNsk => {
io::Error::new(io::ErrorKind::InvalidData, "nsk not in field")
}
DecodingError::LengthInvalid { .. } => unreachable!(),
DecodingError::LengthInvalid { .. } | DecodingError::UnsupportedChildIndex => {
unreachable!()
}
})
}

View File

@ -5,12 +5,10 @@
use memuse::{self, DynamicUsage};
use subtle::{Choice, ConditionallySelectable};
use crate::sapling::{Diversifier, NullifierDerivingKey, PaymentAddress, ViewingKey};
pub mod fingerprint;
pub mod sapling;
#[deprecated(note = "Please use the types exported from the `zip32::sapling` module instead.")]
pub use sapling::{
pub use crate::sapling::zip32::{
sapling_address, sapling_default_address, sapling_derive_internal_fvk, sapling_find_address,
DiversifiableFullViewingKey, ExtendedFullViewingKey, ExtendedSpendingKey,
ZIP32_SAPLING_FVFP_PERSONALIZATION, ZIP32_SAPLING_INT_PERSONALIZATION,
@ -35,6 +33,13 @@ impl From<AccountId> for u32 {
}
}
impl From<AccountId> for ChildIndex {
fn from(id: AccountId) -> Self {
// Account IDs are always hardened in derivation paths.
ChildIndex::hardened(id.0)
}
}
impl ConditionallySelectable for AccountId {
fn conditional_select(a0: &Self, a1: &Self, c: Choice) -> Self {
AccountId(u32::conditional_select(&a0.0, &a1.0, c))
@ -43,41 +48,54 @@ impl ConditionallySelectable for AccountId {
// ZIP 32 structures
/// A child index for a derived key
/// A child index for a derived key.
///
/// Only hardened derivation is supported.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ChildIndex {
NonHardened(u32),
Hardened(u32), // Hardened(n) == n + (1 << 31) == n' in path notation
}
pub struct ChildIndex(u32);
impl ChildIndex {
pub fn from_index(i: u32) -> Self {
match i {
n if n >= (1 << 31) => ChildIndex::Hardened(n - (1 << 31)),
n => ChildIndex::NonHardened(n),
/// Parses the given ZIP 32 child index.
///
/// Returns `None` if the hardened bit is not set.
pub fn from_index(i: u32) -> Option<Self> {
if i >= (1 << 31) {
Some(ChildIndex(i))
} else {
None
}
}
fn master() -> Self {
ChildIndex::from_index(0)
/// Constructs a hardened `ChildIndex` from the given value.
///
/// # Panics
///
/// Panics if `value >= (1 << 31)`.
pub const fn hardened(value: u32) -> Self {
assert!(value < (1 << 31));
Self(value + (1 << 31))
}
fn value(&self) -> u32 {
match *self {
ChildIndex::Hardened(i) => i + (1 << 31),
ChildIndex::NonHardened(i) => i,
}
/// Returns the index as a 32-bit integer, including the hardened bit.
pub fn index(&self) -> u32 {
self.0
}
}
/// A BIP-32 chain code
/// A value that is needed, in addition to a spending key, in order to derive descendant
/// keys and addresses of that key.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ChainCode([u8; 32]);
impl ChainCode {
/// Returns byte representation of the chain code, as required for
/// Constructs a `ChainCode` from the given array.
pub fn new(c: [u8; 32]) -> Self {
Self(c)
}
/// Returns the byte representation of the chain code, as required for
/// [ZIP 32](https://zips.z.cash/zip-0032) encoding.
fn as_bytes(&self) -> &[u8; 32] {
pub fn as_bytes(&self) -> &[u8; 32] {
&self.0
}
}