mirror of
https://github.com/tuneinsight/lattigo.git
synced 2025-09-13 03:27:14 +00:00
BFV/CKKS : public gen API for DBFV and DCKKS
This commit is contained in:
@@ -81,7 +81,7 @@ func (context *Context) SetParameters(params *Parameters) {
|
||||
N := uint64(1 << LogN)
|
||||
t := params.T
|
||||
|
||||
ModuliQ1, ModuliP, ModuliQ2 := genModuli(params)
|
||||
ModuliQ1, ModuliP, ModuliQ2 := GenModuli(params)
|
||||
sigma := params.Sigma
|
||||
|
||||
context.n = N
|
||||
@@ -110,7 +110,7 @@ func (context *Context) SetParameters(params *Parameters) {
|
||||
context.alpha = uint64(len(ModuliP))
|
||||
context.beta = uint64(math.Ceil(float64(len(ModuliQ1)) / float64(context.alpha)))
|
||||
|
||||
context.rescaleParamsKeys = genRescalingParams(context.contextP, context.contextQ1)
|
||||
context.rescaleParamsKeys = GenRescalingParams(context.contextP, context.contextQ1)
|
||||
|
||||
context.logQ = uint64(context.contextQ1P.ModulusBigint.BitLen())
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ func NewEncoder(params *Parameters) (encoder *Encoder) {
|
||||
pos &= (m - 1)
|
||||
}
|
||||
|
||||
encoder.deltaMont = genLiftParams(encoder.bfvContext.contextQ1, encoder.bfvContext.t)
|
||||
encoder.deltaMont = GenLiftParams(encoder.bfvContext.contextQ1, encoder.bfvContext.t)
|
||||
|
||||
encoder.simplescaler = ring.NewSimpleScaler(encoder.bfvContext.t, encoder.bfvContext.contextQ1)
|
||||
encoder.polypool = encoder.bfvContext.contextT.NewPoly()
|
||||
|
||||
@@ -44,7 +44,7 @@ func NewEvaluator(params *Parameters) (evaluator *Evaluator) {
|
||||
evaluator.baseconverter = ring.NewFastBasisExtender(evaluator.bfvContext.contextQ1.Modulus, evaluator.bfvContext.contextP.Modulus)
|
||||
evaluator.decomposer = ring.NewArbitraryDecomposer(evaluator.bfvContext.contextQ1.Modulus, evaluator.bfvContext.contextP.Modulus)
|
||||
|
||||
evaluator.rescaleParamsMul = genRescalingParams(evaluator.bfvContext.contextQ1, evaluator.bfvContext.contextQ2)
|
||||
evaluator.rescaleParamsMul = GenRescalingParams(evaluator.bfvContext.contextQ1, evaluator.bfvContext.contextQ2)
|
||||
evaluator.pHalf = new(big.Int).Rsh(evaluator.bfvContext.contextQ2.ModulusBigint, 1)
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
|
||||
51
bfv/utils.go
51
bfv/utils.go
@@ -5,7 +5,7 @@ import (
|
||||
"math/big"
|
||||
)
|
||||
|
||||
func genLiftParams(context *ring.Context, t uint64) (deltaMont []uint64) {
|
||||
func GenLiftParams(context *ring.Context, t uint64) (deltaMont []uint64) {
|
||||
|
||||
delta := new(big.Int).Quo(context.ModulusBigint, ring.NewUint(t))
|
||||
|
||||
@@ -21,7 +21,7 @@ func genLiftParams(context *ring.Context, t uint64) (deltaMont []uint64) {
|
||||
return
|
||||
}
|
||||
|
||||
func genRescalingParams(contextQ1, contextQ2 *ring.Context) (params []uint64) {
|
||||
func GenRescalingParams(contextQ1, contextQ2 *ring.Context) (params []uint64) {
|
||||
|
||||
params = make([]uint64, len(contextQ2.Modulus))
|
||||
|
||||
@@ -38,7 +38,7 @@ func genRescalingParams(contextQ1, contextQ2 *ring.Context) (params []uint64) {
|
||||
}
|
||||
|
||||
// genModuli generates the appropriate primes from the parameters using generateCKKSPrimes such that all primes are different.
|
||||
func genModuli(params *Parameters) (Q1 []uint64, P []uint64, Q2 []uint64) {
|
||||
func GenModuli(params *Parameters) (Q1 []uint64, P []uint64, Q2 []uint64) {
|
||||
|
||||
// Extracts all the different primes bit size and maps their number
|
||||
primesbitlen := make(map[uint64]uint64)
|
||||
@@ -71,7 +71,7 @@ func genModuli(params *Parameters) (Q1 []uint64, P []uint64, Q2 []uint64) {
|
||||
// For each bitsize, finds that many primes
|
||||
primes := make(map[uint64][]uint64)
|
||||
for key, value := range primesbitlen {
|
||||
primes[key] = generateNTTPrimes(key, uint64(params.LogN), value)
|
||||
primes[key] = ring.GenerateNTTPrimes(key, uint64(params.LogN), value)
|
||||
}
|
||||
|
||||
// Assigns the primes to the ckks moduli chain
|
||||
@@ -97,47 +97,4 @@ func genModuli(params *Parameters) (Q1 []uint64, P []uint64, Q2 []uint64) {
|
||||
return Q1, P, Q2
|
||||
}
|
||||
|
||||
func generateNTTPrimes(logQ, logN, levels uint64) (primes []uint64) {
|
||||
|
||||
// generateCKKSPrimes generates primes given logQ = size of the primes, logN = size of N and level, the number
|
||||
// of levels required. Will return all the appropriate primes, up to the number of level, with the
|
||||
// best avaliable deviation from the base power of 2 for the given level.
|
||||
|
||||
if logQ > 60 {
|
||||
panic("logQ must be between 1 and 60")
|
||||
}
|
||||
|
||||
var x, y, Qpow2, _2N uint64
|
||||
|
||||
primes = []uint64{}
|
||||
|
||||
Qpow2 = 1 << logQ
|
||||
|
||||
_2N = 2 << logN
|
||||
|
||||
x = Qpow2 + 1
|
||||
y = Qpow2 + 1
|
||||
|
||||
for true {
|
||||
|
||||
if ring.IsPrime(y) {
|
||||
primes = append(primes, y)
|
||||
if uint64(len(primes)) == levels {
|
||||
return primes
|
||||
}
|
||||
}
|
||||
|
||||
y -= _2N
|
||||
|
||||
if ring.IsPrime(x) {
|
||||
primes = append(primes, x)
|
||||
if uint64(len(primes)) == levels {
|
||||
return primes
|
||||
}
|
||||
}
|
||||
|
||||
x += _2N
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ func NewContext(params *Parameters) (ckkscontext *Context) {
|
||||
ckkscontext.alpha = uint64(len(params.P))
|
||||
ckkscontext.beta = uint64(math.Ceil(float64(ckkscontext.levels) / float64(ckkscontext.alpha)))
|
||||
|
||||
ckkscontext.moduli, ckkscontext.specialprimes = genModuli(params)
|
||||
ckkscontext.moduli, ckkscontext.specialprimes = GenModuli(params)
|
||||
|
||||
ckkscontext.bigintChain = genBigIntChain(ckkscontext.moduli)
|
||||
|
||||
@@ -88,7 +88,7 @@ func NewContext(params *Parameters) (ckkscontext *Context) {
|
||||
|
||||
ckkscontext.logQ = uint64(ckkscontext.contextKeys.ModulusBigint.BitLen())
|
||||
|
||||
ckkscontext.rescaleParamsKeys = genSwitchkeysRescalingParams(ckkscontext.moduli, ckkscontext.specialprimes)
|
||||
ckkscontext.rescaleParamsKeys = GenSwitchkeysRescalingParams(ckkscontext.moduli, ckkscontext.specialprimes)
|
||||
|
||||
ckkscontext.gaussianSampler = ckkscontext.contextKeys.NewKYSampler(params.Sigma, int(6*params.Sigma))
|
||||
|
||||
|
||||
@@ -120,8 +120,29 @@ func genBigIntChain(Q []uint64) (bigintChain []*big.Int) {
|
||||
return
|
||||
}
|
||||
|
||||
func GenSwitchkeysRescalingParams(Q, P []uint64) (params []uint64) {
|
||||
|
||||
params = make([]uint64, len(Q))
|
||||
|
||||
PBig := ring.NewUint(1)
|
||||
for _, pj := range P {
|
||||
PBig.Mul(PBig, ring.NewUint(pj))
|
||||
}
|
||||
|
||||
tmp := ring.NewUint(0)
|
||||
|
||||
for i := 0; i < len(Q); i++ {
|
||||
|
||||
params[i] = tmp.Mod(PBig, ring.NewUint(Q[i])).Uint64()
|
||||
params[i] = ring.ModExp(params[i], Q[i]-2, Q[i])
|
||||
params[i] = ring.MForm(params[i], Q[i], ring.BRedParams(Q[i]))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// genModuli generates the appropriate primes from the parameters using generateCKKSPrimes such that all primes are different.
|
||||
func genModuli(params *Parameters) (Q []uint64, P []uint64) {
|
||||
func GenModuli(params *Parameters) (Q []uint64, P []uint64) {
|
||||
|
||||
// Extracts all the different primes bit size and maps their number
|
||||
primesbitlen := make(map[uint64]uint64)
|
||||
@@ -145,7 +166,7 @@ func genModuli(params *Parameters) (Q []uint64, P []uint64) {
|
||||
// For each bitsize, finds that many primes
|
||||
primes := make(map[uint64][]uint64)
|
||||
for key, value := range primesbitlen {
|
||||
primes[key] = generateCKKSPrimes(key, uint64(params.LogN), value)
|
||||
primes[key] = ring.GenerateNTTPrimes(key, uint64(params.LogN), value)
|
||||
}
|
||||
|
||||
// Assigns the primes to the ckks moduli chain
|
||||
@@ -165,51 +186,6 @@ func genModuli(params *Parameters) (Q []uint64, P []uint64) {
|
||||
return Q, P
|
||||
}
|
||||
|
||||
func generateCKKSPrimes(logQ, logN, levels uint64) (primes []uint64) {
|
||||
|
||||
// generateCKKSPrimes generates primes given logQ = size of the primes, logN = size of N and level, the number
|
||||
// of levels required. Will return all the appropriate primes, up to the number of level, with the
|
||||
// best avaliable deviation from the base power of 2 for the given level.
|
||||
|
||||
if logQ > 60 {
|
||||
panic("logQ must be between 1 and 60")
|
||||
}
|
||||
|
||||
var x, y, Qpow2, _2N uint64
|
||||
|
||||
primes = []uint64{}
|
||||
|
||||
Qpow2 = 1 << logQ
|
||||
|
||||
_2N = 2 << logN
|
||||
|
||||
x = Qpow2 + 1
|
||||
y = Qpow2 + 1
|
||||
|
||||
for true {
|
||||
|
||||
if ring.IsPrime(y) {
|
||||
primes = append(primes, y)
|
||||
if uint64(len(primes)) == levels {
|
||||
return primes
|
||||
}
|
||||
}
|
||||
|
||||
y -= _2N
|
||||
|
||||
if ring.IsPrime(x) {
|
||||
primes = append(primes, x)
|
||||
if uint64(len(primes)) == levels {
|
||||
return primes
|
||||
}
|
||||
}
|
||||
|
||||
x += _2N
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func sliceBitReverseInPlaceComplex128(slice []complex128, N uint64) {
|
||||
|
||||
var bit, j uint64
|
||||
@@ -231,23 +207,4 @@ func sliceBitReverseInPlaceComplex128(slice []complex128, N uint64) {
|
||||
}
|
||||
}
|
||||
|
||||
func genSwitchkeysRescalingParams(Q, P []uint64) (params []uint64) {
|
||||
|
||||
params = make([]uint64, len(Q))
|
||||
|
||||
PBig := ring.NewUint(1)
|
||||
for _, pj := range P {
|
||||
PBig.Mul(PBig, ring.NewUint(pj))
|
||||
}
|
||||
|
||||
tmp := ring.NewUint(0)
|
||||
|
||||
for i := 0; i < len(Q); i++ {
|
||||
|
||||
params[i] = tmp.Mod(PBig, ring.NewUint(Q[i])).Uint64()
|
||||
params[i] = ring.ModExp(params[i], Q[i]-2, Q[i])
|
||||
params[i] = ring.MForm(params[i], Q[i], ring.BRedParams(Q[i]))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package ring
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
@@ -121,49 +120,48 @@ func IsPrime(num uint64) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// GenerateNTTPrimes generates "n" primes of bitlen "bitLen", suited for NTT with "N",
|
||||
// starting from the integer "start" (which must be 1 mod 2N) and increasing (true) / decreasing (false) order
|
||||
func GenerateNTTPrimes(N, start, n, bitLen uint64, sign bool) ([]uint64, error) {
|
||||
var x, v uint64
|
||||
// GenerateCKKSPrimes generates primes given logQ = size of the primes, logN = size of N and level, the number
|
||||
// of levels required. Will return all the appropriate primes, up to the number of level, with the
|
||||
// best avaliable deviation from the base power of 2 for the given level.
|
||||
func GenerateNTTPrimes(logQ, logN, levels uint64) (primes []uint64) {
|
||||
|
||||
if uint64(bits.Len64(start)) != bitLen {
|
||||
return nil, errors.New("error : start != bitLen")
|
||||
if logQ > 60 {
|
||||
panic("logQ must be between 1 and 60")
|
||||
}
|
||||
|
||||
v = N << 1
|
||||
if start != 0 {
|
||||
if start&((N<<1)-1) != 1 {
|
||||
return nil, errors.New("error : start != 1 mod 2*N")
|
||||
var x, y, Qpow2, _2N uint64
|
||||
|
||||
primes = []uint64{}
|
||||
|
||||
Qpow2 = 1 << logQ
|
||||
|
||||
_2N = 2 << logN
|
||||
|
||||
x = Qpow2 + 1
|
||||
y = Qpow2 + 1
|
||||
|
||||
for true {
|
||||
|
||||
if IsPrime(y) {
|
||||
primes = append(primes, y)
|
||||
if uint64(len(primes)) == levels {
|
||||
return primes
|
||||
}
|
||||
}
|
||||
x = start
|
||||
} else {
|
||||
x = v<<(bitLen-uint64(bits.Len64(v))) + 1
|
||||
}
|
||||
|
||||
primes := make([]uint64, n)
|
||||
|
||||
i := uint64(0)
|
||||
|
||||
for i < n {
|
||||
|
||||
// x gets out of the bitLen bound
|
||||
if uint64(bits.Len64(x)) != bitLen {
|
||||
return primes, nil
|
||||
}
|
||||
y -= _2N
|
||||
|
||||
if IsPrime(x) {
|
||||
primes[i] = x
|
||||
i++
|
||||
primes = append(primes, x)
|
||||
if uint64(len(primes)) == levels {
|
||||
return primes
|
||||
}
|
||||
}
|
||||
|
||||
if sign {
|
||||
x += v
|
||||
} else {
|
||||
x -= v
|
||||
}
|
||||
x += _2N
|
||||
}
|
||||
|
||||
return primes, nil
|
||||
return
|
||||
}
|
||||
|
||||
//===========================
|
||||
|
||||
Reference in New Issue
Block a user