Feature: Identity & Key Generation #4
Labels
No labels
area:api
area:core
area:docs
area:infra
area:ux
dependencies
documentation
duplicate
good first issue
help wanted
invalid
question
rust
status:complete
status:partial
status:planned
type:bug
type:design
type:feature
type:infra
type:refactor
type:research
type:ux
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
icub3d/decentcom#4
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Migrated from GitHub issue icub3d/decentcom#4
Original Author: @icub3d
Original Date: 2026-04-15T14:15:22Z
Feature: Identity & Key Generation
Overview
Implement Ed25519 master key pair generation in the Tauri client, derive it from a BIP39 seed phrase for recoverability, store the private key securely via the OS keychain, and expose the public key to the React frontend in a human-readable display format. This is the foundation of user identity in decentcom -- the public key is the user's portable identity across all servers.
Background
The identity design doc (identity.md) specifies Ed25519 key pairs as the identity primitive. The master public key is the canonical user ID. The private key is stored by the Tauri core using OS-level secure storage and never exposed to the React layer. A BIP39 seed phrase is presented at generation time for recovery. The architecture doc (architecture.md) confirms the signing boundary: all cryptographic operations happen in Rust, the React app only sends data to be signed and receives signatures.
Requirements
Design
API / Interface Changes
Tauri IPC commands (Rust -> React bridge):
has_identityboolgenerate_identity{ pubkey: string, seed_phrase: string[] }import_identity{ seed_phrase: string[] }{ pubkey: string }get_public_key{ pubkey: string }sign{ data: string }{ signature: string }Data Model Changes
None on the server side. The client stores the private key in the OS keychain, not in a database.
Keychain entries:
decentcom_master_privkeyComponent Changes
New files:
Modified files:
Key derivation flow:
Task List
Server-side (none for this feature)
Client-side (Tauri core)
ed25519-dalek,bip39,rand,bs58, and a secure storage plugin (tauri-plugin-strongholdorkeyringcrate) toclient/src-tauri/Cargo.tomlclient/src-tauri/src/identity.rshas_identityIPC commandgenerate_identityIPC commandimport_identityIPC commandget_public_keyIPC command (returns Base58-encoded public key)signIPC command (signs arbitrary bytes, returns Base64 signature)client/src-tauri/src/lib.rsClient-side (React)
useIdentityhook that wrapshas_identity,get_public_key,generate_identity,import_identityhas_identityand offers "Create New Identity" or "Import Existing"App.tsxto route to Setup on first launch, then to the main app after identity is establishedTest List
useIdentityhook returns expected states (tested implicitly byApp.test.tsx)App.test.tsx)SeedPhrase.test.tsx)identity.rs)Implementation Notes
keyringv3 crate (native OS APIs) rather thantauri-plugin-stronghold. Choseasync-secret-service+tokio+crypto-opensslfeatures for Linux libsecret compatibility.mnemonic.to_seed("")) for compatibility with other BIP39 tools. First 32 bytes of the 64-byte seed are used as the Ed25519 signing key seed.Zeroizingwrapper ensures the in-memory copy is cleared on drop.bip39v2 requires therandfeature to exposeMnemonic::generate.Open Questions
tauri-plugin-stronghold(Tauri's built-in encrypted vault) or thekeyringcrate (direct OS keychain access)? Stronghold is more portable but adds a Tauri-specific dependency. Thekeyringcrate uses native OS APIs directly.