commit e959a7a45578cd8815461d9a250bd3c0a782cad2
parent 94b9f89b75ff1925948a896476c91be2dbee310a
Author: Antoine A <>
Date: Fri, 12 Nov 2021 12:39:15 +0100
Optimize decode_segwit_msg
Diffstat:
| M | Cargo.lock | | | 49 | ------------------------------------------------- |
| M | Cargo.toml | | | 3 | --- |
| M | src/lib.rs | | | 72 | ++++++++++++++++++++++++++++-------------------------------------------- |
3 files changed, 28 insertions(+), 96 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -76,15 +76,6 @@ dependencies = [
]
[[package]]
-name = "bitcoin-bech32"
-version = "0.12.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "754eb4c7f35c031f33c95cc257b4c4192a5c9d3de637d3ee78ab052a3f35da57"
-dependencies = [
- "bech32",
-]
-
-[[package]]
name = "bitcoin_hashes"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -124,12 +115,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
-name = "bs58"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3"
-
-[[package]]
name = "bstr"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -304,26 +289,14 @@ version = "0.1.0"
dependencies = [
"argh",
"bech32",
- "bitcoin-bech32",
"bitcoincore-rpc",
- "bs58",
"criterion",
- "digest",
"fastrand",
"rand",
"rustyline",
]
[[package]]
-name = "digest"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
-dependencies = [
- "generic-array",
-]
-
-[[package]]
name = "dirs-next"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -387,16 +360,6 @@ dependencies = [
]
[[package]]
-name = "generic-array"
-version = "0.14.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
-dependencies = [
- "typenum",
- "version_check",
-]
-
-[[package]]
name = "getrandom"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -889,12 +852,6 @@ dependencies = [
]
[[package]]
-name = "typenum"
-version = "1.14.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec"
-
-[[package]]
name = "unicode-segmentation"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -919,12 +876,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372"
[[package]]
-name = "version_check"
-version = "0.9.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
-
-[[package]]
name = "walkdir"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
@@ -7,12 +7,9 @@ edition = "2021"
[dependencies]
bitcoincore-rpc = "0.14.0"
-bs58 = "0.4.0"
fastrand = "1.5.0"
-digest = "0.9.0"
argh = "0.1.6"
rustyline = "9.0.0"
-bitcoin-bech32 = "0.12.1"
bech32 = "0.8.1"
rand = { version = "0.8.4", features = ["getrandom"] }
diff --git a/src/lib.rs b/src/lib.rs
@@ -1,7 +1,4 @@
-use std::collections::BTreeMap;
-
-use bech32::{ToBase32, Variant};
-use bitcoin_bech32::{u5, WitnessProgram};
+use bech32::{u5, FromBase32, ToBase32, Variant};
use bitcoincore_rpc::bitcoin::Amount;
use rand::{rngs::OsRng, RngCore};
@@ -70,6 +67,7 @@ pub fn encode_segwit_msg(network: Network, msg: &[u8; 32]) -> [String; 2] {
#[derive(Debug, Clone)]
pub enum DecodeError {
+ TooManyAddress,
MissingSeqWitAddress,
MagicIdCollision,
}
@@ -79,58 +77,44 @@ pub fn decode_segwit_msg(segwit_addrs: &[impl AsRef<str>]) -> Result<[u8; 32], D
return Err(DecodeError::MissingSeqWitAddress);
}
- let decoded: Vec<[u8; 20]> = segwit_addrs
+ if segwit_addrs.len() > 4 {
+ return Err(DecodeError::TooManyAddress);
+ }
+
+ // Extract parts from every addresses
+ let decoded: Vec<(bool, [u8; 4], [u8; 16])> = segwit_addrs
.into_iter()
.filter_map(|addr| {
- WitnessProgram::from_address(addr.as_ref())
- .ok()
- .and_then(|wp| {
- let pg = wp.program();
- if pg.len() == 20 {
- let mut buf = [0; 20];
- buf.copy_from_slice(pg);
- Some(buf)
- } else {
- None
- }
- })
+ bech32::decode(addr.as_ref()).ok().and_then(|(_, wp, _)| {
+ // Skip version
+ let pg: Vec<u8> = Vec::from_base32(&wp[1..]).unwrap();
+ if pg.len() == 20 {
+ let mut magic_id: [u8; 4] = pg[..4].try_into().unwrap();
+ let key_half: [u8; 16] = pg[4..].try_into().unwrap();
+ let is_first = !pg[0] & 0b1000_0000 == 0;
+ // Clear first bit
+ magic_id[0] &= 0b0111_1111;
+ Some((is_first, magic_id, key_half))
+ } else {
+ None
+ }
+ })
})
.collect();
if decoded.len() < 2 {
return Err(DecodeError::MissingSeqWitAddress);
}
-
- let mut parts: Vec<(bool, [u8; 4], &[u8; 16])> = decoded
+ // Keep only the addresses with duplicated magic id
+ let matches: Vec<&(bool, [u8; 4], [u8; 16])> = decoded
.iter()
- .map(|c| {
- let mut magic_id: [u8; 4] = c[..4].try_into().unwrap();
- let key_half: &[u8; 16] = c[4..].try_into().unwrap();
- let is_first = !c[0] & 0b1000_0000 == 0;
- // Clear first bit
- magic_id[0] &= 0b0111_1111;
- (is_first, magic_id, key_half)
- })
+ .filter(|(_, magic, _)| decoded.iter().filter(|(_, other, _)| other == magic).count() > 1)
.collect();
- let mut map = BTreeMap::new();
-
- for (_, magic, _) in &parts {
- match map.get_mut(magic) {
- Some(prev) => *prev = true,
- None => {
- map.insert(*magic, false);
- }
- }
- }
- map.retain(|_, many| *many);
- assert_eq!(map.len(), 1, "Two possible magic id");
- let magic_id = map.into_keys().next().unwrap();
- parts.retain(|(_, magic, _)| *magic == magic_id);
- assert_eq!(parts.len(), 2, "Magic ID collision");
+ assert_eq!(matches.len(), 2, "Magic ID collision");
let mut key = [0; 32];
- for (is_first, _, half) in parts {
- key[is_first as usize * 16..][..16].copy_from_slice(half);
+ for (is_first, _, half) in matches {
+ key[*is_first as usize * 16..][..16].copy_from_slice(half);
}
Ok(key)
}