2021-01-20 10:54:00 -08:00
//! Key structures for Orchard.
2022-04-28 13:20:23 -07:00
use core ::mem ;
2021-07-15 00:18:01 -07:00
use std ::io ::{ self , Read , Write } ;
2021-03-05 15:25:45 -08:00
2021-03-05 15:36:38 -08:00
use aes ::Aes256 ;
2021-06-02 14:31:18 -07:00
use blake2b_simd ::{ Hash as Blake2bHash , Params } ;
2021-03-05 15:36:38 -08:00
use fpe ::ff1 ::{ BinaryNumeralString , FF1 } ;
2021-12-07 10:02:03 -08:00
use group ::{
ff ::{ Field , PrimeField } ,
prime ::PrimeCurveAffine ,
Curve , GroupEncoding ,
} ;
2022-02-08 07:19:56 -08:00
use pasta_curves ::pallas ;
2021-06-05 14:35:52 -07:00
use rand ::RngCore ;
2021-07-22 15:59:02 -07:00
use subtle ::{ Choice , ConditionallySelectable , ConstantTimeEq , CtOption } ;
2021-06-02 14:31:18 -07:00
use zcash_note_encryption ::EphemeralKeyBytes ;
2021-03-05 15:25:45 -08:00
use crate ::{
address ::Address ,
2021-08-23 10:21:52 -07:00
primitives ::redpallas ::{ self , SpendAuth } ,
2021-03-05 15:25:45 -08:00
spec ::{
2021-05-28 05:11:54 -07:00
commit_ivk , diversify_hash , extract_p , ka_orchard , prf_nf , to_base , to_scalar ,
NonIdentityPallasPoint , NonZeroPallasBase , NonZeroPallasScalar , PrfExpand ,
2021-03-05 15:25:45 -08:00
} ,
2021-08-31 15:49:58 -07:00
zip32 ::{ self , ChildIndex , ExtendedSpendingKey } ,
2021-03-05 15:25:45 -08:00
} ;
2021-01-20 10:54:00 -08:00
2021-06-02 14:31:18 -07:00
const KDF_ORCHARD_PERSONALIZATION : & [ u8 ; 16 ] = b " Zcash_OrchardKDF " ;
2021-07-15 00:18:01 -07:00
const ZIP32_PURPOSE : u32 = 32 ;
2021-06-02 14:31:18 -07:00
2021-01-20 10:54:00 -08:00
/// A spending key, from which all key material is derived.
///
2022-02-18 06:24:22 -08:00
/// $\mathsf{sk}$ as defined in [Zcash Protocol Spec § 4.2.3: Orchard Key Components][orchardkeycomponents].
2021-03-05 15:25:45 -08:00
///
2021-03-05 17:17:51 -08:00
/// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents
2021-11-30 15:25:35 -08:00
#[ derive(Debug, Copy, Clone) ]
2021-03-05 15:25:45 -08:00
pub struct SpendingKey ( [ u8 ; 32 ] ) ;
2021-11-30 15:24:50 -08:00
impl ConstantTimeEq for SpendingKey {
fn ct_eq ( & self , other : & Self ) -> Choice {
self . to_bytes ( ) . ct_eq ( other . to_bytes ( ) )
}
}
2021-03-05 15:25:45 -08:00
impl SpendingKey {
2021-04-14 21:14:34 -07:00
/// Generates a random spending key.
///
/// This is only used when generating dummy notes. Real spending keys should be
/// derived according to [ZIP 32].
///
/// [ZIP 32]: https://zips.z.cash/zip-0032
pub ( crate ) fn random ( rng : & mut impl RngCore ) -> Self {
loop {
let mut bytes = [ 0 ; 32 ] ;
rng . fill_bytes ( & mut bytes ) ;
let sk = SpendingKey ::from_bytes ( bytes ) ;
if sk . is_some ( ) . into ( ) {
break sk . unwrap ( ) ;
}
}
}
2021-03-05 15:25:45 -08:00
/// Constructs an Orchard spending key from uniformly-random bytes.
///
/// 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 ) ;
2021-04-21 15:28:32 -07:00
// If ask = 0, discard this key. We call `derive_inner` rather than
// `SpendAuthorizingKey::from` here because we only need to know
// whether ask = 0; the adjustment to potentially negate ask is not
// needed. Also, `from` would panic on ask = 0.
2021-03-17 12:15:55 -07:00
let ask = SpendAuthorizingKey ::derive_inner ( & sk ) ;
2022-03-30 05:20:55 -07:00
// If ivk is 0 or ⊥, discard this key.
let fvk = ( & sk ) . into ( ) ;
let external_ivk = KeyAgreementPrivateKey ::derive_inner ( & fvk ) ;
let internal_ivk = KeyAgreementPrivateKey ::derive_inner ( & fvk . derive_internal ( ) ) ;
CtOption ::new (
sk ,
! ( ask . is_zero ( ) | external_ivk . is_none ( ) | internal_ivk . is_none ( ) ) ,
)
2021-03-05 15:25:45 -08:00
}
2021-08-02 13:54:48 -07:00
/// Returns the raw bytes of the spending key.
pub fn to_bytes ( & self ) -> & [ u8 ; 32 ] {
& self . 0
}
2021-07-15 00:18:01 -07:00
/// Derives the Orchard spending key for the given seed, coin type, and account.
2021-08-31 15:49:58 -07:00
pub fn from_zip32_seed (
seed : & [ u8 ] ,
coin_type : u32 ,
account : u32 ,
) -> Result < Self , zip32 ::Error > {
2021-07-15 00:18:01 -07:00
// Call zip32 logic
2021-08-31 15:49:58 -07:00
let path = & [
ChildIndex ::try_from ( ZIP32_PURPOSE ) ? ,
ChildIndex ::try_from ( coin_type ) ? ,
ChildIndex ::try_from ( account ) ? ,
] ;
ExtendedSpendingKey ::from_path ( seed , path ) . map ( | esk | esk . sk ( ) )
2021-07-15 00:18:01 -07:00
}
2021-03-05 15:25:45 -08:00
}
2021-01-20 10:54:00 -08:00
2021-03-05 16:58:48 -08:00
/// A spend authorizing key, used to create spend authorization signatures.
2021-08-23 10:25:29 -07:00
/// This type enforces that the corresponding public point (ak^ℙ ) has ỹ = 0.
2021-03-05 15:25:45 -08:00
///
2022-02-18 06:24:22 -08:00
/// $\mathsf{ask}$ as defined in [Zcash Protocol Spec § 4.2.3: Orchard Key Components][orchardkeycomponents].
2021-03-05 15:25:45 -08:00
///
2021-03-05 17:17:51 -08:00
/// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents
2022-02-11 18:04:52 -08:00
#[ derive(Clone, Debug) ]
2021-04-14 21:14:34 -07:00
pub struct SpendAuthorizingKey ( redpallas ::SigningKey < SpendAuth > ) ;
2021-03-05 15:25:45 -08:00
impl SpendAuthorizingKey {
/// Derives ask from sk. Internal use only, does not enforce all constraints.
fn derive_inner ( sk : & SpendingKey ) -> pallas ::Scalar {
2021-05-28 05:11:54 -07:00
to_scalar ( PrfExpand ::OrchardAsk . expand ( & sk . 0 ) )
2021-03-05 15:25:45 -08:00
}
2021-04-14 21:14:34 -07:00
2021-06-05 14:35:52 -07:00
/// Randomizes this spend authorizing key with the given `randomizer`.
///
/// The resulting key can be used to actually sign a spend.
pub fn randomize ( & self , randomizer : & pallas ::Scalar ) -> redpallas ::SigningKey < SpendAuth > {
self . 0. randomize ( randomizer )
2021-04-14 21:14:34 -07:00
}
2021-03-05 15:25:45 -08:00
}
2021-01-20 10:54:00 -08:00
2021-01-21 04:16:50 -08:00
impl From < & SpendingKey > for SpendAuthorizingKey {
2021-03-05 15:25:45 -08:00
fn from ( sk : & SpendingKey ) -> Self {
let ask = Self ::derive_inner ( sk ) ;
// SpendingKey cannot be constructed such that this assertion would fail.
2021-09-06 12:18:18 -07:00
assert! ( ! bool ::from ( ask . is_zero ( ) ) ) ;
2021-03-05 15:25:45 -08:00
// TODO: Add TryFrom<S::Scalar> for SpendAuthorizingKey.
2021-12-07 10:02:03 -08:00
let ret = SpendAuthorizingKey ( ask . to_repr ( ) . try_into ( ) . unwrap ( ) ) ;
2021-03-05 15:25:45 -08:00
// If the last bit of repr_P(ak) is 1, negate ask.
2021-03-08 12:20:09 -08:00
if ( < [ u8 ; 32 ] > ::from ( SpendValidatingKey ::from ( & ret ) . 0 ) [ 31 ] > > 7 ) = = 1 {
2021-12-07 10:02:03 -08:00
SpendAuthorizingKey ( ( - ask ) . to_repr ( ) . try_into ( ) . unwrap ( ) )
2021-03-05 15:25:45 -08:00
} else {
ret
}
2021-01-20 10:54:00 -08:00
}
}
2021-03-08 12:20:09 -08:00
/// A key used to validate spend authorization signatures.
///
/// Defined in [Zcash Protocol Spec § 4.2.3: Orchard Key Components][orchardkeycomponents].
2021-03-15 13:33:07 -07:00
/// Note that this is $\mathsf{ak}^\mathbb{P}$, which by construction is equivalent to
/// $\mathsf{ak}$ but stored here as a RedPallas verification key.
2021-03-08 12:20:09 -08:00
///
/// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents
2021-07-26 11:05:28 -07:00
#[ derive(Debug, Clone, PartialOrd, Ord) ]
2021-04-14 21:14:34 -07:00
pub struct SpendValidatingKey ( redpallas ::VerificationKey < SpendAuth > ) ;
2021-01-20 10:54:00 -08:00
2021-03-08 12:20:09 -08:00
impl From < & SpendAuthorizingKey > for SpendValidatingKey {
2021-03-05 15:25:45 -08:00
fn from ( ask : & SpendAuthorizingKey ) -> Self {
2021-03-08 12:20:09 -08:00
SpendValidatingKey ( ( & ask . 0 ) . into ( ) )
2021-01-20 10:54:00 -08:00
}
}
2021-06-06 04:13:20 -07:00
impl From < & SpendValidatingKey > for pallas ::Point {
fn from ( spend_validating_key : & SpendValidatingKey ) -> pallas ::Point {
pallas ::Point ::from_bytes ( & ( & spend_validating_key . 0 ) . into ( ) ) . unwrap ( )
}
}
2021-04-14 21:14:34 -07:00
impl PartialEq for SpendValidatingKey {
fn eq ( & self , other : & Self ) -> bool {
< [ u8 ; 32 ] > ::from ( & self . 0 ) . eq ( & < [ u8 ; 32 ] > ::from ( & other . 0 ) )
}
}
2021-07-26 11:05:28 -07:00
impl Eq for SpendValidatingKey { }
2021-04-14 21:33:15 -07:00
impl SpendValidatingKey {
/// Randomizes this spend validating key with the given `randomizer`.
pub fn randomize ( & self , randomizer : & pallas ::Scalar ) -> redpallas ::VerificationKey < SpendAuth > {
self . 0. randomize ( randomizer )
}
2021-07-23 13:09:30 -07:00
2021-08-23 10:25:29 -07:00
/// Converts this spend validating key to its serialized form,
/// I2LEOSP_256(ak).
2021-07-23 13:09:30 -07:00
pub ( crate ) fn to_bytes ( & self ) -> [ u8 ; 32 ] {
2021-08-23 10:25:29 -07:00
// This is correct because the wrapped point must have ỹ = 0, and
// so the point repr is the same as I2LEOSP of its x-coordinate.
2021-07-23 13:09:30 -07:00
< [ u8 ; 32 ] > ::from ( & self . 0 )
}
pub ( crate ) fn from_bytes ( bytes : & [ u8 ] ) -> Option < Self > {
2021-08-23 10:21:52 -07:00
< [ u8 ; 32 ] > ::try_from ( bytes )
2021-07-23 13:09:30 -07:00
. ok ( )
2021-12-15 05:48:59 -08:00
. and_then ( | b | {
// Structural validity checks for ak_P:
// - The point must not be the identity
// (which for Pallas is canonically encoded as all-zeroes).
// - The sign of the y-coordinate must be positive.
if b ! = [ 0 ; 32 ] & & b [ 31 ] & 0x80 = = 0 {
2021-08-23 10:21:52 -07:00
< redpallas ::VerificationKey < SpendAuth > > ::try_from ( b ) . ok ( )
} else {
None
}
2021-12-15 05:48:59 -08:00
} )
2021-07-23 13:09:30 -07:00
. map ( SpendValidatingKey )
}
2021-04-14 21:33:15 -07:00
}
2021-03-05 15:25:45 -08:00
/// A key used to derive [`Nullifier`]s from [`Note`]s.
///
2022-02-18 06:24:22 -08:00
/// $\mathsf{nk}$ as defined in [Zcash Protocol Spec § 4.2.3: Orchard Key Components][orchardkeycomponents].
2021-03-05 15:25:45 -08:00
///
2021-03-08 12:27:34 -08:00
/// [`Nullifier`]: crate::note::Nullifier
/// [`Note`]: crate::note::Note
2021-03-05 17:17:51 -08:00
/// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents
2021-07-26 11:05:28 -07:00
#[ derive(Copy, Debug, Clone, PartialEq, Eq, PartialOrd, Ord) ]
2021-03-05 15:25:45 -08:00
pub ( crate ) struct NullifierDerivingKey ( pallas ::Base ) ;
2021-01-20 10:54:00 -08:00
2021-07-22 07:14:34 -07:00
impl NullifierDerivingKey {
pub ( crate ) fn inner ( & self ) -> pallas ::Base {
self . 0
2021-06-06 04:13:20 -07:00
}
}
2021-01-21 04:16:50 -08:00
impl From < & SpendingKey > for NullifierDerivingKey {
2021-03-05 15:25:45 -08:00
fn from ( sk : & SpendingKey ) -> Self {
2021-05-28 05:11:54 -07:00
NullifierDerivingKey ( to_base ( PrfExpand ::OrchardNk . expand ( & sk . 0 ) ) )
2021-01-20 10:54:00 -08:00
}
}
2021-03-15 18:27:08 -07:00
impl NullifierDerivingKey {
pub ( crate ) fn prf_nf ( & self , rho : pallas ::Base ) -> pallas ::Base {
prf_nf ( self . 0 , rho )
}
2021-07-23 13:09:30 -07:00
/// Converts this nullifier deriving key to its serialized form.
2022-01-20 07:16:45 -08:00
pub ( crate ) fn to_bytes ( self ) -> [ u8 ; 32 ] {
2021-07-23 13:09:30 -07:00
< [ u8 ; 32 ] > ::from ( self . 0 )
}
pub ( crate ) fn from_bytes ( bytes : & [ u8 ] ) -> Option < Self > {
2021-08-23 10:21:52 -07:00
let nk_bytes = < [ u8 ; 32 ] > ::try_from ( bytes ) . ok ( ) ? ;
2021-12-07 10:02:03 -08:00
let nk = pallas ::Base ::from_repr ( nk_bytes ) . map ( NullifierDerivingKey ) ;
2021-07-23 13:09:30 -07:00
if nk . is_some ( ) . into ( ) {
Some ( nk . unwrap ( ) )
} else {
None
}
}
2021-03-15 18:27:08 -07:00
}
2021-03-05 17:24:45 -08:00
/// The randomness for $\mathsf{Commit}^\mathsf{ivk}$.
///
2022-02-18 06:24:22 -08:00
/// $\mashsf{rivk}$ as defined in [Zcash Protocol Spec § 4.2.3: Orchard Key Components][orchardkeycomponents].
2021-03-05 17:24:45 -08:00
///
/// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents
2021-07-26 11:05:28 -07:00
#[ derive(Copy, Debug, Clone, PartialEq, Eq, PartialOrd, Ord) ]
2021-06-06 04:13:20 -07:00
pub ( crate ) struct CommitIvkRandomness ( pallas ::Scalar ) ;
2021-03-05 17:24:45 -08:00
impl From < & SpendingKey > for CommitIvkRandomness {
fn from ( sk : & SpendingKey ) -> Self {
2021-05-28 05:11:54 -07:00
CommitIvkRandomness ( to_scalar ( PrfExpand ::OrchardRivk . expand ( & sk . 0 ) ) )
2021-03-05 17:24:45 -08:00
}
}
2021-07-22 07:14:34 -07:00
impl CommitIvkRandomness {
pub ( crate ) fn inner ( & self ) -> pallas ::Scalar {
self . 0
2021-06-06 04:13:20 -07:00
}
2021-07-23 13:09:30 -07:00
/// Converts this nullifier deriving key to its serialized form.
2022-01-20 07:16:45 -08:00
pub ( crate ) fn to_bytes ( self ) -> [ u8 ; 32 ] {
2021-07-23 13:09:30 -07:00
< [ u8 ; 32 ] > ::from ( self . 0 )
}
pub ( crate ) fn from_bytes ( bytes : & [ u8 ] ) -> Option < Self > {
2021-08-23 10:21:52 -07:00
let rivk_bytes = < [ u8 ; 32 ] > ::try_from ( bytes ) . ok ( ) ? ;
2021-12-07 10:02:03 -08:00
let rivk = pallas ::Scalar ::from_repr ( rivk_bytes ) . map ( CommitIvkRandomness ) ;
2021-07-23 13:09:30 -07:00
if rivk . is_some ( ) . into ( ) {
Some ( rivk . unwrap ( ) )
} else {
None
}
}
2021-06-06 04:13:20 -07:00
}
2022-03-30 04:53:46 -07:00
/// The scope of a viewing key or address.
///
/// A "scope" narrows the visibility or usage to a level below "full".
///
/// Consistent usage of `Scope` enables the user to provide consistent views over a wallet
/// to other people. For example, a user can give an external [`IncomingViewingKey`] to a
/// merchant terminal, enabling it to only detect "real" transactions from customers and
/// not internal transactions from the wallet.
#[ derive(Clone, Copy, Debug, PartialEq, Eq) ]
pub enum Scope {
/// A scope used for wallet-external operations, namely deriving addresses to give to
/// other users in order to receive funds.
External ,
/// A scope used for wallet-internal operations, such as creating change notes,
/// auto-shielding, and note management.
Internal ,
}
2021-01-20 10:54:00 -08:00
/// A key that provides the capability to view incoming and outgoing transactions.
///
2021-02-03 06:19:29 -08:00
/// This key is useful anywhere you need to maintain accurate balance, but do not want the
/// ability to spend funds (such as a view-only wallet).
2021-03-08 12:22:38 -08:00
///
/// Defined in [Zcash Protocol Spec § 4.2.3: Orchard Key Components][orchardkeycomponents].
///
/// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents
2021-07-26 11:05:28 -07:00
#[ derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord) ]
2021-01-21 04:16:50 -08:00
pub struct FullViewingKey {
2021-03-08 12:20:09 -08:00
ak : SpendValidatingKey ,
2021-01-21 04:16:50 -08:00
nk : NullifierDerivingKey ,
2021-03-05 17:24:45 -08:00
rivk : CommitIvkRandomness ,
2021-01-20 10:54:00 -08:00
}
2021-01-21 04:16:50 -08:00
impl From < & SpendingKey > for FullViewingKey {
2021-03-05 15:25:45 -08:00
fn from ( sk : & SpendingKey ) -> Self {
FullViewingKey {
ak : ( & SpendAuthorizingKey ::from ( sk ) ) . into ( ) ,
nk : sk . into ( ) ,
2021-03-05 17:24:45 -08:00
rivk : sk . into ( ) ,
2021-03-05 15:25:45 -08:00
}
2021-01-20 10:54:00 -08:00
}
}
2021-07-15 00:18:01 -07:00
impl From < & ExtendedSpendingKey > for FullViewingKey {
fn from ( extsk : & ExtendedSpendingKey ) -> Self {
( & extsk . sk ( ) ) . into ( )
}
}
2021-04-14 21:34:51 -07:00
impl From < FullViewingKey > for SpendValidatingKey {
fn from ( fvk : FullViewingKey ) -> Self {
fvk . ak
}
}
2021-01-21 04:16:50 -08:00
impl FullViewingKey {
2021-03-15 18:27:08 -07:00
pub ( crate ) fn nk ( & self ) -> & NullifierDerivingKey {
& self . nk
}
2022-03-30 04:53:46 -07:00
/// Returns either `rivk` or `rivk_internal` based on `scope`.
pub ( crate ) fn rivk ( & self , scope : Scope ) -> CommitIvkRandomness {
match scope {
Scope ::External = > self . rivk ,
Scope ::Internal = > {
let k = self . rivk . 0. to_repr ( ) ;
let ak = self . ak . to_bytes ( ) ;
let nk = self . nk . to_bytes ( ) ;
CommitIvkRandomness ( to_scalar (
PrfExpand ::OrchardRivkInternal . with_ad_slices ( & k , & [ & ak , & nk ] ) ,
) )
}
}
2022-01-25 19:24:06 -08:00
}
2021-03-05 17:17:51 -08:00
/// Defined in [Zcash Protocol Spec § 4.2.3: Orchard Key Components][orchardkeycomponents].
2021-03-05 15:25:45 -08:00
///
2021-03-05 17:17:51 -08:00
/// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents
2021-03-05 15:25:45 -08:00
fn derive_dk_ovk ( & self ) -> ( DiversifierKey , OutgoingViewingKey ) {
2021-12-07 10:02:03 -08:00
let k = self . rivk . 0. to_repr ( ) ;
let b = [ ( & self . ak . 0 ) . into ( ) , self . nk . 0. to_repr ( ) ] ;
2021-05-28 05:11:54 -07:00
let r = PrfExpand ::OrchardDkOvk . with_ad_slices ( & k , & [ & b [ 0 ] [ .. ] , & b [ 1 ] [ .. ] ] ) ;
2021-03-05 15:25:45 -08:00
(
2021-03-08 13:33:56 -08:00
DiversifierKey ( r [ .. 32 ] . try_into ( ) . unwrap ( ) ) ,
OutgoingViewingKey ( r [ 32 .. ] . try_into ( ) . unwrap ( ) ) ,
2021-03-05 15:25:45 -08:00
)
}
2021-03-15 13:04:36 -07:00
/// Returns the payment address for this key at the given index.
2022-03-30 04:53:46 -07:00
pub fn address_at ( & self , j : impl Into < DiversifierIndex > , scope : Scope ) -> Address {
self . to_ivk ( scope ) . address_at ( j )
2021-03-15 13:04:36 -07:00
}
2021-01-20 10:54:00 -08:00
/// Returns the payment address for this key corresponding to the given diversifier.
2022-03-30 04:53:46 -07:00
pub fn address ( & self , d : Diversifier , scope : Scope ) -> Address {
2021-05-11 03:07:08 -07:00
// Shortcut: we don't need to derive DiversifierKey.
2022-03-30 04:53:46 -07:00
match scope {
Scope ::External = > KeyAgreementPrivateKey ::from_fvk ( self ) ,
Scope ::Internal = > KeyAgreementPrivateKey ::from_fvk ( & self . derive_internal ( ) ) ,
}
. address ( d )
}
/// Returns the scope of the given address, or `None` if the address is not derived
/// from this full viewing key.
pub fn scope_for_address ( & self , address : & Address ) -> Option < Scope > {
2022-04-28 10:13:07 -07:00
[ Scope ::External , Scope ::Internal ]
. into_iter ( )
2022-03-30 04:53:46 -07:00
. find ( | scope | self . to_ivk ( * scope ) . diversifier_index ( address ) . is_some ( ) )
2021-01-20 10:54:00 -08:00
}
2021-07-23 13:09:30 -07:00
/// Serializes the full viewing key as specified in [Zcash Protocol Spec § 5.6.4.4: Orchard Raw Full Viewing Keys][orchardrawfullviewingkeys]
///
/// [orchardrawfullviewingkeys]: https://zips.z.cash/protocol/protocol.pdf#orchardfullviewingkeyencoding
2021-07-15 00:18:01 -07:00
pub fn write < W : Write > ( & self , mut writer : W ) -> io ::Result < ( ) > {
2022-04-28 13:45:05 -07:00
writer . write_all ( & self . to_bytes ( ) )
2021-07-15 00:18:01 -07:00
}
/// Parses a full viewing key from its "raw" encoding as specified in [Zcash Protocol Spec § 5.6.4.4: Orchard Raw Full Viewing Keys][orchardrawfullviewingkeys]
///
/// [orchardrawfullviewingkeys]: https://zips.z.cash/protocol/protocol.pdf#orchardfullviewingkeyencoding
pub fn read < R : Read > ( mut reader : R ) -> io ::Result < Self > {
let mut data = [ 0 u8 ; 96 ] ;
reader . read_exact ( & mut data ) ? ;
Self ::from_bytes ( & data ) . ok_or_else ( | | {
io ::Error ::new (
io ::ErrorKind ::InvalidInput ,
" Unable to deserialize a valid Orchard FullViewingKey from bytes " . to_owned ( ) ,
)
} )
}
/// Serializes the full viewing key as specified in [Zcash Protocol Spec § 5.6.4.4: Orchard Raw Full Viewing Keys][orchardrawfullviewingkeys]
///
/// [orchardrawfullviewingkeys]: https://zips.z.cash/protocol/protocol.pdf#orchardfullviewingkeyencoding
pub fn to_bytes ( & self ) -> [ u8 ; 96 ] {
2021-07-23 13:09:30 -07:00
let mut result = [ 0 u8 ; 96 ] ;
2022-04-28 13:45:05 -07:00
result [ 0 .. 32 ] . copy_from_slice ( & < [ u8 ; 32 ] > ::from ( self . ak . 0. clone ( ) ) ) ;
result [ 32 .. 64 ] . copy_from_slice ( & self . nk . 0. to_repr ( ) ) ;
result [ 64 .. 96 ] . copy_from_slice ( & self . rivk . 0. to_repr ( ) ) ;
2021-07-23 13:09:30 -07:00
result
}
/// Parses a full viewing key from its "raw" encoding as specified in [Zcash Protocol Spec § 5.6.4.4: Orchard Raw Full Viewing Keys][orchardrawfullviewingkeys]
///
/// [orchardrawfullviewingkeys]: https://zips.z.cash/protocol/protocol.pdf#orchardfullviewingkeyencoding
2021-07-15 00:18:01 -07:00
pub fn from_bytes ( bytes : & [ u8 ; 96 ] ) -> Option < Self > {
2021-07-23 13:09:30 -07:00
let ak = SpendValidatingKey ::from_bytes ( & bytes [ .. 32 ] ) ? ;
let nk = NullifierDerivingKey ::from_bytes ( & bytes [ 32 .. 64 ] ) ? ;
let rivk = CommitIvkRandomness ::from_bytes ( & bytes [ 64 .. ] ) ? ;
2022-03-30 05:16:45 -07:00
let fvk = FullViewingKey { ak , nk , rivk } ;
2022-03-30 05:20:55 -07:00
// If either ivk is 0 or ⊥, this FVK is invalid.
2022-03-30 05:16:45 -07:00
let _ : NonZeroPallasBase = Option ::from ( KeyAgreementPrivateKey ::derive_inner ( & fvk ) ) ? ;
2022-03-30 05:20:55 -07:00
let _ : NonZeroPallasBase =
Option ::from ( KeyAgreementPrivateKey ::derive_inner ( & fvk . derive_internal ( ) ) ) ? ;
2022-03-30 05:16:45 -07:00
Some ( fvk )
2021-07-23 13:09:30 -07:00
}
2022-01-06 07:11:37 -08:00
2022-03-30 04:53:46 -07:00
/// Derives an internal full viewing key from a full viewing key, as specified in
/// [ZIP32][orchardinternalfullviewingkey]. Internal use only.
2022-01-06 07:11:37 -08:00
///
/// [orchardinternalfullviewingkey]: https://zips.z.cash/zip-0032#orchard-internal-key-derivation
2022-03-30 04:53:46 -07:00
fn derive_internal ( & self ) -> Self {
2022-02-21 06:41:47 -08:00
FullViewingKey {
2022-01-06 07:11:37 -08:00
ak : self . ak . clone ( ) ,
nk : self . nk ,
2022-03-30 04:53:46 -07:00
rivk : self . rivk ( Scope ::Internal ) ,
}
}
/// Derives an `IncomingViewingKey` for this full viewing key.
pub fn to_ivk ( & self , scope : Scope ) -> IncomingViewingKey {
match scope {
Scope ::External = > IncomingViewingKey ::from_fvk ( self ) ,
Scope ::Internal = > IncomingViewingKey ::from_fvk ( & self . derive_internal ( ) ) ,
}
}
/// Derives an `OutgoingViewingKey` for this full viewing key.
pub fn to_ovk ( & self , scope : Scope ) -> OutgoingViewingKey {
match scope {
Scope ::External = > OutgoingViewingKey ::from_fvk ( self ) ,
Scope ::Internal = > OutgoingViewingKey ::from_fvk ( & self . derive_internal ( ) ) ,
2022-02-21 06:41:47 -08:00
}
2022-01-06 07:11:37 -08:00
}
2021-01-20 10:54:00 -08:00
}
2021-03-05 15:25:45 -08:00
/// A key that provides the capability to derive a sequence of diversifiers.
2021-03-08 12:22:38 -08:00
///
2022-02-18 06:24:22 -08:00
/// $\mathsf{dk}$ as defined in [Zcash Protocol Spec § 4.2.3: Orchard Key Components][orchardkeycomponents].
2021-03-08 12:22:38 -08:00
///
/// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents
2021-07-26 11:05:28 -07:00
#[ derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord) ]
2022-02-14 16:02:08 -08:00
pub ( crate ) struct DiversifierKey ( [ u8 ; 32 ] ) ;
2021-03-05 15:25:45 -08:00
/// The index for a particular diversifier.
2021-07-26 11:05:28 -07:00
#[ derive(Clone, Copy, Debug, PartialEq, Eq) ]
2021-03-05 15:25:45 -08:00
pub struct DiversifierIndex ( [ u8 ; 11 ] ) ;
macro_rules ! di_from {
( $n :ident ) = > {
impl From < $n > for DiversifierIndex {
fn from ( j : $n ) -> Self {
let mut j_bytes = [ 0 ; 11 ] ;
j_bytes [ .. mem ::size_of ::< $n > ( ) ] . copy_from_slice ( & j . to_le_bytes ( ) ) ;
DiversifierIndex ( j_bytes )
}
}
} ;
}
di_from! ( u32 ) ;
di_from! ( u64 ) ;
di_from! ( usize ) ;
2021-11-24 17:08:53 -08:00
impl From < [ u8 ; 11 ] > for DiversifierIndex {
fn from ( j_bytes : [ u8 ; 11 ] ) -> Self {
DiversifierIndex ( j_bytes )
}
}
2022-02-14 15:00:04 -08:00
impl DiversifierIndex {
/// Returns the raw bytes of the diversifier index.
pub fn to_bytes ( & self ) -> & [ u8 ; 11 ] {
& self . 0
2021-03-05 15:25:45 -08:00
}
2022-02-14 15:00:04 -08:00
}
2021-03-05 15:25:45 -08:00
impl DiversifierKey {
/// Returns the diversifier at the given index.
2021-03-05 15:36:38 -08:00
pub fn get ( & self , j : impl Into < DiversifierIndex > ) -> Diversifier {
let ff = FF1 ::< Aes256 > ::new ( & self . 0 , 2 ) . expect ( " valid radix " ) ;
let enc = ff
. encrypt ( & [ ] , & BinaryNumeralString ::from_bytes_le ( & j . into ( ) . 0 [ .. ] ) )
. unwrap ( ) ;
Diversifier ( enc . to_bytes_le ( ) . try_into ( ) . unwrap ( ) )
2021-03-05 15:25:45 -08:00
}
2021-07-20 12:37:07 -07:00
2022-02-11 07:54:14 -08:00
/// Returns the diversifier index obtained by decrypting the diversifier.
pub fn diversifier_index ( & self , d : & Diversifier ) -> DiversifierIndex {
let ff = FF1 ::< Aes256 > ::new ( & self . 0 , 2 ) . expect ( " valid radix " ) ;
let dec = ff
. decrypt ( & [ ] , & BinaryNumeralString ::from_bytes_le ( d . as_array ( ) ) )
. unwrap ( ) ;
DiversifierIndex ::from ( < [ u8 ; 11 ] > ::try_from ( dec . to_bytes_le ( ) ) . unwrap ( ) )
}
2021-07-20 12:37:07 -07:00
/// Return the raw bytes of the diversifier key
pub fn to_bytes ( & self ) -> & [ u8 ; 32 ] {
& self . 0
}
2021-07-21 13:31:37 -07:00
/// Construct a diversifier key from bytes
2021-07-20 12:37:07 -07:00
pub fn from_bytes ( bytes : [ u8 ; 32 ] ) -> Self {
DiversifierKey ( bytes )
}
2021-03-05 15:25:45 -08:00
}
2021-01-20 10:54:00 -08:00
/// A diversifier that can be used to derive a specific [`Address`] from a
/// [`FullViewingKey`] or [`IncomingViewingKey`].
2021-03-08 12:22:38 -08:00
///
2022-02-18 06:24:22 -08:00
/// $\mathsf{d}$ as defined in [Zcash Protocol Spec § 4.2.3: Orchard Key Components][orchardkeycomponents].
2021-03-08 12:22:38 -08:00
///
/// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents
2021-06-10 11:19:08 -07:00
#[ derive(Clone, Copy, Debug, PartialEq, Eq) ]
2021-02-03 06:16:58 -08:00
pub struct Diversifier ( [ u8 ; 11 ] ) ;
2021-01-20 10:54:00 -08:00
2021-03-12 16:04:13 -08:00
impl Diversifier {
2022-07-05 10:54:37 -07:00
///Read a diversifier from a byte array.
pub fn from_bytes ( d : [ u8 ; 11 ] ) -> Self {
2021-06-02 15:22:22 -07:00
Diversifier ( d )
}
2021-03-12 16:04:13 -08:00
/// Returns the byte array corresponding to this diversifier.
pub fn as_array ( & self ) -> & [ u8 ; 11 ] {
& self . 0
}
}
2021-05-11 03:07:08 -07:00
/// The private key $\mathsf{ivk}$ used in $KA^{Orchard}$, for decrypting incoming notes.
///
/// In Sapling this is what was encoded as an incoming viewing key. For Orchard, we store
/// both this and [`DiversifierKey`] inside [`IncomingViewingKey`] for usability (to
/// enable deriving the default address for an incoming viewing key), while this separate
/// type represents $\mathsf{ivk}$.
///
/// Defined in [Zcash Protocol Spec § 4.2.3: Orchard Key Components][orchardkeycomponents].
///
/// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents
///
/// # Implementation notes
///
/// We store $\mathsf{ivk}$ in memory as a scalar instead of a base, so that we aren't
/// incurring an expensive serialize-and-parse step every time we use it (e.g. for trial
/// decryption of notes). When we actually want to serialize ivk, we're guaranteed to get
/// a valid base field element encoding, because we always construct ivk from an integer
/// in the correct range.
2021-07-26 11:05:28 -07:00
#[ derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord) ]
2021-05-11 03:07:08 -07:00
struct KeyAgreementPrivateKey ( NonZeroPallasScalar ) ;
2022-03-30 04:53:46 -07:00
impl KeyAgreementPrivateKey {
/// Derives `KeyAgreementPrivateKey` from fvk.
///
/// Defined in [Zcash Protocol Spec § 4.2.3: Orchard Key Components][orchardkeycomponents].
///
/// [orchardkeycomponents]: https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents
fn from_fvk ( fvk : & FullViewingKey ) -> Self {
2022-03-30 05:16:45 -07:00
// FullViewingKey cannot be constructed such that this unwrap would fail.
2021-05-11 03:07:08 -07:00
let ivk = KeyAgreementPrivateKey ::derive_inner ( fvk ) . unwrap ( ) ;
KeyAgreementPrivateKey ( ivk . into ( ) )
}
}
impl KeyAgreementPrivateKey {
2021-05-21 13:24:08 -07:00
/// Derives ivk from fvk. Internal use only, does not enforce all constraints.
2022-03-17 07:39:15 -07:00
///
/// Defined in [Zcash Protocol Spec § 4.2.3: Orchard Key Components][orchardkeycomponents].
///
/// [orchardkeycomponents]: https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents
2021-05-11 03:07:08 -07:00
fn derive_inner ( fvk : & FullViewingKey ) -> CtOption < NonZeroPallasBase > {
let ak = extract_p ( & pallas ::Point ::from_bytes ( & ( & fvk . ak . 0 ) . into ( ) ) . unwrap ( ) ) ;
commit_ivk ( & ak , & fvk . nk . 0 , & fvk . rivk . 0 )
2022-03-17 07:39:15 -07:00
// sinsemilla::CommitDomain::short_commit returns a value in range
// [0..q_P] ∪ {⊥}:
// - sinsemilla::HashDomain::hash_to_point uses incomplete addition and
// returns a point in P* ∪ {⊥}.
// - sinsemilla::CommitDomain::commit applies a final complete addition step
// and returns a point in P ∪ {⊥}.
// - 0 is not a valid x-coordinate for any Pallas point.
// - sinsemilla::CommitDomain::short_commit calls extract_p_bottom, which
// replaces the identity (which has no affine coordinates) with 0.
//
// Commit^ivk.Output is specified as [1..q_P] ∪ {⊥}, so we explicitly check
// for 0 and map it to None. Note that we are collapsing this case (which is
// rejected by the circuit) with ⊥ (which the circuit explicitly allows for
// efficiency); this is fine because we don't want users of the `orchard`
// crate to encounter either case (and it matches the behaviour described in
// Section 4.2.3 of the protocol spec when generating spending keys).
. and_then ( NonZeroPallasBase ::from_base )
2021-05-11 03:07:08 -07:00
}
/// Returns the payment address for this key corresponding to the given diversifier.
fn address ( & self , d : Diversifier ) -> Address {
2021-06-02 15:22:22 -07:00
let pk_d = DiversifiedTransmissionKey ::derive_inner ( self , & d ) ;
2021-05-11 03:07:08 -07:00
Address ::from_parts ( d , pk_d )
}
}
2021-01-20 10:54:00 -08:00
/// A key that provides the capability to detect and decrypt incoming notes from the block
/// chain, without being able to spend the notes or detect when they are spent.
///
/// This key is useful in situations where you only need the capability to detect inbound
/// payments, such as merchant terminals.
///
2021-02-08 07:01:34 -08:00
/// This key is not suitable for use on its own in a wallet, as it cannot maintain
/// accurate balance. You should use a [`FullViewingKey`] instead.
2021-03-08 12:22:38 -08:00
///
2021-05-11 03:07:08 -07:00
/// Defined in [Zcash Protocol Spec § 5.6.4.3: Orchard Raw Incoming Viewing Keys][orchardinviewingkeyencoding].
2021-03-08 12:22:38 -08:00
///
2021-05-11 03:07:08 -07:00
/// [orchardinviewingkeyencoding]: https://zips.z.cash/protocol/nu5.pdf#orchardinviewingkeyencoding
2021-07-26 11:05:28 -07:00
#[ derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord) ]
2021-05-11 03:07:08 -07:00
pub struct IncomingViewingKey {
dk : DiversifierKey ,
ivk : KeyAgreementPrivateKey ,
}
2021-01-20 10:54:00 -08:00
2022-03-30 04:53:46 -07:00
impl IncomingViewingKey {
/// Helper method.
fn from_fvk ( fvk : & FullViewingKey ) -> Self {
2021-05-11 03:07:08 -07:00
IncomingViewingKey {
2022-02-14 15:00:04 -08:00
dk : fvk . derive_dk_ovk ( ) . 0 ,
2022-03-30 04:53:46 -07:00
ivk : KeyAgreementPrivateKey ::from_fvk ( fvk ) ,
2021-05-11 03:07:08 -07:00
}
2021-01-20 10:54:00 -08:00
}
}
2021-01-21 04:16:50 -08:00
impl IncomingViewingKey {
2021-08-23 10:25:29 -07:00
/// Serializes an Orchard incoming viewing key to its raw encoding as specified in [Zcash Protocol Spec § 5.6.4.3: Orchard Raw Incoming Viewing Keys][orchardrawinviewingkeys]
///
/// [orchardrawinviewingkeys]: https://zips.z.cash/protocol/protocol.pdf#orchardinviewingkeyencoding
2021-07-20 12:37:07 -07:00
pub fn to_bytes ( & self ) -> [ u8 ; 64 ] {
let mut result = [ 0 u8 ; 64 ] ;
2021-11-17 04:12:20 -08:00
result [ .. 32 ] . copy_from_slice ( self . dk . to_bytes ( ) ) ;
2021-12-07 10:02:03 -08:00
result [ 32 .. ] . copy_from_slice ( & self . ivk . 0. to_repr ( ) ) ;
2021-07-20 12:37:07 -07:00
result
}
2021-06-10 11:19:08 -07:00
/// Parses an Orchard incoming viewing key from its raw encoding.
pub fn from_bytes ( bytes : & [ u8 ; 64 ] ) -> CtOption < Self > {
NonZeroPallasBase ::from_bytes ( bytes [ 32 .. ] . try_into ( ) . unwrap ( ) ) . map ( | ivk | {
IncomingViewingKey {
dk : DiversifierKey ( bytes [ .. 32 ] . try_into ( ) . unwrap ( ) ) ,
ivk : KeyAgreementPrivateKey ( ivk . into ( ) ) ,
}
} )
}
2022-02-14 15:00:04 -08:00
/// Checks whether the given address was derived from this incoming viewing
/// key, and returns the diversifier index used to derive the address if
/// so. Returns `None` if the address was not derived from this key.
pub fn diversifier_index ( & self , addr : & Address ) -> Option < DiversifierIndex > {
let j = self . dk . diversifier_index ( & addr . diversifier ( ) ) ;
if & self . address_at ( j ) = = addr {
Some ( j )
} else {
None
}
2021-05-11 03:07:08 -07:00
}
/// Returns the payment address for this key at the given index.
pub fn address_at ( & self , j : impl Into < DiversifierIndex > ) -> Address {
self . address ( self . dk . get ( j ) )
2021-04-19 15:05:56 -07:00
}
2021-01-20 10:54:00 -08:00
/// Returns the payment address for this key corresponding to the given diversifier.
2021-03-17 12:15:55 -07:00
pub fn address ( & self , d : Diversifier ) -> Address {
2021-05-11 03:07:08 -07:00
self . ivk . address ( d )
2021-01-20 10:54:00 -08:00
}
}
2021-02-08 07:01:34 -08:00
/// A key that provides the capability to recover outgoing transaction information from
/// the block chain.
///
/// This key is not suitable for use on its own in a wallet, as it cannot maintain
/// accurate balance. You should use a [`FullViewingKey`] instead.
2021-03-08 12:22:38 -08:00
///
/// Defined in [Zcash Protocol Spec § 4.2.3: Orchard Key Components][orchardkeycomponents].
///
/// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents
2021-04-27 06:49:49 -07:00
#[ derive(Debug, Clone) ]
2021-03-05 15:25:45 -08:00
pub struct OutgoingViewingKey ( [ u8 ; 32 ] ) ;
2021-02-08 07:01:34 -08:00
2022-03-30 04:53:46 -07:00
impl OutgoingViewingKey {
/// Helper method.
fn from_fvk ( fvk : & FullViewingKey ) -> Self {
2021-03-05 15:25:45 -08:00
fvk . derive_dk_ovk ( ) . 1
2021-02-08 07:01:34 -08:00
}
}
2021-03-05 17:03:53 -08:00
2021-06-10 11:19:08 -07:00
impl From < [ u8 ; 32 ] > for OutgoingViewingKey {
fn from ( ovk : [ u8 ; 32 ] ) -> Self {
OutgoingViewingKey ( ovk )
}
}
2021-06-02 15:22:22 -07:00
impl AsRef < [ u8 ; 32 ] > for OutgoingViewingKey {
fn as_ref ( & self ) -> & [ u8 ; 32 ] {
& self . 0
}
}
2021-03-05 17:03:53 -08:00
/// The diversified transmission key for a given payment address.
2021-03-08 12:22:38 -08:00
///
/// Defined in [Zcash Protocol Spec § 4.2.3: Orchard Key Components][orchardkeycomponents].
///
/// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents
2022-05-06 12:05:24 -07:00
#[ derive(Clone, Copy, Debug, Default, PartialEq, Eq) ]
2021-06-02 15:22:22 -07:00
pub struct DiversifiedTransmissionKey ( NonIdentityPallasPoint ) ;
2021-03-05 17:03:53 -08:00
2021-07-22 07:14:34 -07:00
impl DiversifiedTransmissionKey {
pub ( crate ) fn inner ( & self ) -> NonIdentityPallasPoint {
self . 0
2021-07-19 09:42:22 -07:00
}
}
2021-03-05 17:03:53 -08:00
impl DiversifiedTransmissionKey {
2021-03-05 17:17:51 -08:00
/// Defined in [Zcash Protocol Spec § 4.2.3: Orchard Key Components][orchardkeycomponents].
2021-03-05 17:03:53 -08:00
///
2021-03-05 17:17:51 -08:00
/// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents
2021-06-02 15:22:22 -07:00
pub ( crate ) fn derive ( ivk : & IncomingViewingKey , d : & Diversifier ) -> Self {
Self ::derive_inner ( & ivk . ivk , d )
}
fn derive_inner ( ivk : & KeyAgreementPrivateKey , d : & Diversifier ) -> Self {
2021-06-21 10:01:35 -07:00
let g_d = diversify_hash ( d . as_array ( ) ) ;
2021-03-17 12:15:55 -07:00
DiversifiedTransmissionKey ( ka_orchard ( & ivk . 0 , & g_d ) )
2021-03-05 17:03:53 -08:00
}
2021-03-12 16:04:13 -08:00
2021-06-02 15:22:22 -07:00
/// $abst_P(bytes)$
pub ( crate ) fn from_bytes ( bytes : & [ u8 ; 32 ] ) -> CtOption < Self > {
NonIdentityPallasPoint ::from_bytes ( bytes ) . map ( DiversifiedTransmissionKey )
}
2021-03-12 16:04:13 -08:00
/// $repr_P(self)$
2021-05-28 04:11:22 -07:00
pub ( crate ) fn to_bytes ( self ) -> [ u8 ; 32 ] {
2021-03-12 16:04:13 -08:00
self . 0. to_bytes ( )
}
2021-03-05 17:03:53 -08:00
}
2021-04-27 06:49:49 -07:00
2021-07-22 15:59:02 -07:00
impl ConditionallySelectable for DiversifiedTransmissionKey {
fn conditional_select ( a : & Self , b : & Self , choice : Choice ) -> Self {
DiversifiedTransmissionKey ( NonIdentityPallasPoint ::conditional_select (
& a . 0 , & b . 0 , choice ,
) )
}
}
2021-06-02 14:31:18 -07:00
/// An ephemeral secret key used to encrypt an output note on-chain.
///
/// `esk` is "ephemeral" in the sense that each secret key is only used once. In
/// practice, `esk` is derived deterministically from the note that it is encrypting.
///
/// $\mathsf{KA}^\mathsf{Orchard}.\mathsf{Private} := \mathbb{F}^{\ast}_{r_P}$
///
/// Defined in [section 5.4.5.5: Orchard Key Agreement][concreteorchardkeyagreement].
///
/// [concreteorchardkeyagreement]: https://zips.z.cash/protocol/nu5.pdf#concreteorchardkeyagreement
#[ derive(Debug) ]
pub struct EphemeralSecretKey ( pub ( crate ) NonZeroPallasScalar ) ;
impl ConstantTimeEq for EphemeralSecretKey {
fn ct_eq ( & self , other : & Self ) -> subtle ::Choice {
self . 0. ct_eq ( & other . 0 )
}
}
impl EphemeralSecretKey {
pub ( crate ) fn from_bytes ( bytes : & [ u8 ; 32 ] ) -> CtOption < Self > {
NonZeroPallasScalar ::from_bytes ( bytes ) . map ( EphemeralSecretKey )
}
pub ( crate ) fn derive_public ( & self , g_d : NonIdentityPallasPoint ) -> EphemeralPublicKey {
EphemeralPublicKey ( ka_orchard ( & self . 0 , & g_d ) )
}
pub ( crate ) fn agree ( & self , pk_d : & DiversifiedTransmissionKey ) -> SharedSecret {
SharedSecret ( ka_orchard ( & self . 0 , & pk_d . 0 ) )
}
}
/// An ephemeral public key used to encrypt an output note on-chain.
///
/// `epk` is "ephemeral" in the sense that each public key is only used once. In practice,
/// `epk` is derived deterministically from the note that it is encrypting.
///
/// $\mathsf{KA}^\mathsf{Orchard}.\mathsf{Public} := \mathbb{P}^{\ast}$
///
/// Defined in [section 5.4.5.5: Orchard Key Agreement][concreteorchardkeyagreement].
///
/// [concreteorchardkeyagreement]: https://zips.z.cash/protocol/nu5.pdf#concreteorchardkeyagreement
#[ derive(Debug) ]
pub struct EphemeralPublicKey ( NonIdentityPallasPoint ) ;
impl EphemeralPublicKey {
pub ( crate ) fn from_bytes ( bytes : & [ u8 ; 32 ] ) -> CtOption < Self > {
NonIdentityPallasPoint ::from_bytes ( bytes ) . map ( EphemeralPublicKey )
}
pub ( crate ) fn to_bytes ( & self ) -> EphemeralKeyBytes {
EphemeralKeyBytes ( self . 0. to_bytes ( ) )
}
pub ( crate ) fn agree ( & self , ivk : & IncomingViewingKey ) -> SharedSecret {
SharedSecret ( ka_orchard ( & ivk . ivk . 0 , & self . 0 ) )
}
}
/// $\mathsf{KA}^\mathsf{Orchard}.\mathsf{SharedSecret} := \mathbb{P}^{\ast}$
///
/// Defined in [section 5.4.5.5: Orchard Key Agreement][concreteorchardkeyagreement].
///
/// [concreteorchardkeyagreement]: https://zips.z.cash/protocol/nu5.pdf#concreteorchardkeyagreement
#[ derive(Debug) ]
pub struct SharedSecret ( NonIdentityPallasPoint ) ;
impl SharedSecret {
2021-06-10 11:19:08 -07:00
/// For checking test vectors only.
#[ cfg(test) ]
pub ( crate ) fn to_bytes ( & self ) -> [ u8 ; 32 ] {
self . 0. to_bytes ( )
}
2021-08-10 17:19:58 -07:00
/// Only for use in batched note encryption.
2021-08-12 05:46:27 -07:00
pub ( crate ) fn batch_to_affine (
shared_secrets : Vec < Option < Self > > ,
) -> impl Iterator < Item = Option < pallas ::Affine > > {
// Filter out the positions for which ephemeral_key was not a valid encoding.
2021-08-10 17:19:58 -07:00
let secrets : Vec < _ > = shared_secrets
. iter ( )
. filter_map ( | s | s . as_ref ( ) . map ( | s | * ( s . 0 ) ) )
. collect ( ) ;
2021-08-12 05:46:27 -07:00
// Batch-normalize the shared secrets.
2021-08-12 05:40:56 -07:00
let mut secrets_affine = vec! [ pallas ::Affine ::identity ( ) ; secrets . len ( ) ] ;
2021-08-10 17:19:58 -07:00
group ::Curve ::batch_normalize ( & secrets , & mut secrets_affine ) ;
2021-08-12 05:46:27 -07:00
// Re-insert the invalid ephemeral_key positions.
let mut secrets_affine = secrets_affine . into_iter ( ) ;
shared_secrets
. into_iter ( )
. map ( move | s | s . and_then ( | _ | secrets_affine . next ( ) ) )
2021-08-10 17:19:58 -07:00
}
2021-06-02 14:31:18 -07:00
/// Defined in [Zcash Protocol Spec § 5.4.5.6: Orchard Key Agreement][concreteorchardkdf].
///
/// [concreteorchardkdf]: https://zips.z.cash/protocol/nu5.pdf#concreteorchardkdf
pub ( crate ) fn kdf_orchard ( self , ephemeral_key : & EphemeralKeyBytes ) -> Blake2bHash {
2021-08-10 17:19:58 -07:00
Self ::kdf_orchard_inner ( self . 0. to_affine ( ) , ephemeral_key )
}
/// Only for direct use in batched note encryption.
pub ( crate ) fn kdf_orchard_inner (
secret : pallas ::Affine ,
ephemeral_key : & EphemeralKeyBytes ,
) -> Blake2bHash {
2021-06-02 14:31:18 -07:00
Params ::new ( )
. hash_length ( 32 )
. personal ( KDF_ORCHARD_PERSONALIZATION )
. to_state ( )
2021-08-10 17:19:58 -07:00
. update ( & secret . to_bytes ( ) )
2021-06-02 14:31:18 -07:00
. update ( & ephemeral_key . 0 )
. finalize ( )
}
}
2021-04-27 06:49:49 -07:00
/// Generators for property testing.
#[ cfg(any(test, feature = " test-dependencies " )) ]
2021-12-17 14:08:58 -08:00
#[ cfg_attr(docsrs, doc(cfg(feature = " test-dependencies " ))) ]
2021-04-27 06:49:49 -07:00
pub mod testing {
use proptest ::prelude ::* ;
2022-02-11 07:54:14 -08:00
use super ::{ DiversifierIndex , DiversifierKey , EphemeralSecretKey , SpendingKey } ;
2021-04-27 06:49:49 -07:00
prop_compose! {
2022-02-11 07:54:14 -08:00
/// Generate a uniformly distributed Orchard spending key.
2021-04-27 06:49:49 -07:00
pub fn arb_spending_key ( ) (
2021-05-05 10:46:24 -07:00
key in prop ::array ::uniform32 ( prop ::num ::u8 ::ANY )
. prop_map ( SpendingKey ::from_bytes )
. prop_filter (
2021-04-27 06:49:49 -07:00
" Values must correspond to valid Orchard spending keys. " ,
| opt | bool ::from ( opt . is_some ( ) )
)
) -> SpendingKey {
key . unwrap ( )
}
}
2021-06-02 14:31:18 -07:00
prop_compose! {
2022-02-11 07:54:14 -08:00
/// Generate a uniformly distributed Orchard ephemeral secret key.
2021-06-02 14:31:18 -07:00
pub fn arb_esk ( ) (
esk in prop ::array ::uniform32 ( prop ::num ::u8 ::ANY )
. prop_map ( | b | EphemeralSecretKey ::from_bytes ( & b ) )
. prop_filter (
" Values must correspond to valid Orchard ephemeral secret keys. " ,
| opt | bool ::from ( opt . is_some ( ) )
)
) -> EphemeralSecretKey {
esk . unwrap ( )
}
}
2022-02-11 07:54:14 -08:00
prop_compose! {
/// Generate a uniformly distributed Orchard diversifier key.
2022-02-14 16:02:08 -08:00
pub ( crate ) fn arb_diversifier_key ( ) (
2022-02-11 07:54:14 -08:00
dk_bytes in prop ::array ::uniform32 ( prop ::num ::u8 ::ANY )
) -> DiversifierKey {
DiversifierKey ::from_bytes ( dk_bytes )
}
}
prop_compose! {
/// Generate a uniformly distributed diversifier index.
pub fn arb_diversifier_index ( ) (
d_bytes in prop ::array ::uniform11 ( prop ::num ::u8 ::ANY )
) -> DiversifierIndex {
DiversifierIndex ::from ( d_bytes )
}
}
2021-04-27 06:49:49 -07:00
}
2021-05-28 03:57:21 -07:00
#[ cfg(test) ]
mod tests {
use ff ::PrimeField ;
2021-06-02 14:31:18 -07:00
use proptest ::prelude ::* ;
2021-05-28 03:57:21 -07:00
2021-06-02 14:31:18 -07:00
use super ::{
2022-02-11 07:54:14 -08:00
testing ::{ arb_diversifier_index , arb_diversifier_key , arb_esk , arb_spending_key } ,
2021-06-02 14:31:18 -07:00
* ,
} ;
2021-05-28 03:57:21 -07:00
use crate ::{
2021-06-02 15:14:13 -07:00
note ::{ ExtractedNoteCommitment , Nullifier , RandomSeed } ,
2021-05-28 03:57:21 -07:00
value ::NoteValue ,
Note ,
} ;
2021-12-15 05:48:59 -08:00
#[ test ]
fn spend_validating_key_from_bytes ( ) {
// ak_P must not be the identity.
assert! ( SpendValidatingKey ::from_bytes ( & [ 0 ; 32 ] ) . is_none ( ) ) ;
}
2021-06-02 14:31:18 -07:00
#[ test ]
fn parsers_reject_invalid ( ) {
assert! ( bool ::from (
EphemeralSecretKey ::from_bytes ( & [ 0xff ; 32 ] ) . is_none ( )
) ) ;
assert! ( bool ::from (
EphemeralPublicKey ::from_bytes ( & [ 0xff ; 32 ] ) . is_none ( )
) ) ;
}
proptest! {
#[ test ]
fn key_agreement (
sk in arb_spending_key ( ) ,
esk in arb_esk ( ) ,
2022-02-15 07:30:09 -08:00
j in arb_diversifier_index ( ) ,
2021-06-02 14:31:18 -07:00
) {
2022-03-30 04:53:46 -07:00
let ivk = IncomingViewingKey ::from_fvk ( & ( & sk ) . into ( ) ) ;
2022-02-15 07:30:09 -08:00
let addr = ivk . address_at ( j ) ;
2021-06-02 14:31:18 -07:00
let epk = esk . derive_public ( addr . g_d ( ) ) ;
assert! ( bool ::from (
esk . agree ( addr . pk_d ( ) ) . 0. ct_eq ( & epk . agree ( & ivk ) . 0 )
) ) ;
}
}
2022-02-11 07:54:14 -08:00
proptest! {
#[ test ]
fn diversifier_index (
dk in arb_diversifier_key ( ) ,
j in arb_diversifier_index ( ) ,
) {
let d = dk . get ( j ) ;
assert_eq! ( j , dk . diversifier_index ( & d ) ) ;
}
}
2021-05-28 03:57:21 -07:00
#[ test ]
fn test_vectors ( ) {
for tv in crate ::test_vectors ::keys ::test_vectors ( ) {
let sk = SpendingKey ::from_bytes ( tv . sk ) . unwrap ( ) ;
let ask : SpendAuthorizingKey = ( & sk ) . into ( ) ;
assert_eq! ( < [ u8 ; 32 ] > ::from ( & ask . 0 ) , tv . ask ) ;
let ak : SpendValidatingKey = ( & ask ) . into ( ) ;
assert_eq! ( < [ u8 ; 32 ] > ::from ( ak . 0 ) , tv . ak ) ;
let nk : NullifierDerivingKey = ( & sk ) . into ( ) ;
assert_eq! ( nk . 0. to_repr ( ) , tv . nk ) ;
let rivk : CommitIvkRandomness = ( & sk ) . into ( ) ;
assert_eq! ( rivk . 0. to_repr ( ) , tv . rivk ) ;
let fvk : FullViewingKey = ( & sk ) . into ( ) ;
assert_eq! ( < [ u8 ; 32 ] > ::from ( & fvk . ak . 0 ) , tv . ak ) ;
assert_eq! ( fvk . nk ( ) . 0. to_repr ( ) , tv . nk ) ;
assert_eq! ( fvk . rivk . 0. to_repr ( ) , tv . rivk ) ;
2022-03-30 04:53:46 -07:00
let external_ivk = fvk . to_ivk ( Scope ::External ) ;
assert_eq! ( external_ivk . ivk . 0. to_repr ( ) , tv . ivk ) ;
2021-05-28 03:57:21 -07:00
let diversifier = Diversifier ( tv . default_d ) ;
2022-03-30 04:53:46 -07:00
let addr = fvk . address ( diversifier , Scope ::External ) ;
2021-05-28 03:57:21 -07:00
assert_eq! ( & addr . pk_d ( ) . to_bytes ( ) , & tv . default_pk_d ) ;
let rho = Nullifier ::from_bytes ( & tv . note_rho ) . unwrap ( ) ;
let note = Note ::from_parts (
addr ,
NoteValue ::from_raw ( tv . note_v ) ,
rho ,
2021-06-02 15:14:13 -07:00
RandomSeed ::from_bytes ( tv . note_rseed , & rho ) . unwrap ( ) ,
2021-05-28 03:57:21 -07:00
) ;
let cmx : ExtractedNoteCommitment = note . commitment ( ) . into ( ) ;
assert_eq! ( cmx . to_bytes ( ) , tv . note_cmx ) ;
assert_eq! ( note . nullifier ( & fvk ) . to_bytes ( ) , tv . note_nf ) ;
2022-02-01 02:54:50 -08:00
2022-03-30 04:53:46 -07:00
let internal_rivk = fvk . rivk ( Scope ::Internal ) ;
2022-02-01 02:54:50 -08:00
assert_eq! ( internal_rivk . 0. to_repr ( ) , tv . internal_rivk ) ;
2022-03-30 04:53:46 -07:00
let internal_ivk = fvk . to_ivk ( Scope ::Internal ) ;
assert_eq! ( internal_ivk . ivk . 0. to_repr ( ) , tv . internal_ivk ) ;
assert_eq! ( internal_ivk . dk . 0 , tv . internal_dk ) ;
2022-02-01 02:54:50 -08:00
2022-03-30 04:53:46 -07:00
let internal_ovk = fvk . to_ovk ( Scope ::Internal ) ;
2022-02-01 02:54:50 -08:00
assert_eq! ( internal_ovk . 0 , tv . internal_ovk ) ;
2021-05-28 03:57:21 -07:00
}
}
}