Skip to content

Feature/bip322 integration #179

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
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
17 changes: 14 additions & 3 deletions .github/workflows/audit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,28 @@ name: Audit
on:
push:
paths:
# Run if workflow changes
- '.github/workflows/audit.yml'
# Run on changed dependencies
- '**/Cargo.toml'
- '**/Cargo.lock'
# Run if the configuration file changes
- '**/audit.toml'
schedule:
- cron: '0 0 * * 0' # Once per week
# Run manually
workflow_dispatch:

jobs:

security_audit:
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
permissions:
contents: read
issues: write
steps:
- uses: actions/checkout@v4
- uses: actions-rust-lang/audit@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
persist-credentials: false
- uses: actions-rust-lang/audit@v1
name: Audit Rust Dependencies
7 changes: 5 additions & 2 deletions .github/workflows/code_coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ jobs:
runs-on: ubuntu-latest
env:
CARGO_INCREMENTAL: '0'
RUSTFLAGS: '-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off'
RUSTDOCFLAGS: '-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off'
RUSTFLAGS: '-Cinstrument-coverage -Ccodegen-units=1 -Cllvm-args=--inline-threshold=0 -Clink-dead-code -Coverflow-checks=off'
RUSTDOCFLAGS: '-Cinstrument-coverage -Ccodegen-units=1 -Cllvm-args=--inline-threshold=0 -Clink-dead-code -Coverflow-checks=off'

steps:
- name: Checkout
Expand Down Expand Up @@ -42,6 +42,9 @@ jobs:
- name: Test RPC
run: cargo test --features rpc

- name: Test Bip322
run: cargo test --features bip322

