From fd29708eccb235a6e94a5e8b2596a4f230a9cd33 Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Mon, 8 Mar 2021 15:45:18 -0500 Subject: [PATCH] orchard: derive IncomingViewingKey from FullViewingKey Includes sinsemilla commit and short commit --- zebra-chain/src/orchard/keys.rs | 19 ++++++++++++------- zebra-chain/src/orchard/sinsemilla.rs | 21 +++++++++++++++++++++ 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/zebra-chain/src/orchard/keys.rs b/zebra-chain/src/orchard/keys.rs index 8d2dbffb9..dc8fa31a9 100644 --- a/zebra-chain/src/orchard/keys.rs +++ b/zebra-chain/src/orchard/keys.rs @@ -389,7 +389,7 @@ mod ivk_hrp { pub const TESTNET: &str = "zivktestorchard"; } -/// An _Incoming Viewing Key_, as described in [protocol specification +/// An incoming viewing key, as described in [protocol specification /// §4.2.3][ps]. /// /// Used to decrypt incoming notes without spending them. @@ -433,18 +433,23 @@ impl From<[u8; 32]> for IncomingViewingKey { } } -impl From<(SpendValidatingKey, NullifierDerivingKey)> for IncomingViewingKey { - /// For this invocation of Blake2s-256 as _CRH^ivk_. +impl From for IncomingViewingKey { + /// Commit^ivk_rivk(ak, nk) := + /// SinsemillaShortCommit_rcm (︁"z.cash:Orchard-CommitIvk", I2LEBSP_l(ak) || I2LEBSP_l(nk)︁) mod r_P /// /// https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents /// https://zips.z.cash/protocol/protocol.pdf#concreteprfs - fn from((ask, nk): (SpendValidatingKey, NullifierDerivingKey)) -> Self { - unimplemented!(); + fn from(fvk: FullViewingKey) -> Self { + let M = fvk.ak.into().join(fvk.nk.into()); - let hash_bytes = commit_ivk(ask.into(), nk.into()); + // Commit^ivk_rivk + let scalar = sinsemilla_short_commit(fvk.ivk.into(), "z.cash:Orchard-CommitIvk", M); - IncomingViewingKey::from(hash_bytes) + Self { + network: Network::default(), + scalar, + } } } diff --git a/zebra-chain/src/orchard/sinsemilla.rs b/zebra-chain/src/orchard/sinsemilla.rs index a3dd1f8e0..ac6ad83f4 100644 --- a/zebra-chain/src/orchard/sinsemilla.rs +++ b/zebra-chain/src/orchard/sinsemilla.rs @@ -105,3 +105,24 @@ pub fn extract_p(point: pallas::Point) -> pallas::Base { pub fn sinsemilla_hash(D: &[u8], M: &BitVec) -> pallas::Base { extract_p(sinsemilla_hash_to_point(D, M)) } + +/// Sinsemilla commit +/// +/// We construct Sinsemilla commitments by hashing to a point with Sinsemilla +/// hash, and adding a randomized point on the Pallas curve. +/// +/// SinsemillaCommit_r(D, M) := SinsemillaHashToPoint(D || "-M", M) + [r]GroupHash^P(D ||“-r”,"") +/// +/// https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit +#[allow(non_snake_case)] +pub fn sinsemilla_commit(r: pallas::Scalar, D: &[u8], M: &BitVec) -> pallas::Point { + sinsemilla_hash_to_point(D.join(b"-M"), M) + r * pallas_group_hash(D.join(b"r"), b"") +} + +/// SinsemillaShortCommit_r(D, M) := Extract_P(SinsemillaCommit_r(D, M)) +/// +/// https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit +#[allow(non_snake_case)] +pub fn sinsemilla_short_commit(r: pallas::Scalar, D: &[u8], M: &BitVec) -> pallas::Base { + extract_p(sinsemilla_commit(r, D, M)) +}