Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Keystore

An encrypted-on-disk container for a 32-byte private key, using AES-256-GCM with PBKDF2-HMAC-SHA256 key derivation.

Setup

Keystore does not need to be constructed directly — both static methods do the work. Reach for it through Keystore::from_file (load) or Keystore::write_to_file (save):

use {
    anyhow::Result,
    dango_sdk::{Keystore, Secp256k1, Secret},
};
 
fn save() -> Result<()> {
    let secret = Secp256k1::new_random();
    Keystore::write_to_file(&secret, "./key.json", "hunter2")?;
    Ok(())
}
 
fn load() -> Result<Secp256k1> {
    let bytes = Keystore::from_file("./key.json", "hunter2")?;
    Secp256k1::from_bytes(bytes)
}
#[grug::derive(Serde)]
pub struct Keystore {
    pub pk:         ByteArray<33>,
    pub salt:       ByteArray<16>,
    pub nonce:      ByteArray<12>,
    pub ciphertext: Binary,
}

Configuration

Keystore itself has no options. The KDF parameters are fixed:

  • PBKDF2-HMAC-SHA256
  • 600 000 iterations
  • 16-byte salt (OsRng)
  • 12-byte AES-GCM nonce (OsRng)
  • AES-256-GCM cipher

Methods

MethodDescription
from_fileRead and decrypt a keystore file. Returns the raw [u8; 32] private key.
write_to_fileEncrypt a Secret and write a pretty-printed JSON keystore file. Returns the Keystore.

End-to-end example

use {
    anyhow::Result,
    dango_sdk::{Keystore, Secp256k1, Secret},
};
 
fn round_trip() -> Result<()> {
    let secret = Secp256k1::new_random();
    let pubkey = secret.public_key();
 
    Keystore::write_to_file(&secret, "./key.json", "hunter2")?;
 
    let bytes  = Keystore::from_file("./key.json", "hunter2")?;
    let recovered = Secp256k1::from_bytes(bytes)?;
    assert_eq!(pubkey, recovered.public_key());
    Ok(())
}

Notes

  • from_file returns the raw private key bytes, not a Secret. Callers wrap it in Secp256k1::from_bytes or Eip712::from_bytes depending on the account's signing scheme.
  • The file contains the (unencrypted) compressed public key alongside the ciphertext. Treat the file as sensitive even though the private key itself is encrypted.
  • write_to_file is only valid for secrets whose Private type dereferences to [u8] and whose Public type fits in ByteArray<33> (both Secp256k1 and Eip712 qualify).

See also