Vault and procedures
A vault is a named group of binary records inside a client. Records are written from JavaScript with
insert, or produced by the procedures, which keep key material on the Rust side.
import { KeyringSession, Location } from "tauri-plugin-keyring-store-api";
const session = await KeyringSession.load("/vault-a", "");
const vault = (await session.createClient("c1")).getVault("SECRETS");
await vault.insert("blob.bin", [0xde, 0xad]);
await vault.remove(Location.generic("SECRETS", "blob.bin"));
await session.unload();
There is no get for vault records: like in Stronghold, a vault secret can be written and used by a
procedure, but not read back by the webview. Use the store for data the
frontend needs to read.
Locations
A Location names one record in one vault:
const named = Location.generic("WALLET", "seed.bin");
const numbered = Location.counter("WALLET", 0);
A counter is stored under the text of its number: Location.counter("WALLET", 7) and
Location.generic("WALLET", "7") are the same record. Do not mix counters and numeric record
names in one vault.
vault.remove(location) deletes the record in the vault named by the location, not the vault
the KeyringVault was opened for. Removing a missing record is not an error.
Procedures
Need the crypto Cargo feature (default). Each runs in Rust, reads and writes vault records, and
returns only public data.
| Method | Writes to output | Resolves to |
|---|---|---|
generateSLIP10Seed(output, sizeBytes?) | SLIP10 master key from sizeBytes random bytes (16..=64, default 32) | empty array |
deriveSLIP10(chain, "Seed" | "Key", source, output) | child key derived along chain | 32-byte chain code |
recoverBIP39(mnemonic, output, passphrase?) | master key of an existing English mnemonic | empty array |
generateBIP39(output, passphrase?) | master key of a new 24-word mnemonic | the mnemonic as UTF-8 bytes |
getEd25519PublicKey(privateKey) | — | 32-byte public key |
signEd25519(privateKey, msg) | — | 64-byte signature of the UTF-8 of msg |
Keys are stored as SLIP10 extended keys (65 bytes). getEd25519PublicKey and signEd25519 also
accept a record that holds a raw 32-byte Ed25519 secret key.
Derivation
Every segment of chain is hardened (Ed25519 SLIP10 supports only hardened derivation). With
"Seed" the source record holds seed bytes; with "Key" it holds an extended key written by another
procedure.
const master = Location.generic("PRIMARY", "master");
await vault.generateSLIP10Seed(master);
const account0 = Location.generic("PRIMARY", "m/44'/0'/0'");
await vault.deriveSLIP10([44, 0, 0], "Key", master, account0);
const publicKey = await vault.getEd25519PublicKey(account0);
const signature = await vault.signEd25519(account0, "message");
Mnemonics
generateBIP39 returns the 24 words once so the user can write them down. Show them, do not store
them in the webview or in logs. To restore, pass the words to recoverBIP39 with the same passphrase.
const words = new TextDecoder().decode(await vault.generateBIP39(master, "optional passphrase"));
// later, on another device:
await vault.recoverBIP39(words, master, "optional passphrase");
An invalid mnemonic fails with crypto procedure error: BIP39 recover: invalid mnemonic; the error
never names the wrong word.
Not supported
PublicKey with type X25519 rejects with X25519 public key extraction is not implemented.