Skip to content

chainwayxyz/secret-sharing

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Shamir Secret Sharing

A command-line tool for splitting secrets using Shamir's Secret Sharing with optional PGP encryption and BIP39 mnemonic support.

Features

  • Shamir Secret Sharing: Split secrets with configurable threshold (t) and total shares (n)
  • PGP Encryption: Encrypt shares to individual recipients using OpenPGP public keys
  • BIP39 Mnemonic Support: Generate and convert 24-word mnemonic phrases for 32-byte secrets
  • Stdin/Stdout Interface: Easy piping and automation
  • Non-Interactive: Suitable for scripts and automated workflows
  • Secure Sharing: Encrypts secrets with XSalsa20-Poly1305 before splitting the encryption key

Installation

From Source

git clone https://github.com/chainwayxyz/secret-sharing.git
cd secret-sharing
cargo build --release
./target/release/secret-sharing --help

Dependencies

  • shamirsecretsharing - Shamir secret sharing implementation
  • rand - Cryptographic random number generation
  • sequoia-openpgp - OpenPGP implementation (PGP encryption)
  • crypto_secretbox - XSalsa20-Poly1305 authenticated encryption
  • chrono - Timestamp generation for filenames
  • bip39 - BIP39 mnemonic phrase generation and parsing
  • clap - CLI parsing
  • anyhow - Error handling
  • hex - Hex encoding/decoding

Usage

Basic Secret Sharing

Split a secret into shares without encryption:

# From random bytes
openssl rand -hex 32 | secret-sharing share -t 2 -n 3

# Output (hex-encoded shares to stdout):
017276e586b8a646033226dee295250e0f110f8fa537d2f02cd67f33311fdd759f0b700b34876eb...
024c0ca665303e8a1a395e7db2d962d0700e2ab65015c766a519de6fe43860c88d0b700b34876eb...
03e1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890ab...

# Save shares to file
openssl rand -hex 32 | secret-sharing share -t 2 -n 3 > shares.txt

# Reconstruct from any 2 shares
head -2 shares.txt | secret-sharing reconstruct -t 2 --hex

PGP Encrypted Sharing

Step 1: Export Public Keys

First, export PGP public keys to files:

# Export public keys from your GPG keyring
gpg --armor --export [email protected] > alice.asc
gpg --armor --export [email protected] > bob.asc
gpg --armor --export [email protected] > charlie.asc

Step 2: Share and Encrypt

# Split secret and encrypt to recipients
cat wallet.dat | secret-sharing share \
  -k alice.asc,bob.asc,charlie.asc \
  -t 2 -n 3

# Output (files created with threshold, total, and timestamp in filename):
share_01_of_03_t2_for_alice.asc_20251112_180320.pgp
share_02_of_03_t2_for_alice.asc_20251112_180320.pgp
share_03_of_03_t2_for_charlie.asc_20251112_180320.pgp

# Or specify output directory (created automatically if doesn't exist):
cat wallet.dat | secret-sharing share \
  -k alice.asc,bob.asc,charlie.asc \
  -t 2 -n 3 \
  --out backup_shares

# Output:
backup_shares/share_01_of_03_t2_for_alice.asc_20251112_180320.pgp
backup_shares/share_02_of_03_t2_for_bob.asc_20251112_180320.pgp
backup_shares/share_03_of_03_t2_for_charlie.asc_20251112_180320.pgp

Step 3: Reconstruct

Recipients decrypt their shares and reconstruct:

# Each recipient decrypts their share (will prompt for passphrase)
gpg -d share_01_of_03_t2_for_alice.asc_20251112_180320.pgp > share1.txt
gpg -d share_02_of_03_t2_for_bob.asc_20251112_180320.pgp > share2.txt

# Any 2 shares (threshold=2) can reconstruct the original secret
cat share1.txt share2.txt | secret-sharing reconstruct -t 2 > wallet.dat

BIP39 Mnemonic Support

Generate a mnemonic for backup:

# Generate 32-byte secret and display mnemonic
openssl rand -hex 32 | secret-sharing share -t 2 -n 3 --mnemonic > shares.txt

# Output to stderr:
# Mnemonic: park system enable actress february smart husband inner bean session...

# Save mnemonic separately
openssl rand -hex 32 | secret-sharing share -t 2 -n 3 --mnemonic 2> mnemonic.txt > shares.txt

Convert mnemonic back to secret:

# Convert 24-word mnemonic to 32-byte secret (hex output)
echo "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art" | \
  secret-sharing mnemonic-to-secret

# Output:
# 0000000000000000000000000000000000000000000000000000000000000000

# Use in workflow
echo "your 24 words here" | \
  secret-sharing mnemonic-to-secret | \
  secret-sharing share -t 2 -n 3

# Get raw bytes instead of hex
echo "your mnemonic" | secret-sharing mnemonic-to-secret --raw > secret.bin

