[utils]: added subpacakges and updated Write/Read API

This commit is contained in:
Jean-Philippe Bossuat
2023-03-21 10:43:54 +01:00
parent ae9a5a3bcb
commit cb20936495
37 changed files with 451 additions and 310 deletions

58
utils/sampling/prng.go Normal file
View File

@@ -0,0 +1,58 @@
package sampling
import (
"crypto/rand"
"io"
"golang.org/x/crypto/blake2b"
)
// PRNG is an interface for secure (keyed) deterministic 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
}
// 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!
func NewKeyedPRNG(key []byte) (*KeyedPRNG, error) {
var err error
prng := new(KeyedPRNG)
prng.xof, err = blake2b.NewXOF(blake2b.OutputLengthUnknown, key)
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 {
panic("crypto rand error")
}
prng.key = key
prng.xof, err = blake2b.NewXOF(blake2b.OutputLengthUnknown, key)
return prng, err
}
// Read reads bytes from the KeyedPRNG on sum.
func (prng *KeyedPRNG) Read(sum []byte) (n int, err error) {
if n, err = prng.xof.Read(sum); err != nil {
panic(err)
}
return n, nil
}
// Reset resets the PRNG to its initial state.
func (prng *KeyedPRNG) Reset() {
prng.xof.Reset()
}

View File

@@ -0,0 +1,35 @@
package sampling_test
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/tuneinsight/lattigo/v4/utils/sampling"
)
func Test_PRNG(t *testing.T) {
t.Run("PRNG", func(t *testing.T) {
key := []byte{0x49, 0x0a, 0x42, 0x3d, 0x97, 0x9d, 0xc1, 0x07, 0xa1, 0xd7, 0xe9, 0x7b, 0x3b, 0xce, 0xa1, 0xdb,
0x42, 0xf3, 0xa6, 0xd5, 0x75, 0xd2, 0x0c, 0x92, 0xb7, 0x35, 0xce, 0x0c, 0xee, 0x09, 0x7c, 0x98}
Ha, _ := sampling.NewKeyedPRNG(key)
Hb, _ := sampling.NewKeyedPRNG(key)
sum0 := make([]byte, 512)
sum1 := make([]byte, 512)
for i := 0; i < 128; i++ {
Hb.Read(sum1)
}
Hb.Reset()
Ha.Read(sum0)
Hb.Read(sum1)
require.Equal(t, sum0, sum1)
})
}

View File

@@ -0,0 +1,40 @@
package sampling
import (
"crypto/rand"
"encoding/binary"
"math/big"
)
// RandUint64 return a random value between 0 and 0xFFFFFFFFFFFFFFFF.
func RandUint64() uint64 {
b := []byte{0, 0, 0, 0, 0, 0, 0, 0}
if _, err := rand.Read(b); err != nil {
panic(err)
}
return binary.LittleEndian.Uint64(b)
}
// RandFloat64 returns a random float between min and max.
func RandFloat64(min, max float64) float64 {
b := []byte{0, 0, 0, 0, 0, 0, 0, 0}
if _, err := rand.Read(b); err != nil {
panic(err)
}
f := float64(binary.LittleEndian.Uint64(b)) / 1.8446744073709552e+19
return min + f*(max-min)
}
// RandComplex128 returns a random complex with the real and imaginary part between min and max.
func RandComplex128(min, max float64) complex128 {
return complex(RandFloat64(min, max), RandFloat64(min, max))
}
// RandInt generates a random Int in [0, max-1].
func RandInt(max *big.Int) (n *big.Int) {
var err error
if n, err = rand.Int(rand.Reader, max); err != nil {
panic(err)
}
return
}