Skip to content
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
0450bc6
Update deps and fix breaking changes
praveenperera Mar 12, 2025
0ef500f
Make the `CkTransport` trait `async`
praveenperera Mar 14, 2025
e6fa7ab
Fix CLI
praveenperera Mar 14, 2025
42a04fa
Allow transmit to be used in async contexts
praveenperera Mar 14, 2025
5dc76a5
Separate out functions for `TAPSIGNER` & `SATSCARD`
praveenperera Mar 17, 2025
b51dd5b
Separate apdu commands to modules
praveenperera Mar 18, 2025
0440250
Change all `cmd` from `String` to `&'static str`
praveenperera Mar 18, 2025
591f92a
Change all `epubkey` to be 33 bytes
praveenperera Mar 18, 2025
2756692
Create new `TapSignerError`
praveenperera Mar 18, 2025
115374d
Set card nonce as 16 byte array
praveenperera Mar 18, 2025
d1a7bc6
Implement `change` and `backup` commands and validation logic
praveenperera Mar 18, 2025
a81474f
Add `backup` and `change` commands to CLI
praveenperera Mar 18, 2025
d36a8f0
Complete `change` command
praveenperera Mar 18, 2025
bf32158
Improve error handling
praveenperera Mar 19, 2025
fe3033e
Fix imports
praveenperera Mar 19, 2025
a74be41
Rework CvcChangeError
praveenperera Mar 19, 2025
2f8d83e
Make `chain_code` a byte array instead of a Vec
praveenperera Mar 19, 2025
c754df5
Make `derive` signature verification work with a derivation path
praveenperera Mar 24, 2025
22515cc
Use slice instead of Vec for master pubkey
praveenperera Mar 24, 2025
dd01257
Create `CkTapError` enum to represent errors returned by the card
praveenperera Mar 24, 2025
a863a0a
Merge pull request #1 from bitcoinppl/tapsigner-change
praveenperera Mar 27, 2025
cf7f6e2
Adjust wording on `BackupFirst` error
praveenperera Mar 28, 2025
37721f4
Fix signature verification for `derive` command
praveenperera Mar 28, 2025
3dfec7e
Added note about signature verification for derive command
praveenperera Mar 28, 2025
f6841a3
Revert changes, SATSCARD won't have pubkey set
praveenperera Mar 28, 2025
b020c4d
Update tap_signer.rs
praveenperera Mar 28, 2025
98c21e0
Add `StatusCommand` to TapSigner
praveenperera Mar 28, 2025
b787752
Update tap_signer.rs
praveenperera Mar 28, 2025
f93d247
Fix errors in examples
praveenperera Apr 1, 2025
54bd325
Make all commands take a &str instead of a String for cvc and fix tests
praveenperera Apr 1, 2025
c907f6f
Add `psbt` signing to lib
praveenperera Apr 1, 2025
ae2fb07
Use byte arrays whenever possible
praveenperera Apr 1, 2025
898f7be
Add `sign` command to cli
praveenperera Apr 1, 2025
2097a84
Use a `vec` for subpath because it can be 0,1,2 in length
praveenperera Apr 1, 2025
4856cc0
Fix typo in comments
praveenperera Apr 2, 2025
ab0ae62
Make `bitcoin` a regular dependency
praveenperera Apr 2, 2025
0b98baa
Add `reason` to `InvalidScript` error
praveenperera Apr 2, 2025
ad81034
Retry `UnluckyNumber` errors during `sign` command
praveenperera Apr 2, 2025
bbcb1d2
Use secp from `bitcoin`, verify pubkey matches
praveenperera Apr 2, 2025
c71ba3f
Add function to finalize PSBT
praveenperera Apr 2, 2025
37f7fc6
Use byte arrays for `DeriveResponse`
praveenperera Apr 2, 2025
2871698
Get the subpath correctly from the PSBT
praveenperera Apr 2, 2025
fe190c4
Add docs and remove finalizing PSBT, leave it up to the user
praveenperera Apr 3, 2025
7db62ee
Fix clippy warnings
praveenperera Apr 3, 2025
30bfddb
Improve comments on the PSBT signing code
praveenperera Apr 3, 2025
9dfa48d
Merge pull request #2 from bitcoinppl/sign-bitcoin-txn
praveenperera Apr 3, 2025
09c2f57
Derive pubkey from TAPSIGNER if we get a pubkey mismatch
praveenperera Apr 3, 2025
9cf9fbd
Get the correct path for deriving
praveenperera Apr 3, 2025
3ac5f95
Add note about toggling the hardened bit
praveenperera Apr 3, 2025
1f95e27
Update tap_signer.rs
praveenperera Apr 3, 2025
6609c34
Update README.md to show that we've added support for `change` and `b…
praveenperera Apr 3, 2025
3d7c1ec
Make uniffi dep version less restrictive
praveenperera Apr 21, 2025
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
1 change: 1 addition & 0 deletions cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ rust-cktap = { path = "../lib", features = ["pcsc"] }
pcsc = { version = "2" }
clap = { version = "4.3.1", features = ["derive"] }
rpassword = { version = "7.2" }
tokio = { version = "1", features = ["full"] }

