Skip to content
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

Feat/support ada usb #1422

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
4 changes: 3 additions & 1 deletion rust/Cargo.lock

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

2 changes: 1 addition & 1 deletion rust/apps/cardano/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ bech32 = { workspace = true }

[dependencies.cardano-serialization-lib]
git = "https://[email protected]/KeystoneHQ/cardano-serialization-lib.git"
tag = "keystone-0.1.6"
tag = "keystone-0.1.7"
76 changes: 56 additions & 20 deletions rust/apps/cardano/src/structs.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,28 @@
use crate::address::{derive_address, derive_pubkey_hash, AddressType};
use crate::address::derive_pubkey_hash;
use crate::errors::{CardanoError, R};
use alloc::collections::BTreeMap;
use alloc::format;
use alloc::string::{String, ToString};
use alloc::vec;
use alloc::vec::Vec;
use bitcoin::bip32::DerivationPath;
use core::ops::Div;

use app_utils::{impl_internal_struct, impl_public_struct};
use cardano_serialization_lib::protocol_types::{
self, Address, BaseAddress, EnterpriseAddress, RewardAddress,
Address, BaseAddress, EnterpriseAddress, RewardAddress,
};

use cardano_serialization_lib::protocol_types::numeric::BigNum;
use cardano_serialization_lib::protocol_types::{Anchor, DRepKind};
use cardano_serialization_lib::protocol_types::{Ed25519KeyHash, ScriptHash};
use bitcoin::bip32::ChildNumber::{Hardened, Normal};
use cardano_serialization_lib::protocol_types::DRepKind;
use cardano_serialization_lib::{
protocol_types::FixedTransaction as Transaction, protocol_types::VoteKind, Certificate,
CertificateKind, NetworkId, NetworkIdKind,
protocol_types::FixedTransaction as Transaction, protocol_types::VoteKind, NetworkIdKind,
};

use alloc::format;
use bitcoin::bip32::ChildNumber::{Hardened, Normal};
use bitcoin::bip32::DerivationPath;
use core::ops::Div;
use cryptoxide::hashing::blake2b_224;
use hex;
use ur_registry::cardano::cardano_sign_structure::CardanoSignStructure;
use ur_registry::traits::From;

use hex;