- id: coverage
name: Generate coverage
uses: actions-rs/[email protected]
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Changelog info is also documented on the [GitHub releases](https://github.com/bi
page. See [DEVELOPMENT_CYCLE.md](DEVELOPMENT_CYCLE.md) for more details.

## [Unreleased]
- Add support for generic BIP-322 signed message formats.

## [0.27.1]
- Added hardware signers through the use of HWI.
Expand Down
35 changes: 33 additions & 2 deletions Cargo.lock

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

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,19 @@ log = "0.4"
serde_json = "1.0"
thiserror = "2.0.11"
tokio = { version = "1", features = ["full"] }
bdk-bip322 = { git = "https://github.com/aagbotemi/bdk-bip322.git", branch = "master", optional = true }

# Optional dependencies
bdk_bitcoind_rpc = { version = "0.18.0", optional = true }
bdk_electrum = { version = "0.21.0", optional = true }
bdk_esplora = { version = "0.20.1", features = ["async-https", "tokio"], optional = true }
bdk_kyoto = { version = "0.7.1", optional = true }
shlex = { version = "1.3.0", optional = true }
rpassword = "7.4.0"

[features]
default = ["repl", "sqlite"]
bip322 = ["dep:bdk-bip322"]

# To use the app in a REPL mode
repl = ["shlex"]
Expand Down
143 changes: 143 additions & 0 deletions bip322_usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# Testing the Bip322 Subcommand

Ensure you are in a secure environment to prevent key exposure.

To build, run `cargo build --features bip322`
For testing purposes only, use `L3VFeEujGtevx9w18HD1fhRbCH67Az2dpCymeRE1SoPK6XQtaN2k` for private key.

## Signing and Verifying with Different Address Types
1. **Signing and Verifying with Simple**
- Sign a Message(Non-Interactive with `--key_file`):
```bash
./target/debug/bdk-cli bip322 sign \
--key_file /path/to/private_key.txt \
--message "Hello World" \
--address bc1q9vza2e8x573nczrlzms0wvx3gsqjx7vavgkx0l \
--signature_type simple
```

- The file `/path/to/private_key.txt` should contain the WIF private key (e.g., `L3VFeEujGtevx9w18HD1fhRbCH67Az2dpCymeRE1SoPK6XQtaN2k`).


- Sign a Message(Interactive):
```bash
./target/debug/bdk-cli bip322 sign \
--message "Hello World" \
--address bc1q9vza2e8x573nczrlzms0wvx3gsqjx7vavgkx0l \
--signature_type simple
```

- When running this command, the tool will prompt:
```bash
Enter WIF private key:
```
- Enter the WIF private key (e.g., `L3VFeEujGtevx9w18HD1fhRbCH67Az2dpCymeRE1SoPK6XQtaN2k`). The input will not be displayed on the console for security.

- Expected Output:
```json
{
"signature": "AkgwRQIhAOzyynlqt93lOKJr+wmmxIens//zPzl9tqIOua93wO6MAiBi5n5EyAcPScOjf1lAqIUIQtr3zKNeavYabHyR8eGhowEhAsfxIAMZZEKUPYWI4BruhAQjzFT8FSFSajuFwrDL1Yhy"
}
```
- Verify the Signature:
```bash
./target/debug/bdk-cli bip322 verify \
--signature "AkgwRQIhAOzyynlqt93lOKJr+wmmxIens//zPzl9tqIOua93wO6MAiBi5n5EyAcPScOjf1lAqIUIQtr3zKNeavYabHyR8eGhowEhAsfxIAMZZEKUPYWI4BruhAQjzFT8FSFSajuFwrDL1Yhy" \
--message "Hello World" \
--address bc1q9vza2e8x573nczrlzms0wvx3gsqjx7vavgkx0l \
--signature_type simple
```

- No private key is required for verifying the `simple` signature type.

- Expected Output:
```json
{
"is_valid": true
}
```

2. **Signing and Verifying with Legacy**
- Sign a Message(Non-Interactive with `--key_file`):
```bash
./target/debug/bdk-cli bip322 sign \
--key_file /path/to/private_key.txt \
--message "Hello World" \
--address 14vV3aCHBeStb5bkenkNHbe2YAFinYdXgc \
--signature_type legacy
```
- The file `/path/to/private_key.txt` should contain the WIF private key (e.g., `L3VFeEujGtevx9w18HD1fhRbCH67Az2dpCymeRE1SoPK6XQtaN2k`).

- Sign a Message (Interactive):
```bash
./target/debug/bdk-cli bip322 sign \
--message "Hello World" \
--address 14vV3aCHBeStb5bkenkNHbe2YAFinYdXgc \
--signature_type legacy
```

- When running this command, the tool will prompt:
```bash
Enter WIF private key:
```
- Enter the WIF private key (e.g., `L3VFeEujGtevx9w18HD1fhRbCH67Az2dpCymeRE1SoPK6XQtaN2k`). The input will not be displayed on the console for security.


- Expected Output:
```json
{
"signature": "MEUCIQDltsYvnmyS3gba+u+JeEB++nag6FYy1fNEfRBShUF+awIgBrlCXPIZaYs8Yuayg0ZqjyiCbLy9pzZIS7JWT65/nsUB"
}
```
- Verify the Signature (Non-Interactive with `--key_file`):
```bash
./target/debug/bdk-cli bip322 verify \
--signature "MEUCIQDltsYvnmyS3gba+u+JeEB++nag6FYy1fNEfRBShUF+awIgBrlCXPIZaYs8Yuayg0ZqjyiCbLy9pzZIS7JWT65/nsUB" \
--message "Hello World" \
--address 14vV3aCHBeStb5bkenkNHbe2YAFinYdXgc \
--signature_type legacy \
--key_file /path/to/private_key.txt
```

- The file /path/to/private_key.txt must contain the WIF private key used for signing.

- Verify the Signature (Interactive):
```bash
./target/debug/bdk-cli bip322 verify \
--signature "MEUCIQDltsYvnmyS3gba+u+JeEB++nag6FYy1fNEfRBShUF+awIgBrlCXPIZaYs8Yuayg0ZqjyiCbLy9pzZIS7JWT65/nsUB" \
--message "Hello World" \
--address 14vV3aCHBeStb5bkenkNHbe2YAFinYdXgc \
--signature_type legacy
```
- When running this command, the tool will prompt:
```bash
Enter WIF private key:
```
- Enter the WIF private key used for signing.

- Expected Output:
```json
{
"is_valid": true
}
```

3. Signing and Verifying with Full
- Sign a Message (Non-Interactive with `--key_file`):
Same way with Simple, only change the signature type to full

- Sign a Message (Interactive):
Same way with Simple, only change the signature type to full

- Verify the Signature:
Use the signature from the above command in a similar verify command.

## Notes for Testing
- **Security**: Always handle private keys securely. Use the `--key_file` option or the interactive prompt to avoid exposing keys in command-line arguments or insecure environments. For production use, consider using the `wallet` subcommand for secure key generation.

- **Error Handling:** If the signature type, address, or private key is invalid, the CLI will return an error message. Test with invalid inputs (e.g., an empty `--key_file` or invalid WIF key) to ensure proper error handling.

- **Interactive Mode:** When not providing `--key_file`, the tool will prompt for the private key. The input is not echoed to the console for security. If an empty input is provided, an error will be returned.

- **Legacy Verification:** For the `legacy` signature type, a private key is required during verification. Ensure the same key used for signing is provided via `--key_file` or interactively.

55 changes: 55 additions & 0 deletions src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,61 @@ pub enum CliSubCommand {
#[command(flatten)]
wallet_opts: WalletOpts,
},
/// BIP322 message signing and verification operations.
///
/// This subcommand allows for standalone signing and verification of messages using the BIP322
/// standard, without requiring a full wallet setup. It is useful for simple use cases or testing.
///
/// Available operations:
/// - `sign`: Sign a message using a private key in WIF format.
/// - `verify`: Verify a BIP322 signature for a given message and address.
///
/// **Security Note**: This subcommand requires direct handling of private keys. Ensure you are in a
/// secure environment to prevent key exposure. For generating keys securely, consider using the `wallet`
/// subcommand instead.
#[cfg(any(feature = "bip322"))]
Bip322 {
#[command(subcommand)]
subcommand: Bip322SubCommand,
},
}

