Skip to content

Commit 25dc2d2

Browse files
committed
Merge #207: Add elip_liquidex module
7737c82 Add elip_liquidex module (Leonardo Comandini) 2ca6c7b Revert "pset: input/output: add abf" (Leonardo Comandini) Pull request description: Use "liquidex" field for the asset blinding factor. Related ELIP: ElementsProject/ELIPs#18 ACKs for top commit: RCasatta: ACK 7737c82 apoelstra: ACK 7737c82 successfully ran local tests Tree-SHA512: 4bde263a0323cc5c1198c0d024552dd53bc44b5f00572c24da773cb417e5a7020e7158dcb72f6519caff7e3dd2082c049ed9cf5394e91fba7f9a8f8eb8bbaa1a
2 parents 4917d7c + 7737c82 commit 25dc2d2

File tree

4 files changed

+117
-76
lines changed

4 files changed

+117
-76
lines changed

src/pset/elip_liquidex.rs

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
//!
2+
//! An implementation of ELIP0XXX as defined in
3+
//! <https://github.com/ElementsProject/ELIPs/blob/main/elip-0XXX.mediawiki>
4+
//!
5+
//! ELIP0XXX defines how to encode the extra data for LiquiDEX in a PSET.
6+
//!
7+
8+
use crate::pset::{
9+
confidential::AssetBlindingFactor,
10+
encode,
11+
raw::ProprietaryKey,
12+
serialize::{Deserialize, Serialize},
13+
Input, Output,
14+
};
15+
16+
/// Input Asset Blinding Factor keytype as defined in ELIP0XXX
17+
pub const PSBT_ELEMENTS_LIQUIDEX_IN_ABF: u8 = 0x00u8;
18+
19+
/// Output Asset Blinding Factor keytype as defined in ELIP0XXX
20+
pub const PSBT_ELEMENTS_LIQUIDEX_OUT_ABF: u8 = 0x00u8;
21+
22+
/// Prefix for PSET LiquiDEX extension as defined in ELIP0XXX
23+
pub const PSET_LIQUIDEX_PREFIX: &[u8] = b"pset_liquidex";
24+
25+
fn prop_key(keytype: u8) -> ProprietaryKey {
26+
ProprietaryKey {
27+
prefix: PSET_LIQUIDEX_PREFIX.to_vec(),
28+
subtype: keytype,
29+
key: vec![],
30+
}
31+
}
32+
33+
/// ELIP0XXX LiquiDEX extensions
34+
impl Input {
35+
/// Set Asset Blinding Factor
36+
pub fn set_abf(&mut self, abf: AssetBlindingFactor) {
37+
let key = prop_key(PSBT_ELEMENTS_LIQUIDEX_IN_ABF);
38+
self.proprietary.insert(key, abf.serialize());
39+
}
40+
41+
/// Get Asset Blinding Factor
42+
pub fn get_abf(&self) -> Option<Result<AssetBlindingFactor, encode::Error>> {
43+
let key = prop_key(PSBT_ELEMENTS_LIQUIDEX_IN_ABF);
44+
self.proprietary
45+
.get(&key)
46+
.map(|data| AssetBlindingFactor::deserialize(data))
47+
}
48+
}
49+
50+
/// ELIP0XXX LiquiDEX extensions
51+
impl Output {
52+
/// Set Asset Blinding Factor
53+
pub fn set_abf(&mut self, abf: AssetBlindingFactor) {
54+
let key = prop_key(PSBT_ELEMENTS_LIQUIDEX_OUT_ABF);
55+
self.proprietary.insert(key, abf.serialize());
56+
}
57+
58+
/// Get Asset Blinding Factor
59+
pub fn get_abf(&self) -> Option<Result<AssetBlindingFactor, encode::Error>> {
60+
let key = prop_key(PSBT_ELEMENTS_LIQUIDEX_OUT_ABF);
61+
self.proprietary
62+
.get(&key)
63+
.map(|data| AssetBlindingFactor::deserialize(data))
64+
}
65+
}
66+
67+
#[cfg(test)]
68+
mod test {
69+
use super::*;
70+
use crate::encode::{serialize_hex, Encodable};
71+
use crate::hex::{FromHex, ToHex};
72+
73+
// b'\xfc\rpset_liquidex'
74+
const ELIP0XXX_IDENTIFIER: &str = "fc0d707365745f6c69717569646578";
75+
76+
#[test]
77+
fn prop_key_serialize() {
78+
let key = prop_key(PSBT_ELEMENTS_LIQUIDEX_IN_ABF);
79+
let mut vec = vec![];
80+
key.consensus_encode(&mut vec).unwrap();
81+
82+
assert_eq!(
83+
vec.to_hex(),
84+
format!("0d{}00", PSET_LIQUIDEX_PREFIX.to_hex())
85+
);
86+
87+
assert!(vec.to_hex().starts_with(&ELIP0XXX_IDENTIFIER[2..])); // cut proprietary prefix "fc"
88+
}
89+
90+
#[test]
91+
fn set_get_abf() {
92+
// An ABF that's different if serialized in reverse or not
93+
let abf_hex = "3311111111111111111111111111111111111111111111111111111111111111";
94+
let abf_bytes = Vec::<u8>::from_hex(abf_hex).unwrap();
95+
let abf = AssetBlindingFactor::from_slice(&abf_bytes).unwrap();
96+
97+
let mut input = Input::default();
98+
assert!(input.get_abf().is_none());
99+
input.set_abf(abf);
100+
assert_eq!(input.get_abf().unwrap().unwrap(), abf);
101+
let input_hex = serialize_hex(&input);
102+
assert!(input_hex.contains(ELIP0XXX_IDENTIFIER));
103+
assert!(input_hex.contains(abf_hex));
104+
105+
let mut output = Output::default();
106+
assert!(output.get_abf().is_none());
107+
output.set_abf(abf);
108+
assert_eq!(output.get_abf().unwrap().unwrap(), abf);
109+
let output_hex = serialize_hex(&output);
110+
assert!(output_hex.contains(ELIP0XXX_IDENTIFIER));
111+
assert!(output_hex.contains(abf_hex));
112+
}
113+
}

