Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 3 additions & 42 deletions Cargo-latest.lock
Original file line number Diff line number Diff line change
Expand Up @@ -240,12 +240,6 @@ version = "3.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"

[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"

[[package]]
name = "cc"
version = "1.2.34"
Expand Down Expand Up @@ -307,7 +301,6 @@ dependencies = [
"serde",
"serde_json",
"serde_test",
"simplicity-lang",
]

[[package]]
Expand Down Expand Up @@ -342,12 +335,6 @@ dependencies = [
"wasm-bindgen",
]

[[package]]
name = "ghost-cell"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8449d342b1c67f49169e92e71deb7b9b27f30062301a16dbc27a4cc8d2351b7"

[[package]]
name = "hex-conservative"
version = "0.1.2"
Expand Down Expand Up @@ -467,12 +454,13 @@ dependencies = [

[[package]]
name = "miniscript"
version = "12.3.5"
version = "13.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "487906208f38448e186e3deb02f2b8ef046a9078b0de00bdb28bf4fb9b76951c"
checksum = "cd35e2c377504e50159561884b03610711db6c2fec6c89f2b98d94016684726b"
dependencies = [
"bech32 0.11.0",
"bitcoin 0.32.102",
"hex-conservative 1.2.0",
]

[[package]]
Expand Down Expand Up @@ -719,33 +707,6 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"

[[package]]
name = "simplicity-lang"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cff7b10251528d46d9cf60238267911984fedbb0948cccea98dd74fc6bf9f729"
dependencies = [
"bitcoin 0.32.102",
"bitcoin_hashes 1.2.0",
"byteorder",
"elements",
"getrandom",
"ghost-cell",
"hex-conservative 1.2.0",
"miniscript",
"simplicity-sys",
]

[[package]]
name = "simplicity-sys"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "955935733b2735665b4735d9b1361eade6be4c7aea6bca2640345e4c81756f58"
dependencies = [
"bitcoin_hashes 1.2.0",
"cc",
]

[[package]]
name = "syn"
version = "2.0.106"
Expand Down
3 changes: 1 addition & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ base64 = ["bitcoin/base64", "elements/base64"]
[dependencies]
bitcoin = "0.32.0"
elements = "0.27.0"
bitcoin-miniscript = { package = "miniscript", version = "12.0" }
simplicity = { package = "simplicity-lang", version = "0.9.0", optional = true }
bitcoin-miniscript = { package = "miniscript", version = "13.1" }

# Do NOT use this as a feature! Use the `serde` feature instead.
actual-serde = { package = "serde", version = "1.0", optional = true }
Expand Down
2 changes: 1 addition & 1 deletion contrib/test_vars.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
FEATURES_WITH_STD=""

# Test all these features without "std" enabled.
FEATURES_WITHOUT_STD="compiler trace serde rand base64 simplicity"
FEATURES_WITHOUT_STD="compiler trace serde rand base64"

# Run these examples.
EXAMPLES="htlc:compiler parse: sign_multisig: verify_tx: xpub_descriptors: taproot:compiler psbt_sign_finalize:base64"
2 changes: 1 addition & 1 deletion src/confidential/elip151.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ mod test {
(&format!("elwsh(multi(2,{xpub}/<0;1>/*,{xpub}/0/<0;1;2>/*))"), Error::MultipathDescLenMismatch),
] {
let err = confidential_descriptor(invalid_desc).unwrap_err();
assert_eq!(err, expected_err);
assert_eq!(format!("{:?}", err), format!("{:?}", expected_err));
/*
_i = _i + 1;
println!("* Invalid Test vector {}", _i);
Expand Down
118 changes: 112 additions & 6 deletions src/confidential/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -586,10 +586,10 @@ mod tests {
.unwrap(),
};

assert_eq!(
assert!(matches!(
desc.address(&secp, params).unwrap_err(),
Error::Conversion(ConversionError::HardenedChild)
);
));
}

// Same case, reached through `at_derivation_index` on a hardened wildcard blinding
Expand All @@ -605,10 +605,10 @@ mod tests {
let desc = Descriptor::<DescriptorPublicKey, NoExt>::from_str(&desc_str).unwrap();
let definite_desc = desc.at_derivation_index(1).unwrap();

assert_eq!(
assert!(matches!(
definite_desc.address(&secp, params).unwrap_err(),
Error::Conversion(ConversionError::HardenedChild)
);
));
}

#[test]
Expand Down Expand Up @@ -638,10 +638,116 @@ mod tests {
// but we can't enforce this with the Descriptor generic.
let desc_view_str = format!("ct({}/*,elwpkh({}))#ls6mx2ac", xprv, xpub);
let desc_view = Descriptor::<DefiniteDescriptorKey>::from_str(&desc_view_str).unwrap();
assert_eq!(desc_view.address(&secp, params).unwrap_err(), Error::Unexpected("wildcard blinding key".into()));
assert!(matches!(desc_view.address(&secp, params).unwrap_err(), Error::Unexpected(e) if e == "wildcard blinding key"));

let desc_bare_str = format!("ct({}/*,elwpkh({}))#czkz0hwn", xpub, xpub);
let desc_bare = Descriptor::<DefiniteDescriptorKey>::from_str(&desc_bare_str).unwrap();
assert_eq!(desc_bare.address(&secp, params).unwrap_err(), Error::Unexpected("wildcard blinding key".into()));
assert!(matches!(desc_bare.address(&secp, params).unwrap_err(), Error::Unexpected(e) if e == "wildcard blinding key"));
}

#[test]
fn confidential_descriptor_tr_script_tree() {
let secp = secp256k1_zkp::Secp256k1::new();

let nums = "0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0";
let key = "03774eec7a3d550d18e9f89414152025b3b0ad6a342b19481f702d843cff06dfc4";
let ct_key = DescriptorPublicKey::from_str(
"02dce16018bbbb8e36de7b394df5b5166e9adb7498be7d881a85a09aeecf76b623",
)
.unwrap();
let mbk = slip77::MasterBlindingKey::from_seed(b"abcd");

let leaf = crate::Descriptor::from_str(&format!("eltr({nums},pk({key}))")).unwrap();
let tree = crate::Descriptor::from_str(&format!("eltr({nums},{{pk({key}),pk({nums})}})"))
.unwrap();

let tests = vec![
// SLIP77, P2TR with one leaf
ConfidentialTest {
key: Key::Slip77(mbk),
descriptor: leaf.clone(),
descriptor_str: format!("ct(slip77({mbk}),eltr({nums},pk({key})))#0rh5eggz"),
conf_addr: "lq1pqv6pc3c9nlsr6my3tqxl8plf3t7hl73nlxgcuswhkxy8llz32z3p4940lgxlw8ksnmsl0x7kmazr648t5y2js6cl9nchna5s9jdpd0azfc2t8prf77qg",
unconf_addr: "ex1pj6hl5r0hrmgfac0hn0td73pa2n46z9fgdv0jeute76gzexskh73qzgwgq9",
},
// SLIP77, P2TR with a script tree
ConfidentialTest {
key: Key::Slip77(mbk),
descriptor: tree.clone(),
descriptor_str: format!("ct(slip77({mbk}),eltr({nums},{{pk({key}),pk({nums})}}))#jvtacgy4"),
conf_addr: "lq1pqf82jgz44dws8fh9jk759fuwkp72c2f7la0m88pfj4uz0uwgs5qhcyrdxthp89fwnguhrtkp0tlt8sjcen0lxtls357d9mv0rdy79xmufmvnf2d3e42s",
unconf_addr: "ex1pzpkn9msnj5hf5wt34mqh4l4ncfvvehln9lcg60xjak83kj0znd7qmfnsc7",
},
// Bare key, P2TR with one leaf
ConfidentialTest {
key: Key::Bare(ct_key.clone()),
descriptor: leaf,
descriptor_str: format!("ct({ct_key},eltr({nums},pk({key})))#ug7ku7uy"),
conf_addr: "lq1pq2nd3l90apnsrrssxkvzvpj8hrkjvqpm74aualy62d0akacxatm9l940lgxlw8ksnmsl0x7kmazr648t5y2js6cl9nchna5s9jdpd0azl2lt57872fd8",
unconf_addr: "ex1pj6hl5r0hrmgfac0hn0td73pa2n46z9fgdv0jeute76gzexskh73qzgwgq9",
},
// Bare key, P2TR with a script tree
ConfidentialTest {
key: Key::Bare(ct_key.clone()),
descriptor: tree,
descriptor_str: format!("ct({ct_key},eltr({nums},{{pk({key}),pk({nums})}}))#9h54dumz"),
conf_addr: "lq1pqtsl8ku9df0yrd7kh2ulz9wfrf7pdcfzh68sr9ge4dpxaphgjdxhuyrdxthp89fwnguhrtkp0tlt8sjcen0lxtls357d9mv0rdy79xmul76rz04xhhyn",
unconf_addr: "ex1pzpkn9msnj5hf5wt34mqh4l4ncfvvehln9lcg60xjak83kj0znd7qmfnsc7",
},
];

for test in &tests {
test.check(&secp);
}
}

#[test]
fn confidential_descriptor_tr_extension_leaf() {
let secp = secp256k1_zkp::Secp256k1::new();
let params = &elements::AddressParams::LIQUID;

let nums = "0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0";
let key = "03774eec7a3d550d18e9f89414152025b3b0ad6a342b19481f702d843cff06dfc4";
let mbk = slip77::MasterBlindingKey::from_seed(b"abcd");
let tr = format!("eltr({nums},and_v(v:pk({key}),is_exp_asset(out_asset(0))))");

let desc = Descriptor::<DefiniteDescriptorKey>::from_str(&format!("ct(slip77({mbk}),{tr})")).unwrap();
assert!(matches!(desc.descriptor, crate::Descriptor::TrExt(_)));
assert_eq!(desc.descriptor, crate::Descriptor::from_str(&tr).unwrap());
assert_eq!(desc.to_string(), format!("ct(slip77({mbk}),{tr})#plnzm78w"));
assert_eq!(
desc.address(&secp, params).unwrap().to_string(),
"lq1pqfwyv29crkpngrt59ks2xhn8hjjrf48hsmyxh0nqz0y0k2d8hvxtfwfh2j8wk6jd9vg50jpg9hupjyvc9wef38x4rh9hslvagxa99x8wj3ssh4wjccnd",
);
assert_eq!(
desc.unconfidential_address(params).unwrap().to_string(),
"ex1phym4frhtdfxjky28eq5zm7qezxvzhv5cnn23mjmc0kw5rwjjnrhq2rfk85",
);
}

#[test]
fn elip151_tr_script_tree() {
let secp = secp256k1_zkp::Secp256k1::new();
let params = &elements::AddressParams::LIQUID;

let nums = "0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0";
let key = "03774eec7a3d550d18e9f89414152025b3b0ad6a342b19481f702d843cff06dfc4";
let xpub = "xpub661MyMwAqRbcFkPHucMnrGNzDwb6teAX1RbKQmqtEF8kK3Z7LZ59qafCjB9eCRLiTVG3uxBxgKvRgbubRhqSKXnGGb1aoaqLrpMBDrVxga8";
let view_key = "8a378c768713d53492f27f16c8b0b7cc45af4ec27a9bae002c645cdec5b8208b";

let tree = format!("{{pk({xpub}/0/*),pk({key})}}");
let desc = Descriptor::<DescriptorPublicKey>::from_str(&format!("ct(elip151,eltr({nums},{tree}))")).unwrap();
assert_eq!(desc.key.to_string(), view_key);
assert_eq!(desc.to_string(), format!("ct({view_key},eltr({nums},{tree}))#u3auuy5d"));

let desc = desc.at_derivation_index(0).unwrap();
assert_eq!(
desc.address(&secp, params).unwrap().to_string(),
"lq1pq2r4jza4g5p0x9xxunnx745ysh8a6ec5guvg5sh8eastahc55ud5n5y0s9psnfuvqqtl4fce5j92z6k6ttpufwth93djx7465tr5fsnjhwgt8yrzraqc",
);
assert_eq!(
desc.unconfidential_address(params).unwrap().to_string(),
"ex1p6z8czscf57xqq9l65uv6fz4pdtd94s7yh9mjcker02a2936ycfeq07d7qw",
);
}
}
3 changes: 1 addition & 2 deletions src/descriptor/checksum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
use core::fmt;
use core::iter::FromIterator;

use bitcoin_miniscript::expression::check_valid_chars;

use crate::expression::check_valid_chars;
use crate::Error;

const INPUT_CHARSET: &str = "0123456789()[],'/*abcdefgh@:$%{}IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~ijklmnopqrstuvwxyzABCDEFGH`#\"\\ ";
Expand Down
52 changes: 33 additions & 19 deletions src/descriptor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1188,7 +1188,15 @@ impl_from_tree!(
("elsh", 1) => Descriptor::Sh(Sh::from_tree(top)?),
("elcovwsh", 2) => Descriptor::LegacyCSFSCov(LegacyCSFSCov::from_tree(top)?),
("elwsh", 1) => Descriptor::Wsh(Wsh::from_tree(top)?),
("eltr", _) => Descriptor::Tr(Tr::from_tree(top)?),
("eltr", _) => {
// A tree without extension fragments parses as `Descriptor::Tr`.
// Otherwise parse it again with the extension type `T`, and report
// the error from that attempt if it also fails.
match Tr::<Pk, NoExt>::from_tree(top) {
Ok(tr) => Descriptor::Tr(tr),
Err(_) => Descriptor::TrExt(Tr::<Pk, T>::from_tree(top)?),
}
}
_ => Descriptor::Bare(Bare::from_tree(top)?),
})
}
Expand All @@ -1204,24 +1212,9 @@ impl_from_str!(
"Not an Elements Descriptor",
)));
}
// tr tree parsing has special code
// Tr::from_str will check the checksum
// match "tr(" to handle more extensibly
let desc = if s.starts_with(&format!("{}tr", ELMTS_STR)) {
// First try parsing without extensions
match Tr::<Pk, NoExt>::from_str(s) {
Ok(tr) => Descriptor::Tr(tr),
Err(_) => {
// Try parsing with extensions
let tr = Tr::<Pk, T>::from_str(s)?;
Descriptor::TrExt(tr)
}
}
} else {
let desc_str = verify_checksum(s)?;
let top = expression::Tree::from_str(desc_str)?;
expression::FromTree::from_tree(&top)?
};
let desc_str = verify_checksum(s)?;
let top = expression::Tree::from_str(desc_str)?;
let desc: Descriptor<Pk, T> = expression::FromTree::from_tree(&top)?;

if desc.multipath_length_mismatch() {
return Err(Error::MultipathDescLenMismatch);
Expand Down Expand Up @@ -1748,6 +1741,27 @@ mod tests {
)
}

#[test]
fn tr_malformed_script_tree() {
for s in [
"eltr(A,)",
"eltr({pk(A),pk(B)})",
"eltr(A,{})",
"eltr(A,{pk(B)})",
"eltr(A,{pk(B),pk(C),pk(D)})",
"eltr(A,{pk(B)),pk(C)}",
"eltr(A,{pk(B),pk(C)}",
"eltr(A,{pk(B),pk(C)}))",
"eltr(A,{pk(B),pk(C)},pk(D))",
"eltr(A,and_v(v:pk(B),{pk(C),pk(D)}))",
"elwsh({pk(A),pk(B)})",
"elwsh(or_d(pk(A),{pk(B),pk(C)}))",
] {
assert!(Descriptor::<String>::from_str(s).is_err(), "{}", s);
assert!(Tr::<String>::from_str(s).is_err(), "{}", s);
}
}

#[test]
fn tr_script_pubkey() {
let key = Descriptor::<bitcoin::PublicKey>::from_str(
Expand Down
17 changes: 11 additions & 6 deletions src/descriptor/pegin/dynafed_pegin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ impl_from_tree!(
// TODO: Confirm with Andrew about the descriptor type for dynafed
// Assuming sh(wsh) for now.

let fed_desc = BtcDescriptor::<PublicKey>::from_tree(&ms_expr)?;
let fed_desc = BtcDescriptor::<PublicKey>::from_tree(ms_expr.root())?;
let elem_desc = Descriptor::<Pk, CovenantExt<CovExtArgs>>::from_tree(&top.args[1])?;
Ok(Pegin::new(fed_desc, elem_desc))
} else {
Expand Down Expand Up @@ -252,7 +252,9 @@ impl<Pk: MiniscriptKey> Pegin<Pk> {
.into_bytes();
let mut t = TranslateTweak(&claim_script[..], secp);

let tweaked_desc = bitcoin_miniscript::TranslatePk::translate_pk(&self.fed_desc, &mut t)
let tweaked_desc = self
.fed_desc
.translate_pk(&mut t)
.expect("Tweaking must succeed");

let res = tweaked_desc.get_satisfaction(satisfier)?;
Expand Down Expand Up @@ -303,7 +305,8 @@ fn bitcoin_witness_script<C: secp256k1_zkp::Verification, Pk: ToPublicKey>(
) -> Result<BtcScript, Error> {
let mut t = TranslateTweak(claim_script, secp);

let tweaked_desc = bitcoin_miniscript::TranslatePk::translate_pk(fed_desc, &mut t)
let tweaked_desc = fed_desc
.translate_pk(&mut t)
.expect("Tweaking must succeed");
Ok(tweaked_desc.explicit_script()?)
}
Expand All @@ -313,12 +316,14 @@ struct TranslateTweak<'a, 'b, C: secp256k1_zkp::Verification>(
&'b secp256k1_zkp::Secp256k1<C>,
);

impl<'a, 'b, Pk, C> bitcoin_miniscript::Translator<Pk, bitcoin::PublicKey, ()>
for TranslateTweak<'a, 'b, C>
impl<'a, 'b, Pk, C> bitcoin_miniscript::Translator<Pk> for TranslateTweak<'a, 'b, C>
where
Pk: MiniscriptKey + ToPublicKey,
C: secp256k1_zkp::Verification,
{
type TargetPk = bitcoin::PublicKey;
type Error = ();

fn pk(&mut self, pk: &Pk) -> Result<bitcoin::PublicKey, ()> {
Ok(tweak_key(&pk.to_public_key(), self.1, self.0))
}
Expand All @@ -342,7 +347,7 @@ mod tests {
type Segwitv0Script =
bitcoin_miniscript::Miniscript<bitcoin::PublicKey, bitcoin_miniscript::Segwitv0>;

let m = Segwitv0Script::parse(&s).unwrap();
let m = Segwitv0Script::decode(&s).unwrap();
assert_eq!(m.encode(), s);
BtcDescriptor::<_>::new_wsh(m).unwrap()
}
Expand Down
Loading
Loading