From eb56666d3072cbd1584e54792345e53d6eccf76f Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Fri, 16 Oct 2020 14:41:41 -0700 Subject: [PATCH] chain: add ShieldedData::binding_verification_key() --- zebra-chain/src/transaction/shielded_data.rs | 38 +++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/zebra-chain/src/transaction/shielded_data.rs b/zebra-chain/src/transaction/shielded_data.rs index c6df6550..f38ff6cc 100644 --- a/zebra-chain/src/transaction/shielded_data.rs +++ b/zebra-chain/src/transaction/shielded_data.rs @@ -1,8 +1,9 @@ use futures::future::Either; use crate::{ + amount::Amount, primitives::redjubjub::{Binding, Signature}, - sapling::{Nullifier, Output, Spend}, + sapling::{Nullifier, Output, Spend, ValueCommitment}, serialization::serde_helpers, }; @@ -72,6 +73,41 @@ impl ShieldedData { pub fn note_commitments(&self) -> Vec { self.outputs().map(|output| output.cm_u).collect() } + + /// Calculate the Spend/Output binding verification key. + /// + /// Getting the binding signature validating key from the Spend and Output + /// description value commitments and the balancing value implicitly checks + /// that the balancing value is consistent with the value transfered in the + /// Spend and Output descriptions but also proves that the signer knew the + /// randomness used for the Spend and Output value commitments, which + /// prevents replays of Output descriptions. + /// + /// The net value of Spend transfers minus Output transfers in a transaction + /// is called the balancing value, measured in zatoshi as a signed integer + /// v_balance. + /// + /// Consistency of v_balance with the value commitments in Spend + /// descriptions and Output descriptions is enforced by the binding + /// signature. + /// + /// Instead of generating a key pair at random, we generate it as a function + /// of the value commitments in the Spend descriptions and Output + /// descriptions of the transaction, and the balancing value. + /// + /// https://zips.z.cash/protocol/canopy.pdf#saplingbalance + pub fn binding_verification_key( + &self, + value_balance: Amount, + ) -> redjubjub::VerificationKeyBytes { + let cv_old: ValueCommitment = self.spends().map(|spend| spend.cv).sum(); + let cv_new: ValueCommitment = self.outputs().map(|output| output.cv).sum(); + let cv_balance: ValueCommitment = ValueCommitment::new(jubjub::Fr::zero(), value_balance); + + let key_bytes: [u8; 32] = (cv_old - cv_new - cv_balance).into(); + + key_bytes.into() + } } // Technically, it's possible to construct two equivalent representations