zcash_keys: Keep the Ufvk and Uivk encodings private.
This commit is contained in:
parent
9ddbf1e3e9
commit
9e1a4327c3
|
@ -74,7 +74,6 @@ use std::io::{self, Cursor};
|
||||||
use std::num::NonZeroU32;
|
use std::num::NonZeroU32;
|
||||||
use std::ops::RangeInclusive;
|
use std::ops::RangeInclusive;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
use zcash_address::unified::{Encoding, Uivk};
|
|
||||||
use zcash_keys::keys::{
|
use zcash_keys::keys::{
|
||||||
AddressGenerationError, HdSeedFingerprint, UnifiedAddressRequest, UnifiedIncomingViewingKey,
|
AddressGenerationError, HdSeedFingerprint, UnifiedAddressRequest, UnifiedIncomingViewingKey,
|
||||||
};
|
};
|
||||||
|
@ -120,7 +119,7 @@ use {
|
||||||
crate::UtxoId,
|
crate::UtxoId,
|
||||||
rusqlite::Row,
|
rusqlite::Row,
|
||||||
std::collections::BTreeSet,
|
std::collections::BTreeSet,
|
||||||
zcash_address::unified::Ivk,
|
zcash_address::unified::{Encoding, Ivk, Uivk},
|
||||||
zcash_client_backend::wallet::{TransparentAddressMetadata, WalletTransparentOutput},
|
zcash_client_backend::wallet::{TransparentAddressMetadata, WalletTransparentOutput},
|
||||||
zcash_primitives::{
|
zcash_primitives::{
|
||||||
legacy::{
|
legacy::{
|
||||||
|
@ -347,7 +346,7 @@ pub(crate) fn add_account<P: consensus::Parameters>(
|
||||||
":hd_seed_fingerprint": hd_seed_fingerprint.as_ref().map(|fp| fp.as_bytes()),
|
":hd_seed_fingerprint": hd_seed_fingerprint.as_ref().map(|fp| fp.as_bytes()),
|
||||||
":hd_account_index": hd_account_index.map(u32::from),
|
":hd_account_index": hd_account_index.map(u32::from),
|
||||||
":ufvk": viewing_key.ufvk().map(|ufvk| ufvk.encode(params)),
|
":ufvk": viewing_key.ufvk().map(|ufvk| ufvk.encode(params)),
|
||||||
":uivk": viewing_key.uivk().to_uivk().encode(¶ms.network_type()),
|
":uivk": viewing_key.uivk().encode(params),
|
||||||
":orchard_fvk_item_cache": orchard_item,
|
":orchard_fvk_item_cache": orchard_item,
|
||||||
":sapling_fvk_item_cache": sapling_item,
|
":sapling_fvk_item_cache": sapling_item,
|
||||||
":p2pkh_fvk_item_cache": transparent_item,
|
":p2pkh_fvk_item_cache": transparent_item,
|
||||||
|
@ -1503,18 +1502,9 @@ pub(crate) fn get_account<P: Parameters>(
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
let uivk_str: String = row.get("uivk")?;
|
let uivk_str: String = row.get("uivk")?;
|
||||||
let (network, uivk) = Uivk::decode(&uivk_str).map_err(|e| {
|
|
||||||
SqliteClientError::CorruptedData(format!("Failure to decode UIVK: {e}"))
|
|
||||||
})?;
|
|
||||||
if network != params.network_type() {
|
|
||||||
return Err(SqliteClientError::CorruptedData(
|
|
||||||
"UIVK network type does not match wallet network type".to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
ViewingKey::Incoming(Box::new(
|
ViewingKey::Incoming(Box::new(
|
||||||
UnifiedIncomingViewingKey::from_uivk(&uivk).map_err(|e| {
|
UnifiedIncomingViewingKey::decode(params, &uivk_str[..])
|
||||||
SqliteClientError::CorruptedData(format!("Failure to decode UIVK: {e}"))
|
.map_err(SqliteClientError::BadAccountData)?,
|
||||||
})?,
|
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ use rusqlite::{named_params, Transaction};
|
||||||
use schemer_rusqlite::RusqliteMigration;
|
use schemer_rusqlite::RusqliteMigration;
|
||||||
use secrecy::{ExposeSecret, SecretVec};
|
use secrecy::{ExposeSecret, SecretVec};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use zcash_address::unified::Encoding;
|
|
||||||
use zcash_client_backend::{data_api::AccountKind, keys::UnifiedSpendingKey};
|
use zcash_client_backend::{data_api::AccountKind, keys::UnifiedSpendingKey};
|
||||||
use zcash_keys::keys::{HdSeedFingerprint, UnifiedFullViewingKey};
|
use zcash_keys::keys::{HdSeedFingerprint, UnifiedFullViewingKey};
|
||||||
use zcash_primitives::consensus;
|
use zcash_primitives::consensus;
|
||||||
|
@ -122,8 +121,7 @@ impl<P: consensus::Parameters> RusqliteMigration for Migration<P> {
|
||||||
|
|
||||||
let uivk = ufvk_parsed
|
let uivk = ufvk_parsed
|
||||||
.to_unified_incoming_viewing_key()
|
.to_unified_incoming_viewing_key()
|
||||||
.to_uivk()
|
.encode(&self.params);
|
||||||
.encode(&self.params.network_type());
|
|
||||||
|
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
let transparent_item = ufvk_parsed.transparent().map(|k| k.serialize());
|
let transparent_item = ufvk_parsed.transparent().map(|k| k.serialize());
|
||||||
|
|
|
@ -12,8 +12,6 @@ and this library adheres to Rust's notion of
|
||||||
- `impl Display for zcash_keys::keys::AddressGenerationError`
|
- `impl Display for zcash_keys::keys::AddressGenerationError`
|
||||||
- `impl std::error::Error for zcash_keys::keys::AddressGenerationError`
|
- `impl std::error::Error for zcash_keys::keys::AddressGenerationError`
|
||||||
- `zcash_keys::keys::DecodingError`
|
- `zcash_keys::keys::DecodingError`
|
||||||
- `zcash_keys::keys::UnifiedFullViewingKey::from_ufvk`
|
|
||||||
- `zcash_keys::keys::UnifiedFullViewingKey::to_ufvk`
|
|
||||||
- `zcash_keys::keys::UnifiedFullViewingKey::to_unified_incoming_viewing_key`
|
- `zcash_keys::keys::UnifiedFullViewingKey::to_unified_incoming_viewing_key`
|
||||||
- `zcash_keys::keys::UnifiedIncomingViewingKey`
|
- `zcash_keys::keys::UnifiedIncomingViewingKey`
|
||||||
|
|
||||||
|
|
|
@ -740,13 +740,13 @@ impl UnifiedFullViewingKey {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::from_ufvk(&ufvk).map_err(|e| e.to_string())
|
Self::parse(&ufvk).map_err(|e| e.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses a `UnifiedFullViewingKey` from its [ZIP 316] string encoding.
|
/// Parses a `UnifiedFullViewingKey` from its [ZIP 316] string encoding.
|
||||||
///
|
///
|
||||||
/// [ZIP 316]: https://zips.z.cash/zip-0316
|
/// [ZIP 316]: https://zips.z.cash/zip-0316
|
||||||
pub fn from_ufvk(ufvk: &Ufvk) -> Result<Self, DecodingError> {
|
pub fn parse(ufvk: &Ufvk) -> Result<Self, DecodingError> {
|
||||||
#[cfg(feature = "orchard")]
|
#[cfg(feature = "orchard")]
|
||||||
let mut orchard = None;
|
let mut orchard = None;
|
||||||
#[cfg(feature = "sapling")]
|
#[cfg(feature = "sapling")]
|
||||||
|
@ -823,7 +823,7 @@ impl UnifiedFullViewingKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the string encoding of this `UnifiedFullViewingKey` for the given network.
|
/// Returns the string encoding of this `UnifiedFullViewingKey` for the given network.
|
||||||
pub fn to_ufvk(&self) -> Ufvk {
|
fn to_ufvk(&self) -> Ufvk {
|
||||||
let items = std::iter::empty().chain(self.unknown.iter().map(|(typecode, data)| {
|
let items = std::iter::empty().chain(self.unknown.iter().map(|(typecode, data)| {
|
||||||
unified::Fvk::Unknown {
|
unified::Fvk::Unknown {
|
||||||
typecode: *typecode,
|
typecode: *typecode,
|
||||||
|
@ -973,8 +973,24 @@ impl UnifiedIncomingViewingKey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parses a `UnifiedFullViewingKey` from its [ZIP 316] string encoding.
|
||||||
|
///
|
||||||
|
/// [ZIP 316]: https://zips.z.cash/zip-0316
|
||||||
|
pub fn decode<P: consensus::Parameters>(params: &P, encoding: &str) -> Result<Self, String> {
|
||||||
|
let (net, ufvk) = unified::Uivk::decode(encoding).map_err(|e| e.to_string())?;
|
||||||
|
let expected_net = params.network_type();
|
||||||
|
if net != expected_net {
|
||||||
|
return Err(format!(
|
||||||
|
"UIVK is for network {:?} but we expected {:?}",
|
||||||
|
net, expected_net,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Self::parse(&ufvk).map_err(|e| e.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
/// Constructs a unified incoming viewing key from a parsed unified encoding.
|
/// Constructs a unified incoming viewing key from a parsed unified encoding.
|
||||||
pub fn from_uivk(uivk: &Uivk) -> Result<Self, DecodingError> {
|
fn parse(uivk: &Uivk) -> Result<Self, DecodingError> {
|
||||||
#[cfg(feature = "orchard")]
|
#[cfg(feature = "orchard")]
|
||||||
let mut orchard = None;
|
let mut orchard = None;
|
||||||
#[cfg(feature = "sapling")]
|
#[cfg(feature = "sapling")]
|
||||||
|
@ -1041,8 +1057,13 @@ impl UnifiedIncomingViewingKey {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the string encoding of this `UnifiedFullViewingKey` for the given network.
|
||||||
|
pub fn encode<P: consensus::Parameters>(&self, params: &P) -> String {
|
||||||
|
self.render().encode(¶ms.network_type())
|
||||||
|
}
|
||||||
|
|
||||||
/// Converts this unified incoming viewing key to a unified encoding.
|
/// Converts this unified incoming viewing key to a unified encoding.
|
||||||
pub fn to_uivk(&self) -> Uivk {
|
fn render(&self) -> Uivk {
|
||||||
let items = std::iter::empty().chain(self.unknown.iter().map(|(typecode, data)| {
|
let items = std::iter::empty().chain(self.unknown.iter().map(|(typecode, data)| {
|
||||||
unified::Ivk::Unknown {
|
unified::Ivk::Unknown {
|
||||||
typecode: *typecode,
|
typecode: *typecode,
|
||||||
|
@ -1530,7 +1551,7 @@ mod tests {
|
||||||
orchard,
|
orchard,
|
||||||
);
|
);
|
||||||
|
|
||||||
let encoded = uivk.to_uivk().encode(&NetworkType::Main);
|
let encoded = uivk.render().encode(&NetworkType::Main);
|
||||||
|
|
||||||
// Test encoded form against known values; these test vectors contain Orchard receivers
|
// Test encoded form against known values; these test vectors contain Orchard receivers
|
||||||
// that will be treated as unknown if the `orchard` feature is not enabled.
|
// that will be treated as unknown if the `orchard` feature is not enabled.
|
||||||
|
@ -1548,9 +1569,8 @@ mod tests {
|
||||||
assert_eq!(encoded, _encoded_no_t);
|
assert_eq!(encoded, _encoded_no_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
let decoded =
|
let decoded = UnifiedIncomingViewingKey::parse(&Uivk::decode(&encoded).unwrap().1).unwrap();
|
||||||
UnifiedIncomingViewingKey::from_uivk(&Uivk::decode(&encoded).unwrap().1).unwrap();
|
let reencoded = decoded.render().encode(&NetworkType::Main);
|
||||||
let reencoded = decoded.to_uivk().encode(&NetworkType::Main);
|
|
||||||
assert_eq!(encoded, reencoded);
|
assert_eq!(encoded, reencoded);
|
||||||
|
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
|
@ -1570,7 +1590,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
let decoded_with_t =
|
let decoded_with_t =
|
||||||
UnifiedIncomingViewingKey::from_uivk(&Uivk::decode(encoded_with_t).unwrap().1).unwrap();
|
UnifiedIncomingViewingKey::parse(&Uivk::decode(encoded_with_t).unwrap().1).unwrap();
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
decoded_with_t.transparent.map(|t| t.serialize()),
|
decoded_with_t.transparent.map(|t| t.serialize()),
|
||||||
|
|
Loading…
Reference in New Issue