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)
|
N := uint64(1 << LogN)
|
||||||
t := params.T
|
t := params.T
|
||||||
|
|
||||||
ModuliQ1, ModuliP, ModuliQ2 := genModuli(params)
|
ModuliQ1, ModuliP, ModuliQ2 := GenModuli(params)
|
||||||
sigma := params.Sigma
|
sigma := params.Sigma
|
||||||
|
|
||||||
context.n = N
|
context.n = N
|
||||||
@@ -110,7 +110,7 @@ func (context *Context) SetParameters(params *Parameters) {
|
|||||||
context.alpha = uint64(len(ModuliP))
|
context.alpha = uint64(len(ModuliP))
|
||||||
context.beta = uint64(math.Ceil(float64(len(ModuliQ1)) / float64(context.alpha)))
|
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())
|
context.logQ = uint64(context.contextQ1P.ModulusBigint.BitLen())
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ func NewEncoder(params *Parameters) (encoder *Encoder) {
|
|||||||
pos &= (m - 1)
|
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.simplescaler = ring.NewSimpleScaler(encoder.bfvContext.t, encoder.bfvContext.contextQ1)
|
||||||
encoder.polypool = encoder.bfvContext.contextT.NewPoly()
|
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.baseconverter = ring.NewFastBasisExtender(evaluator.bfvContext.contextQ1.Modulus, evaluator.bfvContext.contextP.Modulus)
|
||||||
evaluator.decomposer = ring.NewArbitraryDecomposer(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)
|
evaluator.pHalf = new(big.Int).Rsh(evaluator.bfvContext.contextQ2.ModulusBigint, 1)
|
||||||
|
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
|
|||||||
51
bfv/utils.go
51
bfv/utils.go
@@ -5,7 +5,7 @@ import (
|
|||||||
"math/big"
|
"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))
|
delta := new(big.Int).Quo(context.ModulusBigint, ring.NewUint(t))
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ func genLiftParams(context *ring.Context, t uint64) (deltaMont []uint64) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func genRescalingParams(contextQ1, contextQ2 *ring.Context) (params []uint64) {
|
func GenRescalingParams(contextQ1, contextQ2 *ring.Context) (params []uint64) {
|
||||||
|
|
||||||
params = make([]uint64, len(contextQ2.Modulus))
|
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.
|
// 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
|
// Extracts all the different primes bit size and maps their number
|
||||||
primesbitlen := make(map[uint64]uint64)
|
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
|
// For each bitsize, finds that many primes
|
||||||
primes := make(map[uint64][]uint64)
|
primes := make(map[uint64][]uint64)
|
||||||
for key, value := range primesbitlen {
|
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
|
// 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
|
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.alpha = uint64(len(params.P))
|
||||||
ckkscontext.beta = uint64(math.Ceil(float64(ckkscontext.levels) / float64(ckkscontext.alpha)))
|
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)
|
ckkscontext.bigintChain = genBigIntChain(ckkscontext.moduli)
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ func NewContext(params *Parameters) (ckkscontext *Context) {
|
|||||||
|
|
||||||
ckkscontext.logQ = uint64(ckkscontext.contextKeys.ModulusBigint.BitLen())
|
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))
|
ckkscontext.gaussianSampler = ckkscontext.contextKeys.NewKYSampler(params.Sigma, int(6*params.Sigma))
|
||||||
|
|
||||||
|
|||||||
@@ -120,8 +120,29 @@ func genBigIntChain(Q []uint64) (bigintChain []*big.Int) {
|
|||||||
return
|
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.
|
// 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
|
// Extracts all the different primes bit size and maps their number
|
||||||
primesbitlen := make(map[uint64]uint64)
|
primesbitlen := make(map[uint64]uint64)
|
||||||
@@ -145,7 +166,7 @@ func genModuli(params *Parameters) (Q []uint64, P []uint64) {
|
|||||||
// For each bitsize, finds that many primes
|
// For each bitsize, finds that many primes
|
||||||
primes := make(map[uint64][]uint64)
|
primes := make(map[uint64][]uint64)
|
||||||
for key, value := range primesbitlen {
|
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
|
// Assigns the primes to the ckks moduli chain
|
||||||
@@ -165,51 +186,6 @@ func genModuli(params *Parameters) (Q []uint64, P []uint64) {
|
|||||||
return Q, P
|
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) {
|
func sliceBitReverseInPlaceComplex128(slice []complex128, N uint64) {
|
||||||
|
|
||||||
var bit, j 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
|
package ring
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"math/bits"
|
"math/bits"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -121,49 +120,48 @@ func IsPrime(num uint64) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateNTTPrimes generates "n" primes of bitlen "bitLen", suited for NTT with "N",
|
// GenerateCKKSPrimes generates primes given logQ = size of the primes, logN = size of N and level, the number
|
||||||
// starting from the integer "start" (which must be 1 mod 2N) and increasing (true) / decreasing (false) order
|
// of levels required. Will return all the appropriate primes, up to the number of level, with the
|
||||||
func GenerateNTTPrimes(N, start, n, bitLen uint64, sign bool) ([]uint64, error) {
|
// best avaliable deviation from the base power of 2 for the given level.
|
||||||
var x, v uint64
|
func GenerateNTTPrimes(logQ, logN, levels uint64) (primes []uint64) {
|
||||||
|
|
||||||
if uint64(bits.Len64(start)) != bitLen {
|
if logQ > 60 {
|
||||||
return nil, errors.New("error : start != bitLen")
|
panic("logQ must be between 1 and 60")
|
||||||
}
|
}
|
||||||
|
|
||||||
v = N << 1
|
var x, y, Qpow2, _2N uint64
|
||||||
if start != 0 {
|
|
||||||
if start&((N<<1)-1) != 1 {
|
primes = []uint64{}
|
||||||
return nil, errors.New("error : start != 1 mod 2*N")
|
|
||||||
|
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)
|
y -= _2N
|
||||||
|
|
||||||
i := uint64(0)
|
|
||||||
|
|
||||||
for i < n {
|
|
||||||
|
|
||||||
// x gets out of the bitLen bound
|
|
||||||
if uint64(bits.Len64(x)) != bitLen {
|
|
||||||
return primes, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if IsPrime(x) {
|
if IsPrime(x) {
|
||||||
primes[i] = x
|
primes = append(primes, x)
|
||||||
i++
|
if uint64(len(primes)) == levels {
|
||||||
|
return primes
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if sign {
|
x += _2N
|
||||||
x += v
|
|
||||||
} else {
|
|
||||||
x -= v
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return primes, nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//===========================
|
//===========================
|
||||||
|
|||||||
Reference in New Issue
Block a user