mirror of
https://github.com/tuneinsight/lattigo.git
synced 2025-09-13 03:27:14 +00:00
style: apply feedback from pr
This commit is contained in:
@@ -11,7 +11,6 @@ import (
|
||||
"github.com/tuneinsight/lattigo/v6/circuits/ckks/polynomial"
|
||||
"github.com/tuneinsight/lattigo/v6/core/rlwe"
|
||||
"github.com/tuneinsight/lattigo/v6/ring"
|
||||
"github.com/tuneinsight/lattigo/v6/ring/ringqp"
|
||||
"github.com/tuneinsight/lattigo/v6/schemes/ckks"
|
||||
"github.com/tuneinsight/lattigo/v6/utils"
|
||||
"github.com/tuneinsight/lattigo/v6/utils/bignum"
|
||||
@@ -671,13 +670,8 @@ func (eval Evaluator) ModUp(ctIn *rlwe.Ciphertext) (ctOut *rlwe.Ciphertext, err
|
||||
|
||||
ks := eval.Evaluator.Evaluator
|
||||
|
||||
size := eval.ResidualParameters.BaseRNSDecompositionVectorSize(eval.BootstrappingParameters.MaxLevelQ(), 0)
|
||||
buffDecompQP := make([]ringqp.Poly, size)
|
||||
for i := 0; i < size; i++ {
|
||||
buff := poolQP.GetBuffPolyQP()
|
||||
defer poolQP.RecycleBuffPolyQP(buff)
|
||||
buffDecompQP[i] = *buff
|
||||
}
|
||||
buffDecompQP := poolQP.GetBuffDecompQP(eval.ResidualParameters.Parameters, eval.BootstrappingParameters.MaxLevelQ(), 0)
|
||||
defer eval.pool.RecycleBuffDecompQP(buffDecompQP)
|
||||
|
||||
// ModUp q->QP for ctIn[1] centered around q
|
||||
for j := 0; j < N; j++ {
|
||||
|
||||
@@ -26,6 +26,7 @@ func BenchmarkConcurrentBootstrap(b *testing.B) {
|
||||
evk, _, err := btpParams.GenEvaluationKeys(sk)
|
||||
require.NoError(b, err)
|
||||
|
||||
// Benchmark parallel bootstrapping
|
||||
b.Run(ParamsToString(params, btpParams.LogMaxDimensions().Cols, "Bootstrap/"), func(b *testing.B) {
|
||||
var err error
|
||||
eval, err := NewEvaluator(btpParams, evk)
|
||||
|
||||
@@ -48,13 +48,8 @@ func (eval Evaluator) EvaluateMany(ctIn *rlwe.Ciphertext, linearTransformations
|
||||
levelQ = utils.Min(levelQ, ctIn.Level())
|
||||
|
||||
poolQP := eval.pool.AtLevel(levelQ, levelP)
|
||||
baseRNSDecompositionVectorSize := eval.Evaluator.GetRLWEParameters().BaseRNSDecompositionVectorSize(levelQ, levelP)
|
||||
buffDecompQP := make([]ringqp.Poly, baseRNSDecompositionVectorSize)
|
||||
for i := 0; i < len(buffDecompQP); i++ {
|
||||
buff := poolQP.GetBuffPolyQP()
|
||||
defer poolQP.RecycleBuffPolyQP(buff)
|
||||
buffDecompQP[i] = *buff
|
||||
}
|
||||
buffDecompQP := poolQP.GetBuffDecompQP(*eval.GetRLWEParameters(), levelQ, levelP)
|
||||
defer eval.pool.RecycleBuffDecompQP(buffDecompQP)
|
||||
|
||||
eval.DecomposeNTT(levelQ, levelP, levelP+1, ctIn.Value[1], ctIn.IsNTT, buffDecompQP)
|
||||
|
||||
|
||||
@@ -211,13 +211,8 @@ func (eval Evaluator) PartialTracesSum(ctIn *Ciphertext, offset, n int, opOut *C
|
||||
|
||||
cQ.MetaData = ctInNTT.MetaData
|
||||
|
||||
baseRNSDecompositionVectorSize := eval.params.BaseRNSDecompositionVectorSize(levelQ, levelP)
|
||||
buffDecompQP := make([]ringqp.Poly, baseRNSDecompositionVectorSize)
|
||||
for i := 0; i < len(buffDecompQP); i++ {
|
||||
buff := poolQP.GetBuffPolyQP()
|
||||
defer poolQP.RecycleBuffPolyQP(buff)
|
||||
buffDecompQP[i] = *buff
|
||||
}
|
||||
buffDecompQP := poolQP.GetBuffDecompQP(eval.params, levelQ, levelP)
|
||||
defer eval.pool.RecycleBuffDecompQP(buffDecompQP)
|
||||
|
||||
state := false
|
||||
copy := true
|
||||
|
||||
@@ -29,6 +29,15 @@ func NewPool(rqp *ringqp.Ring, pools ...structs.BufferPool[*[]uint64]) *Pool {
|
||||
return &Pool{ringqpPool}
|
||||
}
|
||||
|
||||
// AtLevel returns a new pool from which objects from polynomials at the given levels can be drawn.
|
||||
// The method accepts up to two levels:
|
||||
// Zero level: the objects returned are built from polynomials at level 0.
|
||||
// One level: the objects returned are built from polynomials in RingQ (resp. RingP) at the given level (resp. level 0).
|
||||
// Two levels: the objects returned are built from polynomials in RingQ (resp. RingP) at levels[0] (resp. levels[1]).
|
||||
func (pool Pool) AtLevel(levels ...int) *Pool {
|
||||
return &Pool{pool.Pool.AtLevel(levels...)}
|
||||
}
|
||||
|
||||
// GetBuffCt returns a ciphertext that can be used as a buffer for intermediate computations.
|
||||
// After use, the ciphertext should be recycled with [Pool.RecycleBuffCt].
|
||||
// The optional dimensions specify the degree and level of the ciphertext (default to 2, eval.params.ringQ.Level()).
|
||||
@@ -99,3 +108,22 @@ func (pool *Pool) GetBuffPt(level ...int) *Plaintext {
|
||||
func (pool *Pool) RecycleBuffPt(pt *Plaintext) {
|
||||
pool.RecycleBuffPoly(&pt.Value)
|
||||
}
|
||||
|
||||
// GetBuffDecompQP returns buffers of polys to be used for RNS decomposition.
|
||||
// After use, the array of buffers must be recycled with [Pool.RecycleBuffDecompQP].
|
||||
func (pool *Pool) GetBuffDecompQP(params Parameters, levelQ, levelP int) []ringqp.Poly {
|
||||
size := params.BaseRNSDecompositionVectorSize(levelQ, levelP)
|
||||
buffDecompQP := make([]ringqp.Poly, size)
|
||||
for i := 0; i < size; i++ {
|
||||
poly := pool.GetBuffPolyQP()
|
||||
buffDecompQP[i] = *poly
|
||||
}
|
||||
return buffDecompQP
|
||||
}
|
||||
|
||||
// RecycleBuffDecompQP recycles a temporary array of polys used for decomposition.
|
||||
func (pool *Pool) RecycleBuffDecompQP(decomp []ringqp.Poly) {
|
||||
for _, poly := range decomp {
|
||||
pool.RecycleBuffPolyQP(&poly)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -729,13 +729,9 @@ func testGadgetProduct(tc *TestContext, levelQ, bpw2 int, t *testing.T) {
|
||||
|
||||
// Setup temporary buffer for decomposition
|
||||
poolQP := tc.eval.pool.AtLevel(levelQ, levelP)
|
||||
size := params.BaseRNSDecompositionVectorSize(levelQ, 0)
|
||||
buffDecompQP := make([]ringqp.Poly, size)
|
||||
for i := 0; i < size; i++ {
|
||||
poly := poolQP.GetBuffPolyQP()
|
||||
defer poolQP.RecycleBuffPolyQP(poly)
|
||||
buffDecompQP[i] = *poly
|
||||
}
|
||||
buffDecompQP := poolQP.GetBuffDecompQP(params, levelQ, levelP)
|
||||
defer poolQP.RecycleBuffDecompQP(buffDecompQP)
|
||||
|
||||
if bpw2 != 0 {
|
||||
t.Skip("method is unsupported for BaseTwoDecomposition != 0")
|
||||
}
|
||||
@@ -966,13 +962,9 @@ func testAutomorphism(tc *TestContext, level, bpw2 int, t *testing.T) {
|
||||
|
||||
// Setup temporary buffer for decomposition
|
||||
poolQP := tc.eval.pool.AtLevel(level, params.MaxLevelP())
|
||||
size := params.BaseRNSDecompositionVectorSize(level, 0)
|
||||
buffDecompQP := make([]ringqp.Poly, size)
|
||||
for i := 0; i < size; i++ {
|
||||
poly := poolQP.GetBuffPolyQP()
|
||||
defer poolQP.RecycleBuffPolyQP(poly)
|
||||
buffDecompQP[i] = *poly
|
||||
}
|
||||
buffDecompQP := poolQP.GetBuffDecompQP(params, level, 0)
|
||||
defer poolQP.RecycleBuffDecompQP(buffDecompQP)
|
||||
|
||||
// Generate a plaintext with values up to 2^30
|
||||
pt := genPlaintext(params, level, 1<<30)
|
||||
|
||||
@@ -1025,13 +1017,8 @@ func testAutomorphism(tc *TestContext, level, bpw2 int, t *testing.T) {
|
||||
|
||||
// Setup temporary buffer for decomposition
|
||||
poolQP := tc.eval.pool.AtLevel(level, params.MaxLevelP())
|
||||
size := params.BaseRNSDecompositionVectorSize(level, 0)
|
||||
buffDecompQP := make([]ringqp.Poly, size)
|
||||
for i := 0; i < size; i++ {
|
||||
poly := poolQP.GetBuffPolyQP()
|
||||
defer poolQP.RecycleBuffPolyQP(poly)
|
||||
buffDecompQP[i] = *poly
|
||||
}
|
||||
buffDecompQP := poolQP.GetBuffDecompQP(params, level, 0)
|
||||
defer poolQP.RecycleBuffDecompQP(buffDecompQP)
|
||||
|
||||
// Generate a plaintext with values up to 2^30
|
||||
pt := genPlaintext(params, level, 1<<30)
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"math"
|
||||
"sync"
|
||||
|
||||
"github.com/tuneinsight/lattigo/v6/circuits/ckks/bootstrapping"
|
||||
"github.com/tuneinsight/lattigo/v6/core/rlwe"
|
||||
@@ -194,22 +193,23 @@ func main() {
|
||||
// To equalize the scale, the function evaluator.SetScale(ciphertext, parameters.DefaultScale()) can be used at the expense of one level.
|
||||
// If the ciphertext is is at level one or greater when given to the bootstrapper, this equalization is automatically done.
|
||||
// Here we bootstrap two ciphertexts in parallel to demonstrate that evaluators are thread-safe.
|
||||
var wg sync.WaitGroup
|
||||
var res1, res2 *rlwe.Ciphertext
|
||||
resChan := make(chan *rlwe.Ciphertext, 1)
|
||||
fmt.Println("Bootstrapping...")
|
||||
wg.Add(1)
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
res2, err = eval.Bootstrap(ciphertext2)
|
||||
res, err := eval.Bootstrap(ciphertext2)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resChan <- res
|
||||
}()
|
||||
res1, err = eval.Bootstrap(ciphertext1)
|
||||
|
||||
res1, err := eval.Bootstrap(ciphertext1)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
res2 := <-resChan
|
||||
fmt.Println("Done")
|
||||
|
||||
//==================
|
||||
|
||||
@@ -759,7 +759,7 @@ func main() {
|
||||
// CONCURRENCY
|
||||
// ==========
|
||||
//
|
||||
// All public structures in Lattigo are thread-safe and can be used concurrently.
|
||||
// In lattigo, a type's methods are thread-safe and can be called concurrently. E.g. one can use an evaluator's methods concurrently.
|
||||
//
|
||||
|
||||
}
|
||||
|
||||
@@ -72,12 +72,12 @@ func (g *GaussianSampler) read(pol Poly, f func(a, b, c uint64) uint64) {
|
||||
|
||||
r := g.baseRing
|
||||
|
||||
randomBufferN := make([]byte, 1024)
|
||||
var randomBufferN [1024]byte
|
||||
var ptr int
|
||||
|
||||
level := r.level
|
||||
|
||||
if _, err := g.prng.Read(randomBufferN); err != nil {
|
||||
if _, err := g.prng.Read(randomBufferN[:]); err != nil {
|
||||
// Sanity check, this error should not happen.
|
||||
panic(err)
|
||||
}
|
||||
@@ -121,7 +121,7 @@ func (g *GaussianSampler) read(pol Poly, f func(a, b, c uint64) uint64) {
|
||||
|
||||
for {
|
||||
// Sample norm with sigma = 1 and sign
|
||||
norm, sign = g.normFloat64(randomBufferN, &ptr)
|
||||
norm, sign = g.normFloat64(randomBufferN[:], &ptr)
|
||||
|
||||
// Sets normFlo = norm * sigma with precision 53 bits
|
||||
// and 0.5 for rounding discretization
|
||||
@@ -160,7 +160,7 @@ func (g *GaussianSampler) read(pol Poly, f func(a, b, c uint64) uint64) {
|
||||
for i := 0; i < N; i++ {
|
||||
|
||||
for {
|
||||
norm, sign = g.normFloat64(randomBufferN, &ptr)
|
||||
norm, sign = g.normFloat64(randomBufferN[:], &ptr)
|
||||
|
||||
if v := norm * sigma; v <= bound {
|
||||
coeffInt = uint64(v + 0.5) // rounding
|
||||
@@ -189,16 +189,15 @@ func (g *GaussianSampler) read(pol Poly, f func(a, b, c uint64) uint64) {
|
||||
//
|
||||
// Algorithm adapted from https://golang.org/src/math/rand/normal.go
|
||||
// to use a secure PRNG instead of math/rand.
|
||||
func (g *GaussianSampler) normFloat64(buffer []byte, ptr *int) (float64, uint64) {
|
||||
func (g *GaussianSampler) normFloat64(buff []byte, ptr *int) (float64, uint64) {
|
||||
|
||||
currPtr := *ptr
|
||||
buff := buffer
|
||||
prng := g.prng
|
||||
buffLen := len(buff)
|
||||
|
||||
read := func() {
|
||||
if currPtr == buffLen {
|
||||
if _, err := prng.Read(buff[:]); err != nil {
|
||||
if _, err := prng.Read(buff); err != nil {
|
||||
// Sanity check, this error should not happen.
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -1240,15 +1240,10 @@ func (eval Evaluator) RotateHoistedNew(ctIn *rlwe.Ciphertext, rotations []int) (
|
||||
func (eval Evaluator) RotateHoisted(ctIn *rlwe.Ciphertext, rotations []int, opOut map[int]*rlwe.Ciphertext) (err error) {
|
||||
levelQ := ctIn.Level()
|
||||
|
||||
baseRNSDecompositionVectorSize := eval.GetParameters().BaseRNSDecompositionVectorSize(levelQ, eval.GetParameters().MaxLevelP())
|
||||
buffDecompQP := make([]ringqp.Poly, baseRNSDecompositionVectorSize)
|
||||
|
||||
poolQP := eval.pool.AtLevel(levelQ, eval.GetParameters().MaxLevelP())
|
||||
for i := 0; i < len(buffDecompQP); i++ {
|
||||
buff := poolQP.GetBuffPolyQP()
|
||||
defer poolQP.RecycleBuffPolyQP(buff)
|
||||
buffDecompQP[i] = *buff
|
||||
}
|
||||
|
||||
buffDecompQP := poolQP.GetBuffDecompQP(*eval.GetRLWEParameters(), levelQ, eval.GetParameters().MaxLevelP())
|
||||
defer poolQP.RecycleBuffDecompQP(buffDecompQP)
|
||||
|
||||
eval.DecomposeNTT(levelQ, eval.GetParameters().MaxLevelP(), eval.GetParameters().PCount(), ctIn.Value[1], ctIn.IsNTT, buffDecompQP)
|
||||
for _, i := range rotations {
|
||||
|
||||
@@ -30,8 +30,8 @@ func (prng *ThreadSafePRNG) Read(sum []byte) (n int, err error) {
|
||||
// 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].
|
||||
// WARNING: If KeyedPRNG is called concurrently by multiple threads, the resulting sequences will be independent and no error will be triggered. However, the result will not be deterministic and therefore, in most cases, it does not make sense to use KeyedPRNG in a concurrent setting.
|
||||
// NOTE: For a PRNG securely seeded with a private key use [ThreadSafePRNG].
|
||||
type KeyedPRNG struct {
|
||||
mutex sync.Mutex
|
||||
key []byte
|
||||
@@ -41,7 +41,7 @@ type KeyedPRNG struct {
|
||||
// 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.
|
||||
// WARNING: KeyedPRNG can be called by multiple threads BUT the generated sequences will not be deterministic.
|
||||
func NewKeyedPRNG(key []byte) (*KeyedPRNG, error) {
|
||||
var err error
|
||||
prng := new(KeyedPRNG)
|
||||
|
||||
Reference in New Issue
Block a user