#[derive(Debug, Subcommand, Clone, PartialEq)]
#[command(rename_all = "snake")]
pub enum Bip322SubCommand {
/// Sign a message using BIP322
Sign {
/// Path to a file containing the private key in WIF format. If not provided, you will be prompted to enter the key securely.
#[arg(long)]
key_file: Option<String>,
/// Address to sign
#[arg(long)]
address: String,
/// The message to sign
#[arg(long)]
message: String,
/// The signature format (e.g., Legacy, Simple, Full)
#[arg(long, default_value = "simple")]
signature_type: String,
},
/// Verify a BIP322 signature
Verify {
/// The address associated with the signature
#[arg(long)]
address: String,
/// Base64-encoded signature
#[arg(long)]
signature: String,
/// The message that was signed
#[arg(long)]
message: String,
/// The signature format (e.g., Legacy, Simple, Full)
#[arg(long, default_value = "simple")]
signature_type: String,
/// Path to a file containing the private key in WIF format. If not provided, you will be prompted to enter the key securely.
#[arg(long)]
key_file: Option<String>,
},
}

/// Wallet operation subcommands.
Expand Down
4 changes: 4 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,8 @@ pub enum BDKCliError {
#[cfg(feature = "rpc")]
#[error("RPC error: {0}")]
BitcoinCoreRpcError(#[from] bdk_bitcoind_rpc::bitcoincore_rpc::Error),

#[error("BIP322 error: {0}")]
#[cfg(any(feature = "bip322"))]
BIP322Error(#[from] bdk_bip322::Error),
}
Loading
Loading