A production-ready Go implementation of Pedersen Verifiable Secret Sharing with human-friendly BIP-39 style mnemonic encoding.
✨ Human-Readable Shares - Shares encoded as BIP-39 compatible mnemonic phrases
🔒 Cryptographically Secure - Based on elliptic curve cryptography (P-256)
✅ Verifiable Shares - Built-in Pedersen commitment verification
📦 Threshold Secret Sharing - Configurable (k,n) threshold schemes
🎯 Production Ready - Comprehensive error handling and validation
⚡ Optimized - Compressed elliptic curve points and efficient encoding
This library implements Pedersen Verifiable Secret Sharing (VSS), a cryptographic protocol that splits a secret into multiple shares where:
- Any k shares can reconstruct the original secret (threshold)
- Fewer than k shares reveal no information about the secret
- Each share can be verified for authenticity without revealing the secret
- Shares are encoded as human-readable mnemonic phrases
go get github.com/IzyPro/pvsspackage main
import (
"fmt"
"github.com/IzyPro/pvss"
)
func main() {
// Initialize the PVSS instance
vss := pvss.NewPedersenVSS()
// Split a secret into 5 shares with a threshold of 3
secret := "My secret message that needs protection"
shares, err := vss.SplitSecret(secret, 5, 3)
if err != nil {
panic(err)
}
fmt.Printf("Generated %d shares:\n", len(shares))
for i, share := range shares {
fmt.Printf("Share %d:\n", i+1)
fmt.Printf(" Key: %s\n", share.Key)
fmt.Printf(" KeyCheck: %s\n\n", share.KeyCheck)
}
// Verify a share
valid, err := vss.VerifyShare(shares[0])
if err != nil {
panic(err)
}
fmt.Printf("Share 1 is valid: %v\n", valid)
// Reconstruct secret using 3 shares
reconstructed, err := vss.ReconstructSecret(shares[:3])
if err != nil {
panic(err)
}
fmt.Printf("Reconstructed secret: %s\n", reconstructed)
fmt.Printf("Match: %v\n", reconstructed == secret)
}type Share struct {
Key string // Mnemonic phrase containing share data
KeyCheck string // Mnemonic phrase containing verification data
}Each share consists of two mnemonic phrases:
- Key: The actual share value encoded as BIP-39 words with checksum
- KeyCheck: Metadata for verification (commitments, threshold, etc.)
Creates a new PVSS instance with P-256 elliptic curve and BIP-39 English word list.
vss := pvss.NewPedersenVSS()Splits a secret into multiple shares.
Parameters:
secret- The secret string to split (must not be empty)numShares- Total number of shares to generate (1-255)threshold- Minimum number of shares required for reconstruction (1 ≤ threshold ≤ numShares)
Returns:
[]Share- Array of generated shareserror- Error if parameters are invalid
Example:
shares, err := vss.SplitSecret("my-secret", 5, 3)Verifies the authenticity of a share using Pedersen commitments.
Parameters:
share- The share to verify
Returns:
bool-trueif share is valid,falseotherwiseerror- Error if share data is corrupted or malformed
Example:
valid, err := vss.VerifyShare(shares[0])
if err != nil {
// Handle error
}
if !valid {
// Share is invalid
}Reconstructs the original secret from shares.
Parameters:
shares- Array of shares (must be at least threshold number)
Returns:
string- The reconstructed secreterror- Error if insufficient shares, corrupted data, or verification fails
Example:
secret, err := vss.ReconstructSecret(shares[:3])- Chunking: The secret is split into 31-byte chunks to fit within the P-256 field
- Polynomial Generation: For each chunk, a random polynomial of degree (threshold-1) is generated with the chunk as the constant term
- Share Evaluation: Each share is a point on the polynomial evaluated at a unique x-coordinate
- Commitment Generation: Pedersen commitments are created for each polynomial coefficient
- Mnemonic Encoding: Share data and metadata are encoded as BIP-39 mnemonic phrases with checksums
- Checksum Validation: Verifies mnemonic phrase integrity
- Commitment Verification: Uses Pedersen commitments to verify share authenticity without revealing the secret
- Mathematical Validation: Ensures share values match the expected polynomial evaluation
- Validation: Checks threshold, checksums, and share consistency
- Lagrange Interpolation: Reconstructs each chunk's secret using the mathematical properties of polynomials
- Chunk Assembly: Combines reconstructed chunks back into the original secret
- Information-Theoretic Security: Fewer than threshold shares reveal no information about the secret
- Verifiable Shares: Pedersen commitments allow share verification without exposing the secret
- Elliptic Curve Cryptography: Uses NIST P-256 curve for commitment generation
- Secure Random Generation: Uses Go's
crypto/randfor all random number generation
The KeyCheck (metadata) contains only verification data:
- Threshold parameter
- Number of chunks
- Pedersen commitments for verification
Critical: The metadata does NOT contain any information that could be used to reconstruct the secret without the required threshold of shares.
The library provides comprehensive error handling:
shares, err := vss.SplitSecret("secret", 5, 3)
if err != nil {
switch {
case errors.Is(err, pvss.ErrInvalidThreshold):
// Handle threshold error
case errors.Is(err, pvss.ErrEmptySecret):
// Handle empty secret error
default:
// Handle other errors
}
}Common errors:
threshold cannot be greater than number of sharesthreshold must be at least 1number of shares cannot exceed 255secret cannot be emptyinsufficient shares: need X, got Yinvalid share phrase checksumduplicate share ID
For a typical secret:
- Share phrase (Key): 8-15 BIP-39 words
- Metadata phrase (KeyCheck): 15-30 BIP-39 words
- Total: ~25-45 words per complete share
Share size scales with:
- Secret length (more chunks = more words)
- Threshold value (higher threshold = more commitments)
- Splitting: O(n × m × t) where n=shares, m=chunks, t=threshold
- Verification: O(m × t) where m=chunks, t=threshold
- Reconstruction: O(t² × m) where t=threshold, m=chunks
// ❌ Don't store all shares together
storeInSameDatabase(shares)
// ✅ Distribute shares across different locations
storeShare(shares[0], "location1")
storeShare(shares[1], "location2")
storeShare(shares[2], "location3")// Create 7 shares with threshold of 4
shares, _ := vss.SplitSecret(secret, 7, 4)
// Distribute to different parties/locations
// This allows up to 3 shares to be lost/compromised
sendToParty("Alice", shares[0])
sendToParty("Bob", shares[1])
sendToParty("Carol", shares[2])
// ... etc// Always verify shares before attempting reconstruction
validShares := []pvss.Share{}
for _, share := range shares {
valid, err := vss.VerifyShare(share)
if err != nil || !valid {
continue // Skip invalid shares
}
validShares = append(validShares, share)
}
if len(validShares) >= threshold {
secret, _ := vss.ReconstructSecret(validShares)
}- Key Management: Distribute cryptographic keys across multiple parties
- Backup Systems: Create redundant backups where no single backup compromises security
- Multi-Party Computation: Enable collaborative secret management
- Disaster Recovery: Ensure critical secrets survive loss of some shares
- Access Control: Require multiple parties to authorize access to sensitive data
- Maximum shares: 255 (limited by 1-byte ID field)
- Chunk size: 31 bytes (ensures safe operation within P-256 field)
- Secret size: Unlimited (automatically chunked)
- Word list: BIP-39 English (2048 words)
Run the test suite:
go test ./...Run with race detector:
go test -race ./...Run benchmarks:
go test -bench=. -benchmemIf you discover a security vulnerability, please contact me on X (Twitter) or LinkedIn instead of using the issue tracker.
- Pedersen, T. P. (1992). "Non-Interactive and Information-Theoretic Secure Verifiable Secret Sharing"
- Shamir, A. (1979). "How to Share a Secret"
- BIP-39: Mnemonic code for generating deterministic keys
- SEC 2: Recommended Elliptic Curve Domain Parameters
- Built with Go's
crypto/ellipticpackage - BIP-39 word list for mnemonic encoding
- Inspired by threshold cryptography research
Note: This library is provided as-is for educational and production use. Always perform appropriate security reviews for your specific use case.