Skip to content

Commit 7c9542c

Browse files
committed
bip322: update proof handling for new bdk-bip322 API
1 parent 15b6f5b commit 7c9542c

File tree

6 files changed

+113
-0
lines changed

6 files changed

+113
-0
lines changed

.github/workflows/audit.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,17 @@ name: Audit
33
on:
44
push:
55
paths:
6+
# Run if workflow changes
7+
- '.github/workflows/audit.yml'
8+
# Run on changed dependencies
69
- '**/Cargo.toml'
710
- '**/Cargo.lock'
11+
# Run if the configuration file changes
12+
- '**/audit.toml'
813
schedule:
914
- cron: '0 0 * * 0' # Once per week
15+
# Run manually
16+
workflow_dispatch:
1017

1118
jobs:
1219

Cargo.lock

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ shlex = { version = "1.3.0", optional = true }
3636
payjoin = { version = "1.0.0-rc.1", features = ["v1", "v2", "io", "_test-utils"], optional = true}
3737
reqwest = { version = "0.12.23", default-features = false, optional = true }
3838
url = { version = "2.5.4", optional = true }
39+
bdk-bip322 = { git = "https://github.com/aagbotemi/bdk-bip322.git", branch = "master", optional = true }
3940

4041
[features]
4142
default = ["repl", "sqlite"]
@@ -55,6 +56,7 @@ rpc = ["bdk_bitcoind_rpc", "_payjoin-dependencies"]
5556

5657
# Internal features
5758
_payjoin-dependencies = ["payjoin", "reqwest", "url"]
59+
bip322 = ["bdk-bip322"]
5860

5961
# Use this to consensus verify transactions at sync time
6062
verify = []

src/commands.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,37 @@ pub enum OfflineWalletSubCommand {
405405
#[arg(env = "BASE64_PSBT", required = true)]
406406
psbt: Vec<String>,
407407
},
408+
/// Sign a message using BIP322
409+
#[cfg(feature = "bip322")]
410+
SignBip322 {
411+
/// The message to sign
412+
#[arg(long)]
413+
message: String,
414+
/// The signature format (e.g., Legacy, Simple, Full)
415+
#[arg(long, default_value = "simple")]
416+
signature_type: String,
417+
/// Address to sign
418+
#[arg(long)]
419+
address: String,
420+
// Optional list of specific UTXOs for proof-of-funds (only for `FullWithProofOfFunds`) #[arg(long)]
421+
utxos: Option<Vec<OutPoint>>,
422+
},
423+
/// Verify a BIP322 signature
424+
#[cfg(feature = "bip322")]
425+
VerifyBip322 {
426+
/// The signature proof to verify
427+
#[arg(long)]
428+
proof: String,
429+
/// The message that was signed
430+
#[arg(long)]
431+
message: String,
432+
/// The signature format (e.g., Legacy, Simple, Full)
433+
#[arg(long, default_value = "simple")]
434+
signature_type: String,
435+
/// The address associated with the signature
436+
#[arg(long)]
437+
address: String,
438+
},
408439
}
409440

410441
/// Wallet subcommands that needs a blockchain backend.

src/handlers.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ use std::str::FromStr;
6969
))]
7070
use std::sync::Arc;
7171

72+
#[cfg(feature = "bip322")]
73+
use crate::error::BDKCliError;
74+
#[cfg(feature = "bip322")]
75+
use bdk_bip322::{BIP322, Bip322Proof, Bip322VerificationResult};
76+
7277
#[cfg(any(
7378
feature = "electrum",
7479
feature = "esplora",
@@ -591,6 +596,46 @@ pub fn handle_offline_wallet_subcommand(
591596
&json!({ "psbt": BASE64_STANDARD.encode(final_psbt.serialize()) }),
592597
)?)
593598
}
599+
#[cfg(feature = "bip322")]
600+
SignBip322 {
601+
message,
602+
signature_type,
603+
address,
604+
utxos,
605+
} => {
606+
let address: Address = parse_address(&address)?;
607+
let signature_format = parse_signature_format(&signature_type)?;
608+
609+
let proof: Bip322Proof = wallet
610+
.sign_bip322(message.as_str(), signature_format, &address, utxos)
611+
.map_err(|e| {
612+
BDKCliError::Generic(format!("Failed to sign BIP-322 message: {e}"))
613+
})?;
614+
615+
Ok(json!({"proof": proof.to_base64()}).to_string())
616+
}
617+
#[cfg(feature = "bip322")]
618+
VerifyBip322 {
619+
proof,
620+
message,
621+
signature_type,
622+
address,
623+
} => {
624+
let address: Address = parse_address(&address)?;
625+
let signature_format = parse_signature_format(&signature_type)?;
626+
627+
let parsed_proof: Bip322Proof = Bip322Proof::from_base64(&proof)
628+
.map_err(|e| BDKCliError::Generic(format!("Invalid proof: {e}")))?;
629+
630+
let is_valid: Bip322VerificationResult =
631+
wallet.verify_bip322(&parsed_proof, &message, signature_format, &address)?;
632+
633+
Ok(json!({
634+
"valid": is_valid.valid,
635+
"proven_amount": is_valid.proven_amount.map(|a| a.to_sat()) // optional field
636+
})
637+
.to_string())
638+
}
594639
}
595640
}
596641

src/utils.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ use bdk_wallet::descriptor::Segwitv0;
5656
use bdk_wallet::keys::{GeneratableKey, GeneratedKey, bip39::WordCount};
5757
use serde_json::{Value, json};
5858

59+
#[cfg(feature = "bip322")]
60+
use bdk_bip322::SignatureFormat;
61+
5962
/// Parse the recipient (Address,Amount) argument from cli input.
6063
pub(crate) fn parse_recipient(s: &str) -> Result<(ScriptBuf, u64), String> {
6164
let parts: Vec<_> = s.split(':').collect();
@@ -95,6 +98,21 @@ pub(crate) fn parse_address(address_str: &str) -> Result<Address, Error> {
9598
Ok(unchecked_address.assume_checked())
9699
}
97100

101+
/// Function to parse the signature format from a string
102+
#[cfg(feature = "bip322")]
103+
pub(crate) fn parse_signature_format(format_str: &str) -> Result<SignatureFormat, Error> {
104+
match format_str.to_lowercase().as_str() {
105+
"legacy" => Ok(SignatureFormat::Legacy),
106+
"simple" => Ok(SignatureFormat::Simple),
107+
"full" => Ok(SignatureFormat::Full),
108+
"fullproofoffunds" => Ok(SignatureFormat::FullProofOfFunds),
109+
_ => Err(Error::Generic(
110+
"Invalid signature format. Use 'legacy', 'simple', 'full', or 'fullproofoffunds'"
111+
.to_string(),
112+
)),
113+
}
114+
}
115+
98116
/// Prepare bdk-cli home directory
99117
///
100118
/// This function is called to check if [`crate::CliOpts`] datadir is set.

0 commit comments

Comments
 (0)