Skip to content

Commit

Permalink
Add jade
Browse files Browse the repository at this point in the history
  • Loading branch information
edouardparis committed Mar 8, 2024
1 parent 51aea7c commit b55b2ea
Show file tree
Hide file tree
Showing 11 changed files with 685 additions and 61 deletions.
16 changes: 11 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ authors.workspace = true
repository.workspace = true

[features]
default = ["ledger", "specter", "coldcard", "bitbox"]
default = ["ledger", "specter", "coldcard", "bitbox", "jade"]
bitbox = ["tokio", "hidapi", "bitbox-api", "regex"]
coldcard = ["dep:coldcard", "regex"]
specter = ["tokio", "tokio-serial", "serialport"]
jade = ["tokio", "tokio-serial", "serde", "serde_cbor", "serialport", "reqwest"]
ledger = ["regex", "tokio", "ledger_bitcoin_client", "ledger-transport-hidapi", "ledger-apdu", "hidapi"]
regex = ["dep:regex"]

Expand All @@ -31,22 +32,27 @@ async-trait = "0.1.52"
futures = "0.3"
bitcoin = { version = "0.31", default-features = false, features = ["base64", "serde", "std"] }

# specter
# specter & jade
tokio-serial = { version = "5.4.1", optional = true }
serialport = { version = "4.2", optional = true }

#bitbox
# jade
serde = { version = "1.0", features = ["derive"], optional = true }
serde_cbor = { version = "0.11", optional = true }
reqwest = { version = "0.11", default-features = false, features = ["json", "rustls-tls"] , optional = true}

# bitbox
bitbox-api = { version = "0.2.3", default-features = false, features = ["usb", "tokio", "multithreaded"], optional = true }

#coldcard
# coldcard
coldcard = { version = "0.12.1", optional = true }

# ledger
ledger_bitcoin_client = { version = "0.4.0", optional = true }
ledger-apdu = { version = "0.10", optional = true }
ledger-transport-hidapi = { version = "0.10.0", optional = true }

#bitbox & ledger
# bitbox & ledger
hidapi = { version = "2.4.1", features = ["linux-static-hidraw"], default-features = false, optional = true }
regex = { version = "1.6.0", optional = true }

