chain: add ShieldedData::binding_verification_key()

This commit is contained in:
Deirdre Connolly 2020-10-16 14:41:41 -07:00 committed by Deirdre Connolly
parent 5a78bbb6c9
commit eb56666d30
1 changed files with 37 additions and 1 deletions

View File

@ -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<jubjub::Fq> {
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<Binding> {
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