[features]
emulator = ["rust-cktap/emulator"]
57 changes: 39 additions & 18 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,21 @@ enum TapSignerCommand {
#[clap(short, long, value_delimiter = ',', num_args = 1..)]
path: Vec<u32>,
},
/// Get a an encrypted backup of the card's private key
Comment thread
praveenperera marked this conversation as resolved.
Outdated
Backup,
/// Change the PIN (CVC) used for card authentication to a new user provided one
Change { new_cvc: String },
Comment thread
praveenperera marked this conversation as resolved.
}

fn main() -> Result<(), Error> {
#[tokio::main]
async fn main() -> Result<(), Error> {
// figure out what type of card we have before parsing cli args
#[cfg(not(feature = "emulator"))]
let mut card = pcsc::find_first()?;
let mut card = pcsc::find_first().await?;

// if emulator feature enabled override pcsc card
#[cfg(feature = "emulator")]
let mut card = emulator::find_emulator()?;
let mut card = emulator::find_emulator().await?;

let rng = &mut rand::thread_rng();

Expand All @@ -86,21 +91,21 @@ fn main() -> Result<(), Error> {
dbg!(&sc);
}
SatsCardCommand::Address => println!("Address: {}", sc.address().unwrap()),
SatsCardCommand::Certs => check_cert(sc),
SatsCardCommand::Read => read(sc, None),
SatsCardCommand::Certs => check_cert(sc).await,
SatsCardCommand::Read => read(sc, None).await,
SatsCardCommand::New => {
let slot = sc.slot().expect("current slot number");
let chain_code = Some(rand_chaincode(rng).to_vec());
let response = &sc.new_slot(slot, chain_code, cvc()).unwrap();
let chain_code = Some(rand_chaincode(rng));
let response = &sc.new_slot(slot, chain_code, &cvc()).await.unwrap();
println!("{}", response)
}
SatsCardCommand::Unseal => {
let slot = sc.slot().expect("current slot number");
let response = &sc.unseal(slot, cvc()).unwrap();
let response = &sc.unseal(slot, &cvc()).await.unwrap();
println!("{}", response)
}
SatsCardCommand::Derive => {
dbg!(&sc.derive());
dbg!(&sc.derive().await);
}
}
}
Expand All @@ -110,15 +115,25 @@ fn main() -> Result<(), Error> {
TapSignerCommand::Debug => {
dbg!(&ts);
}
TapSignerCommand::Certs => check_cert(ts),
TapSignerCommand::Read => read(ts, Some(cvc())),
TapSignerCommand::Certs => check_cert(ts).await,
TapSignerCommand::Read => read(ts, Some(cvc())).await,
TapSignerCommand::Init => {
let chain_code = rand_chaincode(rng).to_vec();
let response = &ts.init(chain_code, cvc());
let chain_code = rand_chaincode(rng);
let response = &ts.init(chain_code, &cvc()).await;
dbg!(response);
}
TapSignerCommand::Derive { path } => {
dbg!(&ts.derive(path, cvc()));
dbg!(&ts.derive(&path, &cvc()).await);
}

TapSignerCommand::Backup => {
let response = &ts.backup(&cvc()).await;
println!("{:?}", response);
}

TapSignerCommand::Change { new_cvc } => {
let response = &ts.change(&new_cvc, &cvc()).await;
Comment thread
praveenperera marked this conversation as resolved.
println!("{:?}", response);
}
}
}
Expand All @@ -129,8 +144,11 @@ fn main() -> Result<(), Error> {

// handler functions for each command

fn check_cert<T: CkTransport>(card: &mut dyn Certificate<T>) {
if let Ok(k) = card.check_certificate() {
async fn check_cert<C, T: CkTransport>(card: &mut C)
where
C: Certificate<T>,
{
if let Ok(k) = card.check_certificate().await {
println!(
"Genuine card from Coinkite.\nHas cert signed by: {}",
k.name()
Expand All @@ -140,8 +158,11 @@ fn check_cert<T: CkTransport>(card: &mut dyn Certificate<T>) {
}
}

fn read<T: CkTransport>(card: &mut dyn Read<T>, cvc: Option<String>) {
match card.read(cvc) {
async fn read<C, T: CkTransport>(card: &mut C, cvc: Option<String>)
where
C: Read<T>,
{
match card.read(cvc).await {
Ok(resp) => println!("{}", resp),
Err(e) => {
dbg!(&e);
Expand Down
11 changes: 7 additions & 4 deletions lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,18 @@ name = "rust_cktap"
ciborium = "0.2.0"
serde = "1"
serde_bytes = "0.11"
secp256k1 = { version = "0.26.0", features = ["rand-std", "bitcoin-hashes-std", "recovery"] }
secp256k1 = { version = "0.30.0", features = ["recovery", "std", "hashes", "rand"] }

# async
tokio = { version = "1.44", features = ["macros"] }

# optional dependencies
pcsc = { version = "2", optional = true }
uniffi = { version = "=0.28.0", features = ["cli"] }
thiserror = "1.0.58"
uniffi = { version = "=0.29.0", features = ["cli"] }
thiserror = "2.0"

[build-dependencies]
uniffi = { version = "=0.28.0", features = ["build"] }
uniffi = { version = "=0.29.0", features = ["build"] }

[features]
default = []
Expand Down
3 changes: 0 additions & 3 deletions lib/build.rs

This file was deleted.

41 changes: 21 additions & 20 deletions lib/examples/pcsc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ fn get_cvc() -> String {
}

// Example using pcsc crate
fn main() -> Result<(), Error> {
let card = pcsc::find_first()?;
#[tokio::main]
async fn main() -> Result<(), Error> {
let card = pcsc::find_first().await?;
dbg!(&card);

let rng = &mut rand::thread_rng();
Expand All @@ -30,25 +31,25 @@ fn main() -> Result<(), Error> {
// if auth delay call wait
while ts.auth_delay.is_some() {
dbg!(ts.auth_delay.unwrap());
ts.wait(None)?;
ts.wait(None).await?;
}

// only do this once per card!
if ts.path.is_none() {
let chain_code = rand_chaincode(rng).to_vec();
let new_result = ts.init(chain_code, cvc)?;
let chain_code = rand_chaincode(rng);
let new_result = ts.init(chain_code, &cvc).await.unwrap();
dbg!(new_result);
}

// let read_result = card.read(cvc.clone())?;
// let read_result = ts.read(Some(cvc.clone())).await?;
// dbg!(read_result);

dbg!(ts.check_certificate().unwrap().name());
dbg!(ts.check_certificate().await.unwrap().name());

//let dump_result = card.dump();

// let path = vec![2147483732, 2147483648, 2147483648];
// let derive_result = card.derive(path, cvc.clone())?;
// let derive_result = ts.derive(path, cvc.clone()).await?;
// dbg!(&derive_result);

// let nfc_result = card.nfc()?;
Expand All @@ -60,17 +61,17 @@ fn main() -> Result<(), Error> {
// if auth delay call wait
while chip.auth_delay.is_some() {
dbg!(chip.auth_delay.unwrap());
chip.wait(None)?;
chip.wait(None).await?;
}

// only do this once per card!
if chip.path.is_none() {
let chain_code = rand_chaincode(rng).to_vec();
let new_result = chip.init(chain_code, get_cvc())?;
let chain_code = rand_chaincode(rng);
let new_result = chip.init(chain_code, &get_cvc()).await.unwrap();
dbg!(new_result);
}

// let read_result = card.read(cvc)?;
// let read_result = chip.read(Some(cvc.clone())).await?;
// dbg!(read_result);

// let nfc_result = card.nfc()?;
Expand All @@ -80,17 +81,17 @@ fn main() -> Result<(), Error> {
// if auth delay call wait
while sc.auth_delay.is_some() {
dbg!(sc.auth_delay.unwrap());
let wait_response = sc.wait(None)?;
let wait_response = sc.wait(None).await?;
dbg!(wait_response);
}

// let read_result = sc.read(None)?;
// let read_result = sc.read(None).await?;
// dbg!(read_result);

// let derive_result = card.derive()?;
// let derive_result = sc.derive().await?;
// dbg!(&derive_result);

dbg!(sc.check_certificate().unwrap().name());
dbg!(sc.check_certificate().await.unwrap().name());

// let nfc_result = card.nfc()?;
// dbg!(nfc_result);
Expand All @@ -99,20 +100,20 @@ fn main() -> Result<(), Error> {
// if slot == &0 {
// // TODO must unseal first
// let chain_code = rand_chaincode(rng).to_vec();
// let new_result = card.new_slot(0, chain_code, get_cvc())?;
// let new_result = sc.new_slot(0, chain_code, get_cvc()).await?;
// }
// }

// let certs_result = card.certs()?;
// dbg!(certs_result);

// let unseal_result = card.unseal(0, get_cvc())?;
// let unseal_result = sc.unseal(0, get_cvc()).await?;
// dbg!(unseal_result);

// let dump_result = card.dump(0, None)?;
// let dump_result = sc.dump(0, None).await?;
// dbg!(dump_result);

// let dump_result = card.dump(0, Some(get_cvc()))?;
// let dump_result = sc.dump(0, Some(get_cvc())).await?;
// dbg!(dump_result);
}
}
Expand Down
Loading