Post-quantum secure one-time signatures using only hash functions.
Lamport signatures provide quantum resistance using only Keccak-256 hash operations. This implementation supports:
- Standard Lamport-256: 256-bit message signing with one-time keys
- Threshold MPC Control: T-Chain MPC jointly controls ONE Lamport key
- Key Chains: Automatic key rotation for continuous operation
- EVM Precompile: Gas-efficient on-chain verification
┌─────────────────────────────────────────────────────────────────────┐
│ THRESHOLD LAMPORT VIA MPC │
│ │
│ T-Chain MPC Network │ Any EVM Chain │
│ ┌─────────────────────────┐ │ ┌──────────────────────┐ │
│ │ Threshold lives HERE │ │ │ Standard Lamport │ │
│ │ (t-of-n signing) │─────────────│ verification only │ │
│ │ │ │ │ (no precompile!) │ │
│ │ • DKG for shares │ │ │ │ │
│ │ • Partial signatures │ │ │ keccak256(sig[i]) │ │
│ │ • Aggregation │ │ │ == pub[i][bit] │ │
│ └─────────────────────────┘ │ └──────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
Key insight: Threshold control lives OFF-CHAIN in the T-Chain MPC network. On-chain sees ONE standard Lamport signature - works on ANY EVM chain!
go get github.com/luxfi/lamportforge install luxfi/lamportnpm install @luxfi/lamport-contractsimport "github.com/luxfi/lamport"
// Generate a one-time key pair
kp, err := lamport.GenerateKeyPair()
// Get public key hash for on-chain storage
pkh := kp.Public.Hash()// Sign a 32-byte message (ONLY USE ONCE!)
message := sha3.Sum256([]byte("Hello, quantum-safe world!"))
sig, err := lamport.Sign(kp.Private, message[:])valid := lamport.Verify(kp.Public, message[:], sig)// Create a chain of 100 one-time keys
chain, err := lamport.NewKeyChain(100)
// Get current key and next PKH (for rotation)
current, _ := chain.Current()
nextPKH, _ := chain.NextPKH()
// After signing, advance to next key
chain.Advance()For T-Chain integration where threshold property is enforced off-chain:
import "github.com/luxfi/lamport/threshold"
// Configure threshold parameters
config := &threshold.Config{
Threshold: 3,
TotalParties: 5,
PartyID: "party-1",
ChainID: 96369, // Lux mainnet
ModuleAddress: common.HexToAddress("0x..."),
}
// Compute message hash (matches on-chain computation)
msg := threshold.ComputeMessage(
safeTxHash,
nextPKH,
config.ModuleAddress,
config.ChainID,
)
// Generate partial signature (this party's share)
partial, err := threshold.SignPartial(config, privateShare, msg)
// Coordinator aggregates partials into final signature
finalSig := threshold.Aggregate(partials...)The contracts/ directory contains production-ready Solidity implementations:
import {LamportLib} from "@luxfi/lamport/LamportLib.sol";
// Verify signature
bool valid = LamportLib.verify_u256(message, sig, pub);
// Compute PKH from public key
bytes32 pkh = LamportLib.computePKH(pub);
// Domain-separated message for threshold signing
uint256 m = LamportLib.computeThresholdMessage(
safeTxHash, nextPKH, address(this), block.chainid
);import {LamportModule} from "@luxfi/lamport/LamportModule.sol";
// Deploy and initialize
LamportModule module = new LamportModule(safeAddress);
// Initialize via Safe transaction with initialPKH
// Execute with Lamport signature
module.execWithLamport(to, value, data, operation, sig, pub, nextPKH);| Contract | Description | Gas |
|---|---|---|
LamportLib.sol |
Core verification library | ~280k verify |
LamportOptimized.sol |
Assembly-optimized verifier | ~380k |
LamportBase.sol |
Abstract base contract | - |
LamportVerifier.sol |
Standalone verifier | ~90k |
LamportModule.sol |
Safe module | ~150k exec |
LamportKeyRegistry.sol |
Key chain management | ~50k register |
Three assembly-optimized verification functions for different use cases:
import {LamportOptimized} from "@luxfi/lamport/LamportOptimized.sol";
LamportOptimized verifier = new LamportOptimized();
// Fast verification with early exit (~390k gas)
bool valid = verifier.verifyFast(bits, sig, pub);
// 4x loop unrolling (~380k gas, lowest cost)
bool valid = verifier.verifyUnrolled(bits, sig, pub);
// Constant-time for side-channel resistance (~435k gas)
bool valid = verifier.verifyBranchless(bits, sig, pub);For Lux-native chains, the Lamport precompile provides gas-efficient verification:
Precompile Address: 0x0200000000000000000000000000000000000006
// Verify Lamport signature via precompile (~15,800 gas vs ~85,000)
(bool valid) = LAMPORT_PRECOMPILE.staticcall(
abi.encode(messageHash, signature, publicKey)
);lamport/
├── primitives/ # Go: Core Lamport types and operations
│ ├── types.go # PrivateKey, PublicKey, Signature, KeyChain
│ ├── sign.go # Signing functions
│ ├── verify.go # Verification functions
│ └── lamport_test.go # Comprehensive tests
├── threshold/ # Go: T-Chain MPC integration
│ ├── config.go # Threshold configuration
│ ├── partial.go # Partial signature generation
│ └── aggregate.go # Signature aggregation
├── precompile/ # Go: EVM precompile interface
│ └── contract.go # Precompile implementation
├── contracts/ # Solidity: Smart contracts
│ ├── LamportLib.sol # Core verification library
│ ├── LamportOptimized.sol # Assembly-optimized verifier
│ ├── LamportBase.sol # Abstract base contract
│ ├── LamportTest.sol # Test helper contract
│ ├── LamportVerifier.sol # Standalone verifier
│ ├── LamportModule.sol # Safe module
│ ├── ILamportModule.sol # Module interface
│ ├── LamportKeyRegistry.sol # Key chain management
│ ├── test/ # Foundry tests (34 tests)
│ └── foundry.toml # Foundry config
├── docs/ # Documentation
│ ├── README.md # Documentation index
│ ├── overview.md # What are Lamport signatures?
│ ├── api.md # API reference
│ ├── security.md # Security model
│ ├── gas.md # Gas optimization
│ ├── integration.md # Integration guide
│ └── threshold.md # Threshold signing
├── paper/ # Academic whitepaper
│ ├── lamport.tex # LaTeX source
│ └── Makefile # Build automation
├── .github/workflows/ # CI/CD
│ └── ci.yml # GitHub Actions
├── main.go # CLI tool
└── Makefile # Build automation
| Operation | Time (Apple M1 Max) | Memory |
|---|---|---|
| KeyGen | 1.2ms | 32KB |
| Sign | 0.8ms | 8KB |
| Verify | 0.6ms | 16KB |
| PKH (keccak256) | 0.3ms | 0 |
- One-Time Property: Each key MUST only sign ONE message. Reuse reveals private key.
- Key Rotation: Use KeyChain for automatic rotation with nextPKH commitment.
- Domain Separation: Include chainId and module address to prevent replay.
- Canonical Digest: Compute safeTxHash ON-CHAIN, never accept from coordinator.
- LP-4105: Lamport OTS for Lux Safe
- LP-4200: Post-Quantum Cryptography Suite
- LP-7324: Ringtail Threshold Signatures
- LP-3310: Safe Multisig Standard
BSD-3-Clause - See LICENSE