Add `UnifiedAddress` generation to `UnifiedFullViewingKey`
This commit is contained in:
parent
ed6016857e
commit
555a621a10
|
@ -1,8 +1,16 @@
|
|||
//! Helper functions for managing light client key material.
|
||||
use zcash_primitives::{consensus, zip32::AccountId};
|
||||
use zcash_primitives::{
|
||||
consensus,
|
||||
zip32::{AccountId, DiversifierIndex},
|
||||
};
|
||||
|
||||
use crate::address::UnifiedAddress;
|
||||
|
||||
#[cfg(feature = "transparent-inputs")]
|
||||
use zcash_primitives::legacy::keys as legacy;
|
||||
use std::convert::TryInto;
|
||||
|
||||
#[cfg(feature = "transparent-inputs")]
|
||||
use zcash_primitives::legacy::keys::{self as legacy, IncomingViewingKey};
|
||||
|
||||
pub mod sapling {
|
||||
use zcash_primitives::zip32::{AccountId, ChildIndex};
|
||||
|
@ -45,6 +53,17 @@ pub mod sapling {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "transparent-inputs")]
|
||||
fn to_transparent_child_index(j: DiversifierIndex) -> Option<u32> {
|
||||
let (low_4_bytes, rest) = j.0.split_at(4);
|
||||
let transparent_j = u32::from_le_bytes(low_4_bytes.try_into().unwrap());
|
||||
if transparent_j > (0x7FFFFFFF) || rest.iter().any(|b| b != &0) {
|
||||
None
|
||||
} else {
|
||||
Some(transparent_j)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[doc(hidden)]
|
||||
pub enum DerivationError {
|
||||
|
@ -164,6 +183,75 @@ impl UnifiedFullViewingKey {
|
|||
pub fn sapling(&self) -> Option<&sapling::ExtendedFullViewingKey> {
|
||||
self.sapling.as_ref()
|
||||
}
|
||||
|
||||
/// Attempts to derive the Unified Address for the given diversifier index.
|
||||
///
|
||||
/// Returns `None` if the specified index does not produce a valid diversifier.
|
||||
// TODO: Allow filtering down by receiver types?
|
||||
pub fn address(&self, j: DiversifierIndex) -> Option<UnifiedAddress> {
|
||||
let sapling = if let Some(extfvk) = self.sapling.as_ref() {
|
||||
Some(extfvk.address(j)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
#[cfg(feature = "transparent-inputs")]
|
||||
let transparent = if let Some(tfvk) = self.transparent.as_ref() {
|
||||
match to_transparent_child_index(j) {
|
||||
Some(transparent_j) => match tfvk
|
||||
.derive_external_ivk()
|
||||
.and_then(|tivk| tivk.derive_address(transparent_j))
|
||||
{
|
||||
Ok(taddr) => Some(taddr),
|
||||
Err(_) => return None,
|
||||
},
|
||||
// Diversifier doesn't generate a valid transparent child index.
|
||||
None => return None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
#[cfg(not(feature = "transparent-inputs"))]
|
||||
let transparent = None;
|
||||
|
||||
UnifiedAddress::from_receivers(None, sapling, transparent)
|
||||
}
|
||||
|
||||
/// Searches the diversifier space starting at diversifier index `j` for one which will
|
||||
/// produce a valid diversifier, and return the Unified Address constructed using that
|
||||
/// diversifier along with the index at which the valid diversifier was found.
|
||||
///
|
||||
/// Returns `None` if no valid diversifier exists
|
||||
pub fn find_address(
|
||||
&self,
|
||||
mut j: DiversifierIndex,
|
||||
) -> Option<(UnifiedAddress, DiversifierIndex)> {
|
||||
// If we need to generate a transparent receiver, check that the user has not
|
||||
// specified an invalid transparent child index, from which we can never search to
|
||||
// find a valid index.
|
||||
#[cfg(feature = "transparent-inputs")]
|
||||
if self.transparent.is_some() && to_transparent_child_index(j).is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Find a working diversifier and construct the associated address.
|
||||
loop {
|
||||
let res = self.address(j);
|
||||
if let Some(ua) = res {
|
||||
break Some((ua, j));
|
||||
}
|
||||
if j.increment().is_err() {
|
||||
break None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the Unified Address corresponding to the smallest valid diversifier index,
|
||||
/// along with that index.
|
||||
pub fn default_address(&self) -> (UnifiedAddress, DiversifierIndex) {
|
||||
self.find_address(DiversifierIndex::new())
|
||||
.expect("UFVK should have at least one valid diversifier")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
Loading…
Reference in New Issue