diff --git a/libs/ur-parse-lib/src/keystone_ur_decoder.rs b/libs/ur-parse-lib/src/keystone_ur_decoder.rs index e9b5e62..32398b1 100644 --- a/libs/ur-parse-lib/src/keystone_ur_decoder.rs +++ b/libs/ur-parse-lib/src/keystone_ur_decoder.rs @@ -126,6 +126,8 @@ mod tests { use crate::keystone_ur_decoder::{probe_decode, MultiURParseResult, URParseResult}; use alloc::string::ToString; use ur_registry::crypto_psbt::CryptoPSBT; + use ur_registry::cardano::cardano_sign_data_request::CardanoSignDataRequest; + use ur_registry::ethereum::eth_sign_request::EthSignRequest; #[test] diff --git a/libs/ur-registry/src/cardano/cardano_sign_data_request.rs b/libs/ur-registry/src/cardano/cardano_sign_data_request.rs new file mode 100644 index 0000000..1457807 --- /dev/null +++ b/libs/ur-registry/src/cardano/cardano_sign_data_request.rs @@ -0,0 +1,107 @@ +use crate::cbor::cbor_map; +use crate::crypto_key_path::CryptoKeyPath; +use crate::error::{URError, URResult}; +use crate::registry_types::{RegistryType, CRYPTO_KEYPATH, CARDANO_SIGN_DATA_REQUEST, UUID}; +use crate::traits::{From as FromCbor, RegistryItem, To, MapSize}; +use crate::types::Bytes; +use alloc::format; +use crate::impl_template_struct; +use alloc::string::{String, ToString}; +use alloc::vec::Vec; +use minicbor::data::{Int, Tag}; +use minicbor::encode::Write; +use minicbor::{Decoder, Encoder}; + +const REQUEST_ID: u8 = 1; +const SIGN_DATA: u8 = 2; +const DERIVATION_PATH: u8 = 3; +const ORIGIN: u8 = 4; + +impl_template_struct!(CardanoSignDataRequest {request_id: Option, sign_data: Bytes, derivation_path: CryptoKeyPath, origin: Option}); + +impl MapSize for CardanoSignDataRequest { + fn map_size(&self) -> u64 { + let mut size = 2; + if self.request_id.is_some() { + size += 1; + } + if self.origin.is_some() { + size += 1; + } + size + } +} + +impl RegistryItem for CardanoSignDataRequest { + fn get_registry_type() -> RegistryType<'static> { + CARDANO_SIGN_DATA_REQUEST + } +} + +impl minicbor::Encode for CardanoSignDataRequest { + fn encode( + &self, + e: &mut Encoder, + _ctx: &mut C, + ) -> Result<(), minicbor::encode::Error> { + e.map(self.map_size())?; + if let Some(request_id) = &self.request_id { + e.int(Int::from(REQUEST_ID))? + .tag(Tag::Unassigned(UUID.get_tag()))? + .bytes(request_id)?; + } + + e.int(Int::from(SIGN_DATA))?.bytes(&self.sign_data)?; + + e.int(Int::from(DERIVATION_PATH))?; + e.tag(Tag::Unassigned(CRYPTO_KEYPATH.get_tag()))?; + CryptoKeyPath::encode(&self.derivation_path, e, _ctx)?; + + if let Some(origin) = &self.origin { + e.int(Int::from(ORIGIN))?.str(origin)?; + } + + Ok(()) + } +} + +impl<'b, C> minicbor::Decode<'b, C> for CardanoSignDataRequest { + fn decode(d: &mut Decoder<'b>, _ctx: &mut C) -> Result { + let mut result: CardanoSignDataRequest = CardanoSignDataRequest::default(); + cbor_map(d, &mut result, |key, obj, d: &mut Decoder| { + let key = + u8::try_from(key).map_err(|e| minicbor::decode::Error::message(e.to_string()))?; + match key { + REQUEST_ID => { + d.tag()?; + obj.set_request_id(Some(d.bytes()?.to_vec())); + } + SIGN_DATA => { + obj.set_sign_data(d.bytes()?.to_vec()); + } + DERIVATION_PATH => { + d.tag()?; + obj.derivation_path = CryptoKeyPath::decode(d, _ctx)?; + } + ORIGIN => { + obj.origin = Some(d.str()?.to_string()); + } + _ => {} + } + Ok(()) + })?; + Ok(result) + } +} + +impl To for CardanoSignDataRequest { + fn to_bytes(&self) -> URResult> { + minicbor::to_vec(self.clone()).map_err(|e| URError::CborEncodeError(e.to_string())) + } +} + +impl FromCbor for CardanoSignDataRequest { + fn from_cbor(bytes: Vec) -> URResult { + minicbor::decode(&bytes).map_err(|e| URError::CborDecodeError(e.to_string())) + } +} diff --git a/libs/ur-registry/src/cardano/cardano_sign_data_signature.rs b/libs/ur-registry/src/cardano/cardano_sign_data_signature.rs new file mode 100644 index 0000000..07582e9 --- /dev/null +++ b/libs/ur-registry/src/cardano/cardano_sign_data_signature.rs @@ -0,0 +1,78 @@ +use crate::cbor::cbor_map; +use crate::impl_template_struct; +use crate::registry_types::{CARDANO_SIGN_DATA_SIGNATURE, RegistryType, UUID}; +use crate::traits::{MapSize, RegistryItem}; +use crate::types::Bytes; +use alloc::string::ToString; +use minicbor::data::{Int, Tag}; +use minicbor::encode::{Error, Write}; +use minicbor::{Decoder, Encoder}; + +const REQUEST_ID: u8 = 1; +const SIGNATURE: u8 = 2; +const PUBLIC_KEY: u8 = 3; + +impl_template_struct!(CardanoSignDataSignature { + request_id: Option, + signature: Bytes, + public_key: Bytes +}); + +impl RegistryItem for CardanoSignDataSignature { + fn get_registry_type() -> RegistryType<'static> { + CARDANO_SIGN_DATA_SIGNATURE + } +} + +impl MapSize for CardanoSignDataSignature { + fn map_size(&self) -> u64 { + let mut size = 2; + if self.request_id.is_some() { + size += 1; + } + size + } +} + +impl minicbor::Encode for CardanoSignDataSignature { + fn encode(&self, e: &mut Encoder, _ctx: &mut C) -> Result<(), Error> { + e.map(self.map_size())?; + + if let Some(id) = &self.request_id { + e.int(Int::from(REQUEST_ID))? + .tag(Tag::Unassigned(UUID.get_tag()))? + .bytes(id)?; + } + + e.int(Int::from(SIGNATURE))?.bytes(&self.signature)?; + + e.int(Int::from(PUBLIC_KEY))?.bytes(&self.public_key)?; + + Ok(()) + } +} + +impl<'b, C> minicbor::Decode<'b, C> for CardanoSignDataSignature { + fn decode(d: &mut Decoder<'b>, _ctx: &mut C) -> Result { + let mut cardano_sign_data_signature = CardanoSignDataSignature::default(); + cbor_map(d, &mut cardano_sign_data_signature, |key, obj, d| { + let key = + u8::try_from(key).map_err(|e| minicbor::decode::Error::message(e.to_string()))?; + match key { + REQUEST_ID => { + d.tag()?; + obj.set_request_id(Some(d.bytes()?.to_vec())); + } + SIGNATURE => { + obj.set_signature(d.bytes()?.to_vec()); + } + PUBLIC_KEY => { + obj.set_public_key(d.bytes()?.to_vec()); + } + _ => {} + } + Ok(()) + })?; + Ok(cardano_sign_data_signature) + } +} diff --git a/libs/ur-registry/src/cardano/cardano_sign_structure.rs b/libs/ur-registry/src/cardano/cardano_sign_structure.rs new file mode 100644 index 0000000..751e512 --- /dev/null +++ b/libs/ur-registry/src/cardano/cardano_sign_structure.rs @@ -0,0 +1,86 @@ +use crate::cbor::cbor_array; +use crate::crypto_key_path::CryptoKeyPath; +use crate::error::{URError, URResult}; +use crate::registry_types::{CARDANO_CERT_KEY, CRYPTO_KEYPATH, RegistryType}; +use crate::traits::{From as FromCbor, MapSize, RegistryItem, To}; +use crate::types::Bytes; + +use alloc::string::{String, ToString}; +use alloc::vec::Vec; +use prost::Message; +use core::convert::From; +use minicbor::data::{Int, Tag}; +use minicbor::encode::{Error, Write}; +use minicbor::{Decoder, Encoder}; + +const KEY_CONTEXT: u8 = 0; +const KEY_PROTECTED_HEADER: u8 = 1; +const KEY_EXTERNAL_AAD: u8 = 2; +const KEY_PAYLOAD: u8 = 3; + +use crate::impl_template_struct; + +impl_template_struct!(CardanoSignStructure { + context: Bytes, + protected_header: Bytes, + external_aad: Bytes, + payload: String +}); + +impl MapSize for CardanoSignStructure { + fn map_size(&self) -> u64 { + 4 + } +} + +impl<'b, C> minicbor::Decode<'b, C> for CardanoSignStructure { + fn decode(d: &mut Decoder<'b>, _ctx: &mut C) -> Result { + let mut cardano_sign_structure = CardanoSignStructure::default(); + cbor_array(d, &mut cardano_sign_structure, |_index, obj, d| { + let _index = + u8::try_from(_index).map_err(|e| minicbor::decode::Error::message(e.to_string()))?; + + match _index { + KEY_CONTEXT => { + obj.context = d.str()?.to_string().encode_to_vec() + } + KEY_PROTECTED_HEADER => { + obj.protected_header = d.bytes()?.to_vec() + } + KEY_EXTERNAL_AAD => { + obj.external_aad = d.bytes()?.to_vec() + } + KEY_PAYLOAD => { + obj.payload = hex::encode(d.bytes()?); + } + _ => { + d.skip()?; + } + } + Ok(()) + })?; + Ok(cardano_sign_structure) + } +} + +impl FromCbor for CardanoSignStructure { + fn from_cbor(bytes: Vec) -> URResult { + minicbor::decode(&bytes).map_err(|e| URError::CborDecodeError(e.to_string())) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_decode_sign_structure() { + let sign_structure_str = "846a5369676e617475726531582aa201276761646472657373581de133a4f1f468454744b2ff3644b2ab79d48e76a3187f902fe8a1bcfaad4058857b22707572706f7365223a224b6f696f73204163636f756e7420566572696669636174696f6e222c226163636f756e74223a2265313333613466316634363834353437343462326666333634346232616237396434386537366133313837663930326665386131626366616164222c226e6f6e6365223a313731393533383936383333347d"; + let sign_structure_bytes = hex::decode(sign_structure_str).unwrap(); + + let sign_structure = CardanoSignStructure::from_cbor(sign_structure_bytes).unwrap(); + let payload = hex::decode(sign_structure.payload).unwrap(); + let payload = String::from_utf8(payload).unwrap(); + assert_eq!(payload, "{\"purpose\":\"Koios Account Verification\",\"account\":\"e133a4f1f468454744b2ff3644b2ab79d48e76a3187f902fe8a1bcfaad\",\"nonce\":1719538968334}"); + } +} \ No newline at end of file diff --git a/libs/ur-registry/src/cardano/mod.rs b/libs/ur-registry/src/cardano/mod.rs index eb725b2..48a8e94 100644 --- a/libs/ur-registry/src/cardano/mod.rs +++ b/libs/ur-registry/src/cardano/mod.rs @@ -1,4 +1,7 @@ pub mod cardano_cert_key; pub mod cardano_sign_request; +pub mod cardano_sign_data_request; pub mod cardano_signature; +pub mod cardano_sign_data_signature; pub mod cardano_utxo; +pub mod cardano_sign_structure; diff --git a/libs/ur-registry/src/macros_impl.rs b/libs/ur-registry/src/macros_impl.rs index 524335d..5329cd0 100644 --- a/libs/ur-registry/src/macros_impl.rs +++ b/libs/ur-registry/src/macros_impl.rs @@ -8,6 +8,8 @@ use crate::bytes::Bytes; use crate::cardano::{ cardano_cert_key::CardanoCertKey, cardano_sign_request::CardanoSignRequest, cardano_signature::CardanoSignature, cardano_utxo::CardanoUTXO, + cardano_sign_data_request::CardanoSignDataRequest, + cardano_sign_data_signature::CardanoSignDataSignature, }; use crate::cosmos::{cosmos_sign_request::CosmosSignRequest, cosmos_signature::CosmosSignature}; use crate::cosmos::{evm_sign_request::EvmSignRequest, evm_signature::EvmSignature}; @@ -50,6 +52,8 @@ impl_cbor_bytes!( CardanoSignature, CardanoUTXO, CardanoSignRequest, + CardanoSignDataRequest, + CardanoSignDataSignature, CardanoCertKey, AptosSignRequest, AptosSignature, diff --git a/libs/ur-registry/src/registry_types.rs b/libs/ur-registry/src/registry_types.rs index e012d55..201f565 100644 --- a/libs/ur-registry/src/registry_types.rs +++ b/libs/ur-registry/src/registry_types.rs @@ -13,6 +13,7 @@ pub enum URType { ArweaveSignRequest(String), AptosSignRequest(String), CardanoSignRequest(String), + CardanoSignDataRequest(String), CosmosSignRequest(String), EvmSignRequest(String), SuiSignRequest(String), @@ -42,6 +43,7 @@ impl URType { "aptos-sign-request" => Ok(URType::AptosSignRequest(type_str.to_string())), "sui-sign-request" => Ok(URType::SuiSignRequest(type_str.to_string())), "cardano-sign-request" => Ok(URType::CardanoSignRequest(type_str.to_string())), + "cardano-sign-data-request" => Ok(URType::CardanoSignDataRequest(type_str.to_string())), "qr-hardware-call" => Ok(URType::QRHardwareCall(type_str.to_string())), "ton-sign-request" => Ok(URType::TonSignRequest(type_str.to_string())), _ => Err(URError::NotSupportURTypeError(type_str.to_string())), @@ -63,6 +65,7 @@ impl URType { URType::ArweaveSignRequest(type_str) => type_str.to_string(), URType::AptosSignRequest(type_str) => type_str.to_string(), URType::CardanoSignRequest(type_str) => type_str.to_string(), + URType::CardanoSignDataRequest(type_str) => type_str.to_string(), URType::SuiSignRequest(type_str) => type_str.to_string(), URType::CosmosSignRequest(type_str) => type_str.to_string(), URType::EvmSignRequest(type_str) => type_str.to_string(), @@ -135,6 +138,8 @@ pub const CARDANO_UTXO: RegistryType = RegistryType("cardano-utxo", Some(2201)); pub const CARDANO_SIGN_REQUEST: RegistryType = RegistryType("cardano-sign-request", Some(2202)); pub const CARDANO_SIGNATURE: RegistryType = RegistryType("cardano-signature", Some(2203)); pub const CARDANO_CERT_KEY: RegistryType = RegistryType("cardano-cert-key", Some(2204)); +pub const CARDANO_SIGN_DATA_REQUEST: RegistryType = RegistryType("cardano-sign-data-request", Some(2205)); +pub const CARDANO_SIGN_DATA_SIGNATURE: RegistryType = RegistryType("cardano-sign-data-signature", Some(2206)); // Sui pub const SUI_SIGN_REQUEST: RegistryType = RegistryType("sui-sign-request", Some(7101)); pub const SUI_SIGNATURE: RegistryType = RegistryType("sui-signature", Some(7102));