diff --git a/Cargo.lock b/Cargo.lock index 7b27f928e..c5ab7fc15 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -719,7 +719,9 @@ name = "zcash_proofs" version = "0.0.0" dependencies = [ "bellman 0.1.0", + "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "sapling-crypto 0.0.1", ] diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 4a2c349d1..e04d52653 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -15,7 +15,7 @@ extern crate lazy_static; use pairing::{ bls12_381::{Bls12, Fr, FrRepr}, - BitIterator, Field, PrimeField, PrimeFieldRepr, + BitIterator, PrimeField, PrimeFieldRepr, }; use sapling_crypto::{ @@ -30,9 +30,8 @@ use sapling_crypto::{ redjubjub::{self, Signature}, }; +use sapling_crypto::circuit::sapling::TREE_DEPTH as SAPLING_TREE_DEPTH; use sapling_crypto::circuit::sprout::{self, TREE_DEPTH as SPROUT_TREE_DEPTH}; -// TODO: make these consistent -const SAPLING_TREE_DEPTH: usize = 32; use bellman::groth16::{ create_random_proof, prepare_verifying_key, verify_proof, Parameters, PreparedVerifyingKey, @@ -43,7 +42,7 @@ use blake2_rfc::blake2s::Blake2s; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use rand::{OsRng, Rand, Rng}; +use rand::{OsRng, Rng}; use std::io::{self, BufReader}; use libc::{c_char, c_uchar, int64_t, size_t, uint32_t, uint64_t}; @@ -62,8 +61,10 @@ use std::ffi::OsString; #[cfg(target_os = "windows")] use std::os::windows::ffi::OsStringExt; -use sapling_crypto::primitives::{ProofGenerationKey, ValueCommitment, ViewingKey}; -use zcash_proofs::sapling::{compute_value_balance, SaplingVerificationContext}; +use sapling_crypto::primitives::{ProofGenerationKey, ViewingKey}; +use zcash_proofs::sapling::{ + CommitmentTreeWitness, SaplingProvingContext, SaplingVerificationContext, +}; pub mod equihash; @@ -981,11 +982,6 @@ pub extern "system" fn librustzcash_sprout_verify( } } -pub struct SaplingProvingContext { - bsk: Fs, - bvk: edwards::Point, -} - #[no_mangle] pub extern "system" fn librustzcash_sapling_output_proof( ctx: *mut SaplingProvingContext, @@ -1030,58 +1026,15 @@ pub extern "system" fn librustzcash_sapling_output_proof( Err(_) => return false, }; - // Initialize secure RNG - let mut rng = OsRng::new().expect("should be able to construct RNG"); - - // We construct ephemeral randomness for the value commitment. This - // randomness is not given back to the caller, but the synthetic - // blinding factor `bsk` is accumulated in the context. - let rcv = Fs::rand(&mut rng); - - // Accumulate the value commitment randomness in the context - { - let mut tmp = rcv.clone(); - tmp.negate(); // Outputs subtract from the total. - tmp.add_assign(&unsafe { &*ctx }.bsk); - - // Update the context - unsafe { &mut *ctx }.bsk = tmp; - } - - // Construct the value commitment for the proof instance - let value_commitment = sapling_crypto::primitives::ValueCommitment:: { - value: value, - randomness: rcv, - }; - - // We now have a full witness for the output proof. - let instance = sapling_crypto::circuit::sapling::Output { - params: &*JUBJUB, - value_commitment: Some(value_commitment.clone()), - payment_address: Some(payment_address.clone()), - commitment_randomness: Some(rcm), - esk: Some(esk.clone()), - }; - // Create proof - let proof = create_random_proof( - instance, + let (proof, value_commitment) = unsafe { &mut *ctx }.output_proof( + esk, + payment_address, + rcm, + value, unsafe { SAPLING_OUTPUT_PARAMS.as_ref() }.unwrap(), - &mut rng, - ).expect("proving should not fail"); - - // Compute the value commitment - let value_commitment: edwards::Point = value_commitment.cm(&JUBJUB).into(); - - // Accumulate the value commitment in the context. We do this to check internal consistency. - { - let mut tmp = value_commitment.clone(); - tmp = tmp.negate(); // Outputs subtract from the total. - tmp = tmp.add(&unsafe { &*ctx }.bvk, &JUBJUB); - - // Update the context - unsafe { &mut *ctx }.bvk = tmp; - } + &JUBJUB, + ); // Write the proof out to the caller proof @@ -1152,54 +1105,11 @@ pub extern "system" fn librustzcash_sapling_binding_sig( sighash: *const [c_uchar; 32], result: *mut [c_uchar; 64], ) -> bool { - // Initialize secure RNG - let mut rng = OsRng::new().expect("should be able to construct RNG"); - - // Grab the current `bsk` from the context - let bsk = redjubjub::PrivateKey::(unsafe { &*ctx }.bsk); - - // Grab the `bvk` using DerivePublic. - let bvk = redjubjub::PublicKey::from_private( - &bsk, - FixedGenerators::ValueCommitmentRandomness, - &JUBJUB, - ); - - // In order to check internal consistency, let's use the accumulated value - // commitments (as the verifier would) and apply valuebalance to compare - // against our derived bvk. - { - // Compute value balance - let mut value_balance = match compute_value_balance(value_balance, &JUBJUB) { - Some(a) => a, - None => return false, - }; - - // Subtract value_balance from current bvk to get final bvk - value_balance = value_balance.negate(); - let mut tmp = unsafe { &*ctx }.bvk.clone(); - tmp = tmp.add(&value_balance, &JUBJUB); - - // The result should be the same, unless the provided valueBalance is wrong. - if bvk.0 != tmp { - return false; - } - } - - // Construct signature message - let mut data_to_be_signed = [0u8; 64]; - bvk.0 - .write(&mut data_to_be_signed[0..32]) - .expect("message buffer should be 32 bytes"); - (&mut data_to_be_signed[32..64]).copy_from_slice(&(unsafe { &*sighash })[..]); - // Sign - let sig = bsk.sign( - &data_to_be_signed, - &mut rng, - FixedGenerators::ValueCommitmentRandomness, - &JUBJUB, - ); + let sig = match unsafe { &*ctx }.binding_sig(value_balance, unsafe { &*sighash }, &JUBJUB) { + Ok(s) => s, + Err(_) => return false, + }; // Write out signature sig.write(&mut (unsafe { &mut *result })[..]) @@ -1262,43 +1172,6 @@ pub extern "system" fn librustzcash_sapling_spend_proof( Err(_) => return false, }; - // Initialize secure RNG - let mut rng = OsRng::new().expect("should be able to construct RNG"); - - // We create the randomness of the value commitment - let rcv = Fs::rand(&mut rng); - - // Accumulate the value commitment randomness in the context - { - let mut tmp = rcv.clone(); - tmp.add_assign(&unsafe { &*ctx }.bsk); - - // Update the context - unsafe { &mut *ctx }.bsk = tmp; - } - - // Construct the value commitment - let value_commitment = ValueCommitment:: { - value: value, - randomness: rcv, - }; - - // Construct the viewing key - let viewing_key = proof_generation_key.into_viewing_key(&JUBJUB); - - // Construct the payment address with the viewing key / diversifier - let payment_address = match viewing_key.into_payment_address(diversifier, &JUBJUB) { - Some(p) => p, - None => return false, - }; - - // This is the result of the re-randomization, we compute it for the caller - let rk = redjubjub::PublicKey::(ak.into()).randomize( - ar, - FixedGenerators::SpendingKeyGenerator, - &JUBJUB, - ); - // We need to compute the anchor of the Spend. let anchor = match Fr::from_repr(read_le(unsafe { &(&*anchor)[..] })) { Ok(p) => p, @@ -1307,140 +1180,25 @@ pub extern "system" fn librustzcash_sapling_spend_proof( // The witness contains the incremental tree witness information, in a // weird serialized format. - let mut witness = unsafe { &(&*witness)[..] }; - - // Skip the first byte, which should be "32" to signify the length of - // the following vector of Pedersen hashes. - assert_eq!(witness[0], SAPLING_TREE_DEPTH as u8); - witness = &witness[1..]; - - // Begin to construct the authentication path - let mut auth_path = vec![None; SAPLING_TREE_DEPTH]; - - // The vector works in reverse - for i in (0..SAPLING_TREE_DEPTH).rev() { - // skip length of inner vector - assert_eq!(witness[0], 32); // the length of a pedersen hash - witness = &witness[1..]; - - // Grab the sibling node at this depth in the tree - let mut sibling = [0u8; 32]; - sibling.copy_from_slice(&witness[0..32]); - witness = &witness[32..]; - - // Sibling node should be an element of Fr - let sibling = match Fr::from_repr(read_le(&sibling)) { - Ok(p) => p, - Err(_) => return false, - }; - - // Set the value in the auth path; we put false here - // for now (signifying the position bit) which we'll - // fill in later. - auth_path[i] = Some((sibling, false)); - } - - // Read the position from the witness - let mut position = witness - .read_u64::() - .expect("should have had index at the end"); - - // Let's compute the nullifier while we have the position - let note = sapling_crypto::primitives::Note { - value: value, - g_d: diversifier - .g_d::(&JUBJUB) - .expect("was a valid diversifier before"), - pk_d: payment_address.pk_d.clone(), - r: rcm, - }; - - let nullifier = note.nf(&viewing_key, position, &JUBJUB); - - // Given the position, let's finish constructing the authentication - // path - for i in 0..SAPLING_TREE_DEPTH { - auth_path[i].as_mut().map(|p| p.1 = (position & 1) == 1); - - position >>= 1; - } - - // The witness should be empty now; if it wasn't, the caller would - // have provided more information than they should have, indicating - // a bug downstream - assert_eq!(witness.len(), 0); - - // We now have the full witness for our circuit - let instance = sapling_crypto::circuit::sapling::Spend { - params: &*JUBJUB, - value_commitment: Some(value_commitment.clone()), - proof_generation_key: Some(proof_generation_key), - payment_address: Some(payment_address), - commitment_randomness: Some(rcm), - ar: Some(ar), - auth_path: auth_path, - anchor: Some(anchor), + let witness = match CommitmentTreeWitness::from_slice(unsafe { &(&*witness)[..] }) { + Ok(w) => w, + Err(_) => return false, }; // Create proof - let proof = create_random_proof( - instance, - unsafe { SAPLING_SPEND_PARAMS.as_ref() }.unwrap(), - &mut rng, - ).expect("proving should not fail"); - - // Try to verify the proof: - // Construct public input for circuit - let mut public_input = [Fr::zero(); 7]; - { - let (x, y) = rk.0.into_xy(); - public_input[0] = x; - public_input[1] = y; - } - { - let (x, y) = value_commitment.cm(&JUBJUB).into_xy(); - public_input[2] = x; - public_input[3] = y; - } - public_input[4] = anchor; - - // Add the nullifier through multiscalar packing - { - let nullifier = multipack::bytes_to_bits_le(&nullifier); - let nullifier = multipack::compute_multipacking::(&nullifier); - - assert_eq!(nullifier.len(), 2); - - public_input[5] = nullifier[0]; - public_input[6] = nullifier[1]; - } - - // Verify the proof - match verify_proof( - unsafe { SAPLING_SPEND_VK.as_ref() }.unwrap(), - &proof, - &public_input[..], - ) { - // No error, and proof verification successful - Ok(true) => {} - - // Any other case - _ => { - return false; - } - } - - // Compute value commitment - let value_commitment: edwards::Point = value_commitment.cm(&JUBJUB).into(); - - // Accumulate the value commitment in the context - { - let mut tmp = value_commitment.clone(); - tmp = tmp.add(&unsafe { &*ctx }.bvk, &JUBJUB); - - // Update the context - unsafe { &mut *ctx }.bvk = tmp; - } + let (proof, value_commitment, rk) = unsafe { &mut *ctx } + .spend_proof( + proof_generation_key, + diversifier, + rcm, + ar, + value, + anchor, + witness, + unsafe { SAPLING_SPEND_PARAMS.as_ref() }.unwrap(), + unsafe { SAPLING_SPEND_VK.as_ref() }.unwrap(), + &JUBJUB, + ).expect("proving should not fail"); // Write value commitment to caller value_commitment @@ -1461,10 +1219,7 @@ pub extern "system" fn librustzcash_sapling_spend_proof( #[no_mangle] pub extern "system" fn librustzcash_sapling_proving_ctx_init() -> *mut SaplingProvingContext { - let ctx = Box::new(SaplingProvingContext { - bsk: Fs::zero(), - bvk: edwards::Point::zero(), - }); + let ctx = Box::new(SaplingProvingContext::new()); Box::into_raw(ctx) } diff --git a/sapling-crypto/src/circuit/sapling/mod.rs b/sapling-crypto/src/circuit/sapling/mod.rs index 31bab6be3..650e16224 100644 --- a/sapling-crypto/src/circuit/sapling/mod.rs +++ b/sapling-crypto/src/circuit/sapling/mod.rs @@ -31,6 +31,8 @@ use super::blake2s; use super::num; use super::multipack; +pub const TREE_DEPTH: usize = 32; + /// This is an instance of the `Spend` circuit. pub struct Spend<'a, E: JubjubEngine> { pub params: &'a E::Params, diff --git a/zcash_proofs/Cargo.toml b/zcash_proofs/Cargo.toml index 91cba88b4..68a4a4531 100644 --- a/zcash_proofs/Cargo.toml +++ b/zcash_proofs/Cargo.toml @@ -7,5 +7,7 @@ authors = [ [dependencies] bellman = { path = "../bellman" } +byteorder = "1" pairing = { path = "../pairing" } +rand = "0.4" sapling-crypto = { path = "../sapling-crypto" } diff --git a/zcash_proofs/src/lib.rs b/zcash_proofs/src/lib.rs index 6e2af65e3..bdebdd634 100644 --- a/zcash_proofs/src/lib.rs +++ b/zcash_proofs/src/lib.rs @@ -1,5 +1,7 @@ extern crate bellman; +extern crate byteorder; extern crate pairing; +extern crate rand; extern crate sapling_crypto; pub mod sapling; diff --git a/zcash_proofs/src/sapling/mod.rs b/zcash_proofs/src/sapling/mod.rs index 87b5feda6..2cfb2e94c 100644 --- a/zcash_proofs/src/sapling/mod.rs +++ b/zcash_proofs/src/sapling/mod.rs @@ -3,12 +3,14 @@ use sapling_crypto::jubjub::{ edwards, fs::FsRepr, FixedGenerators, JubjubBls12, JubjubParams, Unknown, }; +mod prover; mod verifier; +pub use self::prover::{CommitmentTreeWitness, SaplingProvingContext}; pub use self::verifier::SaplingVerificationContext; // This function computes `value` in the exponent of the value commitment base -pub fn compute_value_balance( +fn compute_value_balance( value: i64, params: &JubjubBls12, ) -> Option> { diff --git a/zcash_proofs/src/sapling/prover.rs b/zcash_proofs/src/sapling/prover.rs new file mode 100644 index 000000000..f43dae73f --- /dev/null +++ b/zcash_proofs/src/sapling/prover.rs @@ -0,0 +1,365 @@ +use bellman::groth16::{ + create_random_proof, verify_proof, Parameters, PreparedVerifyingKey, Proof, +}; +use byteorder::{LittleEndian, ReadBytesExt}; +use pairing::{ + bls12_381::{Bls12, Fr, FrRepr}, + Field, PrimeField, PrimeFieldRepr, +}; +use rand::{OsRng, Rand}; +use sapling_crypto::{ + circuit::{ + multipack, + sapling::{Output, Spend, TREE_DEPTH}, + }, + jubjub::{edwards, fs::Fs, FixedGenerators, JubjubBls12, Unknown}, + primitives::{Diversifier, Note, PaymentAddress, ProofGenerationKey, ValueCommitment}, + redjubjub::{PrivateKey, PublicKey, Signature}, +}; + +use super::compute_value_balance; + +/// A witness to a path from a postion in a particular Sapling commitment tree +/// to the root of that tree. +pub struct CommitmentTreeWitness { + auth_path: Vec>, + position: u64, +} + +impl CommitmentTreeWitness { + pub fn from_slice(mut witness: &[u8]) -> Result { + // Skip the first byte, which should be "32" to signify the length of + // the following vector of Pedersen hashes. + assert_eq!(witness[0], TREE_DEPTH as u8); + witness = &witness[1..]; + + // Begin to construct the authentication path + let mut auth_path = vec![None; TREE_DEPTH]; + + // The vector works in reverse + for i in (0..TREE_DEPTH).rev() { + // skip length of inner vector + assert_eq!(witness[0], 32); // the length of a pedersen hash + witness = &witness[1..]; + + // Grab the sibling node at this depth in the tree + let mut sibling = [0u8; 32]; + sibling.copy_from_slice(&witness[0..32]); + witness = &witness[32..]; + + // Sibling node should be an element of Fr + let sibling = match { + let mut repr = FrRepr::default(); + repr.read_le(&sibling[..]).expect("length is 32 bytes"); + Fr::from_repr(repr) + } { + Ok(p) => p, + Err(_) => return Err(()), + }; + + // Set the value in the auth path; we put false here + // for now (signifying the position bit) which we'll + // fill in later. + auth_path[i] = Some((sibling, false)); + } + + // Read the position from the witness + let position = witness + .read_u64::() + .expect("should have had index at the end"); + + // Given the position, let's finish constructing the authentication + // path + let mut tmp = position; + for i in 0..TREE_DEPTH { + auth_path[i].as_mut().map(|p| p.1 = (tmp & 1) == 1); + + tmp >>= 1; + } + + // The witness should be empty now; if it wasn't, the caller would + // have provided more information than they should have, indicating + // a bug downstream + assert_eq!(witness.len(), 0); + + Ok(CommitmentTreeWitness { + auth_path, + position, + }) + } +} + +/// A context object for creating the Sapling components of a Zcash transaction. +pub struct SaplingProvingContext { + bsk: Fs, + bvk: edwards::Point, +} + +impl SaplingProvingContext { + /// Construct a new context to be used with a single transaction. + pub fn new() -> Self { + SaplingProvingContext { + bsk: Fs::zero(), + bvk: edwards::Point::zero(), + } + } + + /// Create the value commitment, re-randomized key, and proof for a Sapling + /// SpendDescription, while accumulating its value commitment randomness + /// inside the context for later use. + pub fn spend_proof( + &mut self, + proof_generation_key: ProofGenerationKey, + diversifier: Diversifier, + rcm: Fs, + ar: Fs, + value: u64, + anchor: Fr, + witness: CommitmentTreeWitness, + proving_key: &Parameters, + verifying_key: &PreparedVerifyingKey, + params: &JubjubBls12, + ) -> Result< + ( + Proof, + edwards::Point, + PublicKey, + ), + (), + > { + // Initialize secure RNG + let mut rng = OsRng::new().expect("should be able to construct RNG"); + + // We create the randomness of the value commitment + let rcv = Fs::rand(&mut rng); + + // Accumulate the value commitment randomness in the context + { + let mut tmp = rcv.clone(); + tmp.add_assign(&self.bsk); + + // Update the context + self.bsk = tmp; + } + + // Construct the value commitment + let value_commitment = ValueCommitment:: { + value: value, + randomness: rcv, + }; + + // Construct the viewing key + let viewing_key = proof_generation_key.into_viewing_key(params); + + // Construct the payment address with the viewing key / diversifier + let payment_address = match viewing_key.into_payment_address(diversifier, params) { + Some(p) => p, + None => return Err(()), + }; + + // This is the result of the re-randomization, we compute it for the caller + let rk = PublicKey::(proof_generation_key.ak.clone().into()).randomize( + ar, + FixedGenerators::SpendingKeyGenerator, + params, + ); + + // Let's compute the nullifier while we have the position + let note = Note { + value: value, + g_d: diversifier + .g_d::(params) + .expect("was a valid diversifier before"), + pk_d: payment_address.pk_d.clone(), + r: rcm, + }; + + let nullifier = note.nf(&viewing_key, witness.position, params); + + // We now have the full witness for our circuit + let instance = Spend { + params, + value_commitment: Some(value_commitment.clone()), + proof_generation_key: Some(proof_generation_key), + payment_address: Some(payment_address), + commitment_randomness: Some(rcm), + ar: Some(ar), + auth_path: witness.auth_path, + anchor: Some(anchor), + }; + + // Create proof + let proof = + create_random_proof(instance, proving_key, &mut rng).expect("proving should not fail"); + + // Try to verify the proof: + // Construct public input for circuit + let mut public_input = [Fr::zero(); 7]; + { + let (x, y) = rk.0.into_xy(); + public_input[0] = x; + public_input[1] = y; + } + { + let (x, y) = value_commitment.cm(params).into_xy(); + public_input[2] = x; + public_input[3] = y; + } + public_input[4] = anchor; + + // Add the nullifier through multiscalar packing + { + let nullifier = multipack::bytes_to_bits_le(&nullifier); + let nullifier = multipack::compute_multipacking::(&nullifier); + + assert_eq!(nullifier.len(), 2); + + public_input[5] = nullifier[0]; + public_input[6] = nullifier[1]; + } + + // Verify the proof + match verify_proof(verifying_key, &proof, &public_input[..]) { + // No error, and proof verification successful + Ok(true) => {} + + // Any other case + _ => { + return Err(()); + } + } + + // Compute value commitment + let value_commitment: edwards::Point = value_commitment.cm(params).into(); + + // Accumulate the value commitment in the context + { + let mut tmp = value_commitment.clone(); + tmp = tmp.add(&self.bvk, params); + + // Update the context + self.bvk = tmp; + } + + Ok((proof, value_commitment, rk)) + } + + /// Create the value commitment and proof for a Sapling OutputDescription, + /// while accumulating its value commitment randomness inside the context + /// for later use. + pub fn output_proof( + &mut self, + esk: Fs, + payment_address: PaymentAddress, + rcm: Fs, + value: u64, + proving_key: &Parameters, + params: &JubjubBls12, + ) -> (Proof, edwards::Point) { + // Initialize secure RNG + let mut rng = OsRng::new().expect("should be able to construct RNG"); + + // We construct ephemeral randomness for the value commitment. This + // randomness is not given back to the caller, but the synthetic + // blinding factor `bsk` is accumulated in the context. + let rcv = Fs::rand(&mut rng); + + // Accumulate the value commitment randomness in the context + { + let mut tmp = rcv.clone(); + tmp.negate(); // Outputs subtract from the total. + tmp.add_assign(&self.bsk); + + // Update the context + self.bsk = tmp; + } + + // Construct the value commitment for the proof instance + let value_commitment = ValueCommitment:: { + value: value, + randomness: rcv, + }; + + // We now have a full witness for the output proof. + let instance = Output { + params, + value_commitment: Some(value_commitment.clone()), + payment_address: Some(payment_address.clone()), + commitment_randomness: Some(rcm), + esk: Some(esk.clone()), + }; + + // Create proof + let proof = + create_random_proof(instance, proving_key, &mut rng).expect("proving should not fail"); + + // Compute the actual value commitment + let value_commitment: edwards::Point = value_commitment.cm(params).into(); + + // Accumulate the value commitment in the context. We do this to check internal consistency. + { + let mut tmp = value_commitment.clone(); + tmp = tmp.negate(); // Outputs subtract from the total. + tmp = tmp.add(&self.bvk, params); + + // Update the context + self.bvk = tmp; + } + + (proof, value_commitment) + } + + /// Create the bindingSig for a Sapling transaction. All calls to spend_proof() + /// and output_proof() must be completed before calling this function. + pub fn binding_sig( + &self, + value_balance: i64, + sighash: &[u8; 32], + params: &JubjubBls12, + ) -> Result { + // Initialize secure RNG + let mut rng = OsRng::new().expect("should be able to construct RNG"); + + // Grab the current `bsk` from the context + let bsk = PrivateKey::(self.bsk); + + // Grab the `bvk` using DerivePublic. + let bvk = PublicKey::from_private(&bsk, FixedGenerators::ValueCommitmentRandomness, params); + + // In order to check internal consistency, let's use the accumulated value + // commitments (as the verifier would) and apply valuebalance to compare + // against our derived bvk. + { + // Compute value balance + let mut value_balance = match compute_value_balance(value_balance, params) { + Some(a) => a, + None => return Err(()), + }; + + // Subtract value_balance from current bvk to get final bvk + value_balance = value_balance.negate(); + let mut tmp = self.bvk.clone(); + tmp = tmp.add(&value_balance, params); + + // The result should be the same, unless the provided valueBalance is wrong. + if bvk.0 != tmp { + return Err(()); + } + } + + // Construct signature message + let mut data_to_be_signed = [0u8; 64]; + bvk.0 + .write(&mut data_to_be_signed[0..32]) + .expect("message buffer should be 32 bytes"); + (&mut data_to_be_signed[32..64]).copy_from_slice(&sighash[..]); + + // Sign + Ok(bsk.sign( + &data_to_be_signed, + &mut rng, + FixedGenerators::ValueCommitmentRandomness, + params, + )) + } +}