Skip to content

Commit 487f31b

Browse files
committed
Merge #201: pset: add optional asset blinding factor to input and output
17d354e pset: test input and output asset blinding factors (Leonardo Comandini) db805b3 pset: output: add asset blinding factor (Leonardo Comandini) d1dfed4 pset: input: add asset blinding factor (Leonardo Comandini) 04ab514 pset: implement (de)serialize for AssetBlindingFactor (Leonardo Comandini) Pull request description: Change corresponding to ElementsProject/elements#1329 ACKs for top commit: apoelstra: ACK 17d354e Tree-SHA512: 14c8d9d096c6412bd15fac1f597a3fbc02a43bee64e3edc8209d487b805671b6cec1fa752337e817324170178a3cf3151bbcbe98dd2646f1e92e3018cd5dceec
2 parents d80aa1b + 17d354e commit 487f31b

File tree

4 files changed

+90
-4
lines changed

4 files changed

+90
-4
lines changed

src/pset/map/input.rs

+14-2
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, locktime};
26+
use crate::{confidential::{self, AssetBlindingFactor}, locktime};
2727
use crate::encode::{self, Decodable};
2828
use crate::hashes::{self, hash160, ripemd160, sha256, sha256d, Hash};
2929
use crate::pset::map::Map;
@@ -168,6 +168,8 @@ 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;
171173
/// A key-value map for an input of the corresponding index in the unsigned
172174
/// transaction.
173175
#[derive(Clone, Debug, PartialEq)]
@@ -301,6 +303,8 @@ pub struct Input {
301303
pub blind_asset_proof: Option<Box<SurjectionProof>>,
302304
/// Whether the issuance is blinded
303305
pub blinded_issuance: Option<u8>,
306+
/// The input asset blinding factor
307+
pub asset_blinding_factor: Option<AssetBlindingFactor>,
304308
/// Other fields
305309
#[cfg_attr(
306310
feature = "serde",
@@ -317,7 +321,7 @@ pub struct Input {
317321

318322
impl Default for Input {
319323
fn default() -> Self {
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() }
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() }
321325
}
322326
}
323327

