From 64eea2a30d77ad227e7459d5e66586da3f38f9c5 Mon Sep 17 00:00:00 2001 From: sanket1729 Date: Sat, 1 Oct 2022 11:24:48 -0700 Subject: [PATCH] add src/pset/mod.rs and src/blind.rs --- src/blind.rs | 456 +++++++++++++++++++++++++++-------------- src/pset/error.rs | 110 +++++++--- src/pset/macros.rs | 17 +- src/pset/map/global.rs | 167 +++++++++------ src/pset/map/input.rs | 186 +++++++++++------ src/pset/map/mod.rs | 2 +- src/pset/map/output.rs | 117 ++++++----- src/pset/mod.rs | 267 +++++++++++++++--------- src/pset/raw.rs | 46 +++-- src/pset/serialize.rs | 75 ++++--- 10 files changed, 932 insertions(+), 511 deletions(-) diff --git a/src/blind.rs b/src/blind.rs index 49682fe5..d9d12918 100644 --- a/src/blind.rs +++ b/src/blind.rs @@ -15,17 +15,21 @@ //! # Transactions Blinding //! -use std::{self, fmt, collections::BTreeMap}; +use std::{self, collections::BTreeMap, fmt}; -use secp256k1_zkp::{self, PedersenCommitment, SecretKey, Tag, Tweak, Verification, ZERO_TWEAK, rand::{CryptoRng, RngCore}}; +use secp256k1_zkp::{ + self, + rand::{CryptoRng, RngCore}, + PedersenCommitment, SecretKey, Tag, Tweak, Verification, ZERO_TWEAK, +}; use secp256k1_zkp::{Generator, RangeProof, Secp256k1, Signing, SurjectionProof}; use crate::{AddressParams, Script, TxIn}; -use crate::{Address, AssetId, Transaction, TxOut, TxOutWitness, - confidential::{Asset, AssetBlindingFactor, Nonce, Value, - ValueBlindingFactor -}}; +use crate::{ + confidential::{Asset, AssetBlindingFactor, Nonce, Value, ValueBlindingFactor}, + Address, AssetId, Transaction, TxOut, TxOutWitness, +}; use crate::hashes; @@ -53,16 +57,25 @@ impl fmt::Display for TxOutError { match self { TxOutError::UnExpectedNullValue => write!(f, "UnExpected Null Value"), TxOutError::UnExpectedNullAsset => write!(f, "UnExpected Null Asset"), - TxOutError::MoneyOutofRange => write!(f, "Explicit amount must be\ - less than 21 million"), + TxOutError::MoneyOutofRange => write!( + f, + "Explicit amount must be\ + less than 21 million" + ), TxOutError::NonUnspendableZeroValue => { - write!(f, "Zero value explicit amounts must be provably unspendable.\ - See IsUnspendable in elements") + write!( + f, + "Zero value explicit amounts must be provably unspendable.\ + See IsUnspendable in elements" + ) } TxOutError::ZeroValueCommitment => { - write!(f, "Tried to create pedersen commitment with zero value.\ + write!( + f, + "Tried to create pedersen commitment with zero value.\ Zero value is only allowed for provable unspendable scripts, - in which case the verification check can ignore the txout") + in which case the verification check can ignore the txout" + ) } TxOutError::IncorrectBlindingFactors => { write!(f, "Incorrect Blinding factors") @@ -106,7 +119,11 @@ impl fmt::Display for VerificationError { write!(f, "Surjection Proof Error {} : for output index {}", i, e) } VerificationError::SurjectionProofVerificationError(i) => { - write!(f, "Surjection proof verification failed for output index {}", i) + write!( + f, + "Surjection proof verification failed for output index {}", + i + ) } VerificationError::IssuanceTransactionInput(i) => { write!(f, "Issuance transaction input {} not supported yet", i) @@ -121,7 +138,10 @@ impl fmt::Display for VerificationError { write!(f, "Output index {} txout: {}", i, e) } VerificationError::BalanceCheckFailed => { - write!(f, "Confidential transaction verification balance check failed") + write!( + f, + "Confidential transaction verification balance check failed" + ) } VerificationError::RangeProofMissing(i) => { write!(f, "Missing Rangeproof for output index {}", i) @@ -224,7 +244,6 @@ pub struct TxOutSecrets { } impl TxOutSecrets { - /// Create a new [`TxOutSecrets`] pub fn new( asset: AssetId, @@ -232,16 +251,19 @@ impl TxOutSecrets { value: u64, value_bf: ValueBlindingFactor, ) -> Self { - Self {asset, asset_bf, value, value_bf } + Self { + asset, + asset_bf, + value, + value_bf, + } } /// Gets the surjection inputs from [`TxOutSecrets`] /// Returns a tuple (assetid, blind_factor, generator) if the blinds are /// consistent with asset commitment /// Otherwise, returns an error - pub fn surjection_inputs(&self, secp: &Secp256k1) - -> (Generator, Tag, Tweak) - { + pub fn surjection_inputs(&self, secp: &Secp256k1) -> (Generator, Tag, Tweak) { let tag = self.asset.into_tag(); let bf = self.asset_bf.into_inner(); let gen = Generator::new_blinded(secp, tag, bf); @@ -261,11 +283,11 @@ impl TxOutSecrets { /// Explicit assets can be provided as [`SurjectionInput::Unknown`]. There is no /// need to construct a `Known` variant with secrets #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum SurjectionInput{ +pub enum SurjectionInput { /// Unknown inputs for whom we don't know the secrets(asset tags/blinding factors) Unknown(Asset), /// Known inputs for whom we know blinding factors - Known{ + Known { /// Asset asset: AssetId, /// Asset Blinding Factor @@ -289,7 +311,6 @@ impl From for SurjectionInput { } impl SurjectionInput { - /// Creates a new [`SurjectionInput`] from commitment pub fn from_comm(asset: Asset) -> Self { Self::Unknown(asset) @@ -304,25 +325,29 @@ impl SurjectionInput { /// that can be used while creating a new [SurjectionProof]. /// /// Only errors when the input asset is Null. - pub fn surjection_target(&self, secp: &Secp256k1) -> Result<(Generator, Tag, Tweak), TxOutError> { + pub fn surjection_target( + &self, + secp: &Secp256k1, + ) -> Result<(Generator, Tag, Tweak), TxOutError> { match self { SurjectionInput::Unknown(asset) => { - let gen = asset.into_asset_gen(secp).ok_or(TxOutError::UnExpectedNullAsset)?; + let gen = asset + .into_asset_gen(secp) + .ok_or(TxOutError::UnExpectedNullAsset)?; // Return the input as 0 tag and 0 tweak. This also correctly handles explicit case Ok((gen, Tag::default(), ZERO_TWEAK)) - }, - SurjectionInput::Known {asset, asset_bf} => { + } + SurjectionInput::Known { asset, asset_bf } => { let tag = asset.into_tag(); let bf = asset_bf.into_inner(); let gen = Generator::new_blinded(secp, tag, bf); Ok((gen, tag, bf)) - }, + } } } } impl Asset { - /// Blinds the asset such that there is a surjection proof between /// the input assets and the output blinded asset. /// @@ -339,16 +364,21 @@ impl Asset { where R: RngCore + CryptoRng, C: Signing, - S: Into + Copy + S: Into + Copy, { - let asset = self.explicit().ok_or(ConfidentialTxOutError::ExpectedExplicitAsset)?; + let asset = self + .explicit() + .ok_or(ConfidentialTxOutError::ExpectedExplicitAsset)?; let out_asset = Asset::new_confidential(secp, asset, asset_bf); let inputs = spent_utxo_secrets .iter() .enumerate() .map(|(i, surject_inp)| { - (*surject_inp).into().surjection_target(secp).map_err(|e| ConfidentialTxOutError::TxOutError(i, e)) + (*surject_inp) + .into() + .surjection_target(secp) + .map_err(|e| ConfidentialTxOutError::TxOutError(i, e)) }) .collect::, _>>()?; @@ -365,7 +395,6 @@ impl Asset { } impl Value { - /// Blinds the values and outputs the blinded value along with [`RangeProof`]. /// This computes the nonce by doing an ECDH with `receiver_blinding_pk` and `ephemeral_sk` /// @@ -381,11 +410,12 @@ impl Value { ephemeral_sk: SecretKey, spk: &Script, msg: &RangeProofMessage, - ) -> Result<(Self, Nonce, RangeProof), ConfidentialTxOutError> - { - let (nonce, shared_secret) = Nonce::with_ephemeral_sk(secp, ephemeral_sk, &receiver_blinding_pk); + ) -> Result<(Self, Nonce, RangeProof), ConfidentialTxOutError> { + let (nonce, shared_secret) = + Nonce::with_ephemeral_sk(secp, ephemeral_sk, &receiver_blinding_pk); - let (value_commit, rangeproof) = self.blind_with_shared_secret(secp, vbf, shared_secret, spk, msg)?; + let (value_commit, rangeproof) = + self.blind_with_shared_secret(secp, vbf, shared_secret, spk, msg)?; Ok((value_commit, nonce, rangeproof)) } @@ -399,10 +429,12 @@ impl Value { shared_secret: SecretKey, spk: &Script, msg: &RangeProofMessage, - ) -> Result<(Self, RangeProof), ConfidentialTxOutError> - { - let value = self.explicit().ok_or(ConfidentialTxOutError::ExpectedExplicitValue)?; - let out_asset_commitment = Generator::new_blinded(secp, msg.asset.into_tag(), msg.bf.into_inner()); + ) -> Result<(Self, RangeProof), ConfidentialTxOutError> { + let value = self + .explicit() + .ok_or(ConfidentialTxOutError::ExpectedExplicitValue)?; + let out_asset_commitment = + Generator::new_blinded(secp, msg.asset.into_tag(), msg.bf.into_inner()); let value_commitment = Value::new_confidential(secp, value, out_asset_commitment, vbf); let rangeproof = RangeProof::new( @@ -456,18 +488,26 @@ impl TxOut { where R: RngCore + CryptoRng, C: Signing, - S: Into + Copy + S: Into + Copy, { let spk = address.script_pubkey(); - let blinder = address.blinding_pubkey.ok_or(ConfidentialTxOutError::NoBlindingKeyInAddress)?; + let blinder = address + .blinding_pubkey + .ok_or(ConfidentialTxOutError::NoBlindingKeyInAddress)?; let asset_bf = AssetBlindingFactor::new(rng); let value_bf = ValueBlindingFactor::new(rng); let out_secrets = TxOutSecrets::new(asset, asset_bf, value, value_bf); let ephemeral_sk = SecretKey::new(rng); let txout = Self::with_txout_secrets( - rng, secp, spk, blinder, ephemeral_sk, out_secrets, spent_utxo_secrets - )?; + rng, + secp, + spk, + blinder, + ephemeral_sk, + out_secrets, + spent_utxo_secrets, + )?; Ok((txout, asset_bf, value_bf, ephemeral_sk)) } @@ -493,16 +533,25 @@ impl TxOut { where R: RngCore + CryptoRng, C: Signing, - S: Into + Copy + S: Into + Copy, { let exp_asset = Asset::Explicit(out_secrets.asset); let (out_asset, surjection_proof) = exp_asset.blind(rng, secp, out_secrets.asset_bf, spent_utxo_secrets)?; - let msg = RangeProofMessage { asset: out_secrets.asset, bf: out_secrets.asset_bf }; + let msg = RangeProofMessage { + asset: out_secrets.asset, + bf: out_secrets.asset_bf, + }; let exp_value = Value::Explicit(out_secrets.value); - let (out_value, nonce, range_proof) = - exp_value.blind(secp, out_secrets.value_bf, receiver_blinding_pk, ephemeral_sk, &spk, &msg)?; + let (out_value, nonce, range_proof) = exp_value.blind( + secp, + out_secrets.value_bf, + receiver_blinding_pk, + ephemeral_sk, + &spk, + &msg, + )?; let txout = TxOut { asset: out_asset, @@ -536,7 +585,7 @@ impl TxOut { where R: RngCore + CryptoRng, C: Signing, - S: Into + Copy + S: Into + Copy, { let (txout, abf, vbf, ephemeral_sk) = Self::new_not_last_confidential( rng, @@ -556,16 +605,18 @@ impl TxOut { // Internally used function for getting the generator from asset // Used in the amount verification check - fn get_asset_gen ( + fn get_asset_gen( &self, secp: &Secp256k1, ) -> Result { - self.asset.into_asset_gen(secp).ok_or(TxOutError::UnExpectedNullAsset) + self.asset + .into_asset_gen(secp) + .ok_or(TxOutError::UnExpectedNullAsset) } // Get the pedersen commitment for the txout. Used internally // in tx verification. - fn get_value_commit ( + fn get_value_commit( &self, secp: &Secp256k1, ) -> Result { @@ -575,19 +626,19 @@ impl TxOut { Value::Null => return Err(TxOutError::UnExpectedNullValue), Value::Explicit(value) => { if value > Self::MAX_MONEY { - return Err(TxOutError::MoneyOutofRange) + return Err(TxOutError::MoneyOutofRange); } if value == 0 { // zero values are only allowed if they are provably // unspendable. if self.script_pubkey.is_provably_unspendable() { - return Err(TxOutError::ZeroValueCommitment) + return Err(TxOutError::ZeroValueCommitment); } else { - return Err(TxOutError::NonUnspendableZeroValue) + return Err(TxOutError::NonUnspendableZeroValue); } } let asset_comm = self.get_asset_gen(secp)?; - Ok(PedersenCommitment::new_unblinded(secp, value, asset_comm)) + Ok(PedersenCommitment::new_unblinded(secp, value, asset_comm)) } Value::Confidential(comm) => Ok(comm), } @@ -618,12 +669,20 @@ impl TxOut { R: RngCore + CryptoRng, C: Signing, { - let out_abf = AssetBlindingFactor::new(rng); let ephemeral_sk = SecretKey::new(rng); let (txout, out_vbf) = TxOut::with_secrets_last( - rng, secp, value, spk, blinder, asset, ephemeral_sk, out_abf, spent_utxo_secrets, output_secrets + rng, + secp, + value, + spk, + blinder, + asset, + ephemeral_sk, + out_abf, + spent_utxo_secrets, + output_secrets, )?; Ok((txout, out_abf, out_vbf, ephemeral_sk)) } @@ -646,7 +705,6 @@ impl TxOut { R: RngCore + CryptoRng, C: Signing, { - let value_blind_inputs = spent_utxo_secrets .iter() .map(|utxo_sec| utxo_sec.value_blind_inputs()) @@ -657,11 +715,23 @@ impl TxOut { .map(|e| e.value_blind_inputs()) .collect::>(); - let out_vbf = - ValueBlindingFactor::last(secp, value, out_abf, &value_blind_inputs, &value_blind_outputs); + let out_vbf = ValueBlindingFactor::last( + secp, + value, + out_abf, + &value_blind_inputs, + &value_blind_outputs, + ); let out_secrets = TxOutSecrets::new(asset, out_abf, value, out_vbf); - let txout = - TxOut::with_txout_secrets(rng, secp, spk, blinder, ephemeral_sk, out_secrets, spent_utxo_secrets)?; + let txout = TxOut::with_txout_secrets( + rng, + secp, + spk, + blinder, + ephemeral_sk, + out_secrets, + spent_utxo_secrets, + )?; Ok((txout, out_vbf)) } @@ -765,7 +835,6 @@ impl From for UnblindError { } impl TxIn { - /// Blind issuances for this [`TxIn`]. Asset amount and token amount must be /// set in [`AssetIssuance`](crate::AssetIssuance) field for this input pub fn blind_issuances_with_bfs( @@ -782,17 +851,25 @@ impl TxIn { let (asset_id, token_id) = self.issuance_ids(); let arr = vec![ (issue_vbf, self.asset_issuance.amount, issue_sk, asset_id), - (token_vbf, self.asset_issuance.inflation_keys, token_sk, token_id) + ( + token_vbf, + self.asset_issuance.inflation_keys, + token_sk, + token_id, + ), ]; for (i, (bf, amt, blind_sk, asset)) in arr.into_iter().enumerate() { let v = match amt { Value::Null => continue, // nothing to blind Value::Explicit(0) => return Err(BlindError::ZeroValueBlindingNotAllowed), Value::Confidential(_) => return Err(BlindError::IssuanceAmountMustBeExplicit), - Value::Explicit(v) => Value::Explicit(v) + Value::Explicit(v) => Value::Explicit(v), }; let spk = Script::new(); - let msg = RangeProofMessage { asset, bf: AssetBlindingFactor::zero() }; + let msg = RangeProofMessage { + asset, + bf: AssetBlindingFactor::zero(), + }; let (comm, prf) = v.blind_with_shared_secret(secp, bf, blind_sk, &spk, &msg)?; if i == 0 { self.asset_issuance.amount = comm; @@ -813,8 +890,15 @@ impl TxIn { &mut self, secp: &Secp256k1, rng: &mut R, - ) -> Result<(ValueBlindingFactor, SecretKey, ValueBlindingFactor, SecretKey), BlindError> { - + ) -> Result< + ( + ValueBlindingFactor, + SecretKey, + ValueBlindingFactor, + SecretKey, + ), + BlindError, + > { let issue_vbf = ValueBlindingFactor::new(rng); let token_vbf = ValueBlindingFactor::new(rng); let issue_sk = SecretKey::new(rng); @@ -826,7 +910,7 @@ impl TxIn { /// Data structure for Unifying inputs and pseudo-inputs. #[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub enum TxInType{ +pub enum TxInType { /// Regular input Input(usize), /// Issuance Pseudo-input @@ -886,8 +970,7 @@ impl Transaction { &self, secp: &Secp256k1, spent_utxos: &[TxOut], - ) -> Result<(), VerificationError> - { + ) -> Result<(), VerificationError> { if spent_utxos.len() != self.input.len() { return Err(VerificationError::UtxoInputLenMismatch); } @@ -896,12 +979,14 @@ impl Transaction { let mut out_commits = vec![]; let mut domain = vec![]; for (i, inp) in self.input.iter().enumerate() { - let gen = spent_utxos[i].get_asset_gen(secp) + let gen = spent_utxos[i] + .get_asset_gen(secp) .map_err(|e| VerificationError::SpentTxOutError(i, e))?; domain.push(gen); in_commits.push( - spent_utxos[i].get_value_commit(secp) - .map_err(|e| VerificationError::SpentTxOutError(i, e))? + spent_utxos[i] + .get_value_commit(secp) + .map_err(|e| VerificationError::SpentTxOutError(i, e))?, ); if inp.has_issuance() { let (asset_id, token_id) = inp.issuance_ids(); @@ -915,7 +1000,7 @@ impl Transaction { Value::Explicit(v) => { let comm = PedersenCommitment::new_unblinded(secp, *v, gen); in_commits.push(comm) - }, + } Value::Confidential(comm) => in_commits.push(*comm), } let gen = Generator::new_unblinded(secp, asset.into_tag()); @@ -925,19 +1010,24 @@ impl Transaction { } for (i, out) in self.output.iter().enumerate() { - // Compute the value commitments and asset generator - let out_commit = out.get_value_commit(secp) + let out_commit = out + .get_value_commit(secp) .map_err(|e| VerificationError::SpentTxOutError(i, e))?; out_commits.push(out_commit); // rangeproof checks if let Some(comm) = out.value.commitment() { - let gen = out.get_asset_gen(secp) - .map_err(|e| VerificationError::TxOutError(i, e))?; - let rangeproof = out.witness.rangeproof.as_ref().ok_or( - VerificationError::RangeProofMissing(i))?; - rangeproof.verify(secp, comm, out.script_pubkey.as_bytes(), gen) + let gen = out + .get_asset_gen(secp) + .map_err(|e| VerificationError::TxOutError(i, e))?; + let rangeproof = out + .witness + .rangeproof + .as_ref() + .ok_or(VerificationError::RangeProofMissing(i))?; + rangeproof + .verify(secp, comm, out.script_pubkey.as_bytes(), gen) .map_err(|e| VerificationError::RangeProofError(i, e))?; } else { // No rangeproof checks for explicit values @@ -945,10 +1035,13 @@ impl Transaction { // Surjection proof checks if let Some(gen) = out.asset.commitment() { - let surjectionproof = out.witness.surjection_proof.as_ref().ok_or( - VerificationError::SurjectionProofMissing(i))?; + let surjectionproof = out + .witness + .surjection_proof + .as_ref() + .ok_or(VerificationError::SurjectionProofMissing(i))?; if !surjectionproof.verify(secp, gen, &domain) { - return Err(VerificationError::SurjectionProofVerificationError(i)) + return Err(VerificationError::SurjectionProofVerificationError(i)); } } else { // No surjection proof checks for explicit assets @@ -956,7 +1049,7 @@ impl Transaction { } // Final Balance check if !secp256k1_zkp::verify_commitments_sum_to_equal(secp, &in_commits, &out_commits) { - return Err(VerificationError::BalanceCheckFailed) + return Err(VerificationError::BalanceCheckFailed); } Ok(()) } @@ -980,20 +1073,30 @@ impl Transaction { { let mut blinds = BTreeMap::new(); // Blinding Issuances unsupported - for (i, txin) in self.input.iter_mut().enumerate() { + for (i, txin) in self.input.iter_mut().enumerate() { if txin.has_issuance() && blind_issuances { let (iss_vbf, iss_sk, tkn_vbf, tkn_sk) = txin.blind_issuances(secp, rng)?; if txin.asset_issuance.amount.is_confidential() { - blinds.insert(TxInType::Issuance(i), (AssetBlindingFactor::zero(), iss_vbf, iss_sk)); + blinds.insert( + TxInType::Issuance(i), + (AssetBlindingFactor::zero(), iss_vbf, iss_sk), + ); } if txin.asset_issuance.inflation_keys.is_confidential() { - blinds.insert(TxInType::ReIssuance(i), (AssetBlindingFactor::zero(), tkn_vbf, tkn_sk)); + blinds.insert( + TxInType::ReIssuance(i), + (AssetBlindingFactor::zero(), tkn_vbf, tkn_sk), + ); } } } // Everything must be explicit - if !self.output.iter().all(|o| o.asset.is_explicit() && o.value.is_explicit()) { - return Err(BlindError::MustHaveAllExplicitTxOuts) + if !self + .output + .iter() + .all(|o| o.asset.is_explicit() && o.value.is_explicit()) + { + return Err(BlindError::MustHaveAllExplicitTxOuts); } // All outputs with script let num_to_blind = self @@ -1006,8 +1109,7 @@ impl Transaction { let mut last_output_index = None; for (i, out) in self.output.iter_mut().enumerate() { if out.is_fee() || !out.nonce.is_confidential() { - out_secrets.push( - TxOutSecrets::new( + out_secrets.push(TxOutSecrets::new( out.asset.explicit().unwrap(), AssetBlindingFactor::zero(), out.value.explicit().unwrap(), @@ -1017,17 +1119,21 @@ impl Transaction { } let blinder = out.nonce.commitment().expect("Confidential"); - let address = Address::from_script(&out.script_pubkey, Some(blinder), &AddressParams::ELEMENTS) - .ok_or(BlindError::InvalidAddress)?; + let address = + Address::from_script(&out.script_pubkey, Some(blinder), &AddressParams::ELEMENTS) + .ok_or(BlindError::InvalidAddress)?; if num_blinded + 1 < num_to_blind { - let (conf_out, abf, vbf, ephemeral_sk) = TxOut::new_not_last_confidential( - rng, secp, out.value.explicit().unwrap(), address, out.asset.explicit().unwrap(), &spent_utxo_secrets + rng, + secp, + out.value.explicit().unwrap(), + address, + out.asset.explicit().unwrap(), + &spent_utxo_secrets, )?; blinds.insert(TxInType::Input(i), (abf, vbf, ephemeral_sk)); - out_secrets.push( - TxOutSecrets::new( + out_secrets.push(TxOutSecrets::new( out.asset.explicit().unwrap(), abf, out.value.explicit().unwrap(), @@ -1049,14 +1155,21 @@ impl Transaction { out.value.explicit().unwrap(), out.asset.explicit().unwrap(), out.script_pubkey.clone(), // TODO: Possible to avoid this clone in future with _mut APIs - blinder + blinder, ) }; // Get Vec<&T> from Vec let out_secrets = out_secrets.iter().collect::>(); let (conf_out, abf, vbf, ephemeral_sk) = TxOut::new_last_confidential( - rng, secp, value, asset, spk, blinder, spent_utxo_secrets, &out_secrets + rng, + secp, + value, + asset, + spk, + blinder, + spent_utxo_secrets, + &out_secrets, )?; blinds.insert(TxInType::Input(last_index), (abf, vbf, ephemeral_sk)); @@ -1090,13 +1203,19 @@ impl fmt::Display for BlindError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { match self { BlindError::InvalidAddress => { - write!(f, "Only sending to valid addresses is supported as of now. \ - Manually construct transactions to send to custom script pubkeys") + write!( + f, + "Only sending to valid addresses is supported as of now. \ + Manually construct transactions to send to custom script pubkeys" + ) } BlindError::TooFewBlindingOutputs => { - write!(f, "Transactions must have atleast confidential outputs \ + write!( + f, + "Transactions must have atleast confidential outputs \ marked for blinding. To mark a output for blinding set nonce field\ - with a blinding pubkey") + with a blinding pubkey" + ) } BlindError::MustHaveAllExplicitTxOuts => { write!(f, "Transaction must all outputs explicit") @@ -1105,8 +1224,12 @@ impl fmt::Display for BlindError { write!(f, "{}", e) } BlindError::NoIssuanceToBlind => write!(f, "No Issuance present"), - BlindError::ZeroValueBlindingNotAllowed => write!(f, "Zero value blinding is not allowed"), - BlindError::IssuanceAmountMustBeExplicit => write!(f, "Issuance amount must be explicit to blind"), + BlindError::ZeroValueBlindingNotAllowed => { + write!(f, "Zero value blinding is not allowed") + } + BlindError::IssuanceAmountMustBeExplicit => { + write!(f, "Issuance amount must be explicit to blind") + } } } } @@ -1143,9 +1266,7 @@ pub trait BlindValueProofs: Sized { ) -> bool; } - impl BlindValueProofs for RangeProof { - /// Outputs a `[RangeProof]` that blinded value_commit /// corresponds to explicit value fn blind_value_proof( @@ -1155,19 +1276,19 @@ impl BlindValueProofs for RangeProof { value_commit: PedersenCommitment, asset_gen: Generator, vbf: ValueBlindingFactor, - ) -> Result{ + ) -> Result { RangeProof::new( secp, - explicit_val, // min_value - value_commit, // value_commit - explicit_val, // value - vbf.into_inner(), // blinding factor - &[], // message - &[], // add commitment + explicit_val, // min_value + value_commit, // value_commit + explicit_val, // value + vbf.into_inner(), // blinding factor + &[], // message + &[], // add commitment SecretKey::new(rng), // nonce - -1, // exp - 0, // min bits - asset_gen, // additional gen + -1, // exp + 0, // min bits + asset_gen, // additional gen ) } @@ -1182,9 +1303,7 @@ impl BlindValueProofs for RangeProof { ) -> bool { let r = self.verify(secp, value_commit, &[], asset_gen); match r { - Ok(e) => { - e.start == explicit_val && e.end - 1 == explicit_val - } + Ok(e) => e.start == explicit_val && e.end - 1 == explicit_val, Err(..) => return false, } } @@ -1224,7 +1343,7 @@ impl BlindAssetProofs for SurjectionProof { rng, asset.into_tag(), abf.into_inner(), - &[(gen, asset.into_tag(), ZERO_TWEAK)] + &[(gen, asset.into_tag(), ZERO_TWEAK)], ) } @@ -1241,14 +1360,14 @@ impl BlindAssetProofs for SurjectionProof { #[cfg(test)] mod tests { - use crate::hashes::hex::FromHex; - use rand::thread_rng; - use secp256k1_zkp::SECP256K1; use super::*; - use crate::encode::deserialize; use crate::confidential; + use crate::encode::deserialize; + use crate::hashes::hex::FromHex; use crate::Script; use bitcoin::{self, Network, PrivateKey, PublicKey}; + use rand::thread_rng; + use secp256k1_zkp::SECP256K1; #[test] fn test_blind_tx() { @@ -1256,33 +1375,71 @@ mod tests { let tx_hex = "020000000001741498f6da8f47eb438d0fb9de099b7e29c0e011b9ab64c3e0eb097a09a6a9220100000000fdffffff0301230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b201000775f04dedb2d102a11e47fd7a0edfb424a43b2d3cf29d700d4b168c92e115709ff7d15070e201dd16001483641e58db3de6067f010d71c9782874572af9fb01230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20100000000000f42400206a1039b0fe0d110d2108f2cc49d637f95b6ac18045af5b302b3c14bf8457994160014ad65ebbed8416659141cc788c1b917d6ff3e059901230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20100000000000000f9000000000000"; let mut tx: Transaction = deserialize(&Vec::::from_hex(tx_hex).unwrap()[..]).unwrap(); let spent_utxo_secrets = TxOutSecrets { - asset: AssetId::from_hex("b2e15d0d7a0c94e4e2ce0fe6e8691b9e451377f6e46e8045a86f7c4b5d4f0f23").unwrap(), - asset_bf: AssetBlindingFactor::from_hex("a5b3d111cdaa5fc111e2723df4caf315864f25fb4610cc737f10d5a55cd4096f").unwrap(), - value: bitcoin::Amount::from_str_in("20999997.97999114", bitcoin::Denomination::Bitcoin).unwrap().as_sat(), - value_bf: ValueBlindingFactor::from_hex("e36a4de359469f547571d117bc5509fb74fba73c84b0cdd6f4edfa7ff7fa457d").unwrap(), + asset: AssetId::from_hex( + "b2e15d0d7a0c94e4e2ce0fe6e8691b9e451377f6e46e8045a86f7c4b5d4f0f23", + ) + .unwrap(), + asset_bf: AssetBlindingFactor::from_hex( + "a5b3d111cdaa5fc111e2723df4caf315864f25fb4610cc737f10d5a55cd4096f", + ) + .unwrap(), + value: bitcoin::Amount::from_str_in( + "20999997.97999114", + bitcoin::Denomination::Bitcoin, + ) + .unwrap() + .as_sat(), + value_bf: ValueBlindingFactor::from_hex( + "e36a4de359469f547571d117bc5509fb74fba73c84b0cdd6f4edfa7ff7fa457d", + ) + .unwrap(), }; #[cfg(feature = "serde")] { use serde_json; - let spent_utxo_secrets_serde: TxOutSecrets = serde_json::from_str(r#" + let spent_utxo_secrets_serde: TxOutSecrets = serde_json::from_str( + r#" { "asset": "b2e15d0d7a0c94e4e2ce0fe6e8691b9e451377f6e46e8045a86f7c4b5d4f0f23", "asset_bf": "a5b3d111cdaa5fc111e2723df4caf315864f25fb4610cc737f10d5a55cd4096f", "value": 2099999797999114, "value_bf": "e36a4de359469f547571d117bc5509fb74fba73c84b0cdd6f4edfa7ff7fa457d" - }"#).unwrap(); + }"#, + ) + .unwrap(); assert_eq!(spent_utxo_secrets, spent_utxo_secrets_serde); } let secp = secp256k1_zkp::Secp256k1::new(); - let _bfs = tx.blind(&mut thread_rng(), &secp, &[spent_utxo_secrets], false).unwrap(); + let _bfs = tx + .blind(&mut thread_rng(), &secp, &[spent_utxo_secrets], false) + .unwrap(); let spent_utxo = TxOut { - asset: Asset::from_commitment(&Vec::::from_hex("0baf634b18e1880c96dcf9947b0e0fd2d38d66d723339174df3fd980148c2f0bb3").unwrap()).unwrap(), - value: Value::from_commitment(&Vec::::from_hex("093baba9076190867fbc5e43132cb2f82245caf603b493d7c0da8b7eda7912fa2c").unwrap()).unwrap(), - nonce: Nonce::from_commitment(&Vec::::from_hex("02a96a456f4936dcf0afbc325ac3798c4464e7b66dd460d564f3f91882d6089a3b").unwrap()).unwrap(), - script_pubkey: Script::from_hex("0014d2bcde17e7744f6377466ca1bd35d212954674c8").unwrap(), + asset: Asset::from_commitment( + &Vec::::from_hex( + "0baf634b18e1880c96dcf9947b0e0fd2d38d66d723339174df3fd980148c2f0bb3", + ) + .unwrap(), + ) + .unwrap(), + value: Value::from_commitment( + &Vec::::from_hex( + "093baba9076190867fbc5e43132cb2f82245caf603b493d7c0da8b7eda7912fa2c", + ) + .unwrap(), + ) + .unwrap(), + nonce: Nonce::from_commitment( + &Vec::::from_hex( + "02a96a456f4936dcf0afbc325ac3798c4464e7b66dd460d564f3f91882d6089a3b", + ) + .unwrap(), + ) + .unwrap(), + script_pubkey: Script::from_hex("0014d2bcde17e7744f6377466ca1bd35d212954674c8") + .unwrap(), witness: TxOutWitness::default(), }; tx.verify_tx_amt_proofs(&secp, &[spent_utxo]).unwrap(); @@ -1327,7 +1484,12 @@ mod tests { input_abf, input_vbf, )]; */ - let txout_secrets = TxOutSecrets { asset, asset_bf, value, value_bf}; + let txout_secrets = TxOutSecrets { + asset, + asset_bf, + value, + value_bf, + }; let spent_utxo_secrets = [txout_secrets]; let (txout, _, _, _) = TxOut::new_not_last_confidential( @@ -1348,7 +1510,6 @@ mod tests { #[test] fn blind_value_proof_test() { - let id = AssetId::from_slice(&[1u8; 32]).unwrap(); let abf = AssetBlindingFactor::new(&mut thread_rng()); let asset = confidential::Asset::new_confidential(SECP256K1, id, abf); @@ -1365,8 +1526,9 @@ mod tests { explicit_val, value_comm, asset_gen, - vbf - ).unwrap(); + vbf, + ) + .unwrap(); let res = proof.blind_value_proof_verify(SECP256K1, explicit_val, asset_gen, value_comm); assert!(res); @@ -1380,12 +1542,8 @@ mod tests { let asset_comm = asset.commitment().unwrap(); // Create the proof - let proof = SurjectionProof::blind_asset_proof( - &mut thread_rng(), - SECP256K1, - id, - abf, - ).unwrap(); + let proof = + SurjectionProof::blind_asset_proof(&mut thread_rng(), SECP256K1, id, abf).unwrap(); let res = proof.blind_asset_proof_verify(SECP256K1, id, asset_comm); assert!(res); diff --git a/src/pset/error.rs b/src/pset/error.rs index b680c619..041284a1 100644 --- a/src/pset/error.rs +++ b/src/pset/error.rs @@ -14,13 +14,13 @@ use std::{error, fmt}; -use crate::Txid; use crate::encode; +use crate::Txid; use super::raw; -use crate::hashes; use crate::blind::ConfidentialTxOutError; +use crate::hashes; use secp256k1_zkp; #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -119,30 +119,54 @@ impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Error::InvalidKey(ref rkey) => write!(f, "invalid key: {}", rkey), - Error::InvalidProprietaryKey => write!(f, "non-proprietary key type found when proprietary key was expected"), + Error::InvalidProprietaryKey => write!( + f, + "non-proprietary key type found when proprietary key was expected" + ), Error::DuplicateKey(ref rkey) => write!(f, "duplicate key: {}", rkey), Error::LocktimeConflict => write!(f, "conflicting locktime requirements"), - Error::UniqueIdMismatch { expected: ref e, actual: ref a } => write!(f, "different id: expected {}, actual {}", e, a), - Error::NonStandardSigHashType(ref sht) => write!(f, "non-standard sighash type: {}", sht), + Error::UniqueIdMismatch { + expected: ref e, + actual: ref a, + } => write!(f, "different id: expected {}, actual {}", e, a), + Error::NonStandardSigHashType(ref sht) => { + write!(f, "non-standard sighash type: {}", sht) + } Error::InvalidMagic => f.write_str("invalid magic"), Error::InvalidSeparator => f.write_str("invalid separator"), - Error::UnsignedTxHasScriptSigs => f.write_str("the unsigned transaction has script sigs"), - Error::UnsignedTxHasScriptWitnesses => f.write_str("the unsigned transaction has script witnesses"), + Error::UnsignedTxHasScriptSigs => { + f.write_str("the unsigned transaction has script sigs") + } + Error::UnsignedTxHasScriptWitnesses => { + f.write_str("the unsigned transaction has script witnesses") + } Error::MustHaveUnsignedTx => { f.write_str("partially signed transactions must have an unsigned transaction") } Error::NoMorePairs => f.write_str("no more key-value pairs for this pset map"), Error::HashParseError(e) => write!(f, "Hash Parse Error: {}", e), - Error::InvalidPreimageHashPair{ref preimage, ref hash, ref hash_type} => { + Error::InvalidPreimageHashPair { + ref preimage, + ref hash, + ref hash_type, + } => { // directly using debug forms of psethash enums - write!(f, "Preimage {:?} does not match {:?} hash {:?}", preimage, hash_type, hash ) + write!( + f, + "Preimage {:?} does not match {:?} hash {:?}", + preimage, hash_type, hash + ) + } + Error::MergeConflict(ref s) => { + write!(f, "Merge conflict: {}", s) } - Error::MergeConflict(ref s) => { write!(f, "Merge conflict: {}", s) } Error::ConsensusEncoding => f.write_str("bitcoin consensus encoding error"), Error::TooLargePset => { write!(f, "Psets with 10_000 or more inputs/outputs unsupported") } - Error::ExpiredPsbtv0Field => f.write_str("psbt v0 field specified in pset(based on pset)"), + Error::ExpiredPsbtv0Field => { + f.write_str("psbt v0 field specified in pset(based on pset)") + } Error::IncorrectPsetVersion => f.write_str("Pset version must be 2"), Error::MissingTxVersion => f.write_str("PSET missing global transaction version"), Error::MissingInputCount => f.write_str("PSET missing input count"), @@ -150,21 +174,39 @@ impl fmt::Display for Error { Error::MissingInputPrevTxId => f.write_str("PSET input missing previous txid"), Error::MissingInputPrevVout => f.write_str("PSET input missing previous output index"), Error::SecpScalarSizeError(actual) => { - write!(f, "PSET blinding scalars must be 32 bytes. Found {} bytes", actual) - } - Error::MissingOutputValue => f.write_str("PSET output missing value. Must have \ - at least one of explicit/confidential value set"), - Error::MissingOutputAsset => f.write_str("PSET output missing asset. Must have \ - at least one of explicit/confidential asset set"), - Error::MissingBlinderIndex => f.write_str("Output is blinded but does not have a blinder index"), - Error::MissingBlindingInfo => f.write_str("Output marked for blinding, but missing \ - some blinding information"), - Error::MissingOutputSpk => f.write_str("PSET output missing script pubkey. Must have \ - exactly one of explicit/confidential script pubkey set"), - Error::InputCountMismatch => f.write_str("PSET input count global field must \ - match the number of inputs"), - Error::OutputCountMismatch => f.write_str("PSET output count global field must \ - match the number of outputs"), + write!( + f, + "PSET blinding scalars must be 32 bytes. Found {} bytes", + actual + ) + } + Error::MissingOutputValue => f.write_str( + "PSET output missing value. Must have \ + at least one of explicit/confidential value set", + ), + Error::MissingOutputAsset => f.write_str( + "PSET output missing asset. Must have \ + at least one of explicit/confidential asset set", + ), + Error::MissingBlinderIndex => { + f.write_str("Output is blinded but does not have a blinder index") + } + Error::MissingBlindingInfo => f.write_str( + "Output marked for blinding, but missing \ + some blinding information", + ), + Error::MissingOutputSpk => f.write_str( + "PSET output missing script pubkey. Must have \ + exactly one of explicit/confidential script pubkey set", + ), + Error::InputCountMismatch => f.write_str( + "PSET input count global field must \ + match the number of inputs", + ), + Error::OutputCountMismatch => f.write_str( + "PSET output count global field must \ + match the number of outputs", + ), } } } @@ -223,8 +265,12 @@ impl fmt::Display for PsetBlindError { write!(f, "Atleast one output secrets should be provided") } PsetBlindError::BlinderIndexOutOfBounds(i, bl) => { - write!(f, "Blinder index {} for output index {} must be less \ - than total input count", bl, i) + write!( + f, + "Blinder index {} for output index {} must be less \ + than total input count", + bl, i + ) } PsetBlindError::MissingInputBlinds(i, bl) => { write!(f, "Output index {} expects blinding input index {}", i, bl) @@ -239,9 +285,13 @@ impl fmt::Display for PsetBlindError { write!(f, "Blinding error {} at output index {}", e, i) } PsetBlindError::BlindingProofsCreationError(i, e) => { - write!(f, "Blinding proof creation error {} at output index {}", e, i) + write!( + f, + "Blinding proof creation error {} at output index {}", + e, i + ) } } } } -impl error::Error for PsetBlindError {} \ No newline at end of file +impl error::Error for PsetBlindError {} diff --git a/src/pset/macros.rs b/src/pset/macros.rs index 6ad0c0ed..82785eda 100644 --- a/src/pset/macros.rs +++ b/src/pset/macros.rs @@ -14,7 +14,11 @@ #[allow(unused_macros)] macro_rules! hex_pset { - ($s:expr) => { $crate::encode::deserialize(& as $crate::hashes::hex::FromHex>::from_hex($s).unwrap()) }; + ($s:expr) => { + $crate::encode::deserialize( + & as $crate::hashes::hex::FromHex>::from_hex($s).unwrap(), + ) + }; } macro_rules! merge { @@ -61,10 +65,7 @@ macro_rules! impl_psetmap_consensus_encoding { ) -> Result { let mut len = 0; for pair in $crate::pset::Map::get_pairs(self)? { - len += $crate::encode::Encodable::consensus_encode( - &pair, - &mut s, - )?; + len += $crate::encode::Encodable::consensus_encode(&pair, &mut s)?; } Ok(len + $crate::encode::Encodable::consensus_encode(&0x00_u8, s)?) @@ -143,7 +144,6 @@ macro_rules! impl_pset_insert_pair { }; } - #[cfg_attr(rustfmt, rustfmt_skip)] macro_rules! impl_pset_get_pair { ($rv:ident.push($slf:ident.$unkeyed_name:ident as <$unkeyed_typeval:expr, _>)) => { @@ -211,9 +211,8 @@ macro_rules! impl_pset_hash_deserialize { ($hash_type:ty) => { impl $crate::pset::serialize::Deserialize for $hash_type { fn deserialize(bytes: &[u8]) -> Result { - <$hash_type>::from_slice(&bytes[..]).map_err(|e| { - $crate::pset::Error::from(e).into() - }) + <$hash_type>::from_slice(&bytes[..]) + .map_err(|e| $crate::pset::Error::from(e).into()) } } }; diff --git a/src/pset/map/global.rs b/src/pset/map/global.rs index 17bb5c7d..c5591bdb 100644 --- a/src/pset/map/global.rs +++ b/src/pset/map/global.rs @@ -13,16 +13,19 @@ // If not, see . // -use std::{collections::BTreeMap, io::{self, Cursor, Read}}; -use std::collections::btree_map::Entry; use std::cmp; +use std::collections::btree_map::Entry; +use std::{ + collections::BTreeMap, + io::{self, Cursor, Read}, +}; -use crate::VarInt; -use crate::encode::{Decodable}; -use crate::pset::{self, map::Map, raw, Error}; -use crate::endian::u32_to_array_le; -use bitcoin::util::bip32::{ExtendedPubKey, KeySource, Fingerprint, DerivationPath, ChildNumber}; use crate::encode; +use crate::encode::Decodable; +use crate::endian::u32_to_array_le; +use crate::pset::{self, map::Map, raw, Error}; +use crate::VarInt; +use bitcoin::util::bip32::{ChildNumber, DerivationPath, ExtendedPubKey, Fingerprint, KeySource}; use secp256k1_zkp::Tweak; // (Not used in pset) Type: Unsigned Transaction PSET_GLOBAL_UNSIGNED_TX = 0x00 @@ -47,7 +50,6 @@ const PSET_GLOBAL_VERSION: u8 = 0xFB; /// Type: Proprietary Use Type PSET_GLOBAL_PROPRIETARY = 0xFC const PSET_GLOBAL_PROPRIETARY: u8 = 0xFC; - /// Proprietary fields in elements /// Type: Global Scalars used in range proofs = 0x00 const PSBT_ELEMENTS_GLOBAL_SCALAR: u8 = 0x00; @@ -76,7 +78,7 @@ pub struct TxData { pub tx_modifiable: Option, } -impl Default for TxData{ +impl Default for TxData { fn default() -> Self { Self { // tx version must be 2 @@ -107,10 +109,16 @@ pub struct Global { /// Elements tx modifiable flag pub elements_tx_modifiable_flag: Option, /// Other Proprietary fields - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))] + #[cfg_attr( + feature = "serde", + serde(with = "crate::serde_utils::btreemap_as_seq_byte_values") + )] pub proprietary: BTreeMap>, /// Unknown global key-value pairs. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))] + #[cfg_attr( + feature = "serde", + serde(with = "crate::serde_utils::btreemap_as_seq_byte_values") + )] pub unknown: BTreeMap>, } @@ -129,7 +137,6 @@ impl Default for Global { } impl Global { - /// Accessor for the number of inputs currently in the PSET pub fn n_inputs(&self) -> usize { self.tx_data.input_count @@ -149,14 +156,14 @@ impl Map for Global { } = pair; match raw_key.type_value { - PSET_GLOBAL_UNSIGNED_TX=> return Err(Error::ExpiredPsbtv0Field)?, + PSET_GLOBAL_UNSIGNED_TX => return Err(Error::ExpiredPsbtv0Field)?, // Can't set the mandatory non-optional fields via insert_pair - PSET_GLOBAL_VERSION | - PSET_GLOBAL_FALLBACK_LOCKTIME | - PSET_GLOBAL_INPUT_COUNT| - PSET_GLOBAL_OUTPUT_COUNT| - PSET_GLOBAL_TX_MODIFIABLE | - PSET_GLOBAL_TX_VERSION => return Err(Error::DuplicateKey(raw_key).into()), + PSET_GLOBAL_VERSION + | PSET_GLOBAL_FALLBACK_LOCKTIME + | PSET_GLOBAL_INPUT_COUNT + | PSET_GLOBAL_OUTPUT_COUNT + | PSET_GLOBAL_TX_MODIFIABLE + | PSET_GLOBAL_TX_VERSION => return Err(Error::DuplicateKey(raw_key).into()), PSET_GLOBAL_PROPRIETARY => { let prop_key = raw::ProprietaryKey::from_key(raw_key.clone())?; if prop_key.is_pset_key() && prop_key.subtype == PSBT_ELEMENTS_GLOBAL_SCALAR { @@ -170,25 +177,29 @@ impl Map for Global { } else { return Err(Error::InvalidKey(raw_key.into()))?; } - } else if prop_key.is_pset_key() && prop_key.subtype == PSBT_ELEMENTS_GLOBAL_TX_MODIFIABLE { + } else if prop_key.is_pset_key() + && prop_key.subtype == PSBT_ELEMENTS_GLOBAL_TX_MODIFIABLE + { if prop_key.key.is_empty() && raw_value.len() == 1 { self.elements_tx_modifiable_flag = Some(raw_value[0]); } else { return Err(Error::InvalidKey(raw_key.into()))?; } } else { - match self.proprietary.entry(prop_key) { - Entry::Vacant(empty_key) => { - empty_key.insert(raw_value); - } - Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key).into()), + match self.proprietary.entry(prop_key) { + Entry::Vacant(empty_key) => { + empty_key.insert(raw_value); + } + Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key).into()), } } } _ => match self.unknown.entry(raw_key) { - Entry::Vacant(empty_key) => {empty_key.insert(raw_value);}, + Entry::Vacant(empty_key) => { + empty_key.insert(raw_value); + } Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone()).into()), - } + }, } Ok(()) @@ -236,9 +247,11 @@ impl Map for Global { value: { let mut ret = Vec::with_capacity(4 + derivation.len() * 4); ret.extend(fingerprint.as_bytes()); - derivation.into_iter().for_each(|n| ret.extend(&u32_to_array_le((*n).into()))); + derivation + .into_iter() + .for_each(|n| ret.extend(&u32_to_array_le((*n).into()))); ret - } + }, }); } @@ -249,7 +262,10 @@ impl Map for Global { // Serialize scalars and elements tx modifiable for scalar in &self.scalars { - let key = raw::ProprietaryKey::from_pset_pair(PSBT_ELEMENTS_GLOBAL_SCALAR, scalar.as_ref().to_vec()); + let key = raw::ProprietaryKey::from_pset_pair( + PSBT_ELEMENTS_GLOBAL_SCALAR, + scalar.as_ref().to_vec(), + ); rv.push(raw::Pair { key: key.to_key(), value: vec![], // This is a bug in elements core c++, parses this value as vec![0] @@ -287,8 +303,9 @@ impl Map for Global { // But since unique ids must be the same, all fields of // tx_data but tx modifiable must be the same // Keep flags from both psets - self.tx_data.tx_modifiable = Some(self.tx_data.tx_modifiable.unwrap_or(0) | - other.tx_data.tx_modifiable.unwrap_or(0)); + self.tx_data.tx_modifiable = Some( + self.tx_data.tx_modifiable.unwrap_or(0) | other.tx_data.tx_modifiable.unwrap_or(0), + ); // Keeping the highest version self.version = cmp::max(self.version, other.version); @@ -298,7 +315,7 @@ impl Map for Global { match self.xpub.entry(xpub) { Entry::Vacant(entry) => { entry.insert((fingerprint1, derivation1)); - }, + } Entry::Occupied(mut entry) => { // Here in case of the conflict we select the version with algorithm: // 1) if everything is equal we do nothing @@ -311,24 +328,21 @@ impl Map for Global { let (fingerprint2, derivation2) = entry.get().clone(); - if derivation1 == derivation2 && fingerprint1 == fingerprint2 - { - continue - } - else if - derivation1.len() < derivation2.len() && - derivation1[..] == derivation2[derivation2.len() - derivation1.len()..] + if derivation1 == derivation2 && fingerprint1 == fingerprint2 { + continue; + } else if derivation1.len() < derivation2.len() + && derivation1[..] == derivation2[derivation2.len() - derivation1.len()..] { - continue - } - else if derivation2[..] == derivation1[derivation1.len() - derivation2.len()..] + continue; + } else if derivation2[..] + == derivation1[derivation1.len() - derivation2.len()..] { entry.insert((fingerprint1, derivation1)); - continue + continue; } - return Err(pset::Error::MergeConflict(format!( - "global xpub {} has inconsistent key sources", xpub - ).to_owned())); + return Err(pset::Error::MergeConflict( + format!("global xpub {} has inconsistent key sources", xpub).to_owned(), + )); } } } @@ -352,10 +366,10 @@ impl_psetmap_consensus_encoding!(Global); impl Decodable for Global { fn consensus_decode(mut d: D) -> Result { - let mut version: Option = None; let mut unknowns: BTreeMap> = Default::default(); - let mut xpub_map: BTreeMap = Default::default(); + let mut xpub_map: BTreeMap = + Default::default(); let mut proprietary = BTreeMap::new(); let mut scalars = Vec::new(); @@ -407,7 +421,9 @@ impl Decodable for Global { ))?; if raw_value.is_empty() || raw_value.len() % 4 != 0 { - return Err(encode::Error::ParseFailed("Incorrect length of global xpub derivation data")) + return Err(encode::Error::ParseFailed( + "Incorrect length of global xpub derivation data", + )); } let child_count = raw_value.len() / 4 - 1; @@ -420,11 +436,18 @@ impl Decodable for Global { } let derivation = DerivationPath::from(path); // Keys, according to BIP-174, must be unique - if xpub_map.insert(xpub, (Fingerprint::from(&fingerprint[..]), derivation)).is_some() { - return Err(encode::Error::ParseFailed("Repeated global xpub key")) + if xpub_map + .insert(xpub, (Fingerprint::from(&fingerprint[..]), derivation)) + .is_some() + { + return Err(encode::Error::ParseFailed( + "Repeated global xpub key", + )); } } else { - return Err(encode::Error::ParseFailed("Xpub global key must contain serialized Xpub data")) + return Err(encode::Error::ParseFailed( + "Xpub global key must contain serialized Xpub data", + )); } } PSET_GLOBAL_VERSION => { @@ -434,7 +457,9 @@ impl Decodable for Global { } PSET_GLOBAL_PROPRIETARY => { let prop_key = raw::ProprietaryKey::from_key(raw_key.clone())?; - if prop_key.is_pset_key() && prop_key.subtype == PSBT_ELEMENTS_GLOBAL_SCALAR { + if prop_key.is_pset_key() + && prop_key.subtype == PSBT_ELEMENTS_GLOBAL_SCALAR + { if raw_value.is_empty() && prop_key.key.len() == 32 { let scalar = Tweak::from_slice(&prop_key.key)?; if !scalars.contains(&scalar) { @@ -445,25 +470,33 @@ impl Decodable for Global { } else { return Err(Error::InvalidKey(raw_key.into()))?; } - } else if prop_key.is_pset_key() && prop_key.subtype == PSBT_ELEMENTS_GLOBAL_TX_MODIFIABLE { + } else if prop_key.is_pset_key() + && prop_key.subtype == PSBT_ELEMENTS_GLOBAL_TX_MODIFIABLE + { if prop_key.key.is_empty() && raw_value.len() == 1 { elements_tx_modifiable_flag = Some(raw_value[0]); } else { return Err(Error::InvalidKey(raw_key.into()))?; } } else { - match proprietary.entry(prop_key) { - Entry::Vacant(empty_key) => { - empty_key.insert(raw_value); - } - Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key).into()), + match proprietary.entry(prop_key) { + Entry::Vacant(empty_key) => { + empty_key.insert(raw_value); + } + Entry::Occupied(_) => { + return Err(Error::DuplicateKey(raw_key).into()) + } } } } _ => match unknowns.entry(raw_key) { - Entry::Vacant(empty_key) => {empty_key.insert(raw_value);}, - Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone()).into()), - } + Entry::Vacant(empty_key) => { + empty_key.insert(raw_value); + } + Entry::Occupied(k) => { + return Err(Error::DuplicateKey(k.key().clone()).into()) + } + }, } } Err(crate::encode::Error::PsetError(crate::pset::Error::NoMorePairs)) => break, @@ -481,7 +514,13 @@ impl Decodable for Global { let output_count = output_count.ok_or(Error::MissingOutputCount)?.0 as usize; let global = Global { - tx_data: TxData { version: tx_version, fallback_locktime, input_count, output_count, tx_modifiable}, + tx_data: TxData { + version: tx_version, + fallback_locktime, + input_count, + output_count, + tx_modifiable, + }, version: version, xpub: xpub_map, proprietary: proprietary, diff --git a/src/pset/map/input.rs b/src/pset/map/input.rs index 8bab6284..daebdc18 100644 --- a/src/pset/map/input.rs +++ b/src/pset/map/input.rs @@ -13,26 +13,30 @@ // use std::fmt; -use std::{cmp, collections::btree_map::{BTreeMap, Entry}, io, str::FromStr}; - +use std::{ + cmp, + collections::btree_map::{BTreeMap, Entry}, + io, + str::FromStr, +}; + +use crate::taproot::{ControlBlock, LeafVersion, TapBranchHash, TapLeafHash}; use crate::{schnorr, AssetId, ContractHash}; -use crate::taproot::{ControlBlock, LeafVersion, TapLeafHash, TapBranchHash}; -use crate::{Script, AssetIssuance, EcdsaSigHashType, Transaction, Txid, TxOut, TxIn, BlockHash}; -use crate::{SchnorrSigHashType, transaction::SighashTypeParseError}; -use crate::encode::{self, Decodable}; use crate::confidential; -use bitcoin::util::bip32::KeySource; -use bitcoin::{self, PublicKey}; -use hashes::Hash; +use crate::encode::{self, Decodable}; use crate::hashes::{self, hash160, ripemd160, sha256, sha256d}; use crate::pset::map::Map; use crate::pset::raw; use crate::pset::serialize; -use crate::pset::{self, Error, error}; +use crate::pset::{self, error, Error}; +use crate::{transaction::SighashTypeParseError, SchnorrSigHashType}; +use crate::{AssetIssuance, BlockHash, EcdsaSigHashType, Script, Transaction, TxIn, TxOut, Txid}; +use bitcoin::util::bip32::KeySource; +use bitcoin::{self, PublicKey}; +use hashes::Hash; use secp256k1_zkp::{self, RangeProof, Tweak, ZERO_TWEAK}; - use crate::OutPoint; /// Type: Non-Witness UTXO PSET_IN_NON_WITNESS_UTXO = 0x00 @@ -78,11 +82,11 @@ const PSBT_IN_TAP_SCRIPT_SIG: u8 = 0x14; /// Type: Taproot Leaf Script PSBT_IN_TAP_LEAF_SCRIPT = 0x14 const PSBT_IN_TAP_LEAF_SCRIPT: u8 = 0x15; /// Type: Taproot Key BIP 32 Derivation Path PSBT_IN_TAP_BIP32_DERIVATION = 0x16 -const PSBT_IN_TAP_BIP32_DERIVATION : u8 = 0x16; +const PSBT_IN_TAP_BIP32_DERIVATION: u8 = 0x16; /// Type: Taproot Internal Key PSBT_IN_TAP_INTERNAL_KEY = 0x17 -const PSBT_IN_TAP_INTERNAL_KEY : u8 = 0x17; +const PSBT_IN_TAP_INTERNAL_KEY: u8 = 0x17; /// Type: Taproot Merkle Root PSBT_IN_TAP_MERKLE_ROOT = 0x18 -const PSBT_IN_TAP_MERKLE_ROOT : u8 = 0x18; +const PSBT_IN_TAP_MERKLE_ROOT: u8 = 0x18; /// Type: Proprietary Use Type PSET_IN_PROPRIETARY = 0xFC const PSET_IN_PROPRIETARY: u8 = 0xFC; @@ -160,7 +164,10 @@ pub struct Input { pub witness_utxo: Option, /// A map from public keys to their corresponding signature as would be /// pushed to the stack from a scriptSig or witness. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_byte_values"))] + #[cfg_attr( + feature = "serde", + serde(with = "crate::serde_utils::btreemap_byte_values") + )] pub partial_sigs: BTreeMap>, /// The sighash type to be used for this input. Signatures for this input /// must use the sighash type. @@ -181,16 +188,28 @@ pub struct Input { pub final_script_witness: Option>>, /// TODO: Proof of reserves commitment /// RIPEMD160 hash to preimage map - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_byte_values"))] + #[cfg_attr( + feature = "serde", + serde(with = "crate::serde_utils::btreemap_byte_values") + )] pub ripemd160_preimages: BTreeMap>, /// SHA256 hash to preimage map - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_byte_values"))] + #[cfg_attr( + feature = "serde", + serde(with = "crate::serde_utils::btreemap_byte_values") + )] pub sha256_preimages: BTreeMap>, /// HSAH160 hash to preimage map - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_byte_values"))] + #[cfg_attr( + feature = "serde", + serde(with = "crate::serde_utils::btreemap_byte_values") + )] pub hash160_preimages: BTreeMap>, /// HAS256 hash to preimage map - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_byte_values"))] + #[cfg_attr( + feature = "serde", + serde(with = "crate::serde_utils::btreemap_byte_values") + )] pub hash256_preimages: BTreeMap>, /// (PSET) Prevout TXID of the input pub previous_txid: Txid, @@ -214,9 +233,9 @@ pub struct Input { #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))] pub tap_key_origins: BTreeMap, KeySource)>, /// Taproot Internal key - pub tap_internal_key : Option, + pub tap_internal_key: Option, /// Taproot Merkle root - pub tap_merkle_root : Option, + pub tap_merkle_root: Option, // Proprietary key-value pairs for this input. /// The issuance value pub issuance_value_amount: Option, @@ -254,10 +273,16 @@ pub struct Input { /// Proof that blinded inflation keys matches the corresponding commitment pub in_issuance_blind_inflation_keys_proof: Option>, /// Other fields - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))] + #[cfg_attr( + feature = "serde", + serde(with = "crate::serde_utils::btreemap_as_seq_byte_values") + )] pub proprietary: BTreeMap>, /// Unknown key-value pairs for this input. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))] + #[cfg_attr( + feature = "serde", + serde(with = "crate::serde_utils::btreemap_as_seq_byte_values") + )] pub unknown: BTreeMap>, } @@ -267,7 +292,7 @@ pub struct Input { /// for converting to/from [`PsbtSighashType`] from/to the desired signature hash type they need. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct PsbtSighashType { - pub (crate) inner: u32, + pub(crate) inner: u32, } serde_string_impl!(PsbtSighashType, "a PsbtSighashType data"); @@ -292,7 +317,11 @@ impl FromStr for PsbtSighashType { // inputs. We also do not support SIGHASH_RESERVED in verbatim form // ("0xFF" string should be used instead). match SchnorrSigHashType::from_str(s) { - Ok(SchnorrSigHashType::Reserved) => return Err(SighashTypeParseError{ unrecognized: s.to_owned() }), + Ok(SchnorrSigHashType::Reserved) => { + return Err(SighashTypeParseError { + unrecognized: s.to_owned(), + }) + } Ok(ty) => return Ok(ty.into()), Err(_) => {} } @@ -302,18 +331,24 @@ impl FromStr for PsbtSighashType { return Ok(PsbtSighashType { inner }); } - Err(SighashTypeParseError{ unrecognized: s.to_owned() }) + Err(SighashTypeParseError { + unrecognized: s.to_owned(), + }) } } impl From for PsbtSighashType { fn from(ecdsa_hash_ty: EcdsaSigHashType) -> Self { - PsbtSighashType { inner: ecdsa_hash_ty as u32 } + PsbtSighashType { + inner: ecdsa_hash_ty as u32, + } } } impl From for PsbtSighashType { fn from(schnorr_hash_ty: SchnorrSigHashType) -> Self { - PsbtSighashType { inner: schnorr_hash_ty as u32 } + PsbtSighashType { + inner: schnorr_hash_ty as u32, + } } } @@ -342,7 +377,6 @@ impl PsbtSighashType { PsbtSighashType { inner: n } } - /// Converts [`PsbtSighashType`] to a raw `u32` sighash flag. /// /// No guarantees are made as to the standardness or validity of the returned value. @@ -351,8 +385,7 @@ impl PsbtSighashType { } } -impl Input{ - +impl Input { /// Obtains the [`EcdsaSigHashType`] for this input if one is specified. If no sighash type is /// specified, returns [`EcdsaSigHashType::All`]. /// @@ -403,15 +436,16 @@ impl Input{ ret.issuance_blinding_nonce = Some(txin.asset_issuance.asset_blinding_nonce); ret.issuance_asset_entropy = Some(txin.asset_issuance.asset_entropy); match txin.asset_issuance.amount { - confidential::Value::Null => { }, + confidential::Value::Null => {} confidential::Value::Explicit(x) => ret.issuance_value_amount = Some(x), confidential::Value::Confidential(comm) => ret.issuance_value_comm = Some(comm), } match txin.asset_issuance.inflation_keys { - confidential::Value::Null => { }, + confidential::Value::Null => {} confidential::Value::Explicit(x) => ret.issuance_inflation_keys = Some(x), - confidential::Value::Confidential(comm) => - ret.issuance_inflation_keys_comm = Some(comm), + confidential::Value::Confidential(comm) => { + ret.issuance_inflation_keys_comm = Some(comm) + } } // Witness @@ -458,15 +492,17 @@ impl Input{ /// Get the issuance for this tx input pub fn asset_issuance(&self) -> AssetIssuance { AssetIssuance { - asset_blinding_nonce: *self.issuance_blinding_nonce.as_ref() - .unwrap_or(&ZERO_TWEAK), + asset_blinding_nonce: *self.issuance_blinding_nonce.as_ref().unwrap_or(&ZERO_TWEAK), asset_entropy: self.issuance_asset_entropy.unwrap_or_default(), amount: match (self.issuance_value_amount, self.issuance_value_comm) { (None, None) => confidential::Value::Null, (_, Some(comm)) => confidential::Value::Confidential(comm), (Some(x), None) => confidential::Value::Explicit(x), }, - inflation_keys: match (self.issuance_inflation_keys, self.issuance_inflation_keys_comm) { + inflation_keys: match ( + self.issuance_inflation_keys, + self.issuance_inflation_keys_comm, + ) { (None, None) => confidential::Value::Null, (_, Some(comm)) => confidential::Value::Confidential(comm), (Some(x), None) => confidential::Value::Explicit(x), @@ -529,18 +565,38 @@ impl Map for Input { } } PSET_IN_RIPEMD160 => { - pset_insert_hash_pair(&mut self.ripemd160_preimages, raw_key, raw_value, error::PsetHash::Ripemd)?; + pset_insert_hash_pair( + &mut self.ripemd160_preimages, + raw_key, + raw_value, + error::PsetHash::Ripemd, + )?; } PSET_IN_SHA256 => { - pset_insert_hash_pair(&mut self.sha256_preimages, raw_key, raw_value, error::PsetHash::Sha256)?; + pset_insert_hash_pair( + &mut self.sha256_preimages, + raw_key, + raw_value, + error::PsetHash::Sha256, + )?; } PSET_IN_HASH160 => { - pset_insert_hash_pair(&mut self.hash160_preimages, raw_key, raw_value, error::PsetHash::Hash160)?; + pset_insert_hash_pair( + &mut self.hash160_preimages, + raw_key, + raw_value, + error::PsetHash::Hash160, + )?; } PSET_IN_HASH256 => { - pset_insert_hash_pair(&mut self.hash256_preimages, raw_key, raw_value, error::PsetHash::Hash256)?; + pset_insert_hash_pair( + &mut self.hash256_preimages, + raw_key, + raw_value, + error::PsetHash::Hash256, + )?; } - PSET_IN_PREVIOUS_TXID| PSET_IN_OUTPUT_INDEX => { + PSET_IN_PREVIOUS_TXID | PSET_IN_OUTPUT_INDEX => { return Err(Error::DuplicateKey(raw_key))?; } PSET_IN_SEQUENCE => { @@ -568,7 +624,7 @@ impl Map for Input { self.tap_script_sigs <= | } } - PSBT_IN_TAP_LEAF_SCRIPT=> { + PSBT_IN_TAP_LEAF_SCRIPT => { impl_pset_insert_pair! { self.tap_scripts <= |< raw_value: (Script, LeafVersion)> } @@ -645,11 +701,11 @@ impl Map for Input { impl_pset_prop_insert_pair!(self.in_issuance_blind_inflation_keys_proof <= | >) } _ => match self.proprietary.entry(prop_key) { - Entry::Vacant(empty_key) => { - empty_key.insert(raw_value); - } - Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key).into()), - } + Entry::Vacant(empty_key) => { + empty_key.insert(raw_value); + } + Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key).into()), + }, } } } @@ -657,9 +713,7 @@ impl Map for Input { Entry::Vacant(empty_key) => { empty_key.insert(raw_value); } - Entry::Occupied(k) => { - return Err(Error::DuplicateKey(k.key().clone()).into()) - } + Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone()).into()), }, } @@ -723,14 +777,20 @@ impl Map for Input { // Mandatory field: Prev Txid rv.push(raw::Pair { - key: raw::Key { type_value: PSET_IN_PREVIOUS_TXID, key: vec![]}, - value: serialize::Serialize::serialize(&self.previous_txid) + key: raw::Key { + type_value: PSET_IN_PREVIOUS_TXID, + key: vec![], + }, + value: serialize::Serialize::serialize(&self.previous_txid), }); // Mandatory field: prev out index rv.push(raw::Pair { - key: raw::Key { type_value: PSET_IN_OUTPUT_INDEX, key: vec![]}, - value: serialize::Serialize::serialize(&self.previous_output_index) + key: raw::Key { + type_value: PSET_IN_OUTPUT_INDEX, + key: vec![], + }, + value: serialize::Serialize::serialize(&self.previous_output_index), }); impl_pset_get_pair! { @@ -887,8 +947,12 @@ impl Map for Input { merge!(tap_merkle_root, self, other); // Should we do this? - self.required_time_locktime = cmp::max(self.required_time_locktime, other.required_time_locktime); - self.required_height_locktime = cmp::max(self.required_height_locktime, other.required_height_locktime); + self.required_time_locktime = + cmp::max(self.required_time_locktime, other.required_time_locktime); + self.required_height_locktime = cmp::max( + self.required_height_locktime, + other.required_height_locktime, + ); // elements merge!(issuance_value_amount, self, other); @@ -919,7 +983,6 @@ impl_psetmap_consensus_encoding!(Input); // not optional and cannot by set by insert_pair impl Decodable for Input { fn consensus_decode(mut d: D) -> Result { - // Sets the default to [0;32] and [0;4] let mut rv = Self::default(); let mut prev_vout: Option = None; @@ -943,7 +1006,10 @@ impl Decodable for Input { prev_vout <= | } } - _ => rv.insert_pair(raw::Pair { key: raw_key, value: raw_value })?, + _ => rv.insert_pair(raw::Pair { + key: raw_key, + value: raw_value, + })?, } } Err(crate::encode::Error::PsetError(crate::pset::Error::NoMorePairs)) => break, diff --git a/src/pset/map/mod.rs b/src/pset/map/mod.rs index 4437c684..8d8f191c 100644 --- a/src/pset/map/mod.rs +++ b/src/pset/map/mod.rs @@ -35,6 +35,6 @@ mod output; pub use self::global::Global; pub use self::global::TxData as GlobalTxData; pub use self::input::Input; +pub use self::input::PsbtSighashType; pub use self::output::Output; pub use self::output::TapTree; -pub use self::input::PsbtSighashType; \ No newline at end of file diff --git a/src/pset/map/output.rs b/src/pset/map/output.rs index 5855d218..d20611ac 100644 --- a/src/pset/map/output.rs +++ b/src/pset/map/output.rs @@ -12,26 +12,26 @@ // If not, see . // -use std::{collections::BTreeMap, io}; use std::collections::btree_map::Entry; +use std::{collections::BTreeMap, io}; use crate::taproot::TapLeafHash; use crate::taproot::{NodeInfo, TaprootBuilder}; -use crate::{Script, encode, TxOutWitness}; -use bitcoin::util::bip32::KeySource; -use bitcoin::{self, PublicKey}; -use crate::{pset, confidential}; use crate::encode::Decodable; use crate::pset::map::Map; use crate::pset::raw; use crate::pset::Error; +use crate::{confidential, pset}; +use crate::{encode, Script, TxOutWitness}; +use bitcoin::util::bip32::KeySource; +use bitcoin::{self, PublicKey}; use secp256k1_zkp::{self, Generator, RangeProof, SurjectionProof}; use crate::issuance; -use crate::TxOut; use crate::AssetId; +use crate::TxOut; /// Type: Redeem Script PSET_OUT_REDEEM_SCRIPT = 0x00 const PSET_OUT_REDEEM_SCRIPT: u8 = 0x00; @@ -131,10 +131,16 @@ pub struct Output { pub blind_asset_proof: Option>, /// Pset /// Other fields - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))] + #[cfg_attr( + feature = "serde", + serde(with = "crate::serde_utils::btreemap_as_seq_byte_values") + )] pub proprietary: BTreeMap>, /// Unknown key-value pairs for this output. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))] + #[cfg_attr( + feature = "serde", + serde(with = "crate::serde_utils::btreemap_as_seq_byte_values") + )] pub unknown: BTreeMap>, } @@ -149,7 +155,6 @@ impl PartialEq for TapTree { } } - impl Eq for TapTree {} impl TapTree { @@ -159,7 +164,9 @@ impl TapTree { // have only 1 element in branch and that is not None. // We make sure that we only allow is_complete builders via the from_inner // constructor - self.0.branch()[0].as_ref().expect("from_inner only parses is_complete builders") + self.0.branch()[0] + .as_ref() + .expect("from_inner only parses is_complete builders") } /// Convert a [`TaprootBuilder`] into a tree if it is complete binary tree. @@ -179,8 +186,7 @@ impl TapTree { } } -impl Output{ - +impl Output { /// Create a new explicit pset output pub fn new_explicit( script: Script, @@ -206,12 +212,12 @@ impl Output{ pub fn from_txout(txout: TxOut) -> Self { let mut rv = Self::default(); match txout.value { - confidential::Value::Null => { }, + confidential::Value::Null => {} confidential::Value::Explicit(x) => rv.amount = Some(x), confidential::Value::Confidential(comm) => rv.amount_comm = Some(comm), } match txout.asset { - confidential::Asset::Null => { }, + confidential::Asset::Null => {} confidential::Asset::Explicit(x) => rv.asset = Some(x), confidential::Asset::Confidential(comm) => rv.asset_comm = Some(comm), } @@ -246,10 +252,13 @@ impl Output{ (None, None) => confidential::Value::Null, }, nonce: if self.is_partially_blinded() { - self.ecdh_pubkey.map(|pk| confidential::Nonce::from(pk.inner)) + self.ecdh_pubkey + .map(|pk| confidential::Nonce::from(pk.inner)) } else { - self.blinding_key.map(|pk| confidential::Nonce::from(pk.inner)) - }.unwrap_or_default(), + self.blinding_key + .map(|pk| confidential::Nonce::from(pk.inner)) + } + .unwrap_or_default(), script_pubkey: self.script_pubkey.clone(), witness: TxOutWitness { surjection_proof: self.asset_surjection_proof.clone(), @@ -266,23 +275,22 @@ impl Output{ /// IsPartiallyBlinded from elements core pub fn is_partially_blinded(&self) -> bool { - self.is_marked_for_blinding() && ( - self.amount_comm.is_some() || - self.asset_comm.is_some() || - self.value_rangeproof.is_some() || - self.asset_surjection_proof.is_some() || - self.ecdh_pubkey.is_some() - ) + self.is_marked_for_blinding() + && (self.amount_comm.is_some() + || self.asset_comm.is_some() + || self.value_rangeproof.is_some() + || self.asset_surjection_proof.is_some() + || self.ecdh_pubkey.is_some()) } /// IsFullyBlinded from elements core pub fn is_fully_blinded(&self) -> bool { - self.is_marked_for_blinding() && - self.amount_comm.is_some() && - self.asset_comm.is_some() && - self.value_rangeproof.is_some() && - self.asset_surjection_proof.is_some() && - self.ecdh_pubkey.is_some() + self.is_marked_for_blinding() + && self.amount_comm.is_some() + && self.asset_comm.is_some() + && self.value_rangeproof.is_some() + && self.asset_surjection_proof.is_some() + && self.ecdh_pubkey.is_some() } } @@ -366,25 +374,33 @@ impl Map for Output { PSBT_ELEMENTS_OUT_BLIND_ASSET_PROOF => { impl_pset_prop_insert_pair!(self.blind_asset_proof <= | >) } - _ => { - match self.proprietary.entry(prop_key) { - Entry::Vacant(empty_key) => {empty_key.insert(raw_value);}, - Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key.clone()).into()), + _ => match self.proprietary.entry(prop_key) { + Entry::Vacant(empty_key) => { + empty_key.insert(raw_value); } - } + Entry::Occupied(_) => { + return Err(Error::DuplicateKey(raw_key.clone()).into()) + } + }, } } else { match self.proprietary.entry(prop_key) { - Entry::Vacant(empty_key) => {empty_key.insert(raw_value);}, - Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key.clone()).into()), + Entry::Vacant(empty_key) => { + empty_key.insert(raw_value); + } + Entry::Occupied(_) => { + return Err(Error::DuplicateKey(raw_key.clone()).into()) + } } } } _ => match self.unknown.entry(raw_key) { - Entry::Vacant(empty_key) => {empty_key.insert(raw_value);}, - Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone()).into()), - } + Entry::Vacant(empty_key) => { + empty_key.insert(raw_value); + } + Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone()).into()), + }, } Ok(()) @@ -436,8 +452,11 @@ impl Map for Output { // Mandatory field: Script rv.push(raw::Pair { - key: raw::Key { type_value: PSET_OUT_SCRIPT, key: vec![]}, - value: pset::serialize::Serialize::serialize(&self.script_pubkey) + key: raw::Key { + type_value: PSET_OUT_SCRIPT, + key: vec![], + }, + value: pset::serialize::Serialize::serialize(&self.script_pubkey), }); // Prop Output fields @@ -516,7 +535,6 @@ impl_psetmap_consensus_encoding!(Output); // not optional and cannot by set by insert_pair impl Decodable for Output { fn consensus_decode(mut d: D) -> Result { - // Sets the default to [0;32] and [0;4] let mut rv = Self::default(); // let mut out_value: Option = None; @@ -536,7 +554,10 @@ impl Decodable for Output { out_spk <= | } } - _ => rv.insert_pair(raw::Pair { key: raw_key, value: raw_value })?, + _ => rv.insert_pair(raw::Pair { + key: raw_key, + value: raw_value, + })?, } } Err(crate::encode::Error::PsetError(crate::pset::Error::NoMorePairs)) => break, @@ -549,16 +570,16 @@ impl Decodable for Output { rv.script_pubkey = spk; if let (None, None) = (rv.amount, rv.amount_comm) { - return Err(encode::Error::PsetError(Error::MissingOutputValue)) + return Err(encode::Error::PsetError(Error::MissingOutputValue)); } if let (None, None) = (rv.asset, rv.asset_comm) { - return Err(encode::Error::PsetError(Error::MissingOutputAsset)) + return Err(encode::Error::PsetError(Error::MissingOutputAsset)); } if let (Some(_), None) = (rv.blinding_key, rv.blinder_index) { - return Err(encode::Error::PsetError(Error::MissingBlinderIndex)) + return Err(encode::Error::PsetError(Error::MissingBlinderIndex)); } if rv.is_marked_for_blinding() && rv.is_partially_blinded() && !rv.is_fully_blinded() { - return Err(encode::Error::PsetError(Error::MissingBlindingInfo)) + return Err(encode::Error::PsetError(Error::MissingBlindingInfo)); } Ok(rv) } diff --git a/src/pset/mod.rs b/src/pset/mod.rs index 3598f970..7e7c1d47 100644 --- a/src/pset/mod.rs +++ b/src/pset/mod.rs @@ -30,18 +30,22 @@ mod map; pub mod raw; pub mod serialize; -use crate::{Transaction, Txid, TxIn, OutPoint, TxInWitness, TxOut, TxOutWitness, SurjectionInput}; -use crate::encode::{self, Encodable, Decodable}; +use crate::blind::{BlindAssetProofs, BlindValueProofs}; use crate::confidential; -use secp256k1_zkp::rand::{CryptoRng, RngCore}; -use secp256k1_zkp::{self, RangeProof, SurjectionProof, SecretKey}; -use crate::{TxOutSecrets, blind::RangeProofMessage, confidential::{AssetBlindingFactor, ValueBlindingFactor}}; +use crate::encode::{self, Decodable, Encodable}; +use crate::{ + blind::RangeProofMessage, + confidential::{AssetBlindingFactor, ValueBlindingFactor}, + TxOutSecrets, +}; +use crate::{OutPoint, SurjectionInput, Transaction, TxIn, TxInWitness, TxOut, TxOutWitness, Txid}; use bitcoin; -use crate::blind::{BlindAssetProofs, BlindValueProofs}; +use secp256k1_zkp::rand::{CryptoRng, RngCore}; +use secp256k1_zkp::{self, RangeProof, SecretKey, SurjectionProof}; pub use self::error::{Error, PsetBlindError}; -pub use self::map::{Global, GlobalTxData, Input, Output, TapTree, PsbtSighashType}; use self::map::Map; +pub use self::map::{Global, GlobalTxData, Input, Output, PsbtSighashType, TapTree}; /// A Partially Signed Transaction. #[derive(Debug, Clone, PartialEq)] @@ -64,7 +68,6 @@ impl Default for PartiallySignedTransaction { } impl PartiallySignedTransaction { - /// Create a new PSET from a raw transaction pub fn from_tx(tx: Transaction) -> Self { let mut global = Global::default(); @@ -74,9 +77,11 @@ impl PartiallySignedTransaction { global.tx_data.version = tx.version; let inputs = tx.input.into_iter().map(Input::from_txin).collect(); - let outputs = tx.output.into_iter().map(|o| { - Output::from_txout(o) - }).collect(); + let outputs = tx + .output + .into_iter() + .map(|o| Output::from_txout(o)) + .collect(); Self { global: global, inputs: inputs, @@ -109,10 +114,10 @@ impl PartiallySignedTransaction { self.global.tx_data.input_count += 1; self.inputs.insert(pos, inp); - for out in self.outputs_mut(){ + for out in self.outputs_mut() { match out.blinder_index { Some(i) if i >= pos as u32 => { - out.blinder_index = Some(i+1); + out.blinder_index = Some(i + 1); } _ => {} } @@ -134,7 +139,7 @@ impl PartiallySignedTransaction { pub fn remove_input(&mut self, index: usize) -> Option { if self.inputs.get(index).is_some() { self.global.tx_data.input_count -= 1; - return Some(self.inputs.remove(index)) + return Some(self.inputs.remove(index)); } None } @@ -169,7 +174,7 @@ impl PartiallySignedTransaction { pub fn remove_output(&mut self, index: usize) -> Option { if self.inputs.get(index).is_some() { self.global.tx_data.output_count -= 1; - return Some(self.outputs.remove(index)) + return Some(self.outputs.remove(index)); } None } @@ -187,7 +192,9 @@ impl PartiallySignedTransaction { /// Accessor for the locktime to be used in the final transaction pub fn locktime(&self) -> Result { match self.global.tx_data { - GlobalTxData{ fallback_locktime, .. } => { + GlobalTxData { + fallback_locktime, .. + } => { #[derive(PartialEq, Eq, PartialOrd, Ord)] enum Locktime { /// No inputs have specified this type of locktime @@ -205,28 +212,30 @@ impl PartiallySignedTransaction { (Some(rt), Some(rh)) => { time_locktime = cmp::max(time_locktime, Locktime::Minimum(rt)); height_locktime = cmp::max(height_locktime, Locktime::Minimum(rh)); - }, + } (Some(rt), None) => { time_locktime = cmp::max(time_locktime, Locktime::Minimum(rt)); height_locktime = Locktime::Disallowed; - }, + } (None, Some(rh)) => { time_locktime = Locktime::Disallowed; height_locktime = cmp::max(height_locktime, Locktime::Minimum(rh)); - }, + } (None, None) => {} } } match (time_locktime, height_locktime) { - (Locktime::Unconstrained, Locktime::Unconstrained) => Ok(fallback_locktime.unwrap_or(0)), + (Locktime::Unconstrained, Locktime::Unconstrained) => { + Ok(fallback_locktime.unwrap_or(0)) + } (Locktime::Minimum(x), _) => Ok(x), (_, Locktime::Minimum(x)) => Ok(x), (Locktime::Disallowed, Locktime::Disallowed) => Err(Error::LocktimeConflict), (Locktime::Unconstrained, Locktime::Disallowed) => unreachable!(), (Locktime::Disallowed, Locktime::Unconstrained) => unreachable!(), } - }, + } } } @@ -256,7 +265,6 @@ impl PartiallySignedTransaction { } } - /// Extract the Transaction from a PartiallySignedTransaction by filling in /// the available signature information in place. pub fn extract_tx(&self) -> Result { @@ -276,10 +284,16 @@ impl PartiallySignedTransaction { witness: TxInWitness { amount_rangeproof: psetin.issuance_value_rangeproof.clone(), inflation_keys_rangeproof: psetin.issuance_keys_rangeproof.clone(), - script_witness: psetin.final_script_witness.as_ref() - .map(|x| x.to_owned()).unwrap_or_default(), - pegin_witness: psetin.pegin_witness.as_ref() - .map(|x| x.to_owned()).unwrap_or_default(), + script_witness: psetin + .final_script_witness + .as_ref() + .map(|x| x.to_owned()) + .unwrap_or_default(), + pegin_witness: psetin + .pegin_witness + .as_ref() + .map(|x| x.to_owned()) + .unwrap_or_default(), }, }; inputs.push(txin); @@ -297,7 +311,8 @@ impl PartiallySignedTransaction { (None, Some(x)) => confidential::Value::Explicit(x), (None, None) => return Err(Error::MissingOutputAsset), }, - nonce: out.ecdh_pubkey + nonce: out + .ecdh_pubkey .map(|x| confidential::Nonce::from(x.inner)) .unwrap_or_default(), script_pubkey: out.script_pubkey.clone(), @@ -349,7 +364,6 @@ impl PartiallySignedTransaction { ), PsetBlindError, > { - let mut blind_out_indices = Vec::new(); for (i, out) in self.outputs.iter().enumerate() { if out.blinding_key.is_none() { @@ -390,18 +404,21 @@ impl PartiallySignedTransaction { inp_txout_sec: &HashMap, ) -> Result, PsetBlindError> { let mut ret = vec![]; - for (i ,inp) in self.inputs().iter().enumerate() { - let utxo = inp.witness_utxo.as_ref().ok_or(PsetBlindError::MissingWitnessUtxo(i))?; + for (i, inp) in self.inputs().iter().enumerate() { + let utxo = inp + .witness_utxo + .as_ref() + .ok_or(PsetBlindError::MissingWitnessUtxo(i))?; let surject_target = match inp_txout_sec.get(&i) { Some(sec) => SurjectionInput::from_txout_secrets(*sec), None => SurjectionInput::Unknown(utxo.asset), }; ret.push(surject_target); - if inp.has_issuance(){ + if inp.has_issuance() { let (asset_id, token_id) = inp.issuance_ids(); if inp.issuance_value_amount.is_some() || inp.issuance_value_comm.is_some() { - let secrets = TxOutSecrets{ + let secrets = TxOutSecrets { asset: asset_id, asset_bf: AssetBlindingFactor::zero(), value: 0, // This value really does not matter in surjection proofs @@ -409,8 +426,10 @@ impl PartiallySignedTransaction { }; ret.push(SurjectionInput::from_txout_secrets(secrets)) } - if inp.issuance_inflation_keys.is_some() || inp.issuance_inflation_keys_comm.is_some() { - let secrets = TxOutSecrets{ + if inp.issuance_inflation_keys.is_some() + || inp.issuance_inflation_keys_comm.is_some() + { + let secrets = TxOutSecrets { asset: token_id, asset_bf: AssetBlindingFactor::zero(), value: 0, // This value really does not matter in surjection proofs @@ -466,7 +485,9 @@ impl PartiallySignedTransaction { &surject_inputs, ) .map_err(|e| PsetBlindError::ConfidentialTxOutError(i, e))?; - let value = self.outputs[i].amount.ok_or(PsetBlindError::MustHaveExplicitTxOut(i))?; + let value = self.outputs[i] + .amount + .ok_or(PsetBlindError::MustHaveExplicitTxOut(i))?; out_secrets.push((value, abf, vbf)); // mutate the pset @@ -475,18 +496,29 @@ impl PartiallySignedTransaction { self.outputs[i].asset_surjection_proof = txout.witness.surjection_proof; self.outputs[i].amount_comm = txout.value.commitment(); self.outputs[i].asset_comm = txout.asset.commitment(); - self.outputs[i].ecdh_pubkey = txout.nonce.commitment().map(|pk| bitcoin::PublicKey{ - inner: pk, - compressed: true - }); - let asset_id = self.outputs[i].asset.ok_or(PsetBlindError::MustHaveExplicitTxOut(i))?; - self.outputs[i].blind_asset_proof = Some(Box::new(SurjectionProof::blind_asset_proof(rng, secp, asset_id, abf) - .map_err(|e| PsetBlindError::BlindingProofsCreationError(i, e))?)); - - let asset_gen = self.outputs[i].asset_comm.expect("Blinding proof creation error"); - let value_comm = self.outputs[i].amount_comm.expect("Blinding proof successful"); - self.outputs[i].blind_value_proof = Some(Box::new(RangeProof::blind_value_proof(rng, secp, value, value_comm, asset_gen, vbf) - .map_err(|e| PsetBlindError::BlindingProofsCreationError(i, e))?)); + self.outputs[i].ecdh_pubkey = + txout.nonce.commitment().map(|pk| bitcoin::PublicKey { + inner: pk, + compressed: true, + }); + let asset_id = self.outputs[i] + .asset + .ok_or(PsetBlindError::MustHaveExplicitTxOut(i))?; + self.outputs[i].blind_asset_proof = Some(Box::new( + SurjectionProof::blind_asset_proof(rng, secp, asset_id, abf) + .map_err(|e| PsetBlindError::BlindingProofsCreationError(i, e))?, + )); + + let asset_gen = self.outputs[i] + .asset_comm + .expect("Blinding proof creation error"); + let value_comm = self.outputs[i] + .amount_comm + .expect("Blinding proof successful"); + self.outputs[i].blind_value_proof = Some(Box::new( + RangeProof::blind_value_proof(rng, secp, value, value_comm, asset_gen, vbf) + .map_err(|e| PsetBlindError::BlindingProofsCreationError(i, e))?, + )); } // return blinding factors used ret.push((abf, vbf)); @@ -555,31 +587,34 @@ impl PartiallySignedTransaction { // blind the last txout let surject_inputs = self.surjection_inputs(inp_txout_sec)?; - let asset_id = self.outputs[last_out_index].asset.ok_or(PsetBlindError::MustHaveExplicitTxOut(last_out_index))?; + let asset_id = self.outputs[last_out_index] + .asset + .ok_or(PsetBlindError::MustHaveExplicitTxOut(last_out_index))?; let out_abf = AssetBlindingFactor::new(rng); let exp_asset = confidential::Asset::Explicit(asset_id); let blind_res = exp_asset.blind(rng, secp, out_abf, &surject_inputs); - let (out_asset_commitment, surjection_proof) = blind_res - .map_err(|e| PsetBlindError::ConfidentialTxOutError(last_out_index, e))?; + let (out_asset_commitment, surjection_proof) = + blind_res.map_err(|e| PsetBlindError::ConfidentialTxOutError(last_out_index, e))?; - let value = self.outputs[last_out_index].amount.ok_or(PsetBlindError::MustHaveExplicitTxOut(last_out_index))?; + let value = self.outputs[last_out_index] + .amount + .ok_or(PsetBlindError::MustHaveExplicitTxOut(last_out_index))?; let exp_value = confidential::Value::Explicit(value); // Get all the explicit outputs let mut exp_out_secrets = vec![]; for (i, out) in self.outputs.iter().enumerate() { if out.blinding_key.is_none() { let amt = out.amount.ok_or(PsetBlindError::MustHaveExplicitTxOut(i))?; - exp_out_secrets.push((amt, AssetBlindingFactor::zero(), ValueBlindingFactor::zero())); + exp_out_secrets.push(( + amt, + AssetBlindingFactor::zero(), + ValueBlindingFactor::zero(), + )); } } - let mut final_vbf = ValueBlindingFactor::last( - secp, - value, - out_abf, - &inp_secrets, - &exp_out_secrets, - ); + let mut final_vbf = + ValueBlindingFactor::last(secp, value, out_abf, &inp_secrets, &exp_out_secrets); // Add all the scalars for value_diff in self.global.scalars.iter() { @@ -591,11 +626,20 @@ impl PartiallySignedTransaction { .ok_or(PsetBlindError::MustHaveExplicitTxOut(last_out_index))?; let ephemeral_sk = SecretKey::new(rng); let spk = &self.outputs[last_out_index].script_pubkey; - let msg = RangeProofMessage { asset: asset_id, bf: out_abf }; - let blind_res = - exp_value.blind(secp, final_vbf, receiver_blinding_pk.inner, ephemeral_sk, spk, &msg); - let (value_commitment, nonce, rangeproof) = blind_res - .map_err(|e| PsetBlindError::ConfidentialTxOutError(last_out_index, e))?; + let msg = RangeProofMessage { + asset: asset_id, + bf: out_abf, + }; + let blind_res = exp_value.blind( + secp, + final_vbf, + receiver_blinding_pk.inner, + ephemeral_sk, + spk, + &msg, + ); + let (value_commitment, nonce, rangeproof) = + blind_res.map_err(|e| PsetBlindError::ConfidentialTxOutError(last_out_index, e))?; // mutate the pset { @@ -603,18 +647,29 @@ impl PartiallySignedTransaction { self.outputs[last_out_index].asset_surjection_proof = Some(Box::new(surjection_proof)); self.outputs[last_out_index].amount_comm = value_commitment.commitment(); self.outputs[last_out_index].asset_comm = out_asset_commitment.commitment(); - self.outputs[last_out_index].ecdh_pubkey = nonce.commitment().map(|pk| bitcoin::PublicKey{ - inner: pk, - compressed: true - }); - let asset_id = self.outputs[last_out_index].asset.ok_or(PsetBlindError::MustHaveExplicitTxOut(last_out_index))?; - self.outputs[last_out_index].blind_asset_proof = Some(Box::new(SurjectionProof::blind_asset_proof(rng, secp, asset_id, out_abf) - .map_err(|e| PsetBlindError::BlindingProofsCreationError(last_out_index, e))?)); - - let asset_gen = self.outputs[last_out_index].asset_comm.expect("Blinding proof creation error"); - let value_comm = self.outputs[last_out_index].amount_comm.expect("Blinding proof successful"); - self.outputs[last_out_index].blind_value_proof = Some(Box::new(RangeProof::blind_value_proof(rng, secp, value, value_comm, asset_gen, final_vbf) - .map_err(|e| PsetBlindError::BlindingProofsCreationError(last_out_index, e))?)); + self.outputs[last_out_index].ecdh_pubkey = + nonce.commitment().map(|pk| bitcoin::PublicKey { + inner: pk, + compressed: true, + }); + let asset_id = self.outputs[last_out_index] + .asset + .ok_or(PsetBlindError::MustHaveExplicitTxOut(last_out_index))?; + self.outputs[last_out_index].blind_asset_proof = Some(Box::new( + SurjectionProof::blind_asset_proof(rng, secp, asset_id, out_abf) + .map_err(|e| PsetBlindError::BlindingProofsCreationError(last_out_index, e))?, + )); + + let asset_gen = self.outputs[last_out_index] + .asset_comm + .expect("Blinding proof creation error"); + let value_comm = self.outputs[last_out_index] + .amount_comm + .expect("Blinding proof successful"); + self.outputs[last_out_index].blind_value_proof = Some(Box::new( + RangeProof::blind_value_proof(rng, secp, value, value_comm, asset_gen, final_vbf) + .map_err(|e| PsetBlindError::BlindingProofsCreationError(last_out_index, e))?, + )); self.global.scalars.clear() } @@ -707,24 +762,26 @@ mod tests { use bitcoin::hashes::hex::{FromHex, ToHex}; fn tx_pset_rtt(tx_hex: &str) { - let tx: Transaction = encode::deserialize(&Vec::::from_hex(tx_hex).unwrap()[..]).unwrap(); + let tx: Transaction = + encode::deserialize(&Vec::::from_hex(tx_hex).unwrap()[..]).unwrap(); let pset = PartiallySignedTransaction::from_tx(tx); let rtt_tx_hex = encode::serialize_hex(&pset.extract_tx().unwrap()); assert_eq!(tx_hex, rtt_tx_hex); let pset_rtt_hex = encode::serialize_hex(&pset); - let pset2 : PartiallySignedTransaction = encode::deserialize(&Vec::::from_hex(&pset_rtt_hex).unwrap()[..]).unwrap(); + let pset2: PartiallySignedTransaction = + encode::deserialize(&Vec::::from_hex(&pset_rtt_hex).unwrap()[..]).unwrap(); assert_eq!(pset, pset2); } fn pset_rtt(pset_hex: &str) { - let pset: PartiallySignedTransaction = encode::deserialize(&Vec::::from_hex(pset_hex).unwrap()[..]).unwrap(); + let pset: PartiallySignedTransaction = + encode::deserialize(&Vec::::from_hex(pset_hex).unwrap()[..]).unwrap(); assert_eq!(encode::serialize_hex(&pset), pset_hex); } #[test] - fn test_pset(){ - + fn test_pset() { tx_pset_rtt("010000000001715df5ccebaf02ff18d6fae7263fa69fed5de59c900f4749556eba41bc7bf2af0000000000000000000201230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b2010000000124101100001f5175517551755175517551755175517551755175517551755175517551755101230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b2010000000005f5e100000000000000"); // Test a issuance test with only sighash all @@ -743,10 +800,10 @@ mod tests { #[test] fn single_blinded_output_pset() { - use std::str::FromStr; + use crate::AssetId; use rand::{self, SeedableRng}; use serde_json; - use crate::AssetId; + use std::str::FromStr; // Initially secp context and rng global state let secp = secp256k1_zkp::Secp256k1::new(); @@ -754,7 +811,8 @@ mod tests { let mut rng = rand::ChaChaRng::seed_from_u64(0); let pset_hex = "70736574ff01020402000000010401010105010201fb04020000000001017a0bb9325c276764451bbc2eb82a4c8c4bb6f4007ba803e5a5ba72d0cd7c09848e1a091622d935953bf06e0b7393239c68c6f810a00fe19d11c6ae343cffd3037077da02535fe4ad0fcd675cd0f62bf73b60a554dc1569b80f1f76a2bbfc9f00d439bf4b160014d2cbec8783bd01c9f178348b08500a830a89a7f9010e20805131ba6b37165c026eed9325ac56059ba872fd569e3ed462734098688b4770010f0400000000000103088c83b50d0000000007fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20104220020e5793ad956ee91ebf3543b37d110701118ed4078ffa0d477eacb8885e486ad8507fc047073657406210212bf0ea45b733dfde8ecb5e896306c4165c666c99fc5d1ab887f71393a975cea07fc047073657408040000000000010308f40100000000000007fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b201040000"; - let mut pset : PartiallySignedTransaction = encode::deserialize(&Vec::::from_hex(&pset_hex).unwrap()[..]).unwrap(); + let mut pset: PartiallySignedTransaction = + encode::deserialize(&Vec::::from_hex(&pset_hex).unwrap()[..]).unwrap(); let btc_txout_secrets_str = r#" { @@ -782,8 +840,7 @@ mod tests { let tx = pset.extract_tx().unwrap(); let btc_txout = pset.inputs[0].witness_utxo.clone().unwrap(); - tx.verify_tx_amt_proofs(&secp, &[btc_txout]) - .unwrap(); + tx.verify_tx_amt_proofs(&secp, &[btc_txout]).unwrap(); } #[test] @@ -791,46 +848,63 @@ mod tests { // Invalid psets // Check Global mandatory field let pset_str = "70736574ff010401000105010001fb040200000000"; - let pset = encode::deserialize::(&Vec::::from_hex(pset_str).unwrap()[..]); + let pset = encode::deserialize::( + &Vec::::from_hex(pset_str).unwrap()[..], + ); pset.expect_err("Missing tx version"); // Check input mandatory field let pset_str = "70736574ff010204020000000104010001fb040200000000"; - let pset = encode::deserialize::(&Vec::::from_hex(pset_str).unwrap()[..]); + let pset = encode::deserialize::( + &Vec::::from_hex(pset_str).unwrap()[..], + ); pset.expect_err("Missing inp count"); let pset_str = "70736574ff010204020000000105010001fb040200000000"; - let pset = encode::deserialize::(&Vec::::from_hex(pset_str).unwrap()[..]); + let pset = encode::deserialize::( + &Vec::::from_hex(pset_str).unwrap()[..], + ); pset.expect_err("Missing out count"); let pset_str = "70736574ff01020402000000010401000105010000"; - let pset = encode::deserialize::(&Vec::::from_hex(pset_str).unwrap()[..]); + let pset = encode::deserialize::( + &Vec::::from_hex(pset_str).unwrap()[..], + ); pset.expect_err("Missing pset version"); // Check inp/out count mismatch let pset_str = "70736574ff01020402000000010401000105010001fb04020000000001017a0ad92644e9bf6cb8d0856a8ca713c8a212d3a62142e85454b7865217890e52ec3108a469a9811ec1c1df7a98dbc3a7f71860293e98c6fad8a7ef6828344e9172547302217d344513f0a5ed1a60ebeba01460c505ad63d95b3542fb303aca8f9382777d160014bd5c31aaea2ddc585f317ee589bc6800bc95e7e6010e208965573f41392a88d8bb106cf13a7bdc69f1ab914cd5e8de11235467b514e5a9010f040100000000"; - let pset = encode::deserialize::(&Vec::::from_hex(pset_str).unwrap()[..]); + let pset = encode::deserialize::( + &Vec::::from_hex(pset_str).unwrap()[..], + ); pset.expect_err("Input count mismatch"); // input mandatory field let pset_str = "70736574ff01020402000000010401010105010001fb04020000000001017a0ad92644e9bf6cb8d0856a8ca713c8a212d3a62142e85454b7865217890e52ec3108a469a9811ec1c1df7a98dbc3a7f71860293e98c6fad8a7ef6828344e9172547302217d344513f0a5ed1a60ebeba01460c505ad63d95b3542fb303aca8f9382777d160014bd5c31aaea2ddc585f317ee589bc6800bc95e7e601010f040100000000"; - let pset = encode::deserialize::(&Vec::::from_hex(pset_str).unwrap()[..]); + let pset = encode::deserialize::( + &Vec::::from_hex(pset_str).unwrap()[..], + ); pset.expect_err("Input mandatory field prevtxid"); // output mandatory amount field let pset_str = "70736574ff01020402000000010401000105010101fb04020000000007fc04707365740220010101010101010101010101010101010101010101010101010101010101010101040000"; - let pset = encode::deserialize::(&Vec::::from_hex(pset_str).unwrap()[..]); + let pset = encode::deserialize::( + &Vec::::from_hex(pset_str).unwrap()[..], + ); pset.expect_err("Output non-mandatory field"); let pset_str = "70736574ff01020402000000010401000105010101fb040200000000010308170000000000000007fc0470736574022009090909090909090909090909090909090909090909090909090909090909090100"; - let pset = encode::deserialize::(&Vec::::from_hex(pset_str).unwrap()[..]); + let pset = encode::deserialize::( + &Vec::::from_hex(pset_str).unwrap()[..], + ); pset.expect_err("Output mandatory field script pubkey"); - // Valid Psets // Check both possible conf/explicit values are allowed for pset let pset_str = "70736574ff01020402000000010401000105010101fb040200000000010308170000000000000007fc0470736574012109090909090909090909090909090909090909090909090909090909090909090907fc04707365740220090909090909090909090909090909090909090909090909090909090909090901040000"; - let pset = encode::deserialize::(&Vec::::from_hex(pset_str).unwrap()[..]); + let pset = encode::deserialize::( + &Vec::::from_hex(pset_str).unwrap()[..], + ); pset.expect("Both conf/explicit value are allowed be present in map"); // Commented code for quick test vector generation @@ -846,7 +920,6 @@ mod tests { // pset.add_output(Output::from_txout(txout)); // println!("{}", encode::serialize_hex(&pset)); - // // Commit an asset // let mut pset = PartiallySignedTransaction::new_v2(); // // use AssetId; diff --git a/src/pset/raw.rs b/src/pset/raw.rs index e85c8010..55f351dc 100644 --- a/src/pset/raw.rs +++ b/src/pset/raw.rs @@ -19,9 +19,11 @@ use std::{fmt, io}; -use crate::encode::{self, Decodable, Encodable, ReadExt, WriteExt, serialize, deserialize, MAX_VEC_SIZE}; -use crate::hashes::hex; use super::Error; +use crate::encode::{ + self, deserialize, serialize, Decodable, Encodable, ReadExt, WriteExt, MAX_VEC_SIZE, +}; +use crate::hashes::hex; use crate::VarInt; /// A PSET key in its raw byte form. #[derive(Debug, PartialEq, Hash, Eq, Clone, Ord, PartialOrd)] @@ -34,7 +36,7 @@ pub struct Key { pub key: Vec, } -impl Key{ +impl Key { /// Helper to create a raw key from pset proprietary key components pub fn from_pset_key(subtype: ProprietaryType, key: Vec) -> Self { let pset_prop_key = ProprietaryKey { @@ -64,7 +66,10 @@ pub type ProprietaryType = u8; /// structure according to BIP 174. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct ProprietaryKey where Subtype: Copy + From + Into { +pub struct ProprietaryKey +where + Subtype: Copy + From + Into, +{ /// Proprietary type prefix used for grouping together keys under some /// application and avoid namespace collision #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::hex_bytes"))] @@ -116,7 +121,7 @@ impl Decodable for Key { return Err(encode::Error::OversizedVectorAllocation { requested: key_byte_size as usize, max: MAX_VEC_SIZE, - }) + }); } let type_value: u8 = Decodable::consensus_decode(&mut d)?; @@ -134,10 +139,7 @@ impl Decodable for Key { } impl Encodable for Key { - fn consensus_encode( - &self, - mut s: S, - ) -> Result { + fn consensus_encode(&self, mut s: S) -> Result { let mut len = 0; len += VarInt((self.key.len() + 1) as u64).consensus_encode(&mut s)?; @@ -152,10 +154,7 @@ impl Encodable for Key { } impl Encodable for Pair { - fn consensus_encode( - &self, - mut s: S, - ) -> Result { + fn consensus_encode(&self, mut s: S) -> Result { let len = self.key.consensus_encode(&mut s)?; Ok(len + self.value.consensus_encode(s)?) } @@ -170,7 +169,10 @@ impl Decodable for Pair { } } -impl Encodable for ProprietaryKey where Subtype: Copy + From + Into { +impl Encodable for ProprietaryKey +where + Subtype: Copy + From + Into, +{ fn consensus_encode(&self, mut e: W) -> Result { let mut len = self.prefix.consensus_encode(&mut e)? + 1; e.emit_u8(self.subtype.into())?; @@ -179,7 +181,10 @@ impl Encodable for ProprietaryKey where Subtype: Copy + From Decodable for ProprietaryKey where Subtype: Copy + From + Into { +impl Decodable for ProprietaryKey +where + Subtype: Copy + From + Into, +{ fn consensus_decode(mut d: D) -> Result { let prefix = Vec::::consensus_decode(&mut d)?; let mut key = vec![]; @@ -190,17 +195,20 @@ impl Decodable for ProprietaryKey where Subtype: Copy + From ProprietaryKey where Subtype: Copy + From + Into { +impl ProprietaryKey +where + Subtype: Copy + From + Into, +{ /// Constructs [ProprietaryKey] from [Key]; returns /// [Error::InvalidProprietaryKey] if `key` do not starts with 0xFC byte pub fn from_key(key: Key) -> Result { if key.type_value != 0xFC { - return Err(Error::InvalidProprietaryKey) + return Err(Error::InvalidProprietaryKey); } Ok(deserialize(&key.key)?) @@ -210,7 +218,7 @@ impl ProprietaryKey where Subtype: Copy + From + Into pub fn to_key(&self) -> Key { Key { type_value: 0xFC, - key: serialize(self) + key: serialize(self), } } } diff --git a/src/pset/serialize.rs b/src/pset/serialize.rs index 92ac7922..75536075 100644 --- a/src/pset/serialize.rs +++ b/src/pset/serialize.rs @@ -19,21 +19,21 @@ use std::io; -use bitcoin::{self, PublicKey, VarInt}; -use crate::{Script, Transaction, TxOut, Txid, BlockHash, AssetId}; -use crate::encode::{self, serialize, deserialize, Decodable, Encodable, deserialize_partial}; -use bitcoin::util::bip32::{ChildNumber, Fingerprint, KeySource}; +use crate::confidential; +use crate::encode::{self, deserialize, deserialize_partial, serialize, Decodable, Encodable}; use crate::hashes::{hash160, ripemd160, sha256, sha256d, Hash}; +use crate::{AssetId, BlockHash, Script, Transaction, TxOut, Txid}; use bitcoin::hashes::hex::ToHex; -use crate::confidential; +use bitcoin::util::bip32::{ChildNumber, Fingerprint, KeySource}; +use bitcoin::{self, PublicKey, VarInt}; use secp256k1_zkp::{self, RangeProof, SurjectionProof, Tweak}; -use crate::taproot::{TapBranchHash, TapLeafHash, ControlBlock, LeafVersion}; +use super::map::{PsbtSighashType, TapTree}; use crate::schnorr; -use super::map::{TapTree, PsbtSighashType}; +use crate::taproot::{ControlBlock, LeafVersion, TapBranchHash, TapLeafHash}; -use crate::taproot::TaprootBuilder; use crate::sighash::SchnorrSigHashType; +use crate::taproot::TaprootBuilder; /// A trait for serializing a value as raw data for insertion into PSET /// key-value pairs. @@ -86,8 +86,7 @@ impl Serialize for Tweak { impl Deserialize for Tweak { fn deserialize(bytes: &[u8]) -> Result { let x = deserialize::<[u8; 32]>(&bytes)?; - Tweak::from_slice(&x) - .map_err(|_| encode::Error::ParseFailed("invalid Tweak")) + Tweak::from_slice(&x).map_err(|_| encode::Error::ParseFailed("invalid Tweak")) } } @@ -113,8 +112,7 @@ impl Serialize for PublicKey { impl Deserialize for PublicKey { fn deserialize(bytes: &[u8]) -> Result { - PublicKey::from_slice(bytes) - .map_err(|_| encode::Error::ParseFailed("invalid public key")) + PublicKey::from_slice(bytes).map_err(|_| encode::Error::ParseFailed("invalid public key")) } } @@ -135,7 +133,7 @@ impl Serialize for KeySource { impl Deserialize for KeySource { fn deserialize(bytes: &[u8]) -> Result { if bytes.len() < 4 { - return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into()) + return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into()); } let fprint: Fingerprint = Fingerprint::from(&bytes[0..4]); @@ -181,10 +179,10 @@ impl Deserialize for PsbtSighashType { impl Serialize for confidential::Value { fn serialize(&self) -> Vec { - match self{ + match self { confidential::Value::Null => vec![], // should never be invoked confidential::Value::Explicit(x) => Serialize::serialize(x), - y => encode::serialize(y) // confidential can serialized as is + y => encode::serialize(y), // confidential can serialized as is } } } @@ -226,10 +224,10 @@ impl Deserialize for secp256k1_zkp::Generator { impl Serialize for confidential::Asset { fn serialize(&self) -> Vec { - match self{ + match self { confidential::Asset::Null => vec![], // should never be invoked confidential::Asset::Explicit(x) => Serialize::serialize(x), - y => encode::serialize(y) // confidential can serialized as is + y => encode::serialize(y), // confidential can serialized as is } } } @@ -285,7 +283,7 @@ impl Deserialize for bitcoin::XOnlyPublicKey { } } -impl Serialize for schnorr::SchnorrSig { +impl Serialize for schnorr::SchnorrSig { fn serialize(&self) -> Vec { self.to_vec() } @@ -299,14 +297,17 @@ impl Deserialize for schnorr::SchnorrSig { .ok_or(encode::Error::ParseFailed("Invalid Sighash type"))?; let sig = secp256k1_zkp::schnorr::Signature::from_slice(&bytes[..64]) .map_err(|_| encode::Error::ParseFailed("Invalid Schnorr signature"))?; - Ok(schnorr::SchnorrSig{ sig, hash_ty }) + Ok(schnorr::SchnorrSig { sig, hash_ty }) } 64 => { let sig = secp256k1_zkp::schnorr::Signature::from_slice(&bytes[..64]) .map_err(|_| encode::Error::ParseFailed("Invalid Schnorr signature"))?; - Ok(schnorr::SchnorrSig{ sig, hash_ty: SchnorrSigHashType::Default }) + Ok(schnorr::SchnorrSig { + sig, + hash_ty: SchnorrSigHashType::Default, + }) } - _ => Err(encode::Error::ParseFailed("Invalid Schnorr signature len")) + _ => Err(encode::Error::ParseFailed("Invalid Schnorr signature len")), } } } @@ -324,7 +325,7 @@ impl Serialize for (bitcoin::XOnlyPublicKey, TapLeafHash) { impl Deserialize for (bitcoin::XOnlyPublicKey, TapLeafHash) { fn deserialize(bytes: &[u8]) -> Result { if bytes.len() < 32 { - return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into()) + return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into()); } let a: bitcoin::XOnlyPublicKey = Deserialize::deserialize(&bytes[..32])?; let b: TapLeafHash = Deserialize::deserialize(&bytes[32..])?; @@ -340,8 +341,7 @@ impl Serialize for ControlBlock { impl Deserialize for ControlBlock { fn deserialize(bytes: &[u8]) -> Result { - Self::from_slice(bytes) - .map_err(|_| encode::Error::ParseFailed("Invalid control block")) + Self::from_slice(bytes).map_err(|_| encode::Error::ParseFailed("Invalid control block")) } } @@ -358,7 +358,7 @@ impl Serialize for (Script, LeafVersion) { impl Deserialize for (Script, LeafVersion) { fn deserialize(bytes: &[u8]) -> Result { if bytes.is_empty() { - return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into()) + return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into()); } // The last byte is LeafVersion. let script = Script::deserialize(&bytes[..bytes.len() - 1])?; @@ -368,11 +368,12 @@ impl Deserialize for (Script, LeafVersion) { } } - impl Serialize for (Vec, KeySource) { fn serialize(&self) -> Vec { - let mut buf = Vec::with_capacity( 32 * self.0.len() + key_source_len(&self.1)); - self.0.consensus_encode(&mut buf).expect("Vecs don't error allocation"); + let mut buf = Vec::with_capacity(32 * self.0.len() + key_source_len(&self.1)); + self.0 + .consensus_encode(&mut buf) + .expect("Vecs don't error allocation"); // TODO: Add support for writing into a writer for key-source buf.extend(self.1.serialize()); buf @@ -381,7 +382,7 @@ impl Serialize for (Vec, KeySource) { impl Deserialize for (Vec, KeySource) { fn deserialize(bytes: &[u8]) -> Result { - let (leafhash_vec, consumed) = deserialize_partial::>(&bytes)?; + let (leafhash_vec, consumed) = deserialize_partial::>(&bytes)?; let key_source = KeySource::deserialize(&bytes[consumed..])?; Ok((leafhash_vec, key_source)) } @@ -399,11 +400,14 @@ impl Serialize for TapTree { // safe to cast from usize to u8 buf.push(leaf_info.merkle_branch.as_inner().len() as u8); buf.push(leaf_info.ver.as_u8()); - leaf_info.script.consensus_encode(&mut buf).expect("Vecs dont err"); + leaf_info + .script + .consensus_encode(&mut buf) + .expect("Vecs dont err"); } buf } - // This should be unreachable as we Taptree is already finalized + // This should be unreachable as we Taptree is already finalized _ => unreachable!(), } } @@ -414,7 +418,9 @@ impl Deserialize for TapTree { let mut builder = TaprootBuilder::new(); let mut bytes_iter = bytes.iter(); while let Some(depth) = bytes_iter.next() { - let version = bytes_iter.next().ok_or(encode::Error::ParseFailed("Invalid Taproot Builder"))?; + let version = bytes_iter + .next() + .ok_or(encode::Error::ParseFailed("Invalid Taproot Builder"))?; let (script, consumed) = deserialize_partial::