Skip to content

Commit

Permalink
Add segwit key derivation as a feature (#447)
Browse files Browse the repository at this point in the history
* Add segwit key derivation as a feature

* Segwit build script

* Fix descriptor

* Fix descriptor syntax

* Fix xpub

* Undo package rename
  • Loading branch information
cryptoquick authored Jan 16, 2024
1 parent 6d751d6 commit ba71951
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 8 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ required-features = ["server"]
all = []
default = []
web = []
segwit = []
server = ["tokio/full", "tower-http/cors"]

[dependencies]
Expand Down
10 changes: 10 additions & 0 deletions build-segwit.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/sh
wasm-pack build --release --target web --features segwit
cp pkg/*.ts lib/web
cp pkg/*.js lib/web
cp pkg/*.wasm lib/web
cp pkg/README.md lib/web
cp pkg/LICENSE* lib/web
cd lib/web
npm install
npm run prepare
4 changes: 2 additions & 2 deletions lib/web/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions lib/web/yarn.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


"@types/node@^20.8.2":
version "20.11.0"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.0.tgz#8e0b99e70c0c1ade1a86c4a282f7b7ef87c9552f"
integrity sha512-o9bjXmDNcF7GbM4CNQpmi+TutCgap/K3w1JyKgxAjqx41zp9qlIAVFi0IhCNsJcXolEqLWhbFbEeL0PvYm4pcQ==
dependencies:
undici-types "~5.26.4"

typescript@^5.2.2:
version "5.3.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.3.tgz#b3ce6ba258e72e6305ba66f5c9b452aaee3ffe37"
integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==

undici-types@~5.26.4:
version "5.26.5"
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
34 changes: 29 additions & 5 deletions src/bitcoin/keys.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
use std::str::FromStr;

#[cfg(feature = "segwit")]
use bdk::miniscript::Segwitv0;
#[cfg(not(feature = "segwit"))]
use bdk::miniscript::Tap;
use bdk::{
bitcoin::{
secp256k1::Secp256k1,
util::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey, ExtendedPubKey, KeySource},
},
keys::{DerivableKey, DescriptorKey, DescriptorKey::Secret as SecretDesc, DescriptorSecretKey},
miniscript::{descriptor::DescriptorKeyParseError, Tap},
miniscript::descriptor::DescriptorKeyParseError,
};
use bip39::{Language, Mnemonic};
use bitcoin::{KeyPair, Network};
Expand Down Expand Up @@ -70,10 +74,16 @@ fn get_descriptor(
let deriv_descriptor = DerivationPath::from_str(path)?;
let derived_xprv = &xprv.derive_priv(&secp, &deriv_descriptor)?;
let origin: KeySource = (xprv.fingerprint(&secp), deriv_descriptor);
#[cfg(not(feature = "segwit"))]
let derived_xprv_desc_key: DescriptorKey<Tap> = derived_xprv.into_descriptor_key(
Some(origin),
DerivationPath::default().child(ChildNumber::from_normal_idx(change)?),
)?;
#[cfg(feature = "segwit")]
let derived_xprv_desc_key: DescriptorKey<Segwitv0> = derived_xprv.into_descriptor_key(
Some(origin),
DerivationPath::default().child(ChildNumber::from_normal_idx(change)?),
)?;

if let SecretDesc(desc_seckey, _, _) = derived_xprv_desc_key {
Ok(desc_seckey)
Expand All @@ -85,15 +95,25 @@ fn get_descriptor(
fn xprv_desc(xprv: &ExtendedPrivKey, path: &str, change: u32) -> Result<String, BitcoinKeysError> {
let xprv = get_descriptor(xprv, path, change)?;

Ok(format!("tr({xprv})"))
#[cfg(not(feature = "segwit"))]
let desc = format!("tr({xprv})");
#[cfg(feature = "segwit")]
let desc = format!("wpkh({xprv})");

Ok(desc)
}

fn xpub_desc(xprv: &ExtendedPrivKey, path: &str, change: u32) -> Result<String, BitcoinKeysError> {
let secp = Secp256k1::new();
let xprv = get_descriptor(xprv, path, change)?;
let xpub = xprv.to_public(&secp)?;

Ok(format!("tr({xpub})"))
#[cfg(not(feature = "segwit"))]
let desc = format!("tr({xpub})");
#[cfg(feature = "segwit")]
let desc = format!("wpkh({xpub})");

Ok(desc)
}

fn watcher_xpub(
Expand Down Expand Up @@ -235,7 +255,11 @@ pub async fn get_marketplace_descriptor() -> Result<Option<SecretString>, Bitcoi
};

let desc_xpub = DescriptorPublicKey::XPub(desc).to_string();
let tap = format!("tr({desc_xpub}/*)");

Ok(Some(SecretString(tap)))
#[cfg(not(feature = "segwit"))]
let desc_str = format!("tr({desc_xpub}/*)");
#[cfg(feature = "segwit")]
let desc_str = format!("wpkh({desc_xpub}/*)");

Ok(Some(SecretString(desc_str)))
}
7 changes: 7 additions & 0 deletions src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,15 @@ pub async fn get_udas_utxo() -> String {
}

// Descriptor strings
#[cfg(not(feature = "segwit"))]
pub const BTC_MAINNET_PATH: &str = "m/86h/0h/0h";
#[cfg(not(feature = "segwit"))]
pub const BTC_TESTNET_PATH: &str = "m/86h/1h/0h";
#[cfg(feature = "segwit")]
pub const BTC_MAINNET_PATH: &str = "m/84h/0h/0h";
#[cfg(feature = "segwit")]
pub const BTC_TESTNET_PATH: &str = "m/84h/1h/0h";

pub static BTC_PATH: Lazy<RwLock<String>> = Lazy::new(|| {
RwLock::new(if dot_env("BITCOIN_NETWORK") == "bitcoin" {
BTC_MAINNET_PATH.to_owned()
Expand Down

0 comments on commit ba71951

Please sign in to comment.