Skip to main content

zing_cli/
keystore.rs

1use sui_crypto::ed25519::Ed25519PrivateKey;
2use sui_sdk_types::Address;
3use std::path::Path;
4use base64ct::Encoding;
5
6/// Load the Ed25519 private key and derive its address from the zing keystore.
7///
8/// The keystore is a JSON array of base64-encoded `flag || privkey` (33 bytes).
9/// flag 0x00 = Ed25519, remaining 32 bytes = private key.
10pub fn load_keypair(keystore_path: &Path, expected_address: &Address) -> anyhow::Result<Ed25519PrivateKey> {
11    let json_str = std::fs::read_to_string(keystore_path)
12        .map_err(|e| anyhow::anyhow!("Cannot read keystore at {}: {}", keystore_path.display(), e))?;
13    let entries: Vec<String> = serde_json::from_str(&json_str)?;
14
15    for entry in &entries {
16        let raw = base64ct::Base64::decode_vec(entry)
17            .map_err(|_| anyhow::anyhow!("Invalid base64 in keystore entry"))?;
18        if raw.len() != 33 {
19            continue;
20        }
21        let flag = raw[0];
22        if flag != 0x00 {
23            // Only Ed25519 supported for now
24            continue;
25        }
26        let key_bytes: [u8; 32] = raw[1..33]
27            .try_into()
28            .map_err(|_| anyhow::anyhow!("Invalid private key length"))?;
29
30        let keypair = Ed25519PrivateKey::new(key_bytes);
31        let derived: Address = keypair.public_key().derive_address();
32
33        if derived == *expected_address {
34            return Ok(keypair);
35        }
36    }
37
38    anyhow::bail!(
39        "No Ed25519 keypair found in keystore matching address: {:?}",
40        expected_address
41    )
42}