impl_public_struct!(ParseContext {
utxos: Vec<CardanoUtxo>,
cert_keys: Vec<CardanoCertKey>,
Expand Down Expand Up @@ -55,6 +52,14 @@ impl_public_struct!(ParsedCardanoSignData {
xpub: String
});

impl_public_struct!(ParsedCardanoSignCip8Data {
payload: String,
derivation_path: String,
message_hash: String,
xpub: String,
hash_payload: bool
});

impl_public_struct!(VotingProcedure {
voter: String,
transaction_id: String,
Expand Down Expand Up @@ -200,6 +205,43 @@ impl ParsedCardanoSignData {
}
}

impl ParsedCardanoSignCip8Data {
pub fn build(
sign_data: Vec<u8>,
derivation_path: String,
xpub: String,
hash_payload: bool,
) -> R<Self> {
let sign_structure = CardanoSignStructure::from_cbor(sign_data.clone());
match sign_structure {
Ok(sign_structure) => {
let raw_payload = sign_structure.get_payload();
let mut payload = String::from_utf8(hex::decode(raw_payload.clone()).unwrap())
.unwrap_or_else(|_| raw_payload.clone());
let mut message_hash = hex::encode(raw_payload);
if hash_payload {
let hash = blake2b_224(payload.as_bytes());
message_hash = hex::encode(hash);
}
Ok(Self {
payload,
derivation_path,
message_hash,
xpub,
hash_payload,
})
}
Err(e) => Ok(Self {
payload: hex::encode(sign_data.clone()),
derivation_path,
message_hash: hex::encode(sign_data),
xpub,
hash_payload,
}),
}
}
}

impl ParsedCardanoTx {
pub fn from_cardano_tx(tx: Transaction, context: ParseContext) -> R<Self> {
let network_id = Self::judge_network_id(&tx);
Expand Down Expand Up @@ -1119,12 +1161,6 @@ impl ParsedCardanoTx {
None => {}
}
}

if !pubkey_hash_paired {
return Err(CardanoError::InvalidTransaction(
"invalid address".to_string(),
));
}
parsed_inputs.push(ParsedCardanoInput {
transaction_hash: utxo.transaction_hash.clone(),
index: utxo.index,
Expand Down
26 changes: 19 additions & 7 deletions rust/apps/cardano/src/transaction.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use crate::errors::{CardanoError, R};
use crate::structs::{ParseContext, ParsedCardanoSignData, ParsedCardanoTx, SignDataResult};
use crate::{
errors::{CardanoError, R},
structs::ParsedCardanoSignCip8Data,
};
use alloc::collections::BTreeMap;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
Expand All @@ -23,6 +26,15 @@ pub fn parse_sign_data(
ParsedCardanoSignData::build(sign_data, derviation_path, xpub)
}

pub fn parse_sign_cip8_data(
sign_data: Vec<u8>,
derviation_path: String,
xpub: String,
hash_payload: bool,
) -> R<ParsedCardanoSignCip8Data> {
ParsedCardanoSignCip8Data::build(sign_data, derviation_path, xpub, hash_payload)
}

pub fn check_tx(tx: Vec<u8>, context: ParseContext) -> R<()> {
let cardano_tx = cardano_serialization_lib::protocol_types::FixedTransaction::from_bytes(tx)?;
ParsedCardanoTx::verify(cardano_tx, context)
Expand Down Expand Up @@ -76,15 +88,15 @@ pub fn sign_tx_hash(
.map_err(|e| CardanoError::SigningFailed(e.to_string()))?;
// construct vkeywitness
vkeys.add(&Vkeywitness::new(
&Vkey::new(&PublicKey::from_bytes(&pubkey).unwrap()),
&Ed25519Signature::from_bytes(signature.to_vec())
Vkey::new(&PublicKey::from_bytes(&pubkey).unwrap()),
Ed25519Signature::from_bytes(signature.to_vec())
.map_err(|e| CardanoError::SigningFailed(e.to_string()))?,
));
}
Err(e) => return Err(e),
}
}
witness_set.set_vkeys(&vkeys);
witness_set.set_vkeys(vkeys);
Ok(witness_set.to_bytes())
}

Expand Down Expand Up @@ -167,16 +179,16 @@ pub fn sign_tx(tx: Vec<u8>, context: ParseContext, icarus_master_key: XPrv) -> R
}
for (pubkey, signature) in signatures {
let v = Vkeywitness::new(
&Vkey::new(
Vkey::new(
&PublicKey::from_bytes(&pubkey)
.map_err(|e| CardanoError::SigningFailed(e.to_string()))?,
),
&Ed25519Signature::from_bytes(signature.to_vec())
Ed25519Signature::from_bytes(signature.to_vec())
.map_err(|e| CardanoError::SigningFailed(e.to_string()))?,
);
vkeys.add(&v);
}
witness_set.set_vkeys(&vkeys);
witness_set.set_vkeys(vkeys);

Ok(witness_set.to_bytes())
}
Expand Down
8 changes: 4 additions & 4 deletions rust/rust_c/src/cardano/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
keystore = { workspace = true}
keystore = { workspace = true }
app_cardano = { workspace = true }
app_utils = { workspace = true }
rust_tools = { workspace = true }
Expand All @@ -17,8 +17,8 @@ hex = { workspace = true }
ur-registry = { workspace = true }
bitcoin = { workspace = true }
ed25519-bip32-core = { workspace = true }

minicbor = { version = "0.19", features = ["alloc"] }
common_rust_c = { path = "../common" }

cryptoxide = { workspace = true }
[features]
debug-memory = []
debug-memory = []
70 changes: 70 additions & 0 deletions rust/rust_c/src/cardano/src/cip8_cbor_data_ledger.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use alloc::vec::Vec;
// follow the ledger signMessage logic
// https://github.com/LedgerHQ/app-cardano/blob/develop/src/signMsg.c#L328
use minicbor::encode::Write;
use minicbor::Encoder;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CardanoCip8SigStructureLedgerType {
pub address_field: Vec<u8>,
pub payload: Vec<u8>,
}
// protectedHeader = {
// 1 : -8, // set algorithm to EdDSA
// “address” : address_bytes // raw address given by the user, or key hash
// }
fn create_protected_header(address_field_bytes: &[u8]) -> Vec<u8> {
let mut buffer = Vec::new();
let mut e = Encoder::new(&mut buffer);
e.map(2).unwrap();
e.i8(1).unwrap();
e.i8(-8).unwrap();
e.str("address").unwrap();
e.bytes(address_field_bytes).unwrap();
buffer
}

// Sig_structure = [
// context : “Signature1”,
// body_protected : CBOR_encode(protectedHeader),
// external_aad : bstr, // empty buffer here
// payload : bstr // message or its hash as bytes
// ]
impl<C> minicbor::Encode<C> for CardanoCip8SigStructureLedgerType {
fn encode<W: Write>(
&self,
e: &mut Encoder<W>,
_ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
e.array(4)?;
e.str("Signature1")?;
let protected_header = create_protected_header(&self.address_field);
e.bytes(&protected_header)?;
e.bytes(&[])?;
e.bytes(&self.payload)?;
Ok(())
}
}

#[cfg(test)]
mod tests {
use super::*;
use hex;
#[test]
fn test1() {
// Signature1
// A20127676164647265737358390014C16D7F43243BD81478E68B9DB53A8528FD4FB1078D58D54A7F11241D227AEFA4B773149170885AADBA30AAB3127CC611DDBC4999DEF61C
// []
// 42D1854B7D69E3B57C64FCC7B4F64171B47DFF43FBA6AC0499FF437F
let cardano_address_hex = hex::decode("0014c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c".to_uppercase()).unwrap();
// payload = blake2b(messageHex)
let data = CardanoCip8SigStructureLedgerType {
address_field: cardano_address_hex,
payload: hex::decode("42D1854B7D69E3B57C64FCC7B4F64171B47DFF43FBA6AC0499FF437F")
.unwrap(),
};
let encoded = minicbor::to_vec(data).unwrap();
let encoded_hex = hex::encode(encoded).to_uppercase();
assert_eq!("846A5369676E6174757265315846A20127676164647265737358390014C16D7F43243BD81478E68B9DB53A8528FD4FB1078D58D54A7F11241D227AEFA4B773149170885AADBA30AAB3127CC611DDBC4999DEF61C40581C42D1854B7D69E3B57C64FCC7B4F64171B47DFF43FBA6AC0499FF437F", encoded_hex);
}
}
Loading
Loading