Skip to content

Commit 37bc6d1

Browse files
committed
Encode Zcash device version in account exports
1 parent 4131bae commit 37bc6d1

2 files changed

Lines changed: 29 additions & 15 deletions

File tree

libs/ur-parse-lib/src/keystone_ur_decoder.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,8 @@ mod tests {
171171
#[test]
172172
fn test_decode_zcash_accounts_registry_ur() {
173173
let seed_fingerprint = hex::decode("d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1").unwrap();
174-
let accounts = ZcashAccounts::new(seed_fingerprint.clone(), vec![]);
174+
let mut accounts = ZcashAccounts::new(seed_fingerprint.clone(), vec![]);
175+
accounts.set_device_version("1.2.3".to_string());
175176
let cbor: Vec<u8> = accounts.try_into().unwrap();
176177
let encoded =
177178
probe_encode(&cbor, 400, ZcashAccounts::get_registry_type().get_type()).unwrap();
@@ -183,7 +184,10 @@ mod tests {
183184
assert_eq!(decoded.ur_type.unwrap().get_type_str(), "zcash-accounts");
184185
assert_eq!(decoded_accounts.get_seed_fingerprint(), seed_fingerprint);
185186
assert!(decoded_accounts.get_accounts().is_empty());
186-
assert_eq!(decoded_accounts.get_device_version(), None);
187+
assert_eq!(
188+
decoded_accounts.get_device_version(),
189+
Some("1.2.3".to_string())
190+
);
187191
}
188192

189193
#[test]

libs/ur-registry/src/zcash/zcash_accounts.rs

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,7 @@
88
//! with a map containing:
99
//! - Seed fingerprint: A byte string that uniquely identifies the seed
1010
//! - Accounts: An array of Zcash unified full viewing keys
11-
//!
12-
//! Decode also accepts a device version string at CBOR map key 3 if present.
13-
//! The standard encoder does not emit that field, preserving the existing
14-
//! two-key account export shape for older consumers.
11+
//! - Device version: An optional firmware version string
1512
1613
use alloc::{
1714
string::{String, ToString},
@@ -70,16 +67,19 @@ impl ZcashAccounts {
7067
self.device_version.clone()
7168
}
7269

73-
/// Stores device version metadata without changing the canonical
74-
/// `zcash-accounts` encoding.
70+
/// Sets the firmware version emitted at CBOR map key 3.
7571
pub fn set_device_version(&mut self, device_version: String) {
7672
self.device_version = Some(device_version);
7773
}
7874
}
7975

8076
impl MapSize for ZcashAccounts {
8177
fn map_size(&self) -> u64 {
82-
2
78+
if self.device_version.is_some() {
79+
3
80+
} else {
81+
2
82+
}
8383
}
8484
}
8585

@@ -107,6 +107,10 @@ impl<C> minicbor::Encode<C> for ZcashAccounts {
107107
ZcashUnifiedFullViewingKey::encode(account, e, _ctx)?;
108108
}
109109

110+
if let Some(device_version) = &self.device_version {
111+
e.int(Int::from(DEVICE_VERSION))?.str(device_version)?;
112+
}
113+
110114
Ok(())
111115
}
112116
}
@@ -259,7 +263,7 @@ mod tests {
259263
}
260264

261265
#[test]
262-
fn test_zcash_accounts_encoder_omits_device_version_for_compatibility() {
266+
fn test_zcash_accounts_encodes_device_version() {
263267
let seed_fingerprint = hex::decode("d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1").unwrap();
264268
let mut accounts = ZcashAccounts::new(seed_fingerprint, vec![]);
265269
accounts.set_device_version("1.2.3".to_string());
@@ -268,16 +272,22 @@ mod tests {
268272

269273
assert_eq!(
270274
hex::encode(&cbor),
271-
"a20150d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d10280"
275+
"a30150d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d102800365312e322e33"
272276
);
273277
let decoded: ZcashAccounts = minicbor::decode(&cbor).unwrap();
274-
assert_eq!(decoded.device_version, None);
278+
assert_eq!(decoded.device_version, Some("1.2.3".to_string()));
275279
}
276280

277281
#[test]
278-
fn test_zcash_accounts_without_device_version_decodes_from_old_cbor() {
282+
fn test_zcash_accounts_without_device_version_preserves_old_cbor() {
279283
let seed_fingerprint = hex::decode("d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1").unwrap();
280-
let cbor = hex::decode("a20150d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d10280").unwrap();
284+
let accounts = ZcashAccounts::new(seed_fingerprint.clone(), vec![]);
285+
let cbor = minicbor::to_vec(&accounts).unwrap();
286+
287+
assert_eq!(
288+
hex::encode(&cbor),
289+
"a20150d1d1d1d1d1d1d1d1d1d1d1d1d1d1d1d10280"
290+
);
281291
let decoded: ZcashAccounts = minicbor::decode(&cbor).unwrap();
282292

283293
assert_eq!(decoded.seed_fingerprint, seed_fingerprint);
@@ -381,6 +391,6 @@ mod tests {
381391

382392
let mut accounts_with_version = ZcashAccounts::new(vec![], vec![]);
383393
accounts_with_version.set_device_version("1.0.0".to_string());
384-
assert_eq!(accounts_with_version.map_size(), 2);
394+
assert_eq!(accounts_with_version.map_size(), 3);
385395
}
386396
}

0 commit comments

Comments
 (0)