# How the Badger KV Store Persists Encrypted Key Shares in mpcium

> Learn how mpcium uses Badger KV store to persist encrypted key shares. Discover how it protects your sensitive data by encrypting shares at rest with BadgerDB encryption and a user-defined password.

- Repository: [Fystack Labs/mpcium](https://github.com/fystack/mpcium)
- Tags: how-to-guide
- Published: 2026-03-02

---

**mpcium transparently encrypts every TSS key share at rest using BadgerDB’s built-in encryption, deriving a 32-byte key from a user-supplied `badger_password` to ensure `LocalPartySaveData` never touches disk as plaintext.**

The `fystack/mpcium` repository implements a secure multi-party computation (MPC) wallet daemon that must protect sensitive key material between sessions. According to the source code, the project leverages BadgerDB’s native encryption capabilities to persist `LocalPartySaveData` structs—generated by the tss-lib library—while maintaining a simple `Put`/`Get` interface for the rest of the application.

## Configuring the Encrypted Badger Store

When the daemon starts, the user-provided password is converted into an encryption key and injected into the Badger configuration.

### Deriving the Encryption Key from CLI Input

In [`cmd/mpcium/main.go`](https://github.com/fystack/mpcium/blob/main/cmd/mpcium/main.go), the initialization logic creates a `BadgerConfig` struct that holds the 32-byte encryption key derived from the `badger_password` flag:

```go
// cmd/mpcium/main.go → NewBadgerKVStore
config := kvstore.BadgerConfig{
    NodeID:              nodeName,
    DBPath:              dbPath,
    EncryptionKey:       []byte(badgerPassword), // 32-byte key from user password
    BackupEncryptionKey: []byte(backupPassword),
    BackupDir:           backupDir,
}
badgerKv, err := kvstore.NewBadgerKVStore(config)

```

This configuration object is passed to the constructor that builds the underlying Badger options.

### Initializing Badger with AES Encryption

Inside [`pkg/kvstore/badger.go`](https://github.com/fystack/mpcium/blob/main/pkg/kvstore/badger.go) (lines 40‑44), the constructor applies the encryption key to Badger’s option builder using `WithEncryptionKey`:

```go
// pkg/kvstore/badger.go
opts := badger.DefaultOptions(config.DBPath).
    WithEncryptionKey(config.EncryptionKey)

```

Badger then transparently encrypts every value using AES before writing it to the LSM tree files, ensuring at-rest encryption without additional application logic.

## Persisting Encrypted Key Shares

After a key-generation round completes, the session serializes the share and stores it via the generic KV interface.

### Serializing LocalPartySaveData

In [`pkg/mpc/ecdsa_keygen_session.go`](https://github.com/fystack/mpcium/blob/main/pkg/mpc/ecdsa_keygen_session.go), the session marshals the `saveData` struct to JSON and calls `Put` with a versioned key:

```go
// pkg/mpc/ecdsa_keygen_session.go → after receiving end data
keyBytes, _ := json.Marshal(saveData)            // serialize share
err = s.kvstore.Put(
    s.composeKey(walletIDWithVersion(s.walletID, s.GetVersion())),
    keyBytes)                                    // encrypted write

```

The same pattern appears in [`pkg/mpc/eddsa_keygen_session.go`](https://github.com/fystack/mpcium/blob/main/pkg/mpc/eddsa_keygen_session.go) for EdDSA shares and across signing and resharing workflows. Because Badger handles encryption transparently, the application code treats `keyBytes` as plaintext while the underlying store encrypts it automatically.

## Retrieving and Decrypting Key Shares

When a signing or resharing session starts, it must load the previously persisted share. The decryption happens transparently inside Badger during the `Get` operation.

### The loadOldShareDataGeneric Helper

In [`pkg/mpc/session.go`](https://github.com/fystack/mpcium/blob/main/pkg/mpc/session.go) (lines 41‑74), the `loadOldShareDataGeneric` method constructs the versioned lookup key, fetches the encrypted payload, and unmarshals it:

```go
// pkg/mpc/session.go → loadOldShareDataGeneric
key := s.composeKey(walletIDWithVersion(walletID, version))
keyData, err := s.kvstore.Get(key)              // transparently decrypted read
json.Unmarshal(keyData, dest)                   // decode back to LocalPartySaveData

```

Because the encryption key was provided at startup, Badger decrypts the value during the `Get` call, returning plaintext JSON to the session handler.

## Encrypted Backup Operations

The repository also supports encrypted backups using a separate key. In [`pkg/kvstore/badger_backup.go`](https://github.com/fystack/mpcium/blob/main/pkg/kvstore/badger_backup.go) (line 96), the executor creates an AES-GCM cipher from the `BackupEncryptionKey` field of `BadgerConfig` before writing the dump to disk, ensuring backups remain encrypted even when exported from the live database.

## Summary

- **BadgerDB provides transparent AES encryption** via `WithEncryptionKey`, ensuring all values are encrypted before reaching LSM files.
- **The encryption key is derived from the `badger_password`** supplied at daemon startup and stored in `BadgerConfig.EncryptionKey`.
- **Key shares are stored as JSON blobs** via `kvstore.Put` in [`pkg/mpc/ecdsa_keygen_session.go`](https://github.com/fystack/mpcium/blob/main/pkg/mpc/ecdsa_keygen_session.go) and sibling files, using versioned keys to handle wallet updates.
- **Retrieval uses `kvstore.Get`** in [`pkg/mpc/session.go`](https://github.com/fystack/mpcium/blob/main/pkg/mpc/session.go), which transparently decrypts the data before unmarshaling into `LocalPartySaveData`.
- **Backups are independently encrypted** using AES-GCM with a separate backup password defined in `BadgerConfig`.

## Frequently Asked Questions

### What encryption algorithm does Badger use for key shares?

BadgerDB uses AES encryption with the key provided via `WithEncryptionKey`. In mpcium, this key is the 32-byte slice derived from the user’s `badger_password`, ensuring standardized AES encryption at rest without custom crypto code in the application layer.

### How is the encryption key derived from the badger_password?

The daemon treats the user-supplied `badger_password` string as a byte slice and passes it directly to `BadgerConfig.EncryptionKey`. According to [`cmd/mpcium/main.go`](https://github.com/fystack/mpcium/blob/main/cmd/mpcium/main.go), this occurs during `NewBadgerKVStore` initialization; the password must be 32 bytes (or Badger will hash/pad it internally) to serve as the AES key.

### Where exactly are the encrypted shares stored in the codebase?

The encrypted shares are persisted in the BadgerDB directory specified by `DBPath` in the configuration. The write path is [`pkg/mpc/ecdsa_keygen_session.go`](https://github.com/fystack/mpcium/blob/main/pkg/mpc/ecdsa_keygen_session.go) (and EdDSA equivalent) which calls `s.kvstore.Put`, while the read path is [`pkg/mpc/session.go`](https://github.com/fystack/mpcium/blob/main/pkg/mpc/session.go) via `loadOldShareDataGeneric`.

### Can I rotate the encryption key for existing Badger databases?

BadgerDB itself does not support in-place encryption key rotation. To rotate keys in mpcium, you would need to export data using the old key (leveraging the backup functionality in [`pkg/kvstore/badger_backup.go`](https://github.com/fystack/mpcium/blob/main/pkg/kvstore/badger_backup.go)), create a new Badger instance with the new `badger_password`, and re-import the shares.