Skip to content

Commit 1d183c3

Browse files
committed
fix: auth key size
1 parent d4fb7d9 commit 1d183c3

10 files changed

Lines changed: 97 additions & 99 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "vss-rust-client-ffi"
3-
version = "0.5.8"
3+
version = "0.5.9"
44
edition = "2021"
55
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
66

bindings/android/gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ android.useAndroidX=true
33
android.nonTransitiveRClass=true
44
kotlin.code.style=official
55
# project settings:
6-
version=0.5.8
6+
version=0.5.9
Binary file not shown.
Binary file not shown.
6.22 KB
Binary file not shown.
Binary file not shown.

src/implementation.rs

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -516,19 +516,7 @@ impl VssClient {
516516
/// Lists all raw keys on the server without any deobfuscation.
517517
/// Diagnostic function to see exactly what keys exist on the server.
518518
pub async fn list_all_raw_keys(&self) -> Result<Vec<KeyVersion>, VssError> {
519-
let request = ListKeyVersionsRequest {
520-
store_id: self.store_id.clone(),
521-
key_prefix: None,
522-
page_size: None,
523-
page_token: None,
524-
};
525-
let results = self
526-
.inner
527-
.list_key_versions(&request)
528-
.await
529-
.map_err(|e| convert_error(e, "list_all_raw_keys"))?
530-
.key_versions;
531-
519+
let results = self.list_all_key_versions_paginated(None).await?;
532520
Ok(results
533521
.into_iter()
534522
.map(|kv| KeyVersion {
@@ -683,19 +671,7 @@ impl VssClient {
683671
prefix: Option<String>,
684672
key_obfuscator: &Option<Arc<KeyObfuscator>>,
685673
) -> Result<Vec<KeyVersion>, VssError> {
686-
let request = ListKeyVersionsRequest {
687-
store_id: self.store_id.clone(),
688-
key_prefix: prefix,
689-
page_size: None,
690-
page_token: None,
691-
};
692-
let results = self
693-
.inner
694-
.list_key_versions(&request)
695-
.await
696-
.map_err(|e| convert_error(e, "list_key_versions"))?
697-
.key_versions;
698-
674+
let results = self.list_all_key_versions_paginated(prefix).await?;
699675
let mut result = Vec::new();
700676
for kv in results {
701677
if let Ok(original_key) = Self::deobfuscate_key(key_obfuscator, &kv.key) {
@@ -707,6 +683,38 @@ impl VssClient {
707683
}
708684
Ok(result)
709685
}
686+
687+
/// Fetches all key versions across pages using pagination.
688+
async fn list_all_key_versions_paginated(
689+
&self,
690+
prefix: Option<String>,
691+
) -> Result<Vec<ExternalKeyValue>, VssError> {
692+
let mut all_results = Vec::new();
693+
let mut page_token: Option<String> = None;
694+
695+
loop {
696+
let request = ListKeyVersionsRequest {
697+
store_id: self.store_id.clone(),
698+
key_prefix: prefix.clone(),
699+
page_size: Some(100),
700+
page_token: page_token.clone(),
701+
};
702+
let response = self
703+
.inner
704+
.list_key_versions(&request)
705+
.await
706+
.map_err(|e| convert_error(e, "list_paginated"))?;
707+
708+
all_results.extend(response.key_versions);
709+
710+
match response.next_page_token {
711+
Some(ref token) if !token.is_empty() => page_token = Some(token.clone()),
712+
_ => break,
713+
}
714+
}
715+
716+
Ok(all_results)
717+
}
710718
}
711719

712720
/// Derives data encryption and obfuscation keys from VSS seed

src/ldk_client.rs

Lines changed: 47 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,9 @@ impl LdkVssClient {
6767
) -> Result<Self, VssError> {
6868
let secp = Secp256k1::new();
6969

70-
// LNURL-auth: from truncated 32-byte seed path (same server identity as app client)
71-
let truncated_seed: [u8; 32] = seed[..32].try_into().unwrap();
70+
// LNURL-auth: from full 64-byte seed (same server identity as ldk-node)
7271
let auth_master_xprv =
73-
Xpriv::new_master(Network::Bitcoin, &truncated_seed).map_err(|e| {
72+
Xpriv::new_master(Network::Bitcoin, &seed).map_err(|e| {
7473
VssError::ConnectionError {
7574
error_details: format!("Failed to create auth master key: {}", e),
7675
}
@@ -265,19 +264,7 @@ impl LdkVssClient {
265264
/// Lists all raw keys on the server without any deobfuscation.
266265
/// Diagnostic function to see exactly what keys exist on the server.
267266
pub async fn list_all_raw_keys(&self) -> Result<Vec<KeyVersion>, VssError> {
268-
let request = ListKeyVersionsRequest {
269-
store_id: self.store_id.clone(),
270-
key_prefix: None,
271-
page_size: None,
272-
page_token: None,
273-
};
274-
let results = self
275-
.inner
276-
.list_key_versions(&request)
277-
.await
278-
.map_err(|e| convert_error(e, "ldk_list_all_raw_keys"))?
279-
.key_versions;
280-
267+
let results = self.list_all_key_versions_paginated(None).await?;
281268
Ok(results
282269
.into_iter()
283270
.map(|kv| KeyVersion {
@@ -293,25 +280,16 @@ impl LdkVssClient {
293280
let obfuscated_key = self.key_obfuscator.obfuscate(&key);
294281
let primary = namespace.primary();
295282
let secondary = namespace.secondary();
283+
let prefix_str = format!("{}#{}", primary, secondary);
296284

297-
match (primary, secondary) {
298-
("", "") => {
299-
// Default namespace: same for V0 and V1
300-
format!("default: {}", obfuscated_key)
301-
}
302-
_ => {
303-
let prefix_str = format!("{}#{}", primary, secondary);
304-
305-
// V0: plaintext prefix + # + obfuscated key
306-
let v0 = format!("{}#{}", prefix_str, obfuscated_key);
285+
// V0: plaintext prefix + # + obfuscated key
286+
let v0 = format!("{}#{}", prefix_str, obfuscated_key);
307287

308-
// V1: obfuscated prefix + # + obfuscated key
309-
let obfuscated_prefix = self.key_obfuscator.obfuscate(&prefix_str);
310-
let v1 = format!("{}#{}", obfuscated_prefix, obfuscated_key);
288+
// V1: obfuscated prefix + # + obfuscated key
289+
let obfuscated_prefix = self.key_obfuscator.obfuscate(&prefix_str);
290+
let v1 = format!("{}#{}", obfuscated_prefix, obfuscated_key);
311291

312-
format!("v0: {}\nv1: {}", v0, v1)
313-
}
314-
}
292+
format!("v0: {}\nv1: {}", v0, v1)
315293
}
316294

317295
// --- Internal helpers ---
@@ -320,16 +298,10 @@ impl LdkVssClient {
320298
fn build_key(&self, key: &str, namespace: &LdkNamespace) -> String {
321299
let primary = namespace.primary();
322300
let secondary = namespace.secondary();
323-
324-
match (primary, secondary) {
325-
("", "") => self.key_obfuscator.obfuscate(key),
326-
_ => {
327-
let prefix = format!("{}#{}", primary, secondary);
328-
let obfuscated_prefix = self.key_obfuscator.obfuscate(&prefix);
329-
let obfuscated_key = self.key_obfuscator.obfuscate(key);
330-
format!("{}#{}", obfuscated_prefix, obfuscated_key)
331-
}
332-
}
301+
let prefix = format!("{}#{}", primary, secondary);
302+
let obfuscated_prefix = self.key_obfuscator.obfuscate(&prefix);
303+
let obfuscated_key = self.key_obfuscator.obfuscate(key);
304+
format!("{}#{}", obfuscated_prefix, obfuscated_key)
333305
}
334306

335307
/// Builds the obfuscated namespace prefix for server-side filtering.
@@ -357,19 +329,7 @@ impl LdkVssClient {
357329
&self,
358330
prefix: Option<String>,
359331
) -> Result<Vec<KeyVersion>, VssError> {
360-
let request = ListKeyVersionsRequest {
361-
store_id: self.store_id.clone(),
362-
key_prefix: prefix,
363-
page_size: None,
364-
page_token: None,
365-
};
366-
let results = self
367-
.inner
368-
.list_key_versions(&request)
369-
.await
370-
.map_err(|e| convert_error(e, "ldk_list_key_versions"))?
371-
.key_versions;
372-
332+
let results = self.list_all_key_versions_paginated(prefix).await?;
373333
let mut result = Vec::new();
374334
for kv in results {
375335
if let Some(original_key) = self.try_deobfuscate(&kv.key) {
@@ -381,4 +341,36 @@ impl LdkVssClient {
381341
}
382342
Ok(result)
383343
}
344+
345+
/// Fetches all key versions across pages using pagination.
346+
async fn list_all_key_versions_paginated(
347+
&self,
348+
prefix: Option<String>,
349+
) -> Result<Vec<ExternalKeyValue>, VssError> {
350+
let mut all_results = Vec::new();
351+
let mut page_token: Option<String> = None;
352+
353+
loop {
354+
let request = ListKeyVersionsRequest {
355+
store_id: self.store_id.clone(),
356+
key_prefix: prefix.clone(),
357+
page_size: Some(100),
358+
page_token: page_token.clone(),
359+
};
360+
let response = self
361+
.inner
362+
.list_key_versions(&request)
363+
.await
364+
.map_err(|e| convert_error(e, "ldk_list_paginated"))?;
365+
366+
all_results.extend(response.key_versions);
367+
368+
match response.next_page_token {
369+
Some(ref token) if !token.is_empty() => page_token = Some(token.clone()),
370+
_ => break,
371+
}
372+
}
373+
374+
Ok(all_results)
375+
}
384376
}

src/tests.rs

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -327,14 +327,14 @@ mod tests {
327327
let (_, obf_master) = derive_data_encryption_and_obfuscation_keys(&vss_seed);
328328
let obfuscator = KeyObfuscator::new(obf_master);
329329

330-
// V0/V1 Default namespace: just obf(key)
330+
// Obfuscation roundtrip: obfuscate then deobfuscate
331331
let obfuscated = obfuscator.obfuscate("network_graph");
332332
assert_eq!(
333333
obfuscator.deobfuscate(&obfuscated).unwrap(),
334334
"network_graph"
335335
);
336336

337-
// V1 with namespace prefix: obf(prefix)#obf(key)
337+
// V1 with namespace prefix (including Default "#"): obf(prefix)#obf(key)
338338
let prefix = obfuscator.obfuscate("monitors#");
339339
let key = obfuscator.obfuscate("network_graph");
340340
let composite = format!("{}#{}", prefix, key);
@@ -378,9 +378,10 @@ mod tests {
378378
.await
379379
.unwrap();
380380

381-
// Default namespace returns single format
381+
// Default namespace returns V0 and V1 format (same as all namespaces)
382382
let default_result = client.debug_obfuscate("network_graph".to_string(), &LdkNamespace::Default);
383-
assert!(default_result.starts_with("default: "));
383+
assert!(default_result.contains("v0: "));
384+
assert!(default_result.contains("v1: "));
384385

385386
// Namespaced returns V0 and V1 formats
386387
let monitors_result = client.debug_obfuscate("network_graph".to_string(), &LdkNamespace::Monitors);
@@ -413,19 +414,16 @@ mod tests {
413414
.await
414415
.unwrap();
415416

416-
// The shared client incorrectly wraps Default namespace with obf("#")#obf(key)
417-
// while ldk-node just uses obf(key) for Default ("", "").
418-
// The dedicated LDK client correctly matches ldk-node's behavior.
417+
// Both clients now correctly use V1 format: obf("#")#obf(key) for Default namespace
419418
let shared_key = shared_client.build_key_ldk("network_graph", &LdkNamespace::Default);
420419
let ldk_debug = ldk_client.debug_obfuscate("network_graph".to_string(), &LdkNamespace::Default);
421-
let ldk_key = ldk_debug.strip_prefix("default: ").unwrap();
422-
423-
// The shared client produces a DIFFERENT key than ldk-node for Default namespace
424-
assert_ne!(shared_key, ldk_key, "shared client should differ from ldk-node for Default namespace");
425-
// The shared client adds a prefix even for Default namespace (bug)
426-
assert!(shared_key.contains('#'), "shared client incorrectly adds prefix for Default namespace");
427-
// The dedicated LDK client produces a key WITHOUT prefix (correct, matches ldk-node)
428-
assert!(!ldk_key.contains('#'), "LDK client should not add prefix for Default namespace");
420+
let v1_line = ldk_debug.lines().find(|l| l.starts_with("v1: ")).unwrap();
421+
let ldk_key = v1_line.strip_prefix("v1: ").unwrap();
422+
423+
// Both clients produce the same V1 key for Default namespace
424+
assert_eq!(shared_key, ldk_key, "shared and LDK clients should produce same key for Default namespace");
425+
// Default namespace V1 key contains '#' separator (obf("#")#obf(key))
426+
assert!(ldk_key.contains('#'), "Default namespace V1 key should contain '#' separator");
429427
}
430428

431429
#[tokio::test]

0 commit comments

Comments
 (0)