src/pset/map/input.rs

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use std::{
2323
use crate::taproot::{ControlBlock, LeafVersion, TapNodeHash, TapLeafHash};
2424
use crate::{schnorr, AssetId, ContractHash};
2525

26-
use crate::{confidential::{self, AssetBlindingFactor}, locktime};
26+
use crate::{confidential, locktime};
2727
use crate::encode::{self, Decodable};
2828
use crate::hashes::{self, hash160, ripemd160, sha256, sha256d, Hash};
2929
use crate::pset::map::Map;
@@ -168,8 +168,6 @@ const PSBT_ELEMENTS_IN_ASSET_PROOF: u8 = 0x14;
168168
/// Note that this does not indicate actual blinding status,
169169
/// but rather the expected blinding status prior to signing.
170170
const PSBT_ELEMENTS_IN_BLINDED_ISSUANCE: u8 = 0x15;
171-
/// The 32 byte asset blinding factor for the input being spent.
172-
const PSBT_ELEMENTS_IN_ASSET_BLINDING_FACTOR: u8 = 0x16;
173171
/// A key-value map for an input of the corresponding index in the unsigned
174172
/// transaction.
175173
#[derive(Clone, Debug, PartialEq)]
@@ -303,8 +301,6 @@ pub struct Input {
303301
pub blind_asset_proof: Option<Box<SurjectionProof>>,
304302
/// Whether the issuance is blinded
305303
pub blinded_issuance: Option<u8>,
306-
/// The input asset blinding factor
307-
pub asset_blinding_factor: Option<AssetBlindingFactor>,
308304
/// Other fields
309305
#[cfg_attr(
310306
feature = "serde",
@@ -321,7 +317,7 @@ pub struct Input {
321317

322318
impl Default for Input {
323319
fn default() -> Self {
324-
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() }
320+
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() }
325321
}
326322
}
327323

@@ -754,9 +750,6 @@ impl Map for Input {
754750
PSBT_ELEMENTS_IN_BLINDED_ISSUANCE => {
755751
impl_pset_prop_insert_pair!(self.blinded_issuance <= <raw_key: _> | <raw_value : u8>)
756752
}
757-
PSBT_ELEMENTS_IN_ASSET_BLINDING_FACTOR => {
758-
impl_pset_prop_insert_pair!(self.asset_blinding_factor <= <raw_key: _> | <raw_value : AssetBlindingFactor>)
759-
}
760753
_ => match self.proprietary.entry(prop_key) {
761754
Entry::Vacant(empty_key) => {
762755
empty_key.insert(raw_value);
@@ -975,10 +968,6 @@ impl Map for Input {
975968
rv.push_prop(self.blinded_issuance as <PSBT_ELEMENTS_IN_BLINDED_ISSUANCE, _>)
976969
}
977970

978-
impl_pset_get_pair! {
979-
rv.push_prop(self.asset_blinding_factor as <PSBT_ELEMENTS_IN_ASSET_BLINDING_FACTOR, _>)
980-
}
981-
982971
for (key, value) in self.proprietary.iter() {
983972
rv.push(raw::Pair {
984973
key: key.to_key(),
@@ -1058,7 +1047,6 @@ impl Map for Input {
10581047
merge!(asset, self, other);
10591048
merge!(blind_asset_proof, self, other);
10601049
merge!(blinded_issuance, self, other);
1061-
merge!(asset_blinding_factor, self, other);
10621050
Ok(())
10631051
}
10641052
}

src/pset/map/output.rs

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::encode::Decodable;
2222
use crate::pset::map::Map;
2323
use crate::pset::raw;
2424
use crate::pset::Error;
25-
use crate::{confidential::{self, AssetBlindingFactor}, pset};
25+
use crate::{confidential, pset};
2626
use crate::{encode, Script, TxOutWitness};
2727
use bitcoin::bip32::KeySource;
2828
use bitcoin::{PublicKey, key::XOnlyPublicKey};
@@ -83,8 +83,6 @@ const PSBT_ELEMENTS_OUT_BLIND_VALUE_PROOF: u8 = 0x09;
8383
/// PSBT_ELEMENTS_OUT_ASSET. If provided, PSBT_ELEMENTS_OUT_ASSET_COMMITMENT must
8484
/// be provided too.
8585
const PSBT_ELEMENTS_OUT_BLIND_ASSET_PROOF: u8 = 0x0a;
86-
/// The 32 byte asset blinding factor for this output.
87-
const PSBT_ELEMENTS_OUT_ASSET_BLINDING_FACTOR: u8 = 0x0b;
8886

8987
/// A key-value map for an output of the corresponding index in the unsigned
9088
/// transaction.
@@ -131,8 +129,6 @@ pub struct Output {
131129
pub blind_value_proof: Option<Box<RangeProof>>,
132130
/// The blind asset surjection proof
133131
pub blind_asset_proof: Option<Box<SurjectionProof>>,
134-
/// The 32 byte asset blinding factor
135-
pub asset_blinding_factor: Option<AssetBlindingFactor>,
136132
/// Pset
137133
/// Other fields
138134
#[cfg_attr(
@@ -378,9 +374,6 @@ impl Map for Output {
378374
PSBT_ELEMENTS_OUT_BLIND_ASSET_PROOF => {
379375
impl_pset_prop_insert_pair!(self.blind_asset_proof <= <raw_key: _> | <raw_value : Box<SurjectionProof>>)
380376
}
381-
PSBT_ELEMENTS_OUT_ASSET_BLINDING_FACTOR => {
382-
impl_pset_prop_insert_pair!(self.asset_blinding_factor <= <raw_key: _> | <raw_value : AssetBlindingFactor>)
383-
}
384377
_ => match self.proprietary.entry(prop_key) {
385378
Entry::Vacant(empty_key) => {
386379
empty_key.insert(raw_value);
@@ -495,10 +488,6 @@ impl Map for Output {
495488
rv.push_prop(self.blind_asset_proof as <PSBT_ELEMENTS_OUT_BLIND_ASSET_PROOF, _>)
496489
}
497490

498-
impl_pset_get_pair! {
499-
rv.push_prop(self.asset_blinding_factor as <PSBT_ELEMENTS_OUT_ASSET_BLINDING_FACTOR, _>)
500-
}
501-
502491
for (key, value) in self.proprietary.iter() {
503492
rv.push(raw::Pair {
504493
key: key.to_key(),
@@ -536,7 +525,6 @@ impl Map for Output {
536525
merge!(blinder_index, self, other);
537526
merge!(blind_value_proof, self, other);
538527
merge!(blind_asset_proof, self, other);
539-
merge!(asset_blinding_factor, self, other);
540528
Ok(())
541529
}
542530
}

src/pset/mod.rs

Lines changed: 1 addition & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ mod map;
3030
pub mod raw;
3131
pub mod serialize;
3232
pub mod elip100;
33+
pub mod elip_liquidex;
3334

3435
#[cfg(feature = "base64")]
3536
mod str;
@@ -1043,53 +1044,4 @@ mod tests {
10431044
let pset_des = encode::deserialize(&pset_bytes).unwrap();
10441045
assert_eq!(pset, pset_des);
10451046
}
1046-
1047-
#[test]
1048-
fn pset_abf() {
1049-
use std::str::FromStr;
1050-
use rand::{self, SeedableRng};
1051-
let secp = secp256k1_zkp::Secp256k1::new();
1052-
#[allow(deprecated)]
1053-
let mut rng = rand::rngs::StdRng::seed_from_u64(0);
1054-
1055-
let policy = crate::AssetId::from_str("5ac9f65c0efcc4775e0baec4ec03abdde22473cd3cf33c0419ca290e0751b225").unwrap();
1056-
let pk = bitcoin::key::PublicKey::from_str("020202020202020202020202020202020202020202020202020202020202020202").unwrap();
1057-
let script = crate::Script::from_hex("0014d2bcde17e7744f6377466ca1bd35d212954674c8").unwrap();
1058-
let sats_in = 10000;
1059-
let sats_fee = 1000;
1060-
let asset_bf = AssetBlindingFactor::from_str("3311111111111111111111111111111111111111111111111111111111111111").unwrap();
1061-
let btc_txout_secrets = TxOutSecrets {
1062-
asset_bf,
1063-
value_bf: ValueBlindingFactor::from_str("2222222222222222222222222222222222222222222222222222222222222222").unwrap(),
1064-
value: sats_in,
1065-
asset: policy,
1066-
};
1067-
let previous_output = TxOut::default(); // Does not match btc_txout_secrets
1068-
let txid = Txid::from_str("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").unwrap();
1069-
let prevout = OutPoint::new(txid, 0);
1070-
1071-
let mut pset = PartiallySignedTransaction::new_v2();
1072-
let mut input = Input::from_prevout(prevout);
1073-
input.witness_utxo = Some(previous_output);
1074-
input.asset_blinding_factor = Some(asset_bf);
1075-
pset.add_input(input);
1076-
1077-
// Add policy
1078-
let mut output = Output::new_explicit(script.clone(), sats_in - sats_fee, policy, Some(pk));
1079-
output.blinder_index = Some(0);
1080-
pset.add_output(output);
1081-
// Add fee
1082-
let output = Output::new_explicit(crate::Script::new(), sats_fee, policy, None);
1083-
pset.add_output(output);
1084-
1085-
let mut inp_txout_sec = HashMap::new();
1086-
inp_txout_sec.insert(0, btc_txout_secrets);
1087-
pset.blind_last(&mut rng, &secp, &inp_txout_sec).unwrap();
1088-
let output = &mut pset.outputs_mut()[0];
1089-
// TODO: output the blinding factors and use the correct one
1090-
output.asset_blinding_factor = Some(asset_bf);
1091-
let pset_bytes = encode::serialize(&pset);
1092-
let pset_des = encode::deserialize(&pset_bytes).unwrap();
1093-
assert_eq!(pset, pset_des);
1094-
}
10951047
}

0 commit comments

Comments
 (0)