How the Automatic Backup System for Key Shares Works in mpcium
mpcium protects node secret key-shares by running a periodic, encrypted, incremental backup job that snapshots the BadgerDB store, encrypts the dump with AES-256-GCM, and writes versioned backup files to disk.
The fystack/mpcium repository implements a threshold-signature scheme where each node holds sensitive key-share material in a local BadgerDB instance. To prevent catastrophic data loss, the automatic backup system for key shares creates encrypted, incremental snapshots at configurable intervals. This article explains the architecture, execution flow, and restoration process based on the actual source code.
Backup Architecture Overview
The system consists of three tightly-coupled components that handle scheduling, execution, and recovery:
| Component | Responsibility | Key Implementation |
|---|---|---|
| Backup starter | Reads configuration, creates a time.Ticker, and calls the store’s Backup() method at regular intervals. |
StartPeriodicBackup in cmd/mpcium/main.go |
| Backup executor | Loads the latest backup version, runs Badger’s incremental DB.Backup, skips when nothing changed, encrypts the payload, writes a self-describing file, and updates the version record. |
badgerBackupExecutor in pkg/kvstore/badger_backup.go |
| Restore logic | Scans the backup directory, sorts files chronologically, decrypts each one, and loads the data into a fresh Badger instance. | RestoreAllBackupsEncrypted / loadEncryptedBackup in pkg/kvstore/badger_backup.go |
Starting the Periodic Backup Job
When the node initializes, the CLI parses backup_enabled (default true) and backup_period_seconds from the configuration. If enabled, main.go invokes:
stopBackup := StartPeriodicBackup(ctx, badgerKV, backupPeriodSeconds)
defer stopBackup()
StartPeriodicBackup creates a time.NewTicker and launches a goroutine that, on every tick, invokes badgerKV.Backup(). The returned stopBackup function cancels the context, cleanly halting the background job during shutdown.
Executing an Incremental Backup
BadgerKVStore.Backup() delegates to the executor defined in pkg/kvstore/badger_backup.go. The badgerBackupExecutor performs the following steps:
1. Version Bookkeeping
LoadVersionInfo reads latest.version (or creates a default record) to obtain the last since offset and version counter.
2. Incremental Badger Dump
The executor calls b.DB.Backup(&plain, since), which streams only the changes since the stored offset. Badger returns nextSince. If the dump is empty or nextSince == since, the backup is skipped to avoid writing redundant files.
3. Encryption
The plain dump (plain.Bytes()) is encrypted with AES-256-GCM via encryption.EncryptAESGCM. The encryption key is derived from the same password used for Badger’s on-disk encryption (appConfig.BadgerPassword).
4. Metadata Creation
A JSON object (BadgerBackupMeta) records:
- Algorithm (
AES-256-GCM) - Nonce (base64)
- Timestamps
- Input
Sinceand outputNextSinceoffsets - Key identifier (
sha256(key)[:16])
5. File Formatting
The backup file consists of:
- A magic header (
"MPCIUM_BACKUP") - A big-endian
uint32length of the metadata JSON - The metadata JSON bytes
- The ciphertext
The filename encodes the node ID, creation time, and version:
backup-<nodeID>-<YYYY-MM-DD_HH-MM-SS>-<version>.enc
6. Persist Version
After a successful write, SaveVersionInfo updates latest.version with the new counter and nextSince.
Restoring from Backup Files
When a node reconstructs its Badger DB after a crash or during initial sync, the restore logic in pkg/kvstore/badger_backup.go executes:
- Creates the target directory for the new database.
- Opens a fresh Badger instance with the original encryption key.
- Iterates over all
backup-*.encfiles in lexical order (SortedEncryptedBackups). - For each file:
- Verifies the magic header.
- Reads the metadata length, unmarshals the JSON, and extracts the nonce.
- Decrypts the ciphertext with
encryption.DecryptAESGCM. - Calls
db.Loadto stream the plaintext backup into Badger.
If any step fails, the restore aborts and cleans up the partially-loaded DB. Successful completion logs a confirmation message.
Configuration and Security
Configuration Knobs
| Flag / Viper key | Description | Default |
|---|---|---|
backup_enabled |
Enables the periodic job. | true |
backup_period_seconds |
Interval between successive backups (seconds). | 300 (5 min – defined in pkg/config/constants.go) |
backup_dir |
Destination directory for encrypted backups. | ./backups |
badger_password |
Password used both for Badger’s on-disk encryption and backup encryption. | must be supplied |
These values are read in cmd/mpcium/main.go via viper.SetDefault, viper.GetBool, viper.GetInt, and viper.GetString.
Security Properties
- Encryption at rest – Backups are AES-256-GCM encrypted with the node’s Badger password, guaranteeing confidentiality even if the backup directory is exposed.
- Integrity – The GCM authentication tag is bundled in the ciphertext; decryption fails if the data is tampered.
- Key identification – The metadata stores a truncated SHA-256 of the encryption key, allowing operators to verify the correct key was used during restore.
- Incremental efficiency – Badger’s native incremental backup means each file contains only the delta since the previous snapshot, reducing I/O and storage overhead.
Code Examples
Starting a Backup Manually
To trigger a backup outside the periodic schedule (e.g., from a REPL or test):
// Assume kvStore is a *kvstore.BadgerKVStore that was created earlier
if err := kvStore.Backup(); err != nil {
log.Fatalf("Backup failed: %v", err)
}
Restoring a Node from Backup
To reconstruct a database from the encrypted backup directory:
executor := kvstore.NewBadgerBackupExecutor(
"my-node", // node ID
nil, // no DB yet – will be created inside RestoreAllBackupsEncrypted
[]byte("my-secret-key"), // same backup encryption key
"/var/mpcium/backups", // directory containing backup-*.enc files
)
if err := executor.RestoreAllBackupsEncrypted("./restored-db", []byte("my-secret-key")); err != nil {
log.Fatalf("Restore failed: %v", err)
}
Summary
- Automatic scheduling – The
StartPeriodicBackupfunction incmd/mpcium/main.golaunches a background ticker that triggers backups at configurable intervals (default 5 minutes). - Incremental snapshots – The
badgerBackupExecutorinpkg/kvstore/badger_backup.gouses Badger’s nativeDB.Backupto capture only changes since the last snapshot, skipping empty cycles. - AES-256-GCM encryption – Every backup file is encrypted with the node’s Badger password, bundled with metadata (nonce, timestamps, version info), and written with a magic header for format verification.
- Versioned file naming – Backups follow the pattern
backup-<nodeID>-<timestamp>-<version>.enc, with an internallatest.versiontracking the logical offset (Since/NextSince). - Restore capability –
RestoreAllBackupsEncryptedscans, decrypts, and loads backup files in chronological order, reconstructing the database state after crashes or migrations.
Frequently Asked Questions
How often does mpcium create automatic backups?
By default, mpcium creates a backup every 300 seconds (5 minutes). You can adjust this interval via the backup_period_seconds configuration key. The ticker logic resides in cmd/mpcium/main.go, and the default value is defined in pkg/config/constants.go.
What encryption algorithm protects the backup files?
Backup files are protected with AES-256-GCM. The encryption uses the same password configured for BadgerDB (badger_password). The implementation in pkg/kvstore/badger_backup.go generates a random nonce for each backup, stores it in the JSON metadata, and appends the GCM authentication tag to the ciphertext to ensure integrity.
Can I restore a node on a different machine using these backups?
Yes. To migrate or recover a node, copy the backup-*.enc files to the new host and invoke RestoreAllBackupsEncrypted from pkg/kvstore/badger_backup.go. You must provide the original badger_password used during backup creation. The restore process opens a fresh Badger instance and replays the incremental dumps in chronological order to reconstruct the key-share database.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →