Skip to content

Commit c3e9f44

Browse files
benma's agentbenma
authored andcommitted
keystore: port antiklepto protocol test to Rust
1 parent 8db607a commit c3e9f44

File tree

6 files changed

+102
-123
lines changed

6 files changed

+102
-123
lines changed

src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2695,8 +2695,8 @@ mod tests {
26952695
let host_nonce = hex!("abababababababababababababababababababababababababababababababab");
26962696
// The host nonce commitment value does not impact this test, but an invalid commitment
26972697
// would fail the antiklepto signature check on the host. The host check is skipped here and
2698-
// tested in test_keystore_antiklepto.c. That the host nonce was included in the sig is
2699-
// tested by the siganture fixture test below.x
2698+
// tested in keystore::tests::test_secp256k1_antiklepto_protocol. That the host nonce was included in the sig is
2699+
// tested by the signature fixture test below.
27002700
let host_nonce_commitment = pb::AntiKleptoHostNonceCommitment {
27012701
commitment: bitbox02::secp256k1::ecdsa_anti_exfil_host_commit(SECP256K1, &host_nonce)
27022702
.unwrap(),

src/rust/bitbox02-rust/src/keystore.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,6 +1202,67 @@ mod tests {
12021202
);
12031203
}
12041204

1205+
#[test]
1206+
fn test_secp256k1_antiklepto_protocol() {
1207+
mock_unlocked();
1208+
1209+
let mut keypath = [84 + HARDENED, 1 + HARDENED, 0 + HARDENED, 0, 0];
1210+
let mut msg = [0x23u8; 32];
1211+
let mut host_nonce = [0x55u8; 32];
1212+
1213+
for index in 0..3 {
1214+
keypath[4] = index;
1215+
msg[0] = index as u8;
1216+
host_nonce[0] = index as u8;
1217+
1218+
// Protocol steps are described in secp256k1/include/secp256k1_ecdsa_s2c.h under
1219+
// "ECDSA Anti-Klepto Protocol".
1220+
1221+
// Protocol step 1.
1222+
let host_commitment_vec =
1223+
bitbox02::secp256k1::ecdsa_anti_exfil_host_commit(SECP256K1, &host_nonce).unwrap();
1224+
let host_commitment: [u8; 32] = host_commitment_vec.try_into().unwrap();
1225+
1226+
// Get pubkey at keypath.
1227+
let private_key = secp256k1_get_private_key(&keypath).unwrap();
1228+
let private_key_bytes: [u8; 32] = private_key.as_slice().try_into().unwrap();
1229+
let secret_key = secp256k1::SecretKey::from_slice(&private_key_bytes).unwrap();
1230+
let public_key = secret_key.public_key(SECP256K1);
1231+
1232+
// Commit - protocol step 2.
1233+
let signer_commitment =
1234+
secp256k1_nonce_commit(&private_key_bytes, &msg, &host_commitment).unwrap();
1235+
// Protocol step 3: host_nonce sent from host to signer to be used in step 4.
1236+
// Sign - protocol step 4.
1237+
let sign_result = secp256k1_sign(&private_key_bytes, &msg, &host_nonce).unwrap();
1238+
1239+
let signature =
1240+
secp256k1::ecdsa::Signature::from_compact(&sign_result.signature).unwrap();
1241+
// Protocol step 5: host verification.
1242+
bitbox02::secp256k1::anti_exfil_host_verify(
1243+
SECP256K1,
1244+
&signature,
1245+
&msg,
1246+
&public_key,
1247+
&host_nonce,
1248+
&signer_commitment,
1249+
)
1250+
.unwrap();
1251+
1252+
let message = secp256k1::Message::from_digest_slice(&msg).unwrap();
1253+
let recoverable_sig = secp256k1::ecdsa::RecoverableSignature::from_compact(
1254+
&sign_result.signature,
1255+
secp256k1::ecdsa::RecoveryId::from_i32(sign_result.recid as i32).unwrap(),
1256+
)
1257+
.unwrap();
1258+
assert!(
1259+
SECP256K1
1260+
.verify_ecdsa(&message, &recoverable_sig.to_standard(), &public_key)
1261+
.is_ok()
1262+
);
1263+
}
1264+
}
1265+
12051266
#[test]
12061267
fn test_secp256k1_schnorr_sign() {
12071268
mock_unlocked_using_mnemonic(

src/rust/bitbox02-sys/build.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ const ALLOWLIST_TYPES: &[&str] = &[
5151
"confirm_params_t",
5252
"trinary_input_string_params_t",
5353
"securechip_error_t",
54+
"secp256k1_ecdsa_s2c_opening",
55+
"secp256k1_ecdsa_signature",
56+
"secp256k1_pubkey",
5457
];
5558

5659
const ALLOWLIST_FNS: &[&str] = &[
@@ -141,6 +144,8 @@ const ALLOWLIST_FNS: &[&str] = &[
141144
"sd_write_bin",
142145
"sdcard_create",
143146
"secp256k1_ecdsa_anti_exfil_host_commit",
147+
"secp256k1_ecdsa_s2c_opening_parse",
148+
"secp256k1_anti_exfil_host_verify",
144149
"securechip_attestation_sign",
145150
"securechip_kdf",
146151
"securechip_model",

src/rust/bitbox02/src/secp256k1.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,40 @@ pub fn ecdsa_anti_exfil_host_commit(secp: &Secp256k1<All>, rand32: &[u8]) -> Res
3232
}
3333
}
3434

35+
#[cfg(feature = "testing")]
36+
pub fn anti_exfil_host_verify(
37+
secp: &Secp256k1<All>,
38+
signature: &bitcoin::secp256k1::ecdsa::Signature,
39+
msg: &[u8; 32],
40+
pubkey: &bitcoin::secp256k1::PublicKey,
41+
host_nonce: &[u8; 32],
42+
signer_commitment: &[u8; 33],
43+
) -> Result<(), ()> {
44+
let mut opening = core::mem::MaybeUninit::<bitbox02_sys::secp256k1_ecdsa_s2c_opening>::uninit();
45+
let parse_res = unsafe {
46+
bitbox02_sys::secp256k1_ecdsa_s2c_opening_parse(
47+
secp.ctx().as_ptr().cast(),
48+
opening.as_mut_ptr(),
49+
signer_commitment.as_ptr(),
50+
)
51+
};
52+
if parse_res != 1 {
53+
return Err(());
54+
}
55+
let opening = unsafe { opening.assume_init() };
56+
let verify_res = unsafe {
57+
bitbox02_sys::secp256k1_anti_exfil_host_verify(
58+
secp.ctx().as_ptr().cast(),
59+
signature.as_c_ptr() as *const bitbox02_sys::secp256k1_ecdsa_signature,
60+
msg.as_ptr(),
61+
pubkey.as_c_ptr() as *const bitbox02_sys::secp256k1_pubkey,
62+
host_nonce.as_ptr(),
63+
&opening,
64+
)
65+
};
66+
if verify_res == 1 { Ok(()) } else { Err(()) }
67+
}
68+
3569
pub fn dleq_prove(
3670
secp: &Secp256k1<All>,
3771
sk: &[u8; 32],

test/unit-test/CMakeLists.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,6 @@ target_include_directories(mocks
4949
set(TEST_LIST
5050
cleanup
5151
"-Wl,--wrap=util_cleanup_32"
52-
keystore_antiklepto
53-
""
5452
gestures
5553
""
5654
random

test/unit-test/test_keystore_antiklepto.c

Lines changed: 0 additions & 119 deletions
This file was deleted.

0 commit comments

Comments
 (0)