From 2ca6c7b37cdf265eb587938b83e379a757a8be0a Mon Sep 17 00:00:00 2001 From: Leonardo Comandini Date: Fri, 26 Jul 2024 17:43:56 +0200 Subject: [PATCH 1/2] Revert "pset: input/output: add abf" This reverts commits: * 17d354eaf537d5ee79f27790568ce5ba037e6012 * db805b3b3a9ca4c3f77ee918549001f9556d6451 * d1dfed49aad7dd4c339bfddaf3d1b4d2f06cc50d --- src/pset/map/input.rs | 16 ++------------ src/pset/map/output.rs | 14 +----------- src/pset/mod.rs | 49 ------------------------------------------ 3 files changed, 3 insertions(+), 76 deletions(-) diff --git a/src/pset/map/input.rs b/src/pset/map/input.rs index 098a2469..618f2eef 100644 --- a/src/pset/map/input.rs +++ b/src/pset/map/input.rs @@ -23,7 +23,7 @@ use std::{ use crate::taproot::{ControlBlock, LeafVersion, TapNodeHash, TapLeafHash}; use crate::{schnorr, AssetId, ContractHash}; -use crate::{confidential::{self, AssetBlindingFactor}, locktime}; +use crate::{confidential, locktime}; use crate::encode::{self, Decodable}; use crate::hashes::{self, hash160, ripemd160, sha256, sha256d, Hash}; use crate::pset::map::Map; @@ -168,8 +168,6 @@ const PSBT_ELEMENTS_IN_ASSET_PROOF: u8 = 0x14; /// Note that this does not indicate actual blinding status, /// but rather the expected blinding status prior to signing. const PSBT_ELEMENTS_IN_BLINDED_ISSUANCE: u8 = 0x15; -/// The 32 byte asset blinding factor for the input being spent. -const PSBT_ELEMENTS_IN_ASSET_BLINDING_FACTOR: u8 = 0x16; /// A key-value map for an input of the corresponding index in the unsigned /// transaction. #[derive(Clone, Debug, PartialEq)] @@ -303,8 +301,6 @@ pub struct Input { pub blind_asset_proof: Option>, /// Whether the issuance is blinded pub blinded_issuance: Option, - /// The input asset blinding factor - pub asset_blinding_factor: Option, /// Other fields #[cfg_attr( feature = "serde", @@ -321,7 +317,7 @@ pub struct Input { impl Default for Input { fn default() -> Self { - Self { non_witness_utxo: Default::default(), witness_utxo: Default::default(), partial_sigs: Default::default(), sighash_type: Default::default(), redeem_script: Default::default(), witness_script: Default::default(), bip32_derivation: Default::default(), final_script_sig: Default::default(), final_script_witness: Default::default(), ripemd160_preimages: Default::default(), sha256_preimages: Default::default(), hash160_preimages: Default::default(), hash256_preimages: Default::default(), previous_txid: Txid::all_zeros(), previous_output_index: Default::default(), sequence: Default::default(), required_time_locktime: Default::default(), required_height_locktime: Default::default(), tap_key_sig: Default::default(), tap_script_sigs: Default::default(), tap_scripts: Default::default(), tap_key_origins: Default::default(), tap_internal_key: Default::default(), tap_merkle_root: Default::default(), issuance_value_amount: Default::default(), issuance_value_comm: Default::default(), issuance_value_rangeproof: Default::default(), issuance_keys_rangeproof: Default::default(), pegin_tx: Default::default(), pegin_txout_proof: Default::default(), pegin_genesis_hash: Default::default(), pegin_claim_script: Default::default(), pegin_value: Default::default(), pegin_witness: Default::default(), issuance_inflation_keys: Default::default(), issuance_inflation_keys_comm: Default::default(), issuance_blinding_nonce: Default::default(), issuance_asset_entropy: Default::default(), in_utxo_rangeproof: Default::default(), in_issuance_blind_value_proof: Default::default(), in_issuance_blind_inflation_keys_proof: Default::default(), amount: Default::default(), blind_value_proof: Default::default(), asset: Default::default(), blind_asset_proof: Default::default(), blinded_issuance: Default::default(), asset_blinding_factor: Default::default(), proprietary: Default::default(), unknown: Default::default() } + Self { non_witness_utxo: Default::default(), witness_utxo: Default::default(), partial_sigs: Default::default(), sighash_type: Default::default(), redeem_script: Default::default(), witness_script: Default::default(), bip32_derivation: Default::default(), final_script_sig: Default::default(), final_script_witness: Default::default(), ripemd160_preimages: Default::default(), sha256_preimages: Default::default(), hash160_preimages: Default::default(), hash256_preimages: Default::default(), previous_txid: Txid::all_zeros(), previous_output_index: Default::default(), sequence: Default::default(), required_time_locktime: Default::default(), required_height_locktime: Default::default(), tap_key_sig: Default::default(), tap_script_sigs: Default::default(), tap_scripts: Default::default(), tap_key_origins: Default::default(), tap_internal_key: Default::default(), tap_merkle_root: Default::default(), issuance_value_amount: Default::default(), issuance_value_comm: Default::default(), issuance_value_rangeproof: Default::default(), issuance_keys_rangeproof: Default::default(), pegin_tx: Default::default(), pegin_txout_proof: Default::default(), pegin_genesis_hash: Default::default(), pegin_claim_script: Default::default(), pegin_value: Default::default(), pegin_witness: Default::default(), issuance_inflation_keys: Default::default(), issuance_inflation_keys_comm: Default::default(), issuance_blinding_nonce: Default::default(), issuance_asset_entropy: Default::default(), in_utxo_rangeproof: Default::default(), in_issuance_blind_value_proof: Default::default(), in_issuance_blind_inflation_keys_proof: Default::default(), amount: Default::default(), blind_value_proof: Default::default(), asset: Default::default(), blind_asset_proof: Default::default(), blinded_issuance: Default::default(), proprietary: Default::default(), unknown: Default::default() } } } @@ -754,9 +750,6 @@ impl Map for Input { PSBT_ELEMENTS_IN_BLINDED_ISSUANCE => { impl_pset_prop_insert_pair!(self.blinded_issuance <= | ) } - PSBT_ELEMENTS_IN_ASSET_BLINDING_FACTOR => { - impl_pset_prop_insert_pair!(self.asset_blinding_factor <= | ) - } _ => match self.proprietary.entry(prop_key) { Entry::Vacant(empty_key) => { empty_key.insert(raw_value); @@ -975,10 +968,6 @@ impl Map for Input { rv.push_prop(self.blinded_issuance as ) } - impl_pset_get_pair! { - rv.push_prop(self.asset_blinding_factor as ) - } - for (key, value) in self.proprietary.iter() { rv.push(raw::Pair { key: key.to_key(), @@ -1058,7 +1047,6 @@ impl Map for Input { merge!(asset, self, other); merge!(blind_asset_proof, self, other); merge!(blinded_issuance, self, other); - merge!(asset_blinding_factor, self, other); Ok(()) } } diff --git a/src/pset/map/output.rs b/src/pset/map/output.rs index bba375b7..ad8df6ff 100644 --- a/src/pset/map/output.rs +++ b/src/pset/map/output.rs @@ -22,7 +22,7 @@ use crate::encode::Decodable; use crate::pset::map::Map; use crate::pset::raw; use crate::pset::Error; -use crate::{confidential::{self, AssetBlindingFactor}, pset}; +use crate::{confidential, pset}; use crate::{encode, Script, TxOutWitness}; use bitcoin::bip32::KeySource; use bitcoin::{PublicKey, key::XOnlyPublicKey}; @@ -83,8 +83,6 @@ const PSBT_ELEMENTS_OUT_BLIND_VALUE_PROOF: u8 = 0x09; /// PSBT_ELEMENTS_OUT_ASSET. If provided, PSBT_ELEMENTS_OUT_ASSET_COMMITMENT must /// be provided too. const PSBT_ELEMENTS_OUT_BLIND_ASSET_PROOF: u8 = 0x0a; -/// The 32 byte asset blinding factor for this output. -const PSBT_ELEMENTS_OUT_ASSET_BLINDING_FACTOR: u8 = 0x0b; /// A key-value map for an output of the corresponding index in the unsigned /// transaction. @@ -131,8 +129,6 @@ pub struct Output { pub blind_value_proof: Option>, /// The blind asset surjection proof pub blind_asset_proof: Option>, - /// The 32 byte asset blinding factor - pub asset_blinding_factor: Option, /// Pset /// Other fields #[cfg_attr( @@ -378,9 +374,6 @@ impl Map for Output { PSBT_ELEMENTS_OUT_BLIND_ASSET_PROOF => { impl_pset_prop_insert_pair!(self.blind_asset_proof <= | >) } - PSBT_ELEMENTS_OUT_ASSET_BLINDING_FACTOR => { - impl_pset_prop_insert_pair!(self.asset_blinding_factor <= | ) - } _ => match self.proprietary.entry(prop_key) { Entry::Vacant(empty_key) => { empty_key.insert(raw_value); @@ -495,10 +488,6 @@ impl Map for Output { rv.push_prop(self.blind_asset_proof as ) } - impl_pset_get_pair! { - rv.push_prop(self.asset_blinding_factor as ) - } - for (key, value) in self.proprietary.iter() { rv.push(raw::Pair { key: key.to_key(), @@ -536,7 +525,6 @@ impl Map for Output { merge!(blinder_index, self, other); merge!(blind_value_proof, self, other); merge!(blind_asset_proof, self, other); - merge!(asset_blinding_factor, self, other); Ok(()) } } diff --git a/src/pset/mod.rs b/src/pset/mod.rs index de80556e..351202e0 100644 --- a/src/pset/mod.rs +++ b/src/pset/mod.rs @@ -1043,53 +1043,4 @@ mod tests { let pset_des = encode::deserialize(&pset_bytes).unwrap(); assert_eq!(pset, pset_des); } - - #[test] - fn pset_abf() { - use std::str::FromStr; - use rand::{self, SeedableRng}; - let secp = secp256k1_zkp::Secp256k1::new(); - #[allow(deprecated)] - let mut rng = rand::rngs::StdRng::seed_from_u64(0); - - let policy = crate::AssetId::from_str("5ac9f65c0efcc4775e0baec4ec03abdde22473cd3cf33c0419ca290e0751b225").unwrap(); - let pk = bitcoin::key::PublicKey::from_str("020202020202020202020202020202020202020202020202020202020202020202").unwrap(); - let script = crate::Script::from_hex("0014d2bcde17e7744f6377466ca1bd35d212954674c8").unwrap(); - let sats_in = 10000; - let sats_fee = 1000; - let asset_bf = AssetBlindingFactor::from_str("3311111111111111111111111111111111111111111111111111111111111111").unwrap(); - let btc_txout_secrets = TxOutSecrets { - asset_bf, - value_bf: ValueBlindingFactor::from_str("2222222222222222222222222222222222222222222222222222222222222222").unwrap(), - value: sats_in, - asset: policy, - }; - let previous_output = TxOut::default(); // Does not match btc_txout_secrets - let txid = Txid::from_str("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").unwrap(); - let prevout = OutPoint::new(txid, 0); - - let mut pset = PartiallySignedTransaction::new_v2(); - let mut input = Input::from_prevout(prevout); - input.witness_utxo = Some(previous_output); - input.asset_blinding_factor = Some(asset_bf); - pset.add_input(input); - - // Add policy - let mut output = Output::new_explicit(script.clone(), sats_in - sats_fee, policy, Some(pk)); - output.blinder_index = Some(0); - pset.add_output(output); - // Add fee - let output = Output::new_explicit(crate::Script::new(), sats_fee, policy, None); - pset.add_output(output); - - let mut inp_txout_sec = HashMap::new(); - inp_txout_sec.insert(0, btc_txout_secrets); - pset.blind_last(&mut rng, &secp, &inp_txout_sec).unwrap(); - let output = &mut pset.outputs_mut()[0]; - // TODO: output the blinding factors and use the correct one - output.asset_blinding_factor = Some(asset_bf); - let pset_bytes = encode::serialize(&pset); - let pset_des = encode::deserialize(&pset_bytes).unwrap(); - assert_eq!(pset, pset_des); - } } From 7737c82356ae09718645888c8076c7880d187e4b Mon Sep 17 00:00:00 2001 From: Leonardo Comandini Date: Fri, 26 Jul 2024 17:32:29 +0200 Subject: [PATCH 2/2] Add elip_liquidex module --- src/pset/elip_liquidex.rs | 113 ++++++++++++++++++++++++++++++++++++++ src/pset/mod.rs | 1 + 2 files changed, 114 insertions(+) create mode 100644 src/pset/elip_liquidex.rs diff --git a/src/pset/elip_liquidex.rs b/src/pset/elip_liquidex.rs new file mode 100644 index 00000000..a25471bc --- /dev/null +++ b/src/pset/elip_liquidex.rs @@ -0,0 +1,113 @@ +//! +//! An implementation of ELIP0XXX as defined in +//! +//! +//! ELIP0XXX defines how to encode the extra data for LiquiDEX in a PSET. +//! + +use crate::pset::{ + confidential::AssetBlindingFactor, + encode, + raw::ProprietaryKey, + serialize::{Deserialize, Serialize}, + Input, Output, +}; + +/// Input Asset Blinding Factor keytype as defined in ELIP0XXX +pub const PSBT_ELEMENTS_LIQUIDEX_IN_ABF: u8 = 0x00u8; + +/// Output Asset Blinding Factor keytype as defined in ELIP0XXX +pub const PSBT_ELEMENTS_LIQUIDEX_OUT_ABF: u8 = 0x00u8; + +/// Prefix for PSET LiquiDEX extension as defined in ELIP0XXX +pub const PSET_LIQUIDEX_PREFIX: &[u8] = b"pset_liquidex"; + +fn prop_key(keytype: u8) -> ProprietaryKey { + ProprietaryKey { + prefix: PSET_LIQUIDEX_PREFIX.to_vec(), + subtype: keytype, + key: vec![], + } +} + +/// ELIP0XXX LiquiDEX extensions +impl Input { + /// Set Asset Blinding Factor + pub fn set_abf(&mut self, abf: AssetBlindingFactor) { + let key = prop_key(PSBT_ELEMENTS_LIQUIDEX_IN_ABF); + self.proprietary.insert(key, abf.serialize()); + } + + /// Get Asset Blinding Factor + pub fn get_abf(&self) -> Option> { + let key = prop_key(PSBT_ELEMENTS_LIQUIDEX_IN_ABF); + self.proprietary + .get(&key) + .map(|data| AssetBlindingFactor::deserialize(data)) + } +} + +/// ELIP0XXX LiquiDEX extensions +impl Output { + /// Set Asset Blinding Factor + pub fn set_abf(&mut self, abf: AssetBlindingFactor) { + let key = prop_key(PSBT_ELEMENTS_LIQUIDEX_OUT_ABF); + self.proprietary.insert(key, abf.serialize()); + } + + /// Get Asset Blinding Factor + pub fn get_abf(&self) -> Option> { + let key = prop_key(PSBT_ELEMENTS_LIQUIDEX_OUT_ABF); + self.proprietary + .get(&key) + .map(|data| AssetBlindingFactor::deserialize(data)) + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::encode::{serialize_hex, Encodable}; + use crate::hex::{FromHex, ToHex}; + + // b'\xfc\rpset_liquidex' + const ELIP0XXX_IDENTIFIER: &str = "fc0d707365745f6c69717569646578"; + + #[test] + fn prop_key_serialize() { + let key = prop_key(PSBT_ELEMENTS_LIQUIDEX_IN_ABF); + let mut vec = vec![]; + key.consensus_encode(&mut vec).unwrap(); + + assert_eq!( + vec.to_hex(), + format!("0d{}00", PSET_LIQUIDEX_PREFIX.to_hex()) + ); + + assert!(vec.to_hex().starts_with(&ELIP0XXX_IDENTIFIER[2..])); // cut proprietary prefix "fc" + } + + #[test] + fn set_get_abf() { + // An ABF that's different if serialized in reverse or not + let abf_hex = "3311111111111111111111111111111111111111111111111111111111111111"; + let abf_bytes = Vec::::from_hex(abf_hex).unwrap(); + let abf = AssetBlindingFactor::from_slice(&abf_bytes).unwrap(); + + let mut input = Input::default(); + assert!(input.get_abf().is_none()); + input.set_abf(abf); + assert_eq!(input.get_abf().unwrap().unwrap(), abf); + let input_hex = serialize_hex(&input); + assert!(input_hex.contains(ELIP0XXX_IDENTIFIER)); + assert!(input_hex.contains(abf_hex)); + + let mut output = Output::default(); + assert!(output.get_abf().is_none()); + output.set_abf(abf); + assert_eq!(output.get_abf().unwrap().unwrap(), abf); + let output_hex = serialize_hex(&output); + assert!(output_hex.contains(ELIP0XXX_IDENTIFIER)); + assert!(output_hex.contains(abf_hex)); + } +} diff --git a/src/pset/mod.rs b/src/pset/mod.rs index 351202e0..0c832edc 100644 --- a/src/pset/mod.rs +++ b/src/pset/mod.rs @@ -30,6 +30,7 @@ mod map; pub mod raw; pub mod serialize; pub mod elip100; +pub mod elip_liquidex; #[cfg(feature = "base64")] mod str;