1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
// Copyright (c) 2022-2023 The MobileCoin Foundation
//! Key Image APDUs, used for key matching
use encdec::{Decode, Encode};
use mc_core::keys::TxOutPublic;
use mc_crypto_ring_signature::KeyImage;
use super::{ApduError, ApduStatic, Instruction, MOB_APDU_CLA};
use crate::helpers::{ki, pub_key};
/// Resolve a key image for a specific subaddress and `txout_public_key`
///
/// ## Encoding:
/// ```text
/// 0 1 2 3
/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | WALLET_INDEX |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | SUBADDRESS_INDEX |
/// | (8-bytes) |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | |
/// / TXOUT_PUBLIC_KEY /
/// / (32-byte Ristretto Public Key) /
/// | |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// ```
#[derive(Clone, PartialEq, Debug, Encode, Decode)]
#[encdec(error = "ApduError")]
pub struct KeyImageReq {
/// SLIP-0010 account index
pub account_index: u32,
/// Subkey index
pub subaddress_index: u64,
/// TX_OUT public key
#[encdec(with = "pub_key")]
pub txout_public_key: TxOutPublic,
}
impl KeyImageReq {
/// Create a new application version APDU
pub fn new(account_index: u32, subaddress_index: u64, txout_public_key: TxOutPublic) -> Self {
Self {
account_index,
subaddress_index,
txout_public_key,
}
}
}
impl ApduStatic for KeyImageReq {
const CLA: u8 = MOB_APDU_CLA;
const INS: u8 = Instruction::GetKeyImage as u8;
}
/// Key image response APDU
///
/// ## Encoding:
/// ```text
/// 0 1 2 3
/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | WALLET_INDEX |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | SUBADDRESS_INDEX |
/// | (8-byte u64) |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | |
/// / KEY_IMAGE /
/// / (32-byte compressed Ristretto point) /
/// | |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// ```
#[derive(Copy, Clone, PartialEq, Debug, Encode, Decode)]
#[encdec(error = "ApduError")]
pub struct KeyImageResp {
/// SLIP-0010 account index
pub account_index: u32,
/// Subaddress index
pub subaddress_index: u64,
/// Key Image (compressed point)
#[encdec(with = "ki")]
pub key_image: KeyImage,
}
impl KeyImageResp {
/// Create a new [`KeyImage`] APDU
pub fn new(account_index: u32, subaddress_index: u64, key_image: KeyImage) -> Self {
Self {
account_index,
subaddress_index,
key_image,
}
}
}
#[cfg(test)]
mod test {
use mc_crypto_keys::{RistrettoPrivate, RistrettoPublic};
use mc_crypto_ring_signature::KeyImage;
use mc_util_from_random::FromRandom;
use rand::random;
use rand_core::OsRng;
use super::*;
use crate::test::encode_decode_apdu;
#[test]
fn key_image_get_apdu() {
let pub_key = RistrettoPublic::from(&RistrettoPrivate::from_random(&mut OsRng {}));
let apdu = KeyImageReq::new(random(), random(), pub_key.into());
let mut buff = [0u8; 128];
encode_decode_apdu(&mut buff, &apdu);
}
#[test]
fn key_image_ans_apdu() {
let key_image = KeyImage::from(&RistrettoPrivate::from_random(&mut OsRng {}));
let apdu = KeyImageResp::new(random(), random(), key_image);
let mut buff = [0u8; 256];
encode_decode_apdu(&mut buff, &apdu);
}
}