feat: deterministic key generation from seeded PRNG

Add NewEncryptorFromPRNG and NewKeyGeneratorFromEncryptor to support
consensus-safe FHE keygen where all validators must derive identical keys
from a shared seed.
This commit is contained in:
2026-04-13 03:11:41 -07:00
parent 9a7cb0169f
commit 8c50b24c80
+21 -2
View File
@@ -102,16 +102,26 @@ func newEncryptor(params Parameters) *Encryptor {
// CAUTION: THIS FUNCTION SHOULD BE USED FOR TESTING PURPOSES ONLY.
// WARNING: The resulting encryptor is not meant to be used concurrently.
func newTestEncryptorWithKeyedPRNG(params ParameterProvider, key EncryptionKey, prng *sampling.KeyedPRNG) *Encryptor {
return NewEncryptorFromPRNG(params, key, prng)
}
// NewEncryptorFromPRNG creates an [Encryptor] using the provided deterministic PRNG
// instead of crypto/rand. This is required for consensus-critical code where all
// validators must produce identical keys from the same seed.
//
// WARNING: The resulting encryptor is not safe for concurrent use. The caller must
// ensure sequential access or use external synchronization.
func NewEncryptorFromPRNG(params ParameterProvider, key EncryptionKey, prng *sampling.KeyedPRNG) *Encryptor {
p := *params.GetRLWEParameters()
enc := NewEncryptor(params, key)
xeSampler, err := ring.NewSampler(prng, p.RingQ(), p.Xe(), false)
if err != nil {
panic(fmt.Errorf("NewEncryptorWithPRNG: cannot create xeSampler %w", err))
panic(fmt.Errorf("NewEncryptorFromPRNG: cannot create xeSampler %w", err))
}
xsSampler, err := ring.NewSampler(prng, p.RingQ(), p.Xs(), false)
if err != nil {
panic(fmt.Errorf("NewEncryptorWithPRNG: cannot create xsSampler %w", err))
panic(fmt.Errorf("NewEncryptorFromPRNG: cannot create xsSampler %w", err))
}
uniformSampler := ringqp.NewUniformSampler(prng, *p.RingQP())
enc.prng = prng
@@ -122,6 +132,15 @@ func newTestEncryptorWithKeyedPRNG(params ParameterProvider, key EncryptionKey,
return enc
}
// NewKeyGeneratorFromEncryptor creates a [KeyGenerator] from a pre-configured [Encryptor].
// This allows callers to provide a deterministic PRNG for consensus-critical keygen.
func NewKeyGeneratorFromEncryptor(enc *Encryptor, params ParameterProvider) *KeyGenerator {
return &KeyGenerator{
Encryptor: enc,
pool: NewPool(params.GetRLWEParameters().RingQP()),
}
}
// Encrypt encrypts the input plaintext using the stored encryption key and writes the result on ct.
// The method currently accepts only *[Ciphertext] as ct.
// If a [Plaintext] is given, then the output [Ciphertext] [MetaData] will match the [Plaintext] [MetaData].