A simple, dependency-free Go implementation of SLH-DSA (Stateless Hash-Based Digital Signature Algorithm) as specified in FIPS 205.
SLH-DSA is a post-quantum digital signature scheme, designed to be secure against attacks by quantum computers.
- Zero external dependencies - Uses only Go 1.24+ standard library
- Simple API - Just
GenerateKey,Sign, andVerify - Easy to read - Clean, straightforward implementation
- FIPS 205 compliant - Validated against official NIST test vectors
go get github.com/KarpelesLab/slhdsaRequires Go 1.24 or later.
package main
import (
"crypto/rand"
"fmt"
"github.com/KarpelesLab/slhdsa"
)
func main() {
// Generate a key pair
sk, err := slhdsa.GenerateKey(rand.Reader, slhdsa.SHA2_128f)
if err != nil {
panic(err)
}
// Sign a message (implements crypto.Signer)
message := []byte("Hello, post-quantum world!")
signature, err := sk.Sign(nil, message, nil)
if err != nil {
panic(err)
}
// Verify the signature
pk := sk.Public().(*slhdsa.PublicKey)
valid := pk.Verify(signature, message, nil)
fmt.Println("Signature valid:", valid)
}All 12 FIPS 205 parameter sets are supported:
| Parameter Set | Security | Signature Size | Public Key | Private Key |
|---|---|---|---|---|
SHA2_128s |
128-bit | 7,856 bytes | 32 bytes | 64 bytes |
SHA2_128f |
128-bit | 17,088 bytes | 32 bytes | 64 bytes |
SHA2_192s |
192-bit | 16,224 bytes | 48 bytes | 96 bytes |
SHA2_192f |
192-bit | 35,664 bytes | 48 bytes | 96 bytes |
SHA2_256s |
256-bit | 29,792 bytes | 64 bytes | 128 bytes |
SHA2_256f |
256-bit | 49,856 bytes | 64 bytes | 128 bytes |
SHAKE_128s |
128-bit | 7,856 bytes | 32 bytes | 64 bytes |
SHAKE_128f |
128-bit | 17,088 bytes | 32 bytes | 64 bytes |
SHAKE_192s |
192-bit | 16,224 bytes | 48 bytes | 96 bytes |
SHAKE_192f |
192-bit | 35,664 bytes | 48 bytes | 96 bytes |
SHAKE_256s |
256-bit | 29,792 bytes | 64 bytes | 128 bytes |
SHAKE_256f |
256-bit | 49,856 bytes | 64 bytes | 128 bytes |
The s variants are slower but produce smaller signatures. The f variants are faster but produce larger signatures.
The PrivateKey type implements crypto.Signer and crypto.MessageSigner (Go 1.25+).
sk, err := slhdsa.GenerateKey(rand.Reader, slhdsa.SHA2_128f)// Basic signing (deterministic) - implements crypto.Signer
sig, err := sk.Sign(nil, message, nil)
// With context (for domain separation)
sig, err := sk.Sign(nil, message, &slhdsa.Options{Context: []byte("my-context")})
// With randomness (hedged signing, may help against side-channel attacks)
sig, err := sk.Sign(rand.Reader, message, nil)pk := sk.Public().(*slhdsa.PublicKey)
valid := pk.Verify(signature, message, nil)
// With context (must match what was used during signing)
valid := pk.Verify(signature, message, []byte("my-context"))// Export keys
skBytes := sk.Bytes()
pkBytes := sk.Public().Bytes()
// Import keys
sk, err := slhdsa.NewPrivateKey(slhdsa.SHA2_128f, skBytes)
pk, err := slhdsa.NewPublicKey(slhdsa.SHA2_128f, pkBytes)MIT License - see LICENSE file.