Expand Down
2 changes: 1 addition & 1 deletion cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ path = "src/bin/hwi.rs"
clap = { version = "4.4.7", features = ["derive"] }
bitcoin = "0.31"
hex = "0.4"
async-hwi = "0.0.14"
async-hwi = { path = ".." }
tokio = { version = "1", features = ["macros", "net", "rt", "rt-multi-thread", "io-util", "sync"] }
2 changes: 1 addition & 1 deletion cli/src/bin/hwi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
}
Commands::Device(DeviceCommands::List) => {
for device in command::list(args.network, None).await? {
eprint!("{}", device.get_master_fingerprint().await?,);
eprint!("{}", device.get_master_fingerprint().await?);
eprint!(" {}", device.device_kind());
if let Ok(version) = device.get_version().await.map(|v| v.to_string()) {
eprint!(" {}", version);
Expand Down
18 changes: 18 additions & 0 deletions cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub mod command {
use async_hwi::{
bitbox::{api::runtime, BitBox02, PairingBitbox02WithLocalCache},
coldcard,
jade::{self, Jade},
ledger::{HidApi, Ledger, LedgerSimulator, TransportHID},
specter::{Specter, SpecterSimulator},
HWI,
Expand Down Expand Up @@ -31,6 +32,23 @@ pub mod command {
}
}

match Jade::enumerate().await {
Err(e) => println!("{:?}", e),
Ok(devices) => {
for device in devices {
if let Ok(info) = device.get_info().await {
if info.jade_state == jade::api::JadeState::Locked {
if let Err(e) = device.auth().await {
eprintln!("{:?}", e);
continue;
}
}
hws.push(device.into());
}
}
}
}

if let Ok(device) = LedgerSimulator::try_connect().await {
hws.push(device.into());
}
Expand Down
2 changes: 1 addition & 1 deletion src/bitbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@ mod tests {
use super::*;

#[test]
fn test_extract_keys_and_template() {
fn test_extract_script_config_policy() {
let policy = extract_script_config_policy("wsh(or_d(pk([f5acc2fd/49'/1'/0']tpubDCbK3Ysvk8HjcF6mPyrgMu3KgLiaaP19RjKpNezd8GrbAbNg6v5BtWLaCt8FNm6QkLseopKLf5MNYQFtochDTKHdfgG6iqJ8cqnLNAwtXuP/**),and_v(v:pkh(tpubDDtb2WPYwEWw2WWDV7reLV348iJHw2HmhzvPysKKrJw3hYmvrd4jasyoioVPdKGQqjyaBMEvTn1HvHWDSVqQ6amyyxRZ5YjpPBBGjJ8yu8S/**),older(100))))").unwrap();
assert_eq!(2, policy.pubkeys.len());
assert_eq!(
Expand Down
142 changes: 142 additions & 0 deletions src/jade/api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/// See https://github.com/Blockstream/Jade/blob/master/docs/index.rst
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
pub struct Request<'a, T: Serialize> {
pub id: String,
pub method: &'a str,
pub params: Option<T>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct EmptyRequest;

#[derive(Debug, Serialize, Deserialize)]
pub struct Response<T> {
pub id: String,
pub result: Option<T>,
pub error: Option<Error>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Error {
pub code: i32,
pub message: Option<String>,
pub data: Option<Vec<u8>>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct GetXpubParams<'a> {
pub network: &'a str,
pub path: Vec<u32>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct AuthUserParams<'a> {
pub network: &'a str,
pub epoch: u64,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum AuthUserResponse {
Authenticated(bool),
PinServerRequired {
http_request: PinServerRequest<String>,
},
}

#[derive(Debug, Serialize, Deserialize)]
pub struct PinServerRequest<T> {
pub params: PinServerRequestParams<T>,
#[serde(alias = "on-reply")]
pub onreply: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct PinServerRequestParams<T> {
pub urls: PinServerUrls,
pub method: String,
pub accept: String,
pub data: T,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum PinServerUrls {
Array(Vec<String>),
Object { url: String, onion: String },
}

#[derive(Debug, Serialize, Deserialize)]
pub struct PinServerEncryptedData {
pub cke: String,
pub encrypted_data: String,
pub hmac_encrypted_data: String,
pub ske: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct HandShakeInitParams {
pub sig: String,
pub ske: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct HandShakeInitResponse {
pub http_request: PinServerRequest<PinServerEncryptedData>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct HandShakeCompleteParams {
pub encrypted_key: String,
pub hmac: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct GetInfoResponse {
#[serde(alias = "JADE_VERSION")]
pub jade_version: String,
#[serde(alias = "JADE_STATE")]
pub jade_state: JadeState,
#[serde(alias = "JADE_NETWORKS")]
pub jade_networks: JadeNetworks,
}

#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum JadeState {
#[serde(alias = "UNINIT")]
Uninit,
#[serde(alias = "UNSAVED")]
Unsaved,
#[serde(alias = "LOCKED")]
Locked,
#[serde(alias = "READY")]
Ready,
#[serde(alias = "TEMP")]
Temp,
}

#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum JadeNetworks {
#[serde(alias = "MAIN")]
Main,
#[serde(alias = "TEST")]
Test,
#[serde(alias = "ALL")]
All,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct RegisterDescriptorParams<'a> {
pub network: &'a str,
pub descriptor_name: String,
pub descriptor: String,
pub datavalues: Vec<DataValue>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct DataValue {
pub key: String,
pub value: String,
}
Loading

0 comments on commit b55b2ea

Please sign in to comment.