diff --git a/Cargo.lock b/Cargo.lock index 4009ad9..3924e1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1431,7 +1431,7 @@ dependencies = [ [[package]] name = "ur-parse-lib" -version = "1.0.4" +version = "1.0.7" dependencies = [ "hex", "keystone-ur", @@ -1440,7 +1440,7 @@ dependencies = [ [[package]] name = "ur-registry" -version = "1.0.5" +version = "1.0.7" dependencies = [ "base64", "bs58", @@ -1460,7 +1460,7 @@ dependencies = [ [[package]] name = "ur-registry-ffi" -version = "1.0.4" +version = "1.0.7" dependencies = [ "anyhow", "bip32", diff --git a/libs/ur-parse-lib/Cargo.toml b/libs/ur-parse-lib/Cargo.toml index 42b3d56..47a9542 100644 --- a/libs/ur-parse-lib/Cargo.toml +++ b/libs/ur-parse-lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ur-parse-lib" -version = "1.0.4" +version = "1.0.7" edition = "2024" description = "UR parsing and encoding helpers built on Keystone UR registry" license = "MIT" @@ -10,7 +10,7 @@ homepage = "https://github.com/KeystoneHQ/keystone-sdk-rust" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ur-registry = { path = "../ur-registry", version = "1.0.3", default-features = false, features = ["core"] } +ur-registry = { path = "../ur-registry", version = "1.0.6", default-features = false, features = ["core"] } ur = { package = "keystone-ur", version = "0.1.0", default-features = false } hex = { version = "0.4.3", features = ["alloc"], default-features = false } diff --git a/libs/ur-parse-lib/src/keystone_ur_decoder.rs b/libs/ur-parse-lib/src/keystone_ur_decoder.rs index f562182..d2454f8 100644 --- a/libs/ur-parse-lib/src/keystone_ur_decoder.rs +++ b/libs/ur-parse-lib/src/keystone_ur_decoder.rs @@ -171,7 +171,8 @@ mod tests { #[test] fn test_decode_zcash_accounts_registry_ur() { let seed_fingerprint = hex::decode("d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1").unwrap(); - let accounts = ZcashAccounts::new(seed_fingerprint.clone(), vec![]); + let mut accounts = ZcashAccounts::new(seed_fingerprint.clone(), vec![]); + accounts.set_device_version("1.2.3".to_string()); let cbor: Vec = accounts.try_into().unwrap(); let encoded = probe_encode(&cbor, 400, ZcashAccounts::get_registry_type().get_type()).unwrap(); @@ -183,7 +184,10 @@ mod tests { assert_eq!(decoded.ur_type.unwrap().get_type_str(), "zcash-accounts"); assert_eq!(decoded_accounts.get_seed_fingerprint(), seed_fingerprint); assert!(decoded_accounts.get_accounts().is_empty()); - assert_eq!(decoded_accounts.get_device_version(), None); + assert_eq!( + decoded_accounts.get_device_version(), + Some("1.2.3".to_string()) + ); } #[test] diff --git a/libs/ur-registry-ffi/Cargo.toml b/libs/ur-registry-ffi/Cargo.toml index 9d1b67f..9bc64a0 100644 --- a/libs/ur-registry-ffi/Cargo.toml +++ b/libs/ur-registry-ffi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ur-registry-ffi" -version = "1.0.4" +version = "1.0.7" edition = "2024" description = "FFI bindings for Keystone UR registry" license = "MIT" @@ -10,7 +10,7 @@ homepage = "https://github.com/KeystoneHQ/keystone-sdk-rust" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ur-registry = { path = "../ur-registry", version = "1.0.3" } +ur-registry = { path = "../ur-registry", version = "1.0.6" } hex = "0.4.3" ffi-support = "0.4" anyhow = "1.0" diff --git a/libs/ur-registry/Cargo.toml b/libs/ur-registry/Cargo.toml index f652f25..ece5897 100644 --- a/libs/ur-registry/Cargo.toml +++ b/libs/ur-registry/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ur-registry" -version = "1.0.5" +version = "1.0.7" edition = "2024" description = "Keystone UR registry types and encoders/decoders for multi-chain payloads" license = "MIT" diff --git a/libs/ur-registry/src/zcash/zcash_accounts.rs b/libs/ur-registry/src/zcash/zcash_accounts.rs index f88b0e0..314f7f3 100644 --- a/libs/ur-registry/src/zcash/zcash_accounts.rs +++ b/libs/ur-registry/src/zcash/zcash_accounts.rs @@ -8,10 +8,7 @@ //! with a map containing: //! - Seed fingerprint: A byte string that uniquely identifies the seed //! - Accounts: An array of Zcash unified full viewing keys -//! -//! Decode also accepts a device version string at CBOR map key 3 if present. -//! The standard encoder does not emit that field, preserving the existing -//! two-key account export shape for older consumers. +//! - Device version: An optional firmware version string use alloc::{ string::{String, ToString}, @@ -70,8 +67,7 @@ impl ZcashAccounts { self.device_version.clone() } - /// Stores device version metadata without changing the canonical - /// `zcash-accounts` encoding. + /// Sets the firmware version emitted at CBOR map key 3. pub fn set_device_version(&mut self, device_version: String) { self.device_version = Some(device_version); } @@ -79,7 +75,11 @@ impl ZcashAccounts { impl MapSize for ZcashAccounts { fn map_size(&self) -> u64 { - 2 + if self.device_version.is_some() { + 3 + } else { + 2 + } } } @@ -107,6 +107,10 @@ impl minicbor::Encode for ZcashAccounts { ZcashUnifiedFullViewingKey::encode(account, e, _ctx)?; } + if let Some(device_version) = &self.device_version { + e.int(Int::from(DEVICE_VERSION))?.str(device_version)?; + } + Ok(()) } } @@ -259,7 +263,7 @@ mod tests { } #[test] - fn test_zcash_accounts_encoder_omits_device_version_for_compatibility() { + fn test_zcash_accounts_encodes_device_version() { let seed_fingerprint = hex::decode("d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1").unwrap(); let mut accounts = ZcashAccounts::new(seed_fingerprint, vec![]); accounts.set_device_version("1.2.3".to_string()); @@ -268,16 +272,22 @@ mod tests { assert_eq!( hex::encode(&cbor), - "a20150d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d10280" + "a30150d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d102800365312e322e33" ); let decoded: ZcashAccounts = minicbor::decode(&cbor).unwrap(); - assert_eq!(decoded.device_version, None); + assert_eq!(decoded.device_version, Some("1.2.3".to_string())); } #[test] - fn test_zcash_accounts_without_device_version_decodes_from_old_cbor() { + fn test_zcash_accounts_without_device_version_preserves_old_cbor() { let seed_fingerprint = hex::decode("d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1").unwrap(); - let cbor = hex::decode("a20150d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d10280").unwrap(); + let accounts = ZcashAccounts::new(seed_fingerprint.clone(), vec![]); + let cbor = minicbor::to_vec(&accounts).unwrap(); + + assert_eq!( + hex::encode(&cbor), + "a20150d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d10280" + ); let decoded: ZcashAccounts = minicbor::decode(&cbor).unwrap(); assert_eq!(decoded.seed_fingerprint, seed_fingerprint); @@ -381,6 +391,6 @@ mod tests { let mut accounts_with_version = ZcashAccounts::new(vec![], vec![]); accounts_with_version.set_device_version("1.0.0".to_string()); - assert_eq!(accounts_with_version.map_size(), 2); + assert_eq!(accounts_with_version.map_size(), 3); } }