From 07eb99c46507e08acf7a1075bade4a3a2e8b8452 Mon Sep 17 00:00:00 2001 From: narodnik Date: Wed, 12 May 2021 11:50:47 +0200 Subject: [PATCH] working signatures for clear inputs (deposits) --- src/bin/tx.rs | 48 +++++++++------------ src/tx.rs | 115 ++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 118 insertions(+), 45 deletions(-) diff --git a/src/bin/tx.rs b/src/bin/tx.rs index c392dc978..9d985fd20 100644 --- a/src/bin/tx.rs +++ b/src/bin/tx.rs @@ -4,6 +4,7 @@ use ff::{Field, PrimeField}; use group::Group; use rand::rngs::OsRng; use std::io; +use std::path::Path; use sapvi::crypto::{ coin::Coin, @@ -17,23 +18,33 @@ use sapvi::error::{Error, Result}; use sapvi::serial::{Decodable, Encodable, VarInt}; use sapvi::tx; -fn txbuilding() { - //{ - // let params = setup_mint_prover(); - // save_params("mint.params", ¶ms); - //} - //{ - // let params = setup_spend_prover(); - // save_params("spend.params", ¶ms); - //} +fn main() { + // Auto create trusted ceremony parameters if they don't exist + if !Path::new("mint.params").exists() { + let params = setup_mint_prover(); + save_params("mint.params", ¶ms); + } + if !Path::new("spend.params").exists() { + let params = setup_spend_prover(); + save_params("spend.params", ¶ms); + } + + // Load trusted setup parameters let (mint_params, mint_pvk) = load_params("mint.params").expect("params should load"); let (spend_params, spend_pvk) = load_params("spend.params").expect("params should load"); + // Cashier creates a secret key + let cashier_secret = jubjub::Fr::random(&mut OsRng); + // This is their public key + let cashier_public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * cashier_secret; + + // Wallet 1 creates a secret key let secret = jubjub::Fr::random(&mut OsRng); + // This is their public key let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret; let builder = tx::TransactionBuilder { - clear_inputs: vec![tx::TransactionBuilderClearInputInfo { value: 110 }], + clear_inputs: vec![tx::TransactionBuilderClearInputInfo { value: 110, signature_secret: cashier_secret }], inputs: vec![], outputs: vec![tx::TransactionBuilderOutputInfo { value: 110, public }], }; @@ -106,22 +117,5 @@ fn txbuilding() { let tx = tx::Transaction::decode(&tx_data[..]).unwrap(); assert!(tx.verify(&mint_pvk, &spend_pvk)); } - - /*let note = Note { - serial: jubjub::Fr::random(&mut OsRng), - value: 110, - coin_blind: jubjub::Fr::random(&mut OsRng), - valcom_blind: jubjub::Fr::random(&mut OsRng), - }; - - let secret = jubjub::Fr::random(&mut OsRng); - let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret; - - let encrypted_note = note.encrypt(&public).unwrap(); - let note2 = encrypted_note.decrypt(&secret).unwrap(); - assert_eq!(note.value, note2.value);*/ } -fn main() { - txbuilding(); -} diff --git a/src/tx.rs b/src/tx.rs index 447e07415..266f6d4d8 100644 --- a/src/tx.rs +++ b/src/tx.rs @@ -26,7 +26,7 @@ pub struct TransactionBuilder { impl TransactionBuilder { fn compute_remainder_blind( - clear_inputs: &Vec, + clear_inputs: &Vec, input_blinds: &Vec, output_blinds: &Vec, ) -> jubjub::Fr { @@ -54,10 +54,14 @@ impl TransactionBuilder { ) -> Transaction { let mut clear_inputs = vec![]; for input in &self.clear_inputs { + let signature_public = + zcash_primitives::constants::SPENDING_KEY_GENERATOR * input.signature_secret; + let valcom_blind: jubjub::Fr = jubjub::Fr::random(&mut OsRng); - let clear_input = TransactionClearInput { + let clear_input = PartialTransactionClearInput { value: input.value, valcom_blind, + signature_public }; clear_inputs.push(clear_input); } @@ -69,8 +73,6 @@ impl TransactionBuilder { input_blinds.push(input.note.valcom_blind.clone()); let signature_secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng); - let signature_public = - zcash_primitives::constants::SPENDING_KEY_GENERATOR * signature_secret; // make proof @@ -148,6 +150,14 @@ impl TransactionBuilder { .encode(&mut unsigned_tx_data) .expect("TODO handle this"); + let mut clear_inputs = vec![]; + for (input, info) in partial_tx.clear_inputs.into_iter().zip(self.clear_inputs) { + let secret = schnorr::SecretKey(info.signature_secret.clone()); + let signature = secret.sign(&unsigned_tx_data[..]); + let input = TransactionClearInput::from_partial(input, signature); + clear_inputs.push(input); + } + let mut inputs = vec![]; for (input, signature_secret) in partial_tx .inputs @@ -160,7 +170,7 @@ impl TransactionBuilder { } Transaction { - clear_inputs: partial_tx.clear_inputs, + clear_inputs, inputs, outputs: partial_tx.outputs, } @@ -169,6 +179,7 @@ impl TransactionBuilder { pub struct TransactionBuilderClearInputInfo { pub value: u64, + pub signature_secret: jubjub::Fr, } pub struct TransactionBuilderInputInfo { @@ -185,7 +196,7 @@ pub struct TransactionBuilderOutputInfo { } pub struct PartialTransaction { - pub clear_inputs: Vec, + pub clear_inputs: Vec, pub inputs: Vec, pub outputs: Vec, } @@ -239,7 +250,7 @@ impl Decodable for Transaction { impl Transaction { fn encode_without_signature(&self, mut s: S) -> Result { let mut len = 0; - len += self.clear_inputs.encode(&mut s)?; + len += self.clear_inputs.encode_without_signature(&mut s)?; len += self.inputs.encode_without_signature(&mut s)?; len += self.outputs.encode(s)?; Ok(len) @@ -280,6 +291,12 @@ impl Transaction { self .encode_without_signature(&mut unsigned_tx_data) .expect("TODO handle this"); + for input in &self.clear_inputs { + let public = schnorr::PublicKey(input.signature_public.clone()); + if !public.verify(&unsigned_tx_data[..], &input.signature) { + return false; + } + } for input in &self.inputs { let public = schnorr::PublicKey(input.revealed.signature_public.clone()); if !public.verify(&unsigned_tx_data[..], &input.signature) { @@ -294,8 +311,47 @@ impl Transaction { pub struct TransactionClearInput { pub value: u64, pub valcom_blind: jubjub::Fr, + pub signature_public: jubjub::SubgroupPoint, + pub signature: schnorr::Signature, } +impl TransactionClearInput { + fn from_partial(partial: PartialTransactionClearInput, signature: schnorr::Signature) -> Self { + Self { + value: partial.value, + valcom_blind: partial.valcom_blind, + signature_public: partial.signature_public, + signature + } + } + + fn encode_without_signature(&self, mut s: S) -> Result { + let mut len = 0; + len += self.value.encode(&mut s)?; + len += self.valcom_blind.encode(&mut s)?; + len += self.signature_public.encode(s)?; + Ok(len) + } +} + +macro_rules! impl_vec_without_signature { + ($type: ty) => { + impl EncodableWithoutSignature for Vec<$type> { + #[inline] + fn encode_without_signature(&self, mut s: S) -> Result { + let mut len = 0; + len += VarInt(self.len() as u64).encode(&mut s)?; + for c in self.iter() { + len += c.encode_without_signature(&mut s)?; + } + Ok(len) + } + } + }; +} + +impl_vec_without_signature!(TransactionClearInput); + impl_vec!(TransactionClearInput); impl Encodable for TransactionClearInput { @@ -303,6 +359,8 @@ impl Encodable for TransactionClearInput { let mut len = 0; len += self.value.encode(&mut s)?; len += self.valcom_blind.encode(&mut s)?; + len += self.signature_public.encode(&mut s)?; + len += self.signature.encode(s)?; Ok(len) } } @@ -311,7 +369,37 @@ impl Decodable for TransactionClearInput { fn decode(mut d: D) -> Result { Ok(Self { value: Decodable::decode(&mut d)?, - valcom_blind: Decodable::decode(d)?, + valcom_blind: Decodable::decode(&mut d)?, + signature_public: Decodable::decode(&mut d)?, + signature: Decodable::decode(d)?, + }) + } +} + +pub struct PartialTransactionClearInput { + pub value: u64, + pub valcom_blind: jubjub::Fr, + pub signature_public: jubjub::SubgroupPoint, +} + +impl_vec!(PartialTransactionClearInput); + +impl Encodable for PartialTransactionClearInput { + fn encode(&self, mut s: S) -> Result { + let mut len = 0; + len += self.value.encode(&mut s)?; + len += self.valcom_blind.encode(&mut s)?; + len += self.signature_public.encode(&mut s)?; + Ok(len) + } +} + +impl Decodable for PartialTransactionClearInput { + fn decode(mut d: D) -> Result { + Ok(Self { + value: Decodable::decode(&mut d)?, + valcom_blind: Decodable::decode(&mut d)?, + signature_public: Decodable::decode(&mut d)?, }) } } @@ -368,16 +456,7 @@ trait EncodableWithoutSignature { fn encode_without_signature(&self, s: S) -> Result; } -impl EncodableWithoutSignature for Vec { - fn encode_without_signature(&self, mut s: S) -> Result { - let mut len = 0; - len += VarInt(self.len() as u64).encode(&mut s)?; - for c in self.iter() { - len += c.encode_without_signature(&mut s)?; - } - Ok(len) - } -} +impl_vec_without_signature!(TransactionInput); impl Encodable for TransactionInput { fn encode(&self, mut s: S) -> Result {