Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
f077979
Orchard key components
str4d Mar 5, 2021
ceac39d
Implement ZIP 32 diversifier derivation
str4d Mar 5, 2021
eaa7158
Use reddsa to instantiate orchard::redpallas
str4d Mar 5, 2021
2750170
Use orchard::redpallas types in orchard::keys implementation
str4d Mar 6, 2021
5772c71
Add doctest example to orchard::Address that exercises key derivation
str4d Mar 6, 2021
a61be5d
Fix typo in documentation
str4d Mar 6, 2021
71542f7
Add internal DiversifiedTransmissionKey type
str4d Mar 6, 2021
9455158
Use protocol spec URL anchors as link handles
str4d Mar 6, 2021
57c6492
Add internal CommitIvkRandomness type
str4d Mar 6, 2021
cfaa61a
Remove unnecessary conversions for DiversifierIndex
str4d Mar 8, 2021
26701c3
Fix commit_ivk specification
str4d Mar 8, 2021
307787e
Use spec name for SpendValidatingKey
str4d Mar 8, 2021
bf5fb7a
Add missing spec links to key docs
str4d Mar 8, 2021
cef44f5
Fix intra-crate doc links
str4d Mar 8, 2021
2462bb2
Use [u8; 64] as the output of prf_expand to match the spec
str4d Mar 8, 2021
f7cad77
Add clarifying note about nomenclature
str4d Mar 8, 2021
e98f324
Ensure diversify_hash does not return the identity
str4d Mar 15, 2021
e0b40cb
FullViewingKey::address_at(impl Into<DiversifierIndex>)
str4d Mar 15, 2021
46bf89c
Update ivk derivation to match latest protocol spec draft
str4d Mar 15, 2021
3c8befa
Remove TODO from extract_p
str4d Mar 15, 2021
8e55b46
Deduplicate default address generation
str4d Mar 15, 2021
e041726
Make address generation infallible again
str4d Mar 17, 2021
42ea809
Update protocol spec references
str4d Mar 17, 2021
861eec1
Document sinsemilla::Pad
str4d Mar 17, 2021
51fd94d
Fix section numbers after spec changes
str4d Mar 18, 2021
05e86a4
Reuse the hasher inside diversify_hash
str4d Mar 18, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 12 additions & 38 deletions src/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use aes::Aes256;
use fpe::ff1::{BinaryNumeralString, FF1};
use group::GroupEncoding;
use halo2::{arithmetic::FieldExt, pasta::pallas};
use subtle::{Choice, CtOption};
use subtle::CtOption;

use crate::{
address::Address,
Expand All @@ -32,17 +32,9 @@ impl SpendingKey {
/// Returns `None` if the bytes do not correspond to a valid Orchard spending key.
pub fn from_bytes(sk: [u8; 32]) -> CtOption<Self> {
let sk = SpendingKey(sk);
// If ask = 0, or the default address would be ⊥, discard this key.
let ask_not_zero = !SpendAuthorizingKey::derive_inner(&sk).ct_is_zero();
let have_default_address = Choice::from({
let fvk = FullViewingKey::from(&sk);
if fvk.default_address_inner().is_some() {
1
} else {
0
}
});
CtOption::new(sk, ask_not_zero & have_default_address)
// If ask = 0, discard this key.
let ask = SpendAuthorizingKey::derive_inner(&sk);
CtOption::new(sk, !ask.ct_is_zero())
}
}

Expand Down Expand Up @@ -164,31 +156,16 @@ impl FullViewingKey {

/// Returns the default payment address for this key.
pub fn default_address(&self) -> Address {
self.default_address_inner()
.expect("Default address works by construction")
}

fn default_address_inner(&self) -> Option<Address> {
self.address(DiversifierKey::from(self).default_diversifier())
}

/// Returns the payment address for this key at the given index.
///
/// Returns `None` if the diversifier does not correspond to an address. This happens
/// with negligible probability; in most cases unwrapping the result will be fine, but
/// if you have specific stability requirements then you can either convert this into
/// an error, or try another diversifier index (e.g. incrementing).
pub fn address_at(&self, j: impl Into<DiversifierIndex>) -> Option<Address> {
pub fn address_at(&self, j: impl Into<DiversifierIndex>) -> Address {
self.address(DiversifierKey::from(self).get(j))
}

/// Returns the payment address for this key corresponding to the given diversifier.
///
/// Returns `None` if the diversifier does not correspond to an address. This happens
/// with negligible probability; in most cases unwrapping the result will be fine, but
/// if you have specific stability requirements then you can either convert this into
/// an error, or try another diversifier.
pub fn address(&self, d: Diversifier) -> Option<Address> {
pub fn address(&self, d: Diversifier) -> Address {
IncomingViewingKey::from(self).address(d)
}
}
Expand Down Expand Up @@ -275,13 +252,9 @@ impl From<&FullViewingKey> for IncomingViewingKey {

impl IncomingViewingKey {
/// Returns the payment address for this key corresponding to the given diversifier.
///
/// Returns `None` if the diversifier does not correspond to an address. This happens
/// with negligible probability; in most cases unwrapping the result will be fine, but
/// if you have specific stability requirements then you can either convert this into
/// an error, or try another diversifier.
pub fn address(&self, d: Diversifier) -> Option<Address> {
DiversifiedTransmissionKey::derive(self, &d).map(|pk_d| Address::from_parts(d, pk_d))
pub fn address(&self, d: Diversifier) -> Address {
let pk_d = DiversifiedTransmissionKey::derive(self, &d);
Address::from_parts(d, pk_d)
}
}

Expand Down Expand Up @@ -315,7 +288,8 @@ impl DiversifiedTransmissionKey {
/// Defined in [Zcash Protocol Spec § 4.2.3: Orchard Key Components][orchardkeycomponents].
///
/// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents
fn derive(ivk: &IncomingViewingKey, d: &Diversifier) -> Option<Self> {
diversify_hash(&d.0).map(|g_d| DiversifiedTransmissionKey(ka_orchard(&ivk.0, &g_d)))
fn derive(ivk: &IncomingViewingKey, d: &Diversifier) -> Self {
let g_d = diversify_hash(&d.0);
DiversifiedTransmissionKey(ka_orchard(&ivk.0, &g_d))
}
}
20 changes: 17 additions & 3 deletions src/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,13 @@ pub(crate) fn commit_ivk(
/// Defined in [Zcash Protocol Spec § 5.4.1.6: DiversifyHash^Sapling and DiversifyHash^Orchard Hash Functions][concretediversifyhash].
///
/// [concretediversifyhash]: https://zips.z.cash/protocol/nu5.pdf#concretediversifyhash
pub(crate) fn diversify_hash(d: &[u8; 11]) -> Option<pallas::Point> {
pub(crate) fn diversify_hash(d: &[u8; 11]) -> pallas::Point {
let pk_d = pallas::Point::hash_to_curve("z.cash:Orchard-gd")(d);
if pk_d.is_identity().into() {
None
// If the identity occurs, we replace it with a different fixed point.
pallas::Point::hash_to_curve("z.cash:Orchard-gd")(&[])
} else {
Some(pk_d)
pk_d
}
}

Expand Down Expand Up @@ -107,3 +108,16 @@ pub(crate) fn extract_p(point: &pallas::Point) -> pallas::Base {
pallas::Base::zero()
}
}

#[cfg(test)]
mod tests {
use group::Group;
use halo2::{arithmetic::CurveExt, pasta::pallas};

#[test]
fn diversify_hash_substitution() {
assert!(!bool::from(
pallas::Point::hash_to_curve("z.cash:Orchard-gd")(&[]).is_identity()
));
}
}