mirror of
https://github.com/tuneinsight/lattigo.git
synced 2025-09-13 03:27:14 +00:00
refactor: make keyedprng thread-safe, restrict usage + add warning
This commit is contained in:
@@ -2,41 +2,46 @@ package sampling
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/crypto/blake2b"
|
||||
)
|
||||
|
||||
// PRNG is an interface for secure (keyed) deterministic generation of random bytes
|
||||
// PRNG is an interface for secure generation of random bytes
|
||||
type PRNG interface {
|
||||
io.Reader
|
||||
}
|
||||
|
||||
// KeyedPRNG is a structure storing the parameters used to securely and deterministically generate shared
|
||||
// sequences of random bytes among different parties using the hash function blake2b. Backward sequence
|
||||
// security (given the digest i, compute the digest i-1) is ensured by default, however forward sequence
|
||||
// security (given the digest i, compute the digest i+1) is only ensured if the KeyedPRNG is keyed.
|
||||
type KeyedPRNG struct {
|
||||
key []byte
|
||||
xof blake2b.XOF
|
||||
}
|
||||
|
||||
type ThreadSafePRNG struct {
|
||||
}
|
||||
|
||||
// NewPRNG returns a new PRNG that is thread-safe
|
||||
func NewPRNG() (*ThreadSafePRNG, error) {
|
||||
return &ThreadSafePRNG{}, nil
|
||||
}
|
||||
|
||||
// Read reads bytes from the KeyedPRNG on sum.
|
||||
func (prng *ThreadSafePRNG) Read(sum []byte) (n int, err error) {
|
||||
tmpPRNG, err := NewPRNG()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("crypto rand error: %w", err)
|
||||
}
|
||||
return tmpPRNG.Read(sum)
|
||||
return rand.Read(sum)
|
||||
}
|
||||
|
||||
// KeyedPRNG is a structure storing the parameters used to securely and *deterministically* generate shared
|
||||
// sequences of random bytes among different parties using the hash function blake2b. Backward sequence
|
||||
// security (given the digest i, compute the digest i-1) is ensured by default, however forward sequence
|
||||
// security (given the digest i, compute the digest i+1) is only ensured if the KeyedPRNG is keyed.
|
||||
// WARNING: KeyedPRNG should NOT be called by multiple threads. It does not make sense to do so as the resulting
|
||||
// sequence will not be deterministic for a given key. For a PRNG securely seeded with a private keyuse [ThreadSafePRNG].
|
||||
type KeyedPRNG struct {
|
||||
mutex sync.Mutex
|
||||
key []byte
|
||||
xof blake2b.XOF
|
||||
}
|
||||
|
||||
// NewKeyedPRNG creates a new instance of KeyedPRNG.
|
||||
// Accepts an optional key, else set key=nil which is treated as key=[]byte{}
|
||||
// WARNING: A PRNG INITIALISED WITH key=nil IS INSECURE!
|
||||
// WARNING: KeyedPRNG should NOT be called by multiple threads. If that occurs, the generated sequence will not be deterministic.
|
||||
func NewKeyedPRNG(key []byte) (*KeyedPRNG, error) {
|
||||
var err error
|
||||
prng := new(KeyedPRNG)
|
||||
@@ -44,19 +49,6 @@ func NewKeyedPRNG(key []byte) (*KeyedPRNG, error) {
|
||||
return prng, err
|
||||
}
|
||||
|
||||
// NewPRNG creates KeyedPRNG keyed from rand.Read for instances were no key should be provided by the user
|
||||
func NewPRNG() (*KeyedPRNG, error) {
|
||||
var err error
|
||||
prng := new(KeyedPRNG)
|
||||
key := make([]byte, 64)
|
||||
if _, err := rand.Read(key); err != nil {
|
||||
return nil, fmt.Errorf("crypto rand error: %w", err)
|
||||
}
|
||||
prng.key = key
|
||||
prng.xof, err = blake2b.NewXOF(blake2b.OutputLengthUnknown, key)
|
||||
return prng, err
|
||||
}
|
||||
|
||||
// Key returns a copy of the key used to seed the PRNG.
|
||||
// This value can be used with `NewKeyedPRNG` to instantiate
|
||||
// a new PRNG that will produce the same stream of bytes.
|
||||
@@ -67,11 +59,17 @@ func (prng *KeyedPRNG) Key() (key []byte) {
|
||||
}
|
||||
|
||||
// Read reads bytes from the KeyedPRNG on sum.
|
||||
// WARNING: Read() should NOT be called concurrently by multiple threads. If that occurs, the generated sequence will not be deterministic.
|
||||
func (prng *KeyedPRNG) Read(sum []byte) (n int, err error) {
|
||||
prng.mutex.Lock()
|
||||
defer prng.mutex.Unlock()
|
||||
return prng.xof.Read(sum)
|
||||
}
|
||||
|
||||
// Reset resets the PRNG to its initial state.
|
||||
// WARNING: KeyedPRNG's methods should not be called concurrently. If that occurs, the generated sequence will not be deterministic.
|
||||
func (prng *KeyedPRNG) Reset() {
|
||||
prng.mutex.Lock()
|
||||
defer prng.mutex.Unlock()
|
||||
prng.xof.Reset()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user