@@ -750,6 +754,9 @@ impl Map for Input {
750754
PSBT_ELEMENTS_IN_BLINDED_ISSUANCE => {
751755
impl_pset_prop_insert_pair!(self.blinded_issuance <= <raw_key: _> | <raw_value : u8>)
752756
}
757+
PSBT_ELEMENTS_IN_ASSET_BLINDING_FACTOR => {
758+
impl_pset_prop_insert_pair!(self.asset_blinding_factor <= <raw_key: _> | <raw_value : AssetBlindingFactor>)
759+
}
753760
_ => match self.proprietary.entry(prop_key) {
754761
Entry::Vacant(empty_key) => {
755762
empty_key.insert(raw_value);
@@ -968,6 +975,10 @@ impl Map for Input {
968975
rv.push_prop(self.blinded_issuance as <PSBT_ELEMENTS_IN_BLINDED_ISSUANCE, _>)
969976
}
970977

978+
impl_pset_get_pair! {
979+
rv.push_prop(self.asset_blinding_factor as <PSBT_ELEMENTS_IN_ASSET_BLINDING_FACTOR, _>)
980+
}
981+
971982
for (key, value) in self.proprietary.iter() {
972983
rv.push(raw::Pair {
973984
key: key.to_key(),
@@ -1047,6 +1058,7 @@ impl Map for Input {
10471058
merge!(asset, self, other);
10481059
merge!(blind_asset_proof, self, other);
10491060
merge!(blinded_issuance, self, other);
1061+
merge!(asset_blinding_factor, self, other);
10501062
Ok(())
10511063
}
10521064
}

src/pset/map/output.rs

+13-1
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, pset};
25+
use crate::{confidential::{self, AssetBlindingFactor}, pset};
2626
use crate::{encode, Script, TxOutWitness};
2727
use bitcoin::bip32::KeySource;
2828
use bitcoin::{PublicKey, key::XOnlyPublicKey};
@@ -83,6 +83,8 @@ 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;
8688

8789
/// A key-value map for an output of the corresponding index in the unsigned
8890
/// transaction.
@@ -129,6 +131,8 @@ pub struct Output {
129131
pub blind_value_proof: Option<Box<RangeProof>>,
130132
/// The blind asset surjection proof
131133
pub blind_asset_proof: Option<Box<SurjectionProof>>,
134+
/// The 32 byte asset blinding factor
135+
pub asset_blinding_factor: Option<AssetBlindingFactor>,
132136
/// Pset
133137
/// Other fields
134138
#[cfg_attr(
@@ -374,6 +378,9 @@ impl Map for Output {
374378
PSBT_ELEMENTS_OUT_BLIND_ASSET_PROOF => {
375379
impl_pset_prop_insert_pair!(self.blind_asset_proof <= <raw_key: _> | <raw_value : Box<SurjectionProof>>)
376380
}
381+
PSBT_ELEMENTS_OUT_ASSET_BLINDING_FACTOR => {
382+
impl_pset_prop_insert_pair!(self.asset_blinding_factor <= <raw_key: _> | <raw_value : AssetBlindingFactor>)
383+
}
377384
_ => match self.proprietary.entry(prop_key) {
378385
Entry::Vacant(empty_key) => {
379386
empty_key.insert(raw_value);
@@ -488,6 +495,10 @@ impl Map for Output {
488495
rv.push_prop(self.blind_asset_proof as <PSBT_ELEMENTS_OUT_BLIND_ASSET_PROOF, _>)
489496
}
490497

498+
impl_pset_get_pair! {
499+
rv.push_prop(self.asset_blinding_factor as <PSBT_ELEMENTS_OUT_ASSET_BLINDING_FACTOR, _>)
500+
}
501+
491502
for (key, value) in self.proprietary.iter() {
492503
rv.push(raw::Pair {
493504
key: key.to_key(),
@@ -525,6 +536,7 @@ impl Map for Output {
525536
merge!(blinder_index, self, other);
526537
merge!(blind_value_proof, self, other);
527538
merge!(blind_asset_proof, self, other);
539+
merge!(asset_blinding_factor, self, other);
528540
Ok(())
529541
}
530542
}

src/pset/mod.rs

+49
Original file line numberDiff line numberDiff line change
@@ -1043,4 +1043,53 @@ mod tests {
10431043
let pset_des = encode::deserialize(&pset_bytes).unwrap();
10441044
assert_eq!(pset, pset_des);
10451045
}
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+
}
10461095
}

src/pset/serialize.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
use std::convert::TryFrom;
2121
use std::io;
2222

23-
use crate::confidential;
23+
use crate::confidential::{self, AssetBlindingFactor};
2424
use crate::encode::{self, deserialize, deserialize_partial, serialize, Decodable, Encodable};
2525
use crate::hashes::{hash160, ripemd160, sha256, sha256d, Hash};
2626
use crate::{AssetId, BlockHash, Script, Transaction, TxOut, Txid};
@@ -96,6 +96,19 @@ impl Deserialize for Tweak {
9696
}
9797
}
9898

99+
impl Serialize for AssetBlindingFactor {
100+
fn serialize(&self) -> Vec<u8> {
101+
encode::serialize(self.into_inner().as_ref())
102+
}
103+
}
104+
105+
impl Deserialize for AssetBlindingFactor {
106+
fn deserialize(bytes: &[u8]) -> Result<Self, encode::Error> {
107+
let x = deserialize::<[u8; 32]>(bytes)?;
108+
AssetBlindingFactor::from_slice(&x).map_err(|_| encode::Error::ParseFailed("invalid AssetBlindingFactor"))
109+
}
110+
}
111+
99112
impl Serialize for Script {
100113
fn serialize(&self) -> Vec<u8> {
101114
self.to_bytes()

0 commit comments

Comments
 (0)