From 59ed258c7f673031cb22524004d72d54991cb38e Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 25 Jul 2019 22:37:16 +0100 Subject: [PATCH] Make Amount opaque, and use it more This helps to ensure type-safety of values that are required to satisfy zatoshi range bounds. --- librustzcash/src/rustzcash.rs | 11 ++ zcash_primitives/src/prover.rs | 14 ++- zcash_primitives/src/transaction/builder.rs | 68 ++++++++--- .../src/transaction/components.rs | 29 +++-- .../src/transaction/components/amount.rs | 115 ++++++++++++------ zcash_primitives/src/transaction/mod.rs | 9 +- zcash_primitives/src/transaction/sighash.rs | 11 +- zcash_primitives/src/transaction/tests.rs | 12 +- zcash_proofs/src/prover.rs | 9 +- zcash_proofs/src/sapling/mod.rs | 5 +- zcash_proofs/src/sapling/prover.rs | 6 +- zcash_proofs/src/sapling/verifier.rs | 3 +- 12 files changed, 203 insertions(+), 89 deletions(-) diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 4f27fa1..0fad706 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -63,6 +63,7 @@ use zcash_primitives::{ merkle_tree::CommitmentTreeWitness, note_encryption::sapling_ka_agree, sapling::{merkle_hash, spend_sig}, + transaction::components::Amount, zip32, JUBJUB, }; use zcash_proofs::{ @@ -704,6 +705,11 @@ pub extern "system" fn librustzcash_sapling_final_check( binding_sig: *const [c_uchar; 64], sighash_value: *const [c_uchar; 32], ) -> bool { + let value_balance = match Amount::from_i64(value_balance, true) { + Ok(vb) => vb, + Err(()) => return false, + }; + // Deserialize the signature let binding_sig = match Signature::read(&(unsafe { &*binding_sig })[..]) { Ok(sig) => sig, @@ -1022,6 +1028,11 @@ pub extern "system" fn librustzcash_sapling_binding_sig( sighash: *const [c_uchar; 32], result: *mut [c_uchar; 64], ) -> bool { + let value_balance = match Amount::from_i64(value_balance, true) { + Ok(vb) => vb, + Err(()) => return false, + }; + // Sign let sig = match unsafe { &*ctx }.binding_sig(value_balance, unsafe { &*sighash }, &JUBJUB) { Ok(s) => s, diff --git a/zcash_primitives/src/prover.rs b/zcash_primitives/src/prover.rs index 87a76c7..1d40965 100644 --- a/zcash_primitives/src/prover.rs +++ b/zcash_primitives/src/prover.rs @@ -8,7 +8,9 @@ use sapling_crypto::{ }; use crate::{ - merkle_tree::CommitmentTreeWitness, sapling::Node, transaction::components::GROTH_PROOF_SIZE, + merkle_tree::CommitmentTreeWitness, + sapling::Node, + transaction::components::{Amount, GROTH_PROOF_SIZE}, }; /// Interface for creating zero-knowledge proofs for shielded transactions. @@ -63,7 +65,7 @@ pub trait TxProver { fn binding_sig( &self, ctx: &mut Self::SaplingProvingContext, - value_balance: i64, + value_balance: Amount, sighash: &[u8; 32], ) -> Result; } @@ -80,8 +82,10 @@ pub(crate) mod mock { }; use crate::{ - merkle_tree::CommitmentTreeWitness, sapling::Node, - transaction::components::GROTH_PROOF_SIZE, JUBJUB, + merkle_tree::CommitmentTreeWitness, + sapling::Node, + transaction::components::{Amount, GROTH_PROOF_SIZE}, + JUBJUB, }; use super::TxProver; @@ -153,7 +157,7 @@ pub(crate) mod mock { fn binding_sig( &self, _ctx: &mut Self::SaplingProvingContext, - _value_balance: i64, + _value_balance: Amount, _sighash: &[u8; 32], ) -> Result { Err(()) diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index b7bcb62..36490e4 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -18,13 +18,12 @@ use crate::{ prover::TxProver, sapling::{spend_sig, Node}, transaction::{ - components::{Amount, OutputDescription, SpendDescription, TxOut}, + components::{amount::DEFAULT_FEE, Amount, OutputDescription, SpendDescription, TxOut}, signature_hash_data, Transaction, TransactionData, SIGHASH_ALL, }, JUBJUB, }; -const DEFAULT_FEE: Amount = Amount(10000); const DEFAULT_TX_EXPIRY_DELTA: u32 = 20; /// If there are any shielded inputs, always have at least two shielded outputs, padding @@ -88,7 +87,7 @@ impl SaplingOutput { let note = Note { g_d, pk_d: to.pk_d.clone(), - value: value.0 as u64, + value: value.into(), r: rcm, }; @@ -252,7 +251,8 @@ impl Builder { let alpha = Fs::random(&mut self.rng); - self.mtx.value_balance += Amount(note.value as i64); + self.mtx.value_balance += + Amount::from_u64(note.value).map_err(|_| Error(ErrorKind::InvalidAmount))?; self.spends.push(SpendDescriptionInfo { extsk, @@ -528,7 +528,7 @@ impl Builder { } self.mtx.binding_sig = Some( prover - .binding_sig(&mut ctx, self.mtx.value_balance.0, &sighash) + .binding_sig(&mut ctx, self.mtx.value_balance, &sighash) .map_err(|()| Error(ErrorKind::BindingSig))?, ); @@ -564,7 +564,7 @@ mod tests { let to = extfvk.default_address().unwrap().1; let mut builder = Builder::new(0); - match builder.add_sapling_output(ovk, to, Amount(-1), None) { + match builder.add_sapling_output(ovk, to, Amount::from_i64(-1, true).unwrap(), None) { Err(e) => assert_eq!(e.kind(), &ErrorKind::InvalidAmount), Ok(_) => panic!("Should have failed"), } @@ -573,7 +573,10 @@ mod tests { #[test] fn fails_on_negative_transparent_output() { let mut builder = Builder::new(0); - match builder.add_transparent_output(&TransparentAddress::PublicKey([0; 20]), Amount(-1)) { + match builder.add_transparent_output( + &TransparentAddress::PublicKey([0; 20]), + Amount::from_i64(-1, true).unwrap(), + ) { Err(e) => assert_eq!(e.kind(), &ErrorKind::InvalidAmount), Ok(_) => panic!("Should have failed"), } @@ -591,7 +594,10 @@ mod tests { { let builder = Builder::new(0); match builder.build(1, MockTxProver) { - Err(e) => assert_eq!(e.kind(), &ErrorKind::ChangeIsNegative(Amount(-10000))), + Err(e) => assert_eq!( + e.kind(), + &ErrorKind::ChangeIsNegative(Amount::from_i64(-10000, true).unwrap()) + ), Ok(_) => panic!("Should have failed"), } } @@ -605,10 +611,18 @@ mod tests { { let mut builder = Builder::new(0); builder - .add_sapling_output(ovk.clone(), to.clone(), Amount(50000), None) + .add_sapling_output( + ovk.clone(), + to.clone(), + Amount::from_u64(50000).unwrap(), + None, + ) .unwrap(); match builder.build(1, MockTxProver) { - Err(e) => assert_eq!(e.kind(), &ErrorKind::ChangeIsNegative(Amount(-60000))), + Err(e) => assert_eq!( + e.kind(), + &ErrorKind::ChangeIsNegative(Amount::from_i64(-60000, true).unwrap()) + ), Ok(_) => panic!("Should have failed"), } } @@ -618,10 +632,16 @@ mod tests { { let mut builder = Builder::new(0); builder - .add_transparent_output(&TransparentAddress::PublicKey([0; 20]), Amount(50000)) + .add_transparent_output( + &TransparentAddress::PublicKey([0; 20]), + Amount::from_u64(50000).unwrap(), + ) .unwrap(); match builder.build(1, MockTxProver) { - Err(e) => assert_eq!(e.kind(), &ErrorKind::ChangeIsNegative(Amount(-60000))), + Err(e) => assert_eq!( + e.kind(), + &ErrorKind::ChangeIsNegative(Amount::from_i64(-60000, true).unwrap()) + ), Ok(_) => panic!("Should have failed"), } } @@ -647,13 +667,24 @@ mod tests { ) .unwrap(); builder - .add_sapling_output(ovk.clone(), to.clone(), Amount(30000), None) + .add_sapling_output( + ovk.clone(), + to.clone(), + Amount::from_u64(30000).unwrap(), + None, + ) .unwrap(); builder - .add_transparent_output(&TransparentAddress::PublicKey([0; 20]), Amount(20000)) + .add_transparent_output( + &TransparentAddress::PublicKey([0; 20]), + Amount::from_u64(20000).unwrap(), + ) .unwrap(); match builder.build(1, MockTxProver) { - Err(e) => assert_eq!(e.kind(), &ErrorKind::ChangeIsNegative(Amount(-1))), + Err(e) => assert_eq!( + e.kind(), + &ErrorKind::ChangeIsNegative(Amount::from_i64(-1, true).unwrap()) + ), Ok(_) => panic!("Should have failed"), } } @@ -678,10 +709,13 @@ mod tests { .add_sapling_spend(extsk, to.diversifier, note2, witness2) .unwrap(); builder - .add_sapling_output(ovk, to, Amount(30000), None) + .add_sapling_output(ovk, to, Amount::from_u64(30000).unwrap(), None) .unwrap(); builder - .add_transparent_output(&TransparentAddress::PublicKey([0; 20]), Amount(20000)) + .add_transparent_output( + &TransparentAddress::PublicKey([0; 20]), + Amount::from_u64(20000).unwrap(), + ) .unwrap(); match builder.build(1, MockTxProver) { Err(e) => assert_eq!(e.kind(), &ErrorKind::BindingSig), diff --git a/zcash_primitives/src/transaction/components.rs b/zcash_primitives/src/transaction/components.rs index f72dfc5..c7dcebd 100644 --- a/zcash_primitives/src/transaction/components.rs +++ b/zcash_primitives/src/transaction/components.rs @@ -10,7 +10,7 @@ use std::io::{self, Read, Write}; use legacy::Script; use JUBJUB; -mod amount; +pub mod amount; pub use self::amount::Amount; // π_A + π_B + π_C @@ -76,7 +76,12 @@ pub struct TxOut { impl TxOut { pub fn read(mut reader: &mut R) -> io::Result { - let value = Amount::read_i64(&mut reader, false)?; + let value = { + let mut tmp = [0; 8]; + reader.read_exact(&mut tmp)?; + Amount::from_i64_le_bytes(tmp, false) + } + .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "value out of range"))?; let script_pubkey = Script::read(&mut reader)?; Ok(TxOut { @@ -86,7 +91,7 @@ impl TxOut { } pub fn write(&self, mut writer: W) -> io::Result<()> { - writer.write_i64::(self.value.0)?; + writer.write_all(&self.value.to_i64_le_bytes())?; self.script_pubkey.write(&mut writer) } } @@ -298,10 +303,20 @@ impl std::fmt::Debug for JSDescription { impl JSDescription { pub fn read(mut reader: R, use_groth: bool) -> io::Result { // Consensus rule (§4.3): Canonical encoding is enforced here - let vpub_old = Amount::read_u64(&mut reader)?; + let vpub_old = { + let mut tmp = [0; 8]; + reader.read_exact(&mut tmp)?; + Amount::from_u64_le_bytes(tmp) + } + .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "vpub_old out of range"))?; // Consensus rule (§4.3): Canonical encoding is enforced here - let vpub_new = Amount::read_u64(&mut reader)?; + let vpub_new = { + let mut tmp = [0; 8]; + reader.read_exact(&mut tmp)?; + Amount::from_u64_le_bytes(tmp) + } + .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "vpub_new out of range"))?; // Consensus rule (§4.3): One of vpub_old and vpub_new being zero is // enforced by CheckTransactionWithoutProofVerification() in zcashd. @@ -374,8 +389,8 @@ impl JSDescription { } pub fn write(&self, mut writer: W) -> io::Result<()> { - writer.write_i64::(self.vpub_old.0)?; - writer.write_i64::(self.vpub_new.0)?; + writer.write_all(&self.vpub_old.to_i64_le_bytes())?; + writer.write_all(&self.vpub_new.to_i64_le_bytes())?; writer.write_all(&self.anchor)?; writer.write_all(&self.nullifiers[0])?; writer.write_all(&self.nullifiers[1])?; diff --git a/zcash_primitives/src/transaction/components/amount.rs b/zcash_primitives/src/transaction/components/amount.rs index fa9ee06..dca7056 100644 --- a/zcash_primitives/src/transaction/components/amount.rs +++ b/zcash_primitives/src/transaction/components/amount.rs @@ -1,13 +1,13 @@ -use byteorder::{LittleEndian, ReadBytesExt}; -use std::io::{self, Read}; use std::iter::Sum; use std::ops::{Add, AddAssign, Sub, SubAssign}; const COIN: i64 = 1_0000_0000; const MAX_MONEY: i64 = 21_000_000 * COIN; +pub const DEFAULT_FEE: Amount = Amount(10000); + #[derive(Clone, Copy, Debug, PartialEq)] -pub struct Amount(pub i64); +pub struct Amount(i64); impl Amount { /// Returns a zero-valued Amount. @@ -15,38 +15,51 @@ impl Amount { Amount(0) } - // Read an Amount from a signed 64-bit little-endian integer. - pub fn read_i64(mut reader: R, allow_negative: bool) -> io::Result { - let amount = reader.read_i64::()?; + /// Creates an Amount from an i64. + /// + /// Returns an error if the amount is out of range. + pub fn from_i64(amount: i64, allow_negative: bool) -> Result { if 0 <= amount && amount <= MAX_MONEY { Ok(Amount(amount)) } else if allow_negative && -MAX_MONEY <= amount && amount < 0 { Ok(Amount(amount)) } else { - Err(io::Error::new( - io::ErrorKind::InvalidData, - if allow_negative { - "Amount not in {-MAX_MONEY..MAX_MONEY}" - } else { - "Amount not in {0..MAX_MONEY}" - }, - )) + Err(()) } } - // Read an Amount from an unsigned 64-bit little-endian integer. - pub fn read_u64(mut reader: R) -> io::Result { - let amount = reader.read_u64::()?; + /// Creates an Amount from a u64. + /// + /// Returns an error if the amount is out of range. + pub fn from_u64(amount: u64) -> Result { if amount <= MAX_MONEY as u64 { Ok(Amount(amount as i64)) } else { - Err(io::Error::new( - io::ErrorKind::InvalidData, - "Amount not in {0..MAX_MONEY}", - )) + Err(()) } } + /// Reads an Amount from a signed 64-bit little-endian integer. + /// + /// Returns an error if the amount is out of range. + pub fn from_i64_le_bytes(bytes: [u8; 8], allow_negative: bool) -> Result { + let amount = i64::from_le_bytes(bytes); + Amount::from_i64(amount, allow_negative) + } + + /// Reads an Amount from an unsigned 64-bit little-endian integer. + /// + /// Returns an error if the amount is out of range. + pub fn from_u64_le_bytes(bytes: [u8; 8]) -> Result { + let amount = u64::from_le_bytes(bytes); + Amount::from_u64(amount) + } + + /// Returns the Amount encoded as a signed 64-bit little-endian integer. + pub fn to_i64_le_bytes(self) -> [u8; 8] { + self.0.to_le_bytes() + } + /// Returns `true` if `self` is positive and `false` if the number is zero or /// negative. pub const fn is_positive(self) -> bool { @@ -60,6 +73,18 @@ impl Amount { } } +impl From for i64 { + fn from(amount: Amount) -> i64 { + amount.0 + } +} + +impl From for u64 { + fn from(amount: Amount) -> u64 { + amount.0 as u64 + } +} + impl Add for Amount { type Output = Amount; @@ -101,42 +126,54 @@ mod tests { #[test] fn amount_in_range() { let zero = b"\x00\x00\x00\x00\x00\x00\x00\x00"; - assert_eq!(Amount::read_u64(&zero[..]).unwrap(), Amount(0)); - assert_eq!(Amount::read_i64(&zero[..], false).unwrap(), Amount(0)); - assert_eq!(Amount::read_i64(&zero[..], true).unwrap(), Amount(0)); + assert_eq!(Amount::from_u64_le_bytes(zero.clone()).unwrap(), Amount(0)); + assert_eq!( + Amount::from_i64_le_bytes(zero.clone(), false).unwrap(), + Amount(0) + ); + assert_eq!( + Amount::from_i64_le_bytes(zero.clone(), true).unwrap(), + Amount(0) + ); let neg_one = b"\xff\xff\xff\xff\xff\xff\xff\xff"; - assert!(Amount::read_u64(&neg_one[..]).is_err()); - assert!(Amount::read_i64(&neg_one[..], false).is_err()); - assert_eq!(Amount::read_i64(&neg_one[..], true).unwrap(), Amount(-1)); + assert!(Amount::from_u64_le_bytes(neg_one.clone()).is_err()); + assert!(Amount::from_i64_le_bytes(neg_one.clone(), false).is_err()); + assert_eq!( + Amount::from_i64_le_bytes(neg_one.clone(), true).unwrap(), + Amount(-1) + ); let max_money = b"\x00\x40\x07\x5a\xf0\x75\x07\x00"; - assert_eq!(Amount::read_u64(&max_money[..]).unwrap(), Amount(MAX_MONEY)); assert_eq!( - Amount::read_i64(&max_money[..], false).unwrap(), + Amount::from_u64_le_bytes(max_money.clone()).unwrap(), Amount(MAX_MONEY) ); assert_eq!( - Amount::read_i64(&max_money[..], true).unwrap(), + Amount::from_i64_le_bytes(max_money.clone(), false).unwrap(), + Amount(MAX_MONEY) + ); + assert_eq!( + Amount::from_i64_le_bytes(max_money.clone(), true).unwrap(), Amount(MAX_MONEY) ); let max_money_p1 = b"\x01\x40\x07\x5a\xf0\x75\x07\x00"; - assert!(Amount::read_u64(&max_money_p1[..]).is_err()); - assert!(Amount::read_i64(&max_money_p1[..], false).is_err()); - assert!(Amount::read_i64(&max_money_p1[..], true).is_err()); + assert!(Amount::from_u64_le_bytes(max_money_p1.clone()).is_err()); + assert!(Amount::from_i64_le_bytes(max_money_p1.clone(), false).is_err()); + assert!(Amount::from_i64_le_bytes(max_money_p1.clone(), true).is_err()); let neg_max_money = b"\x00\xc0\xf8\xa5\x0f\x8a\xf8\xff"; - assert!(Amount::read_u64(&neg_max_money[..]).is_err()); - assert!(Amount::read_i64(&neg_max_money[..], false).is_err()); + assert!(Amount::from_u64_le_bytes(neg_max_money.clone()).is_err()); + assert!(Amount::from_i64_le_bytes(neg_max_money.clone(), false).is_err()); assert_eq!( - Amount::read_i64(&neg_max_money[..], true).unwrap(), + Amount::from_i64_le_bytes(neg_max_money.clone(), true).unwrap(), Amount(-MAX_MONEY) ); let neg_max_money_m1 = b"\xff\xbf\xf8\xa5\x0f\x8a\xf8\xff"; - assert!(Amount::read_u64(&neg_max_money_m1[..]).is_err()); - assert!(Amount::read_i64(&neg_max_money_m1[..], false).is_err()); - assert!(Amount::read_i64(&neg_max_money_m1[..], true).is_err()); + assert!(Amount::from_u64_le_bytes(neg_max_money_m1.clone()).is_err()); + assert!(Amount::from_i64_le_bytes(neg_max_money_m1.clone(), false).is_err()); + assert!(Amount::from_i64_le_bytes(neg_max_money_m1.clone(), true).is_err()); } } diff --git a/zcash_primitives/src/transaction/mod.rs b/zcash_primitives/src/transaction/mod.rs index d8024eb..e5b83e5 100644 --- a/zcash_primitives/src/transaction/mod.rs +++ b/zcash_primitives/src/transaction/mod.rs @@ -185,7 +185,12 @@ impl Transaction { }; let (value_balance, shielded_spends, shielded_outputs) = if is_sapling_v4 { - let vb = Amount::read_i64(&mut reader, true)?; + let vb = { + let mut tmp = [0; 8]; + reader.read_exact(&mut tmp)?; + Amount::from_i64_le_bytes(tmp, true) + } + .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "valueBalance out of range"))?; let ss = Vector::read(&mut reader, SpendDescription::read)?; let so = Vector::read(&mut reader, OutputDescription::read)?; (vb, ss, so) @@ -262,7 +267,7 @@ impl Transaction { } if is_sapling_v4 { - writer.write_i64::(self.value_balance.0)?; + writer.write_all(&self.value_balance.to_i64_le_bytes())?; Vector::write(&mut writer, &self.shielded_spends, |w, e| e.write(w))?; Vector::write(&mut writer, &self.shielded_outputs, |w, e| e.write(w))?; } diff --git a/zcash_primitives/src/transaction/sighash.rs b/zcash_primitives/src/transaction/sighash.rs index bcc971a..b4e9a69 100644 --- a/zcash_primitives/src/transaction/sighash.rs +++ b/zcash_primitives/src/transaction/sighash.rs @@ -30,13 +30,6 @@ macro_rules! update_u32 { }; } -macro_rules! update_i64 { - ($h:expr, $value:expr, $tmp:expr) => { - (&mut $tmp[..8]).write_i64::($value).unwrap(); - $h.update(&$tmp[..8]); - }; -} - macro_rules! update_hash { ($h:expr, $cond:expr, $value:expr) => { if $cond { @@ -214,7 +207,7 @@ pub fn signature_hash_data( update_u32!(h, tx.lock_time, tmp); update_u32!(h, tx.expiry_height, tmp); if sigversion == SigHashVersion::Sapling { - update_i64!(h, tx.value_balance.0, tmp); + h.update(&tx.value_balance.to_i64_le_bytes()); } update_u32!(h, hash_type, tmp); @@ -222,7 +215,7 @@ pub fn signature_hash_data( let mut data = vec![]; tx.vin[n].prevout.write(&mut data).unwrap(); script_code.write(&mut data).unwrap(); - (&mut data).write_i64::(amount.0).unwrap(); + data.extend_from_slice(&amount.to_i64_le_bytes()); (&mut data) .write_u32::(tx.vin[n].sequence) .unwrap(); diff --git a/zcash_primitives/src/transaction/tests.rs b/zcash_primitives/src/transaction/tests.rs index 1ebac3a..7d84100 100644 --- a/zcash_primitives/src/transaction/tests.rs +++ b/zcash_primitives/src/transaction/tests.rs @@ -1902,7 +1902,11 @@ fn zip_0143() { for tv in test_vectors { let tx = Transaction::read(&tv.tx[..]).unwrap(); let transparent_input = if let Some(n) = tv.transparent_input { - Some((n as usize, Script(tv.script_code), Amount(tv.amount))) + Some(( + n as usize, + Script(tv.script_code), + Amount::from_i64(tv.amount, false).unwrap(), + )) } else { None }; @@ -5393,7 +5397,11 @@ fn zip_0243() { for tv in test_vectors { let tx = Transaction::read(&tv.tx[..]).unwrap(); let transparent_input = if let Some(n) = tv.transparent_input { - Some((n as usize, Script(tv.script_code), Amount(tv.amount))) + Some(( + n as usize, + Script(tv.script_code), + Amount::from_i64(tv.amount, false).unwrap(), + )) } else { None }; diff --git a/zcash_proofs/src/prover.rs b/zcash_proofs/src/prover.rs index 005d7eb..4b5b0f4 100644 --- a/zcash_proofs/src/prover.rs +++ b/zcash_proofs/src/prover.rs @@ -10,8 +10,11 @@ use sapling_crypto::{ }; use std::path::Path; use zcash_primitives::{ - merkle_tree::CommitmentTreeWitness, prover::TxProver, sapling::Node, - transaction::components::GROTH_PROOF_SIZE, JUBJUB, + merkle_tree::CommitmentTreeWitness, + prover::TxProver, + sapling::Node, + transaction::components::{Amount, GROTH_PROOF_SIZE}, + JUBJUB, }; use crate::{load_parameters, sapling::SaplingProvingContext}; @@ -182,7 +185,7 @@ impl TxProver for LocalTxProver { fn binding_sig( &self, ctx: &mut Self::SaplingProvingContext, - value_balance: i64, + value_balance: Amount, sighash: &[u8; 32], ) -> Result { ctx.binding_sig(value_balance, sighash, &JUBJUB) diff --git a/zcash_proofs/src/sapling/mod.rs b/zcash_proofs/src/sapling/mod.rs index 4c37306..98c4ba3 100644 --- a/zcash_proofs/src/sapling/mod.rs +++ b/zcash_proofs/src/sapling/mod.rs @@ -2,6 +2,7 @@ use pairing::bls12_381::Bls12; use sapling_crypto::jubjub::{ edwards, fs::FsRepr, FixedGenerators, JubjubBls12, JubjubParams, Unknown, }; +use zcash_primitives::transaction::components::Amount; mod prover; mod verifier; @@ -11,12 +12,12 @@ pub use self::verifier::SaplingVerificationContext; // This function computes `value` in the exponent of the value commitment base fn compute_value_balance( - value: i64, + value: Amount, params: &JubjubBls12, ) -> Option> { // Compute the absolute value (failing if -i64::MAX is // the value) - let abs = match value.checked_abs() { + let abs = match i64::from(value).checked_abs() { Some(a) => a as u64, None => return None, }; diff --git a/zcash_proofs/src/sapling/prover.rs b/zcash_proofs/src/sapling/prover.rs index fce4d8e..4b5a5f4 100644 --- a/zcash_proofs/src/sapling/prover.rs +++ b/zcash_proofs/src/sapling/prover.rs @@ -13,7 +13,9 @@ use sapling_crypto::{ primitives::{Diversifier, Note, PaymentAddress, ProofGenerationKey, ValueCommitment}, redjubjub::{PrivateKey, PublicKey, Signature}, }; -use zcash_primitives::{merkle_tree::CommitmentTreeWitness, sapling::Node}; +use zcash_primitives::{ + merkle_tree::CommitmentTreeWitness, sapling::Node, transaction::components::Amount, +}; use super::compute_value_balance; @@ -245,7 +247,7 @@ impl SaplingProvingContext { /// and output_proof() must be completed before calling this function. pub fn binding_sig( &self, - value_balance: i64, + value_balance: Amount, sighash: &[u8; 32], params: &JubjubBls12, ) -> Result { diff --git a/zcash_proofs/src/sapling/verifier.rs b/zcash_proofs/src/sapling/verifier.rs index e83c426..47fc9fe 100644 --- a/zcash_proofs/src/sapling/verifier.rs +++ b/zcash_proofs/src/sapling/verifier.rs @@ -6,6 +6,7 @@ use sapling_crypto::{ jubjub::{edwards, FixedGenerators, JubjubBls12, Unknown}, redjubjub::{PublicKey, Signature}, }; +use zcash_primitives::transaction::components::Amount; use super::compute_value_balance; @@ -169,7 +170,7 @@ impl SaplingVerificationContext { /// have been checked before calling this function. pub fn final_check( &self, - value_balance: i64, + value_balance: Amount, sighash_value: &[u8; 32], binding_sig: Signature, params: &JubjubBls12,