CLI Reference

share

Split a secret into shares.

secret-sharing share -t <threshold> -n <total> [OPTIONS]

Options:

  • -t, --threshold <N>: Minimum shares needed to reconstruct (required)
  • -n, --total <N>: Total number of shares to create (required)
  • -k, --keys <FILES>: Comma-separated PGP public key files (optional)
  • -m, --mnemonic: Display BIP39 mnemonic (requires exactly 32 bytes input)
  • -o, --out <DIR>: Output directory for encrypted files (created if doesn't exist)

Input: Secret from stdin (raw bytes or 64-char hex string for 32 bytes)

Output:

  • Without -k: Hex shares to stdout (one per line)
  • With -k: Encrypted .pgp files created, filenames printed to stdout

Filename Format: share_XX_of_YY_tZ_for_<recipient>_<timestamp>.pgp

  • XX = Share number (01, 02, 03...)
  • YY = Total shares
  • Z = Threshold
  • <recipient> = Sanitized key identifier
  • <timestamp> = YYYYMMDD_HHMMSS

reconstruct

Reconstruct a secret from shares.

secret-sharing reconstruct -t <threshold> [--hex]

Options:

  • -t, --threshold <N>: Threshold value used during sharing (required)
  • --hex: Output as hex instead of raw bytes

Input: Hex-encoded shares from stdin, one per line (blank lines and # comments ignored). Each encrypted share includes a trailing newline for easy concatenation.

Output: Reconstructed secret to stdout

mnemonic-to-secret

Convert a BIP39 mnemonic phrase (24 words) to a 32-byte secret.

secret-sharing mnemonic-to-secret [--raw]

Options:

  • --raw: Output raw bytes (default: hex output)

Input: BIP39 mnemonic phrase from stdin

Output: 32-byte secret to stdout (hex by default)

Security

This implementation uses proper Shamir Secret Sharing with encryption, following the approach used in the reference implementation:

  1. A random 32-byte encryption key is generated for each secret
  2. The key is split using Shamir's Secret Sharing algorithm
  3. The actual secret is encrypted with XSalsa20-Poly1305
  4. Each share contains: [keyshare (33 bytes)] + [encrypted secret]

This ensures that:

  • Individual shares reveal nothing about the original secret
  • Only combining threshold shares reconstructs the encryption key
  • The encryption key is used to decrypt the ciphertext
  • Meets true secret sharing security requirements

PGP Encryption

This tool uses Sequoia-OpenPGP, a modern PGP implementation that:

  • Properly selects encryption-capable subkeys
  • Supports modern PGP standards
  • Provides better security and performance

The tool automatically uses encryption-capable subkeys when available, ensuring compatibility with standard GPG key structures where:

  • Primary key is marked for certification [C]
  • Subkeys are marked for signing [S], encryption [E], or authentication [A]

Examples

Backup a Wallet File

# Export public keys
gpg --armor --export [email protected] > alice.asc
gpg --armor --export [email protected] > bob.asc
gpg --armor --export [email protected] > charlie.asc

# Split and encrypt wallet to output directory
cat wallet.dat | secret-sharing share \
  -k alice.asc,bob.asc,charlie.asc \
  -t 2 -n 3 \
  --out wallet_backup

# Files created in wallet_backup/:
# share_01_of_03_t2_for_alice.asc_20251112_180320.pgp
# share_02_of_03_t2_for_bob.asc_20251112_180320.pgp
# share_03_of_03_t2_for_charlie.asc_20251112_180320.pgp

Recover from Shares

# Decrypt shares (each person with their private key)
gpg -d wallet_backup/share_01_of_03_t2_for_alice.asc_20251112_180320.pgp > share1.txt
gpg -d wallet_backup/share_02_of_03_t2_for_bob.asc_20251112_180320.pgp > share2.txt

# Reconstruct wallet (need 2 out of 3 shares, as threshold=2)
cat share1.txt share2.txt | secret-sharing reconstruct -t 2 > wallet.dat

Generate Secret with Mnemonic

# Generate secret and save both mnemonic and shares
openssl rand -hex 32 | \
  secret-sharing share -t 2 -n 3 --mnemonic \
  2> backup-mnemonic.txt \
  > backup-shares.txt

# Later, recover secret from mnemonic
cat backup-mnemonic.txt | \
  sed 's/Mnemonic: //' | \
  secret-sharing mnemonic-to-secret

Testing

Run the full test suite:

cargo test

Test coverage includes:

  • Unit tests for core crypto functions
  • Integration tests for CLI workflows
  • PGP encryption and decryption tests
  • BIP39 mnemonic generation and parsing tests
  • Share/reconstruct roundtrip tests

References

This implementation is inspired by and follows the cryptographic approach of dsprenkels/sss-cli

Packages

No packages published

Languages