Skip to content

Commit 47eee43

Browse files
committed
f add FromStr impl
1 parent f59da14 commit 47eee43

File tree

5 files changed

+69
-4
lines changed

5 files changed

+69
-4
lines changed

fuzz/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ elements-miniscript = { path = "..", features = ["compiler"] }
2121
[workspace]
2222
members = ["."]
2323

24+
[[bin]]
25+
name = "roundtrip_confidential"
26+
path = "fuzz_targets/roundtrip_confidential.rs"
27+
2428
[[bin]]
2529
name = "roundtrip_descriptor"
2630
path = "fuzz_targets/roundtrip_descriptor.rs"

src/confidential/mod.rs

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
pub mod hash_to_private;
2121
pub mod slip77;
2222

23-
use crate::{Error, MiniscriptKey, ToPublicKey};
23+
use crate::descriptor::checksum::verify_checksum;
24+
use crate::{expression, Error, MiniscriptKey, ToPublicKey};
25+
use crate::expression::FromTree;
2426
use elements::hashes::hex;
2527
use elements::secp256k1_zkp;
2628
use crate::extensions::{CovenantExt, CovExtArgs, Extension, ParseableExt};
@@ -39,7 +41,7 @@ pub enum Key<Pk: MiniscriptKey> {
3941
Bare(Pk),
4042
}
4143

42-
impl<Pk: MiniscriptKey + fmt::Display> fmt::Display for Key<Pk> {
44+
impl<Pk: MiniscriptKey> fmt::Display for Key<Pk> {
4345
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4446
match *self {
4547
Key::HashToPrivate(ref keys) => {
@@ -115,6 +117,48 @@ impl<Pk: MiniscriptKey + ToPublicKey, T: Extension + ParseableExt> Descriptor<Pk
115117
}
116118
}
117119

120+
impl<Pk: MiniscriptKey, T: Extension> fmt::Display for Descriptor<Pk, T> {
121+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122+
write!(f, "ct({},{})", self.key, self.descriptor)
123+
}
124+
}
125+
126+
impl_from_str!(
127+
;T; Extension,
128+
Descriptor<Pk, T>,
129+
type Err = Error;,
130+
fn from_str(s: &str) -> Result<Descriptor<Pk, T>, Error> {
131+
let desc_str = verify_checksum(s)?;
132+
let top = expression::Tree::from_str(desc_str)?;
133+
134+
if top.name != "ct" {
135+
return Err(Error::BadDescriptor(String::from(
136+
"Not a CT Descriptor",
137+
)));
138+
}
139+
if top.args.len() != 2 {
140+
return Err(Error::BadDescriptor(
141+
format!("CT descriptor had {} arguments rather than 2", top.args.len())
142+
));
143+
}
144+
145+
let keyexpr = &top.args[0];
146+
Ok(Descriptor {
147+
key: match (keyexpr.name, keyexpr.args.len()) {
148+
("slip77", 1) => Key::Slip77(expression::terminal(&keyexpr.args[0], hex::FromHex::from_hex)?),
149+
("hash_to_private", 0) => return Err(Error::BadDescriptor(
150+
format!("hash_to_private must have a nonzero number of keys")
151+
)),
152+
("hash_to_private", _) => Key::HashToPrivate(
153+
keyexpr.args.iter().map(|arg| expression::terminal(arg, Pk::from_str)).collect::<Result<Vec<_>, _>>()?
154+
),
155+
_ => Key::Bare(expression::terminal(&keyexpr, Pk::from_str)?),
156+
},
157+
descriptor: crate::Descriptor::from_tree(&top.args[1])?,
158+
})
159+
}
160+
);
161+
118162
#[cfg(test)]
119163
mod tests {
120164
use super::*;
@@ -196,12 +240,24 @@ mod tests {
196240
desc.address(&secp, &elements::AddressParams::ELEMENTS).unwrap().to_string(),
197241
"el1qq2rr0dcmn6mfvcf7x486z3djs7j283arxspjj6adzgjsjxsa5r0v2rmqvvk2ce5ksnxcs9ecgtnryt7xg34068lggvfp79zus",
198242
);
243+
assert_eq!(
244+
desc.to_string(),
245+
"ct(hash_to_private(02fb7a8c3b2fc3e42095b51d8c28e37f15ec3da8f84ec7d51cbbc83abd39eec2d6,03d5614e0f8983f8d1bed90299e8cb40b1f0fd61d36d7e2958682cca625d14d744,03cb8d2ef4aaf7be6a9bb80afe798e6cf72fd102b46c44f81c31593ae62a3c7de8,032ea1c87f4023d48ad3a30acf1ac63b6d8a876b880c0ddc9a4163ab6a25f28a2b,03d38adcd566db859f59ba28cc6cba54e9c9ae5399b875034e6038f1e22fe3f2ff,02729d8336d93c59ab20edb4cf7589ff5dbc159d2e239e80d0db01ddd22b994f0b,02fde5e64596d934e0d560afff13d7f9732b3751555f836c5093ee69d4fa3d836f,029f00e038dbc4ecd875d5170feff8f56ae7e0c0a90467454d78a4212e1964194d,0247c0c61ad7b6671c4ea9b277bffb0b27412ae2d2795cccadb405b152a67ff250,03e8485a732bced45ad81ac259d9889459a0c6128a16b6782cc68edfa43fea2783,02412e2ba495c3f52f80a6db41524079f293ae2d47f6a239550879b0430b3c0e0e,023569dac5cefeac572481ad6eb1205c59a774236352c2a34a6f04c9597ea5218f,02bb22f63397b818ac12f43a47446333cbc3da79427469257561801f0bdd0d8342,03fbff1f52bb55262c83a66873433e8408eec5f06a24f33eb2f2eab146e47c7d2a,02253adb8820f73fdeec7a3472baddde79795d7792f4fb6d748b8b33bda9d30449,03517fb63ed0136223d9b2239ce2594a78b7ad4adf3194dbfe94cd30047d2d868e,02be9a86606e90a1cc3a97393a295ee9661e943e7585519266d230b31cf8b1812c,034e93eb5054ab504205855ddafb4bfe1e0deacc51929c784c0b2f9b11123ec2e2,0212d3048099d52ee4b8153f75623fc7153788f659e8c1df21ac2e6ff21561cb10),elwpkh(03774eec7a3d550d18e9f89414152025b3b0ad6a342b19481f702d843cff06dfc4)#pmkay5r6)",
246+
);
199247
// Same address with sorted blinding keys (should be the same)
200248
desc.key = Key::HashToPrivate(sorted_keys);
201249
assert_eq!(
202250
desc.address(&secp, &elements::AddressParams::ELEMENTS).unwrap().to_string(),
203251
"el1qq2rr0dcmn6mfvcf7x486z3djs7j283arxspjj6adzgjsjxsa5r0v2rmqvvk2ce5ksnxcs9ecgtnryt7xg34068lggvfp79zus",
204252
);
253+
// but notice that when serializing as a string, the key order has changed
254+
// FIXME: is this the correct behavior? (i vote yes, so string round-tripping works)
255+
// FIXME: should equality use the sorted order? (i vote no because it's hard to do)
256+
// FIXME: should the answer to either of these be in the spec? (yeah, probably)
257+
assert_eq!(
258+
desc.to_string(),
259+
"ct(hash_to_private(0212d3048099d52ee4b8153f75623fc7153788f659e8c1df21ac2e6ff21561cb10,02253adb8820f73fdeec7a3472baddde79795d7792f4fb6d748b8b33bda9d30449,023569dac5cefeac572481ad6eb1205c59a774236352c2a34a6f04c9597ea5218f,02412e2ba495c3f52f80a6db41524079f293ae2d47f6a239550879b0430b3c0e0e,0247c0c61ad7b6671c4ea9b277bffb0b27412ae2d2795cccadb405b152a67ff250,02729d8336d93c59ab20edb4cf7589ff5dbc159d2e239e80d0db01ddd22b994f0b,029f00e038dbc4ecd875d5170feff8f56ae7e0c0a90467454d78a4212e1964194d,02bb22f63397b818ac12f43a47446333cbc3da79427469257561801f0bdd0d8342,02be9a86606e90a1cc3a97393a295ee9661e943e7585519266d230b31cf8b1812c,02fb7a8c3b2fc3e42095b51d8c28e37f15ec3da8f84ec7d51cbbc83abd39eec2d6,02fde5e64596d934e0d560afff13d7f9732b3751555f836c5093ee69d4fa3d836f,032ea1c87f4023d48ad3a30acf1ac63b6d8a876b880c0ddc9a4163ab6a25f28a2b,034e93eb5054ab504205855ddafb4bfe1e0deacc51929c784c0b2f9b11123ec2e2,03517fb63ed0136223d9b2239ce2594a78b7ad4adf3194dbfe94cd30047d2d868e,03cb8d2ef4aaf7be6a9bb80afe798e6cf72fd102b46c44f81c31593ae62a3c7de8,03d38adcd566db859f59ba28cc6cba54e9c9ae5399b875034e6038f1e22fe3f2ff,03d5614e0f8983f8d1bed90299e8cb40b1f0fd61d36d7e2958682cca625d14d744,03e8485a732bced45ad81ac259d9889459a0c6128a16b6782cc68edfa43fea2783,03fbff1f52bb55262c83a66873433e8408eec5f06a24f33eb2f2eab146e47c7d2a),elwpkh(03774eec7a3d550d18e9f89414152025b3b0ad6a342b19481f702d843cff06dfc4)#pmkay5r6)",
260+
);
205261

206262
// P2PKH address
207263
desc.descriptor = crate::Descriptor::new_pkh(spk_key.clone());

src/confidential/slip77.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ impl hex::FromHex for MasterBlindingKey {
8989
}
9090
}
9191

92+
impl std::str::FromStr for MasterBlindingKey {
93+
type Err = hex::Error;
94+
fn from_str(s: &str) -> Result<Self, Self::Err> { hex::FromHex::from_hex(s) }
95+
}
96+
9297
#[cfg(test)]
9398
mod tests {
9499
use super::*;

src/descriptor/checksum.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ pub fn desc_checksum(desc: &str) -> Result<String, Error> {
4848
/// descriptor types. Checks and verifies the checksum
4949
/// if it is present and returns the descriptor string
5050
/// without the checksum
51-
pub(super) fn verify_checksum(s: &str) -> Result<&str, Error> {
51+
pub(crate) fn verify_checksum(s: &str) -> Result<&str, Error> {
5252
for ch in s.as_bytes() {
5353
if *ch < 20 || *ch > 127 {
5454
return Err(Error::Unprintable(*ch));

src/descriptor/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ pub use self::bare::{Bare, Pkh};
5757
pub use self::segwitv0::{Wpkh, Wsh, WshInner};
5858
pub use self::sh::{Sh, ShInner};
5959
pub use self::sortedmulti::SortedMultiVec;
60-
mod checksum;
60+
pub(crate) mod checksum;
6161
mod key;
6262
pub use self::csfs_cov::{CovError, CovOperations, LegacyCSFSCov, LegacyCovSatisfier};
6363
pub use self::key::{

0 commit comments

Comments
 (0)