From 58f84af22e4cb5494053eec65934c8a277ff6e0b Mon Sep 17 00:00:00 2001 From: David Rusu Date: Wed, 12 May 2021 11:30:51 -0400 Subject: [PATCH] feat(dbc_owners): make room in MintRequest for input ownership proof --- Cargo.toml | 1 + src/dbc.rs | 20 +++++--- src/lib.rs | 2 +- src/mint.rs | 131 ++++++++++++++++++++++++++++++---------------------- 4 files changed, 91 insertions(+), 63 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8620220..c78ee08 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ quickcheck = "1" quickcheck_macros = "1" rand = "0.7.1" bls_dkg = "0.3" +threshold_crypto = "0.4" [dependencies.tiny-keccak] version = "2.0.0" diff --git a/src/dbc.rs b/src/dbc.rs index 414d3e7..6e12969 100644 --- a/src/dbc.rs +++ b/src/dbc.rs @@ -55,12 +55,12 @@ impl Dbc { mod tests { use super::*; - use std::collections::{BTreeSet, HashSet}; + use std::collections::{BTreeSet, HashMap, HashSet}; use quickcheck_macros::quickcheck; use crate::tests::{NonZeroTinyInt, TinyInt}; - use crate::{Mint, MintRequest}; + use crate::{Mint, MintRequest, MintTransaction}; fn divide(amount: u64, n_ways: u8) -> impl Iterator { (0..n_ways).into_iter().map(move |i| { @@ -83,7 +83,10 @@ mod tests { }) .collect(); - MintRequest { inputs, outputs } + MintRequest { + transaction: MintTransaction { inputs, outputs }, + input_ownership_proofs: HashMap::default(), + } } #[test] @@ -132,9 +135,10 @@ mod tests { let (split_transaction, split_transaction_sigs) = genesis.reissue(mint_request.clone()).unwrap(); - assert_eq!(split_transaction, mint_request.to_transaction()); + assert_eq!(split_transaction, mint_request.transaction.blinded()); let inputs: HashSet<_> = mint_request + .transaction .outputs .into_iter() .map(|content| Dbc { @@ -150,10 +154,13 @@ mod tests { let content = DbcContent::new(input_hashes.clone(), amount, 0, crate::bls_dkg_id()); let outputs = vec![content].into_iter().collect(); - let mint_request = MintRequest { inputs, outputs }; + let mint_request = MintRequest { + transaction: MintTransaction { inputs, outputs }, + input_ownership_proofs: HashMap::default(), + }; let (transaction, transaction_sigs) = genesis.reissue(mint_request.clone()).unwrap(); - assert_eq!(mint_request.to_transaction(), transaction); + assert_eq!(mint_request.transaction.blinded(), transaction); let fuzzed_parents = input_hashes .into_iter() @@ -183,6 +190,7 @@ mod tests { .to_owned(), ); let mut repeating_inputs = mint_request + .transaction .inputs .iter() .cycle() diff --git a/src/lib.rs b/src/lib.rs index a318266..8c35167 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,7 +24,7 @@ pub use crate::{ dbc_transaction::DbcTransaction, error::{Error, Result}, key_manager::{ChainNode, KeyCache, KeyManager, PublicKey, Signature}, - mint::{Mint, MintRequest}, + mint::{Mint, MintRequest, MintTransaction}, }; pub(crate) fn bls_dkg_id() -> bls_dkg::PublicKeySet { diff --git a/src/mint.rs b/src/mint.rs index 224d964..73a86fe 100644 --- a/src/mint.rs +++ b/src/mint.rs @@ -13,7 +13,7 @@ // input is vaid // Outputs <= input value -use std::collections::{BTreeMap, BTreeSet, HashSet}; +use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use crate::{ Dbc, DbcContent, DbcContentHash, DbcTransaction, Error, KeyCache, KeyManager, PublicKey, @@ -38,20 +38,20 @@ impl SpendBook { } #[derive(Debug, Clone)] -pub struct MintRequest { +pub struct MintTransaction { pub inputs: HashSet, pub outputs: HashSet, } -impl MintRequest { - pub fn to_transaction(&self) -> DbcTransaction { +impl MintTransaction { + pub fn blinded(&self) -> DbcTransaction { DbcTransaction { inputs: self.inputs.iter().map(|i| i.name()).collect(), outputs: self.outputs.iter().map(|i| i.hash()).collect(), } } - pub fn verify_transaction_balances(&self) -> Result<()> { + pub fn verify_balances(&self) -> Result<()> { let input: u64 = self.inputs.iter().map(|input| input.amount()).sum(); let output: u64 = self.outputs.iter().map(|output| output.amount).sum(); if input != output { @@ -62,6 +62,13 @@ impl MintRequest { } } +#[derive(Debug, Clone)] +pub struct MintRequest { + pub transaction: MintTransaction, + // Signatures from the owners of each input, signing `self.transaction.blinded().hash()` + pub input_ownership_proofs: HashMap, +} + pub struct Mint { pub(crate) key_mgr: KeyManager, spendbook: SpendBook, @@ -109,15 +116,16 @@ impl Mint { &mut self, mint_request: MintRequest, ) -> Result<(DbcTransaction, InputSignatures)> { - mint_request.verify_transaction_balances()?; - let transaction = mint_request.to_transaction(); + mint_request.transaction.verify_balances()?; + let transaction = mint_request.transaction.blinded(); - self.validate_transaction_input_dbcs(&mint_request.inputs)?; - self.validate_transaction_outputs(&transaction.inputs, &mint_request.outputs)?; + // TODO: move this validation into the MintTransaction struct + self.validate_transaction_input_dbcs(&mint_request.transaction.inputs)?; + self.validate_transaction_outputs(&transaction.inputs, &mint_request.transaction.outputs)?; let transaction_sigs = self.sign_transaction(&transaction); - for input in mint_request.inputs.iter() { + for input in mint_request.transaction.inputs.iter() { self.spendbook.log(input.name(), transaction.clone()); } @@ -223,29 +231,25 @@ mod tests { }) .collect(); - let mint_request = MintRequest { inputs, outputs }; + let mint_request = MintRequest { + transaction: MintTransaction { inputs, outputs }, + input_ownership_proofs: HashMap::default(), + }; let (transaction, transaction_sigs) = genesis.reissue(mint_request.clone()).unwrap(); // Verify transaction returned to us by the Mint matches our request - assert_eq!(mint_request.to_transaction(), transaction); - assert_eq!( - transaction.inputs, - mint_request.inputs.iter().map(|i| i.name()).collect() - ); - assert_eq!( - transaction.outputs, - mint_request.outputs.iter().map(|o| o.hash()).collect() - ); + assert_eq!(mint_request.transaction.blinded(), transaction); // Verify signatures corespond to each input let (pubkey, sig) = transaction_sigs.values().cloned().next().unwrap(); - for input in mint_request.inputs.iter() { + for input in mint_request.transaction.inputs.iter() { assert_eq!(transaction_sigs.get(&input.name()), Some(&(pubkey, sig))); } assert_eq!(transaction_sigs.len(), transaction.inputs.len()); let output_dbcs: Vec<_> = mint_request + .transaction .outputs .into_iter() .map(|content| Dbc { @@ -276,24 +280,30 @@ mod tests { let input_hashes: BTreeSet<_> = vec![genesis_dbc.name()].into_iter().collect(); let mint_request = MintRequest { - inputs: inputs.clone(), - outputs: vec![DbcContent::new( - input_hashes.clone(), - 1000, - 0, - crate::bls_dkg_id(), - )] - .into_iter() - .collect(), + transaction: MintTransaction { + inputs: inputs.clone(), + outputs: vec![DbcContent::new( + input_hashes.clone(), + 1000, + 0, + crate::bls_dkg_id(), + )] + .into_iter() + .collect(), + }, + input_ownership_proofs: HashMap::default(), }; let (t, s) = genesis.reissue(mint_request).unwrap(); let double_spend_mint_request = MintRequest { - inputs, - outputs: vec![DbcContent::new(input_hashes, 1000, 1, crate::bls_dkg_id())] - .into_iter() - .collect(), + transaction: MintTransaction { + inputs, + outputs: vec![DbcContent::new(input_hashes, 1000, 1, crate::bls_dkg_id())] + .into_iter() + .collect(), + }, + input_ownership_proofs: HashMap::default(), }; let res = genesis.reissue(double_spend_mint_request); @@ -352,8 +362,11 @@ mod tests { .collect(); let mint_request = MintRequest { - inputs: gen_inputs, - outputs: input_content.clone(), + transaction: MintTransaction { + inputs: gen_inputs, + outputs: input_content.clone(), + }, + input_ownership_proofs: HashMap::default(), }; let (transaction, transaction_sigs) = genesis.reissue(mint_request).unwrap(); @@ -386,8 +399,11 @@ mod tests { .collect(); let mint_request = MintRequest { - inputs: input_dbcs, - outputs: outputs.clone(), + transaction: MintTransaction { + inputs: input_dbcs, + outputs: outputs.clone(), + }, + input_ownership_proofs: HashMap::default(), }; let many_to_many_result = genesis.reissue(mint_request); @@ -493,24 +509,27 @@ mod tests { let input_content_hashes: BTreeSet<_> = vec![input_content.hash()].into_iter().collect(); let fraudulant_reissue_result = genesis.reissue(MintRequest { - inputs: vec![Dbc { - content: input_content, - transaction: DbcTransaction { - inputs: Default::default(), - outputs: input_content_hashes.clone(), - }, - transaction_sigs: Default::default(), - }] - .into_iter() - .collect(), - outputs: vec![DbcContent { - parents: input_content_hashes, - amount: 100, - output_number: 0, - owner: crate::bls_dkg_id(), - }] - .into_iter() - .collect(), + transaction: MintTransaction { + inputs: vec![Dbc { + content: input_content, + transaction: DbcTransaction { + inputs: Default::default(), + outputs: input_content_hashes.clone(), + }, + transaction_sigs: Default::default(), + }] + .into_iter() + .collect(), + outputs: vec![DbcContent { + parents: input_content_hashes, + amount: 100, + output_number: 0, + owner: crate::bls_dkg_id(), + }] + .into_iter() + .collect(), + }, + input_ownership_proofs: HashMap::default(), }); assert!(fraudulant_reissue_result.is_err()); }