mirror of
https://github.com/tuneinsight/lattigo.git
synced 2025-09-13 03:27:14 +00:00
[bfv/ckkd] : Moduli internals are now public
This commit is contained in:
@@ -103,7 +103,7 @@ func genTestParams(params *Parameters) (testctx *testContext, err error) {
|
||||
|
||||
func testParameters(testctx *testContext, t *testing.T) {
|
||||
t.Run("Parameters/NewParametersFromModuli", func(t *testing.T) {
|
||||
p, err := NewParametersFromModuli(testctx.params.logN, testctx.params.Moduli, testctx.params.t)
|
||||
p, err := NewParametersFromModuli(testctx.params.logN, testctx.params.Moduli(), testctx.params.t)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, p.Equals(testctx.params))
|
||||
})
|
||||
|
||||
375
bfv/params.go
375
bfv/params.go
@@ -49,180 +49,68 @@ const DefaultSigma = 3.2
|
||||
var DefaultParams = []*Parameters{
|
||||
|
||||
{
|
||||
logN: 12,
|
||||
t: 65537,
|
||||
Moduli: Moduli{
|
||||
qi: []uint64{0x7ffffec001, 0x8000016001}, // 39 + 39 bits
|
||||
pi: []uint64{0x40002001}, // 30 bits
|
||||
qiMul: []uint64{0xfffffffffffc001, 0x100000000000e001}}, // 60 + 60 bits
|
||||
logN: 12,
|
||||
t: 65537,
|
||||
qi: []uint64{0x7ffffec001, 0x8000016001}, // 39 + 39 bits
|
||||
pi: []uint64{0x40002001}, // 30 bits
|
||||
qiMul: []uint64{0xfffffffffffc001, 0x100000000000e001}, // 60 + 60 bits
|
||||
sigma: DefaultSigma,
|
||||
},
|
||||
|
||||
{
|
||||
logN: 13,
|
||||
t: 65537,
|
||||
Moduli: Moduli{
|
||||
qi: []uint64{0x3fffffffef8001, 0x4000000011c001, 0x40000000120001}, // 54 + 54 + 54 bits
|
||||
pi: []uint64{0x7ffffffffb4001}, // 55 bits
|
||||
qiMul: []uint64{0xfffffffffffc001, 0xffffffffffe8001, 0x1000000000024001}}, // 60 + 60 + 60 bits
|
||||
logN: 13,
|
||||
t: 65537,
|
||||
qi: []uint64{0x3fffffffef8001, 0x4000000011c001, 0x40000000120001}, // 54 + 54 + 54 bits
|
||||
pi: []uint64{0x7ffffffffb4001}, // 55 bits
|
||||
qiMul: []uint64{0xfffffffffffc001, 0xffffffffffe8001, 0x1000000000024001}, // 60 + 60 + 60 bits
|
||||
sigma: DefaultSigma,
|
||||
},
|
||||
|
||||
{
|
||||
logN: 14,
|
||||
t: 65537,
|
||||
Moduli: Moduli{
|
||||
qi: []uint64{0x100000000060001, 0x80000000068001, 0x80000000080001,
|
||||
0x3fffffffef8001, 0x40000000120001, 0x3fffffffeb8001}, // 56 + 55 + 55 + 54 + 54 + 54 bits
|
||||
pi: []uint64{0x80000000130001, 0x7fffffffe90001}, // 55 + 55 bits
|
||||
qiMul: []uint64{0xffffffffffe8001, 0xffffffffffd8001, 0xffffffffffc0001,
|
||||
0x1000000000078001, 0xffffffffff28001, 0xfffffffffe38001}}, // 60 + 60 + 60 + 60 + 60 + 60 bits
|
||||
qi: []uint64{0x100000000060001, 0x80000000068001, 0x80000000080001,
|
||||
0x3fffffffef8001, 0x40000000120001, 0x3fffffffeb8001}, // 56 + 55 + 55 + 54 + 54 + 54 bits
|
||||
pi: []uint64{0x80000000130001, 0x7fffffffe90001}, // 55 + 55 bits
|
||||
qiMul: []uint64{0xffffffffffe8001, 0xffffffffffd8001, 0xffffffffffc0001,
|
||||
0x1000000000078001, 0xffffffffff28001, 0xfffffffffe38001}, // 60 + 60 + 60 + 60 + 60 + 60 bits
|
||||
sigma: DefaultSigma,
|
||||
},
|
||||
|
||||
{
|
||||
logN: 15,
|
||||
t: 65537,
|
||||
Moduli: Moduli{
|
||||
qi: []uint64{0x7ffffffffe70001, 0x7ffffffffe10001, 0x7ffffffffcc0001, // 59 + 59 + 59 bits
|
||||
0x400000000270001, 0x400000000350001, 0x400000000360001, // 58 + 58 + 58 bits
|
||||
0x3ffffffffc10001, 0x3ffffffffbe0001, 0x3ffffffffbd0001, // 58 + 58 + 58 bits
|
||||
0x4000000004d0001, 0x400000000570001, 0x400000000660001}, // 58 + 58 + 58 bits
|
||||
pi: []uint64{0xffffffffffc0001, 0x10000000001d0001, 0x10000000006e0001}, // 60 + 60 + 60 bits
|
||||
qiMul: []uint64{0xfffffffff840001, 0x1000000000860001, 0x1000000000870001, // 60 + 60 + 60 bits
|
||||
0x1000000000930001, 0xfffffffff6a0001, 0x1000000000980001, // 60 + 60 + 60 bits
|
||||
0xfffffffff5a0001, 0xfffffffff550001, 0x1000000000b00001, // 60 + 60 + 60 bits
|
||||
0xfffffffff330001, 0x1000000000ce0001, 0xfffffffff2a0001}}, // 60 + 60 + 60 bits
|
||||
qi: []uint64{0x7ffffffffe70001, 0x7ffffffffe10001, 0x7ffffffffcc0001, // 59 + 59 + 59 bits
|
||||
0x400000000270001, 0x400000000350001, 0x400000000360001, // 58 + 58 + 58 bits
|
||||
0x3ffffffffc10001, 0x3ffffffffbe0001, 0x3ffffffffbd0001, // 58 + 58 + 58 bits
|
||||
0x4000000004d0001, 0x400000000570001, 0x400000000660001}, // 58 + 58 + 58 bits
|
||||
pi: []uint64{0xffffffffffc0001, 0x10000000001d0001, 0x10000000006e0001}, // 60 + 60 + 60 bits
|
||||
qiMul: []uint64{0xfffffffff840001, 0x1000000000860001, 0x1000000000870001, // 60 + 60 + 60 bits
|
||||
0x1000000000930001, 0xfffffffff6a0001, 0x1000000000980001, // 60 + 60 + 60 bits
|
||||
0xfffffffff5a0001, 0xfffffffff550001, 0x1000000000b00001, // 60 + 60 + 60 bits
|
||||
0xfffffffff330001, 0x1000000000ce0001, 0xfffffffff2a0001}, // 60 + 60 + 60 bits
|
||||
sigma: DefaultSigma,
|
||||
},
|
||||
}
|
||||
|
||||
// Moduli stores the NTT primes of the RNS representation.
|
||||
type Moduli struct {
|
||||
qi []uint64 // Ciphertext prime moduli
|
||||
pi []uint64 // Keys additional prime moduli
|
||||
qiMul []uint64 // Ciphertext secondary prime moduli
|
||||
}
|
||||
|
||||
// Qi returns a new slice with the factors of the ciphertext modulus q
|
||||
func (m *Moduli) Qi() []uint64 {
|
||||
qi := make([]uint64, len(m.qi))
|
||||
copy(qi, m.qi)
|
||||
return qi
|
||||
}
|
||||
|
||||
// QiCount returns the number of factors of the ciphertext modulus q
|
||||
func (m *Moduli) QiCount() uint64 {
|
||||
return uint64(len(m.qi))
|
||||
}
|
||||
|
||||
// Pi returns a new slice with the factors of the ciphertext modulus extention P
|
||||
func (m *Moduli) Pi() []uint64 {
|
||||
pi := make([]uint64, len(m.pi))
|
||||
copy(pi, m.pi)
|
||||
return pi
|
||||
}
|
||||
|
||||
// PiCount returns the number of factors of the ciphertext modulus extention P
|
||||
func (m *Moduli) PiCount() uint64 {
|
||||
return uint64(len(m.pi))
|
||||
}
|
||||
|
||||
// QPiCount returns the number of factors of the ciphertext modulus Q + the modulus extension P
|
||||
func (m *Moduli) QPiCount() uint64 {
|
||||
return m.QiCount() + m.PiCount()
|
||||
}
|
||||
|
||||
// LogQP returns the size of the extended modulus QP in bits
|
||||
func (m *Moduli) LogQP() uint64 {
|
||||
tmp := ring.NewUint(1)
|
||||
for _, qi := range m.qi {
|
||||
tmp.Mul(tmp, ring.NewUint(qi))
|
||||
}
|
||||
for _, pi := range m.pi {
|
||||
tmp.Mul(tmp, ring.NewUint(pi))
|
||||
}
|
||||
return uint64(tmp.BitLen())
|
||||
}
|
||||
|
||||
// LogQ returns the size of the modulus Q in bits
|
||||
func (m *Moduli) LogQ() uint64 {
|
||||
tmp := ring.NewUint(1)
|
||||
for _, qi := range m.qi {
|
||||
tmp.Mul(tmp, ring.NewUint(qi))
|
||||
}
|
||||
return uint64(tmp.BitLen())
|
||||
}
|
||||
|
||||
// LogP returns the size of the modulus P in bits
|
||||
func (m *Moduli) LogP() uint64 {
|
||||
tmp := ring.NewUint(1)
|
||||
for _, pi := range m.pi {
|
||||
tmp.Mul(tmp, ring.NewUint(pi))
|
||||
}
|
||||
return uint64(tmp.BitLen())
|
||||
}
|
||||
|
||||
// LogQAlpha returns the size in bits of the sum of the norm of
|
||||
// each element of the special RNS decomposition basis for the
|
||||
// key-switching.
|
||||
// LogQAlpha is the size of the element that is multipled by the
|
||||
// error during the keyswitching and then divided by P.
|
||||
// LogQAlpha should be smaller than P or the error added during
|
||||
// the key-switching wont be negligible.
|
||||
func (m *Moduli) LogQAlpha() uint64 {
|
||||
|
||||
alpha := m.PiCount()
|
||||
|
||||
if alpha == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
res := ring.NewUint(0)
|
||||
var j uint64
|
||||
for i := uint64(0); i < m.QiCount(); i = i + alpha {
|
||||
|
||||
j = i + alpha
|
||||
if j > m.QiCount() {
|
||||
j = m.QiCount()
|
||||
}
|
||||
|
||||
tmp := ring.NewUint(1)
|
||||
for _, qi := range m.qi[i:j] {
|
||||
tmp.Mul(tmp, ring.NewUint(qi))
|
||||
}
|
||||
|
||||
res.Add(res, tmp)
|
||||
}
|
||||
|
||||
return uint64(res.BitLen())
|
||||
}
|
||||
|
||||
// Alpha returns the number of moduli in in P
|
||||
func (m *Moduli) Alpha() uint64 {
|
||||
return m.PiCount()
|
||||
}
|
||||
|
||||
// Beta returns the number of element in the RNS decomposition basis: Ceil(lenQi / lenPi)
|
||||
func (m *Moduli) Beta() uint64 {
|
||||
if m.Alpha() != 0 {
|
||||
return uint64(math.Ceil(float64(m.QiCount()) / float64(m.Alpha())))
|
||||
}
|
||||
|
||||
return 0
|
||||
Qi []uint64 // Ciphertext prime moduli
|
||||
Pi []uint64 // Keys additional prime moduli
|
||||
QiMul []uint64 // Ciphertext secondary prime moduli
|
||||
}
|
||||
|
||||
// Copy creates a copy of the target Moduli.
|
||||
func (m *Moduli) Copy() Moduli {
|
||||
|
||||
qi := make([]uint64, len(m.qi))
|
||||
copy(qi, m.qi)
|
||||
qi := make([]uint64, len(m.Qi))
|
||||
copy(qi, m.Qi)
|
||||
|
||||
pi := make([]uint64, len(m.pi))
|
||||
copy(pi, m.pi)
|
||||
pi := make([]uint64, len(m.Pi))
|
||||
copy(pi, m.Pi)
|
||||
|
||||
qiMul := make([]uint64, len(m.qiMul))
|
||||
copy(qiMul, m.qiMul)
|
||||
qiMul := make([]uint64, len(m.QiMul))
|
||||
copy(qiMul, m.QiMul)
|
||||
|
||||
return Moduli{qi, pi, qiMul}
|
||||
}
|
||||
@@ -251,14 +139,16 @@ func (m *LogModuli) Copy() LogModuli {
|
||||
|
||||
// Parameters represents a given parameter set for the BFV cryptosystem.
|
||||
type Parameters struct {
|
||||
Moduli
|
||||
logN uint64 // Log Ring degree (power of 2)
|
||||
logN uint64 // Log Ring degree (power of 2)
|
||||
qi []uint64
|
||||
pi []uint64
|
||||
qiMul []uint64
|
||||
t uint64 // Plaintext modulus
|
||||
sigma float64 // Gaussian sampling standard deviation
|
||||
}
|
||||
|
||||
// NewParametersFromModuli creates a new Parameters struct and returns a pointer to it.
|
||||
func NewParametersFromModuli(logN uint64, m Moduli, t uint64) (p *Parameters, err error) {
|
||||
func NewParametersFromModuli(logN uint64, m *Moduli, t uint64) (p *Parameters, err error) {
|
||||
|
||||
p = new(Parameters)
|
||||
|
||||
@@ -273,7 +163,14 @@ func NewParametersFromModuli(logN uint64, m Moduli, t uint64) (p *Parameters, er
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p.Moduli = m.Copy()
|
||||
p.qi = make([]uint64, len(m.Qi))
|
||||
copy(p.qi, m.Qi)
|
||||
|
||||
p.pi = make([]uint64, len(m.Pi))
|
||||
copy(p.pi, m.Pi)
|
||||
|
||||
p.qiMul = make([]uint64, len(m.QiMul))
|
||||
copy(p.qiMul, m.QiMul)
|
||||
|
||||
p.sigma = DefaultSigma
|
||||
|
||||
@@ -283,7 +180,7 @@ func NewParametersFromModuli(logN uint64, m Moduli, t uint64) (p *Parameters, er
|
||||
}
|
||||
|
||||
// NewParametersFromLogModuli creates a new Parameters struct and returns a pointer to it.
|
||||
func NewParametersFromLogModuli(logN uint64, lm LogModuli, t uint64) (p *Parameters, err error) {
|
||||
func NewParametersFromLogModuli(logN uint64, lm *LogModuli, t uint64) (p *Parameters, err error) {
|
||||
|
||||
if err = checkLogModuli(lm); err != nil {
|
||||
return nil, err
|
||||
@@ -326,23 +223,141 @@ func (p *Parameters) WithT(T uint64) (pCopy *Parameters) {
|
||||
}
|
||||
|
||||
// LogModuli generates a LogModuli struct from the parameters' Moduli struct and returns it.
|
||||
func (p *Parameters) LogModuli() LogModuli {
|
||||
var lm LogModuli
|
||||
func (p *Parameters) LogModuli() (lm *LogModuli) {
|
||||
lm = new(LogModuli)
|
||||
lm.LogQi = make([]uint64, len(p.qi), len(p.qi))
|
||||
for i := range p.qi {
|
||||
lm.LogQi[i] = uint64(math.Round(math.Log2(float64(p.qi[i]))))
|
||||
}
|
||||
|
||||
lm.LogPi = make([]uint64, len(p.pi), len(p.pi))
|
||||
for i := range p.pi {
|
||||
lm.LogPi[i] = uint64(math.Round(math.Log2(float64(p.pi[i]))))
|
||||
}
|
||||
|
||||
lm.LogQiMul = make([]uint64, len(p.qiMul), len(p.qiMul))
|
||||
for i := range p.qiMul {
|
||||
lm.LogQiMul[i] = uint64(math.Round(math.Log2(float64(p.qiMul[i]))))
|
||||
}
|
||||
return lm
|
||||
return
|
||||
}
|
||||
|
||||
// Moduli returns a struct Moduli with the moduli of the parameters
|
||||
func (p *Parameters) Moduli() (m *Moduli) {
|
||||
m = new(Moduli)
|
||||
m.Qi = make([]uint64, len(p.qi))
|
||||
copy(m.Qi, p.qi)
|
||||
m.Pi = make([]uint64, len(p.pi))
|
||||
copy(m.Pi, p.pi)
|
||||
m.QiMul = make([]uint64, len(p.qiMul))
|
||||
copy(m.QiMul, p.qiMul)
|
||||
return
|
||||
}
|
||||
|
||||
// Qi returns a new slice with the factors of the ciphertext modulus q
|
||||
func (p *Parameters) Qi() []uint64 {
|
||||
qi := make([]uint64, len(p.qi))
|
||||
copy(qi, p.qi)
|
||||
return qi
|
||||
}
|
||||
|
||||
// QiCount returns the number of factors of the ciphertext modulus q
|
||||
func (p *Parameters) QiCount() uint64 {
|
||||
return uint64(len(p.qi))
|
||||
}
|
||||
|
||||
// Pi returns a new slice with the factors of the ciphertext modulus extention P
|
||||
func (p *Parameters) Pi() []uint64 {
|
||||
pi := make([]uint64, len(p.pi))
|
||||
copy(pi, p.pi)
|
||||
return pi
|
||||
}
|
||||
|
||||
// PiCount returns the number of factors of the ciphertext modulus extention P
|
||||
func (p *Parameters) PiCount() uint64 {
|
||||
return uint64(len(p.pi))
|
||||
}
|
||||
|
||||
// QPiCount returns the number of factors of the ciphertext modulus Q + the modulus extension P
|
||||
func (p *Parameters) QPiCount() uint64 {
|
||||
return p.QiCount() + p.PiCount()
|
||||
}
|
||||
|
||||
// LogQP returns the size of the extended modulus QP in bits
|
||||
func (p *Parameters) LogQP() uint64 {
|
||||
tmp := ring.NewUint(1)
|
||||
for _, qi := range p.qi {
|
||||
tmp.Mul(tmp, ring.NewUint(qi))
|
||||
}
|
||||
for _, pi := range p.pi {
|
||||
tmp.Mul(tmp, ring.NewUint(pi))
|
||||
}
|
||||
return uint64(tmp.BitLen())
|
||||
}
|
||||
|
||||
// LogQ returns the size of the modulus Q in bits
|
||||
func (p *Parameters) LogQ() uint64 {
|
||||
tmp := ring.NewUint(1)
|
||||
for _, qi := range p.qi {
|
||||
tmp.Mul(tmp, ring.NewUint(qi))
|
||||
}
|
||||
return uint64(tmp.BitLen())
|
||||
}
|
||||
|
||||
// LogP returns the size of the modulus P in bits
|
||||
func (p *Parameters) LogP() uint64 {
|
||||
tmp := ring.NewUint(1)
|
||||
for _, pi := range p.pi {
|
||||
tmp.Mul(tmp, ring.NewUint(pi))
|
||||
}
|
||||
return uint64(tmp.BitLen())
|
||||
}
|
||||
|
||||
// LogQAlpha returns the size in bits of the sum of the norm of
|
||||
// each element of the special RNS decomposition basis for the
|
||||
// key-switching.
|
||||
// LogQAlpha is the size of the element that is multipled by the
|
||||
// error during the keyswitching and then divided by P.
|
||||
// LogQAlpha should be smaller than P or the error added during
|
||||
// the key-switching wont be negligible.
|
||||
func (p *Parameters) LogQAlpha() uint64 {
|
||||
|
||||
alpha := p.PiCount()
|
||||
|
||||
if alpha == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
res := ring.NewUint(0)
|
||||
var j uint64
|
||||
for i := uint64(0); i < p.QiCount(); i = i + alpha {
|
||||
|
||||
j = i + alpha
|
||||
if j > p.QiCount() {
|
||||
j = p.QiCount()
|
||||
}
|
||||
|
||||
tmp := ring.NewUint(1)
|
||||
for _, qi := range p.qi[i:j] {
|
||||
tmp.Mul(tmp, ring.NewUint(qi))
|
||||
}
|
||||
|
||||
res.Add(res, tmp)
|
||||
}
|
||||
|
||||
return uint64(res.BitLen())
|
||||
}
|
||||
|
||||
// Alpha returns the number of moduli in in P
|
||||
func (p *Parameters) Alpha() uint64 {
|
||||
return p.PiCount()
|
||||
}
|
||||
|
||||
// Beta returns the number of element in the RNS decomposition basis: Ceil(lenQi / lenPi)
|
||||
func (p *Parameters) Beta() uint64 {
|
||||
if p.Alpha() != 0 {
|
||||
return uint64(math.Ceil(float64(p.QiCount()) / float64(p.Alpha())))
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// NewPolyQ returns a new empty polynomial of degree 2^logN in basis qi.
|
||||
@@ -367,8 +382,12 @@ func (p *Parameters) Copy() (paramsCopy *Parameters) {
|
||||
paramsCopy.logN = p.logN
|
||||
paramsCopy.t = p.t
|
||||
paramsCopy.sigma = p.sigma
|
||||
paramsCopy.Moduli = p.Moduli.Copy()
|
||||
|
||||
paramsCopy.qi = make([]uint64, len(p.qi))
|
||||
copy(paramsCopy.qi, p.qi)
|
||||
paramsCopy.pi = make([]uint64, len(p.pi))
|
||||
copy(paramsCopy.pi, p.pi)
|
||||
paramsCopy.qiMul = make([]uint64, len(p.qiMul))
|
||||
copy(paramsCopy.qiMul, p.qiMul)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -438,40 +457,40 @@ func (p *Parameters) UnmarshalBinary(data []byte) error {
|
||||
b.ReadUint64Slice(p.pi)
|
||||
b.ReadUint64Slice(p.qiMul)
|
||||
|
||||
err := checkModuli(p.Moduli, p.logN) // TODO: check more than moduli.
|
||||
err := checkModuli(p.Moduli(), p.logN) // TODO: check more than moduli.
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkModuli(m Moduli, logN uint64) (err error) {
|
||||
func checkModuli(m *Moduli, logN uint64) (err error) {
|
||||
|
||||
if len(m.qi) > MaxModuliCount {
|
||||
if len(m.Qi) > MaxModuliCount {
|
||||
return fmt.Errorf("#qi is larger than %d", MaxModuliCount)
|
||||
}
|
||||
|
||||
if len(m.pi) > MaxModuliCount {
|
||||
if len(m.Pi) > MaxModuliCount {
|
||||
return fmt.Errorf("#Pi is larger than %d", MaxModuliCount)
|
||||
}
|
||||
|
||||
if len(m.qiMul) > MaxModuliCount {
|
||||
if len(m.QiMul) > MaxModuliCount {
|
||||
return fmt.Errorf("#qiMul is larger than %d", MaxModuliCount)
|
||||
}
|
||||
|
||||
for i, qi := range m.qi {
|
||||
for i, qi := range m.Qi {
|
||||
if uint64(bits.Len64(qi)-1) > MaxModuliSize+1 {
|
||||
return fmt.Errorf("qi bit-size for i=%d is larger than %d", i, MaxModuliSize)
|
||||
}
|
||||
}
|
||||
|
||||
for i, pi := range m.pi {
|
||||
for i, pi := range m.Pi {
|
||||
if uint64(bits.Len64(pi)-1) > MaxModuliSize+1 {
|
||||
return fmt.Errorf("Pi bit-size for i=%d is larger than %d", i, MaxModuliSize)
|
||||
}
|
||||
}
|
||||
|
||||
for i, qi := range m.qiMul {
|
||||
for i, qi := range m.QiMul {
|
||||
if uint64(bits.Len64(qi)-1) > MaxModuliSize+1 {
|
||||
return fmt.Errorf("qiMul bitsize n°%d is larger than %d", i, MaxModuliSize)
|
||||
}
|
||||
@@ -479,19 +498,19 @@ func checkModuli(m Moduli, logN uint64) (err error) {
|
||||
|
||||
N := uint64(1 << logN)
|
||||
|
||||
for i, qi := range m.qi {
|
||||
for i, qi := range m.Qi {
|
||||
if !ring.IsPrime(qi) || qi&((N<<1)-1) != 1 {
|
||||
return fmt.Errorf("qi n°%d is not an NTT prime", i)
|
||||
}
|
||||
}
|
||||
|
||||
for i, pi := range m.pi {
|
||||
for i, pi := range m.Pi {
|
||||
if !ring.IsPrime(pi) || pi&((N<<1)-1) != 1 {
|
||||
return fmt.Errorf("Pi n°%d is not an NTT prime", i)
|
||||
}
|
||||
}
|
||||
|
||||
for i, qi := range m.qiMul {
|
||||
for i, qi := range m.QiMul {
|
||||
if !ring.IsPrime(qi) || qi&((N<<1)-1) != 1 {
|
||||
return fmt.Errorf("qiMul n°%d is not an NTT prime", i)
|
||||
}
|
||||
@@ -500,7 +519,7 @@ func checkModuli(m Moduli, logN uint64) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkLogModuli(lm LogModuli) (err error) {
|
||||
func checkLogModuli(lm *LogModuli) (err error) {
|
||||
|
||||
// Checks if the parameters are empty
|
||||
if lm.LogQi == nil || len(lm.LogQi) == 0 {
|
||||
@@ -541,7 +560,9 @@ func checkLogModuli(lm LogModuli) (err error) {
|
||||
}
|
||||
|
||||
// GenModuli generates the appropriate primes from the parameters using generateNTTPrimes such that all primes are different.
|
||||
func genModuli(lm LogModuli, logN uint64) (m Moduli) {
|
||||
func genModuli(lm *LogModuli, logN uint64) (m *Moduli) {
|
||||
|
||||
m = new(Moduli)
|
||||
|
||||
// Extracts all the different primes bit-size and maps their number
|
||||
primesbitlen := make(map[uint64]uint64)
|
||||
@@ -565,24 +586,24 @@ func genModuli(lm LogModuli, logN uint64) (m Moduli) {
|
||||
}
|
||||
|
||||
// Assigns the primes to the CKKS moduli chain
|
||||
m.qi = make([]uint64, len(lm.LogQi))
|
||||
m.Qi = make([]uint64, len(lm.LogQi))
|
||||
for i, qi := range lm.LogQi {
|
||||
m.qi[i] = primes[qi][0]
|
||||
m.Qi[i] = primes[qi][0]
|
||||
primes[qi] = primes[qi][1:]
|
||||
}
|
||||
|
||||
// Assigns the primes to the special primes list for the extended ring
|
||||
m.pi = make([]uint64, len(lm.LogPi))
|
||||
m.Pi = make([]uint64, len(lm.LogPi))
|
||||
for i, pj := range lm.LogPi {
|
||||
m.pi[i] = primes[pj][0]
|
||||
m.Pi[i] = primes[pj][0]
|
||||
primes[pj] = primes[pj][1:]
|
||||
}
|
||||
|
||||
m.qiMul = make([]uint64, len(lm.LogQiMul))
|
||||
m.QiMul = make([]uint64, len(lm.LogQiMul))
|
||||
for i, qi := range lm.LogQiMul {
|
||||
m.qiMul[i] = primes[qi][0]
|
||||
m.QiMul[i] = primes[qi][0]
|
||||
primes[qi] = primes[qi][1:]
|
||||
}
|
||||
|
||||
return m
|
||||
return
|
||||
}
|
||||
|
||||
@@ -56,41 +56,39 @@ var DefaultBootstrappSchemeParams = []*Parameters{
|
||||
{
|
||||
logN: 16,
|
||||
logSlots: 15,
|
||||
Moduli: Moduli{
|
||||
qi: []uint64{
|
||||
0x80000000080001, // 55 Q0
|
||||
0x2000000a0001, // 45
|
||||
0x2000000e0001, // 45
|
||||
0x1fffffc20001, // 45
|
||||
0x200000440001, // 45
|
||||
0x200000500001, // 45
|
||||
0x200000620001, // 45
|
||||
0x1fffff980001, // 45
|
||||
0x2000006a0001, // 45
|
||||
0x1fffff7e0001, // 45
|
||||
0x200000860001, // 45
|
||||
0x100000000060001, // 56 StC (28 + 28)
|
||||
0xffa0001, // 28 StC
|
||||
0x80000000440001, // 55 Sine (double angle)
|
||||
0x7fffffffba0001, // 55 Sine (double angle)
|
||||
0x80000000500001, // 55 Sine
|
||||
0x7fffffffaa0001, // 55 Sine
|
||||
0x800000005e0001, // 55 Sine
|
||||
0x7fffffff7e0001, // 55 Sine
|
||||
0x7fffffff380001, // 55 Sine
|
||||
0x80000000ca0001, // 55 Sine
|
||||
0x200000000e0001, // 53 CtS
|
||||
0x20000000140001, // 53 CtS
|
||||
0x20000000280001, // 53 CtS
|
||||
0x1fffffffd80001, // 53 CtS
|
||||
},
|
||||
pi: []uint64{
|
||||
0xfffffffff00001, // 56
|
||||
0xffffffffd80001, // 56
|
||||
0x1000000002a0001, // 56
|
||||
0xffffffffd20001, // 56
|
||||
0x100000000480001, // 56
|
||||
},
|
||||
qi: []uint64{
|
||||
0x80000000080001, // 55 Q0
|
||||
0x2000000a0001, // 45
|
||||
0x2000000e0001, // 45
|
||||
0x1fffffc20001, // 45
|
||||
0x200000440001, // 45
|
||||
0x200000500001, // 45
|
||||
0x200000620001, // 45
|
||||
0x1fffff980001, // 45
|
||||
0x2000006a0001, // 45
|
||||
0x1fffff7e0001, // 45
|
||||
0x200000860001, // 45
|
||||
0x100000000060001, // 56 StC (28 + 28)
|
||||
0xffa0001, // 28 StC
|
||||
0x80000000440001, // 55 Sine (double angle)
|
||||
0x7fffffffba0001, // 55 Sine (double angle)
|
||||
0x80000000500001, // 55 Sine
|
||||
0x7fffffffaa0001, // 55 Sine
|
||||
0x800000005e0001, // 55 Sine
|
||||
0x7fffffff7e0001, // 55 Sine
|
||||
0x7fffffff380001, // 55 Sine
|
||||
0x80000000ca0001, // 55 Sine
|
||||
0x200000000e0001, // 53 CtS
|
||||
0x20000000140001, // 53 CtS
|
||||
0x20000000280001, // 53 CtS
|
||||
0x1fffffffd80001, // 53 CtS
|
||||
},
|
||||
pi: []uint64{
|
||||
0xfffffffff00001, // 56
|
||||
0xffffffffd80001, // 56
|
||||
0x1000000002a0001, // 56
|
||||
0xffffffffd20001, // 56
|
||||
0x100000000480001, // 56
|
||||
},
|
||||
scale: 1 << 45,
|
||||
sigma: DefaultSigma,
|
||||
@@ -99,38 +97,36 @@ var DefaultBootstrappSchemeParams = []*Parameters{
|
||||
{
|
||||
logN: 16,
|
||||
logSlots: 15,
|
||||
Moduli: Moduli{
|
||||
qi: []uint64{
|
||||
0x80000000080001, // 55 Q0
|
||||
0xffffffffffc0001, // 60
|
||||
0x10000000006e0001, // 60
|
||||
0xfffffffff840001, // 60
|
||||
0x1000000000860001, // 60
|
||||
0xfffffffff6a0001, // 60
|
||||
0x1000000000980001, // 60
|
||||
0xfffffffff5a0001, // 60
|
||||
0x1000000000b00001, // 60 StC (30)
|
||||
0x1000000000ce0001, // 60 StC (30+30)
|
||||
0x80000000440001, // 55 Sine (double angle)
|
||||
0x7fffffffba0001, // 55 Sine (double angle)
|
||||
0x80000000500001, // 55 Sine
|
||||
0x7fffffffaa0001, // 55 Sine
|
||||
0x800000005e0001, // 55 Sine
|
||||
0x7fffffff7e0001, // 55 Sine
|
||||
0x7fffffff380001, // 55 Sine
|
||||
0x80000000ca0001, // 55 Sine
|
||||
0x200000000e0001, // 53 CtS
|
||||
0x20000000140001, // 53 CtS
|
||||
0x20000000280001, // 53 CtS
|
||||
0x1fffffffd80001, // 53 CtS
|
||||
},
|
||||
pi: []uint64{
|
||||
0x1fffffffffe00001, // Pi 61
|
||||
0x1fffffffffc80001, // Pi 61
|
||||
0x1fffffffffb40001, // Pi 61
|
||||
0x1fffffffff500001, // Pi 61
|
||||
0x1fffffffff420001, // Pi 61
|
||||
},
|
||||
qi: []uint64{
|
||||
0x80000000080001, // 55 Q0
|
||||
0xffffffffffc0001, // 60
|
||||
0x10000000006e0001, // 60
|
||||
0xfffffffff840001, // 60
|
||||
0x1000000000860001, // 60
|
||||
0xfffffffff6a0001, // 60
|
||||
0x1000000000980001, // 60
|
||||
0xfffffffff5a0001, // 60
|
||||
0x1000000000b00001, // 60 StC (30)
|
||||
0x1000000000ce0001, // 60 StC (30+30)
|
||||
0x80000000440001, // 55 Sine (double angle)
|
||||
0x7fffffffba0001, // 55 Sine (double angle)
|
||||
0x80000000500001, // 55 Sine
|
||||
0x7fffffffaa0001, // 55 Sine
|
||||
0x800000005e0001, // 55 Sine
|
||||
0x7fffffff7e0001, // 55 Sine
|
||||
0x7fffffff380001, // 55 Sine
|
||||
0x80000000ca0001, // 55 Sine
|
||||
0x200000000e0001, // 53 CtS
|
||||
0x20000000140001, // 53 CtS
|
||||
0x20000000280001, // 53 CtS
|
||||
0x1fffffffd80001, // 53 CtS
|
||||
},
|
||||
pi: []uint64{
|
||||
0x1fffffffffe00001, // Pi 61
|
||||
0x1fffffffffc80001, // Pi 61
|
||||
0x1fffffffffb40001, // Pi 61
|
||||
0x1fffffffff500001, // Pi 61
|
||||
0x1fffffffff420001, // Pi 61
|
||||
},
|
||||
scale: 1 << 30,
|
||||
sigma: DefaultSigma,
|
||||
@@ -138,45 +134,43 @@ var DefaultBootstrappSchemeParams = []*Parameters{
|
||||
|
||||
{
|
||||
logN: 16,
|
||||
logSlots: 10,
|
||||
Moduli: Moduli{
|
||||
qi: []uint64{
|
||||
0x80000000080001, // 55 Q0
|
||||
0x2000000a0001, // 45
|
||||
0x2000000e0001, // 45
|
||||
0x1fffffc20001, // 45
|
||||
0x200000440001, // 45
|
||||
0x200000500001, // 45
|
||||
0x200000620001, // 45
|
||||
0x1fffff980001, // 45
|
||||
0x2000006a0001, // 45
|
||||
0x1fffff7e0001, // 45
|
||||
0x100000000060001, // 56 StC (28 + 28)
|
||||
0xffa0001, // 28 StC
|
||||
0xffffffffffc0001, // 60 Sine (double angle)
|
||||
0x10000000006e0001, // 60 Sine (double angle)
|
||||
0xfffffffff840001, // 60 Sine (double angle)
|
||||
0x1000000000860001, // 60 Sine
|
||||
0xfffffffff6a0001, // 60 Sine
|
||||
0x1000000000980001, // 60 Sine
|
||||
0xfffffffff5a0001, // 60 Sine
|
||||
0x1000000000b00001, // 60 Sine
|
||||
0x1000000000ce0001, // 60 Sine
|
||||
0xfffffffff2a0001, // 60 Sine
|
||||
0xfffffffff240001, // 60 Sine
|
||||
0x200000000e0001, // 53 CtS
|
||||
0x20000000140001, // 53 CtS
|
||||
0x20000000280001, // 53 CtS
|
||||
0x1fffffffd80001, // 53 CtS
|
||||
},
|
||||
pi: []uint64{
|
||||
0x1fffffffffe00001, // Pi 61
|
||||
0x1fffffffffc80001, // Pi 61
|
||||
0x1fffffffffb40001, // Pi 61
|
||||
0x1fffffffff500001, // Pi 61
|
||||
0x1fffffffff420001, // Pi 61
|
||||
0x1fffffffff380001, // Pi 61
|
||||
},
|
||||
logSlots: 15,
|
||||
qi: []uint64{
|
||||
0x80000000080001, // 55 Q0
|
||||
0x2000000a0001, // 45
|
||||
0x2000000e0001, // 45
|
||||
0x1fffffc20001, // 45
|
||||
0x200000440001, // 45
|
||||
0x200000500001, // 45
|
||||
0x200000620001, // 45
|
||||
0x1fffff980001, // 45
|
||||
0x2000006a0001, // 45
|
||||
0x1fffff7e0001, // 45
|
||||
0x100000000060001, // 56 StC (28 + 28)
|
||||
0xffa0001, // 28 StC
|
||||
0xffffffffffc0001, // 60 Sine (double angle)
|
||||
0x10000000006e0001, // 60 Sine (double angle)
|
||||
0xfffffffff840001, // 60 Sine (double angle)
|
||||
0x1000000000860001, // 60 Sine
|
||||
0xfffffffff6a0001, // 60 Sine
|
||||
0x1000000000980001, // 60 Sine
|
||||
0xfffffffff5a0001, // 60 Sine
|
||||
0x1000000000b00001, // 60 Sine
|
||||
0x1000000000ce0001, // 60 Sine
|
||||
0xfffffffff2a0001, // 60 Sine
|
||||
0xfffffffff240001, // 60 Sine
|
||||
0x200000000e0001, // 53 CtS
|
||||
0x20000000140001, // 53 CtS
|
||||
0x20000000280001, // 53 CtS
|
||||
0x1fffffffd80001, // 53 CtS
|
||||
},
|
||||
pi: []uint64{
|
||||
0x1fffffffffe00001, // Pi 61
|
||||
0x1fffffffffc80001, // Pi 61
|
||||
0x1fffffffffb40001, // Pi 61
|
||||
0x1fffffffff500001, // Pi 61
|
||||
0x1fffffffff420001, // Pi 61
|
||||
0x1fffffffff380001, // Pi 61
|
||||
},
|
||||
scale: 1 << 45,
|
||||
sigma: DefaultSigma,
|
||||
@@ -184,28 +178,26 @@ var DefaultBootstrappSchemeParams = []*Parameters{
|
||||
|
||||
{
|
||||
logN: 15,
|
||||
logSlots: 10,
|
||||
Moduli: Moduli{
|
||||
qi: []uint64{
|
||||
0x7fffb0001, // 35 Q0
|
||||
0x4000000420001, // 50
|
||||
0x1fc0001, // 25
|
||||
0xffffffffffc0001, // 60 StC (30+30)
|
||||
0x4000000120001, // 50 Sine
|
||||
0x40000001b0001, // 50 Sine
|
||||
0x3ffffffdf0001, // 50 Sine
|
||||
0x4000000270001, // 50 Sine
|
||||
0x3ffffffd20001, // 50 Sine
|
||||
0x3ffffffcd0001, // 50 Sine
|
||||
0x4000000350001, // 50 Sine
|
||||
0x3ffffffc70001, // 50 Sine
|
||||
0x1fffffff50001, // 49 CtS
|
||||
0x1ffffffea0001, // 49 CtS
|
||||
},
|
||||
pi: []uint64{
|
||||
0x7e40000000001, // 50
|
||||
0x7c80000000001, // 50
|
||||
},
|
||||
logSlots: 14,
|
||||
qi: []uint64{
|
||||
0x7fffb0001, // 35 Q0
|
||||
0x4000000420001, // 50
|
||||
0x1fc0001, // 25
|
||||
0xffffffffffc0001, // 60 StC (30+30)
|
||||
0x4000000120001, // 50 Sine
|
||||
0x40000001b0001, // 50 Sine
|
||||
0x3ffffffdf0001, // 50 Sine
|
||||
0x4000000270001, // 50 Sine
|
||||
0x3ffffffd20001, // 50 Sine
|
||||
0x3ffffffcd0001, // 50 Sine
|
||||
0x4000000350001, // 50 Sine
|
||||
0x3ffffffc70001, // 50 Sine
|
||||
0x1fffffff50001, // 49 CtS
|
||||
0x1ffffffea0001, // 49 CtS
|
||||
},
|
||||
pi: []uint64{
|
||||
0x7e40000000001, // 50
|
||||
0x7c80000000001, // 50
|
||||
},
|
||||
scale: 1 << 25,
|
||||
sigma: DefaultSigma,
|
||||
|
||||
@@ -178,7 +178,7 @@ func verifyTestVectors(testContext *testParams, decryptor Decryptor, valuesWant
|
||||
func testParameters(testContext *testParams, t *testing.T) {
|
||||
|
||||
t.Run("Parameters/NewParametersFromModuli/", func(t *testing.T) {
|
||||
p, err := NewParametersFromModuli(testContext.params.LogN(), testContext.params.Moduli)
|
||||
p, err := NewParametersFromModuli(testContext.params.LogN(), testContext.params.Moduli())
|
||||
p.SetLogSlots(testContext.params.LogSlots())
|
||||
p.SetScale(testContext.params.Scale())
|
||||
assert.NoError(t, err)
|
||||
@@ -443,6 +443,9 @@ func testEvaluatorRescale(testContext *testParams, t *testing.T) {
|
||||
values, _, ciphertext := newTestVectors(testContext, testContext.encryptorSk, complex(-1, -1), complex(1, 1), t)
|
||||
|
||||
nbRescales := testContext.params.MaxLevel()
|
||||
if nbRescales > 5 {
|
||||
nbRescales = 5
|
||||
}
|
||||
|
||||
for i := uint64(0); i < nbRescales; i++ {
|
||||
constant := testContext.ringQ.Modulus[ciphertext.Level()]
|
||||
|
||||
405
ckks/params.go
405
ckks/params.go
@@ -38,11 +38,9 @@ var DefaultParams = []*Parameters{
|
||||
//LogQi = 109
|
||||
{logN: 12,
|
||||
logSlots: 11,
|
||||
Moduli: Moduli{ // 37 + 32
|
||||
qi: []uint64{0x200000e001,
|
||||
0x100006001},
|
||||
pi: []uint64{0x3ffffea001}, // 38
|
||||
},
|
||||
qi: []uint64{0x200000e001, // 37 + 32
|
||||
0x100006001},
|
||||
pi: []uint64{0x3ffffea001}, // 38
|
||||
scale: 1 << 32,
|
||||
sigma: DefaultSigma,
|
||||
},
|
||||
@@ -50,15 +48,13 @@ var DefaultParams = []*Parameters{
|
||||
//LogQi = 218
|
||||
{logN: 13,
|
||||
logSlots: 12,
|
||||
Moduli: Moduli{ // 33 + 5 x 30
|
||||
qi: []uint64{0x1fffec001,
|
||||
0x3fff4001,
|
||||
0x3ffe8001,
|
||||
0x40020001,
|
||||
0x40038001,
|
||||
0x3ffc0001},
|
||||
pi: []uint64{0x800004001}, // 35
|
||||
},
|
||||
qi: []uint64{0x1fffec001, // 33 + 5 x 30
|
||||
0x3fff4001,
|
||||
0x3ffe8001,
|
||||
0x40020001,
|
||||
0x40038001,
|
||||
0x3ffc0001},
|
||||
pi: []uint64{0x800004001}, // 35
|
||||
scale: 1 << 30,
|
||||
sigma: DefaultSigma,
|
||||
},
|
||||
@@ -66,14 +62,12 @@ var DefaultParams = []*Parameters{
|
||||
//LogQiP = 438
|
||||
{logN: 14,
|
||||
logSlots: 13,
|
||||
Moduli: Moduli{ // 45 + 9 x 34
|
||||
qi: []uint64{0x200000008001, 0x400018001,
|
||||
0x3fffd0001, 0x400060001,
|
||||
0x400068001, 0x3fff90001,
|
||||
0x400080001, 0x4000a8001,
|
||||
0x400108001, 0x3ffeb8001},
|
||||
pi: []uint64{0x7fffffd8001, 0x7fffffc8001}, // 43, 43
|
||||
},
|
||||
qi: []uint64{0x200000008001, 0x400018001, // 45 + 9 x 34
|
||||
0x3fffd0001, 0x400060001,
|
||||
0x400068001, 0x3fff90001,
|
||||
0x400080001, 0x4000a8001,
|
||||
0x400108001, 0x3ffeb8001},
|
||||
pi: []uint64{0x7fffffd8001, 0x7fffffc8001}, // 43, 43
|
||||
scale: 1 << 34,
|
||||
sigma: DefaultSigma,
|
||||
},
|
||||
@@ -81,16 +75,13 @@ var DefaultParams = []*Parameters{
|
||||
//LogQi = 880
|
||||
{logN: 15,
|
||||
logSlots: 14,
|
||||
Moduli: Moduli{ // 50 + 17 x 40
|
||||
qi: []uint64{0x4000000120001, 0x10000140001, 0xffffe80001,
|
||||
0x10000290001, 0xffffc40001, 0x100003e0001,
|
||||
0x10000470001, 0x100004b0001, 0xffffb20001,
|
||||
0x10000500001, 0x10000650001, 0xffff940001,
|
||||
0xffff8a0001, 0xffff820001, 0xffff780001,
|
||||
0x10000890001, 0xffff750001, 0x10000960001},
|
||||
pi: []uint64{0x40000001b0001, 0x3ffffffdf0001, 0x4000000270001}, // 50, 50, 50
|
||||
},
|
||||
|
||||
qi: []uint64{0x4000000120001, 0x10000140001, 0xffffe80001, // 50 + 17 x 40
|
||||
0x10000290001, 0xffffc40001, 0x100003e0001,
|
||||
0x10000470001, 0x100004b0001, 0xffffb20001,
|
||||
0x10000500001, 0x10000650001, 0xffff940001,
|
||||
0xffff8a0001, 0xffff820001, 0xffff780001,
|
||||
0x10000890001, 0xffff750001, 0x10000960001},
|
||||
pi: []uint64{0x40000001b0001, 0x3ffffffdf0001, 0x4000000270001}, // 50, 50, 50
|
||||
scale: 1 << 40,
|
||||
sigma: DefaultSigma,
|
||||
},
|
||||
@@ -98,18 +89,16 @@ var DefaultParams = []*Parameters{
|
||||
//LogQi = 1761
|
||||
{logN: 16,
|
||||
logSlots: 15,
|
||||
Moduli: Moduli{ // 55 + 33 x 45
|
||||
qi: []uint64{0x80000000080001, 0x2000000a0001, 0x2000000e0001, 0x1fffffc20001,
|
||||
0x200000440001, 0x200000500001, 0x200000620001, 0x1fffff980001,
|
||||
0x2000006a0001, 0x1fffff7e0001, 0x200000860001, 0x200000a60001,
|
||||
0x200000aa0001, 0x200000b20001, 0x200000c80001, 0x1fffff360001,
|
||||
0x200000e20001, 0x1fffff060001, 0x200000fe0001, 0x1ffffede0001,
|
||||
0x1ffffeca0001, 0x1ffffeb40001, 0x200001520001, 0x1ffffe760001,
|
||||
0x2000019a0001, 0x1ffffe640001, 0x200001a00001, 0x1ffffe520001,
|
||||
0x200001e80001, 0x1ffffe0c0001, 0x1ffffdee0001, 0x200002480001,
|
||||
0x1ffffdb60001, 0x200002560001},
|
||||
pi: []uint64{0x80000000440001, 0x7fffffffba0001, 0x80000000500001, 0x7fffffffaa0001}, // 4 x 55
|
||||
},
|
||||
qi: []uint64{0x80000000080001, 0x2000000a0001, 0x2000000e0001, 0x1fffffc20001, // 55 + 33 x 45
|
||||
0x200000440001, 0x200000500001, 0x200000620001, 0x1fffff980001,
|
||||
0x2000006a0001, 0x1fffff7e0001, 0x200000860001, 0x200000a60001,
|
||||
0x200000aa0001, 0x200000b20001, 0x200000c80001, 0x1fffff360001,
|
||||
0x200000e20001, 0x1fffff060001, 0x200000fe0001, 0x1ffffede0001,
|
||||
0x1ffffeca0001, 0x1ffffeb40001, 0x200001520001, 0x1ffffe760001,
|
||||
0x2000019a0001, 0x1ffffe640001, 0x200001a00001, 0x1ffffe520001,
|
||||
0x200001e80001, 0x1ffffe0c0001, 0x1ffffdee0001, 0x200002480001,
|
||||
0x1ffffdb60001, 0x200002560001},
|
||||
pi: []uint64{0x80000000440001, 0x7fffffffba0001, 0x80000000500001, 0x7fffffffaa0001}, // 4 x 55
|
||||
scale: 1 << 45,
|
||||
sigma: DefaultSigma,
|
||||
},
|
||||
@@ -117,142 +106,18 @@ var DefaultParams = []*Parameters{
|
||||
|
||||
// Moduli stores the NTT primes of the RNS representation.
|
||||
type Moduli struct {
|
||||
qi []uint64 // Ciphertext prime moduli
|
||||
pi []uint64 // Keys additional prime moduli
|
||||
}
|
||||
|
||||
// Qi returns a new slice with the factors of the ciphertext modulus q
|
||||
func (m *Moduli) Qi() []uint64 {
|
||||
qi := make([]uint64, len(m.qi))
|
||||
copy(qi, m.qi)
|
||||
return qi
|
||||
}
|
||||
|
||||
// QiCount returns the number of factors of the ciphertext modulus Q
|
||||
func (m *Moduli) QiCount() uint64 {
|
||||
return uint64(len(m.qi))
|
||||
}
|
||||
|
||||
// Pi returns a new slice with the factors of the ciphertext modulus extention P
|
||||
func (m *Moduli) Pi() []uint64 {
|
||||
pi := make([]uint64, len(m.pi))
|
||||
copy(pi, m.pi)
|
||||
return pi
|
||||
}
|
||||
|
||||
// PiCount returns the number of factors of the ciphertext modulus extention P
|
||||
func (m *Moduli) PiCount() uint64 {
|
||||
return uint64(len(m.pi))
|
||||
}
|
||||
|
||||
// QPiCount returns the number of factors of the ciphertext modulus + the extention modulus P
|
||||
func (m *Moduli) QPiCount() uint64 {
|
||||
return uint64(len(m.qi) + len(m.pi))
|
||||
}
|
||||
|
||||
// LogQP returns the size of the extended modulus QP in bits
|
||||
func (m *Moduli) LogQP() uint64 {
|
||||
tmp := ring.NewUint(1)
|
||||
for _, qi := range m.qi {
|
||||
tmp.Mul(tmp, ring.NewUint(qi))
|
||||
}
|
||||
for _, pi := range m.pi {
|
||||
tmp.Mul(tmp, ring.NewUint(pi))
|
||||
}
|
||||
return uint64(tmp.BitLen())
|
||||
}
|
||||
|
||||
// LogQLvl returns the size of the modulus Q in bits at a specific level
|
||||
func (m *Moduli) LogQLvl(level uint64) uint64 {
|
||||
tmp := m.QLvl(level)
|
||||
return uint64(tmp.BitLen())
|
||||
}
|
||||
|
||||
// QLvl returns the product of the moduli at the given level as a big.Int
|
||||
func (m *Moduli) QLvl(level uint64) *big.Int {
|
||||
tmp := ring.NewUint(1)
|
||||
for _, qi := range m.qi[:level+1] {
|
||||
tmp.Mul(tmp, ring.NewUint(qi))
|
||||
}
|
||||
return tmp
|
||||
}
|
||||
|
||||
// LogQ returns the size of the modulus Q in bits
|
||||
func (m *Moduli) LogQ() uint64 {
|
||||
return m.LogQLvl(m.QiCount() - 1)
|
||||
}
|
||||
|
||||
// Q returns the product of all the moduli as a big.Int
|
||||
func (m *Moduli) Q() *big.Int {
|
||||
return m.QLvl(m.QiCount() - 1)
|
||||
}
|
||||
|
||||
// LogP returns the size of the modulus P in bits
|
||||
func (m *Moduli) LogP() uint64 {
|
||||
tmp := ring.NewUint(1)
|
||||
for _, pi := range m.pi {
|
||||
tmp.Mul(tmp, ring.NewUint(pi))
|
||||
}
|
||||
return uint64(tmp.BitLen())
|
||||
}
|
||||
|
||||
// LogQAlpha returns the size in bits of the sum of the norm of
|
||||
// each element of the special RNS decomposition basis for the
|
||||
// key-switching.
|
||||
// LogQAlpha is the size of the element that is multipled by the
|
||||
// error during the keyswitching and then divided by P.
|
||||
// LogQAlpha should be smaller than P or the error added during
|
||||
// the key-switching wont be negligible.
|
||||
func (m *Moduli) LogQAlpha() uint64 {
|
||||
|
||||
alpha := m.PiCount()
|
||||
|
||||
if alpha == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
res := ring.NewUint(0)
|
||||
var j uint64
|
||||
for i := uint64(0); i < m.QiCount(); i = i + alpha {
|
||||
|
||||
j = i + alpha
|
||||
if j > m.QiCount() {
|
||||
j = m.QiCount()
|
||||
}
|
||||
|
||||
tmp := ring.NewUint(1)
|
||||
for _, qi := range m.qi[i:j] {
|
||||
tmp.Mul(tmp, ring.NewUint(qi))
|
||||
}
|
||||
|
||||
res.Add(res, tmp)
|
||||
}
|
||||
|
||||
return uint64(res.BitLen())
|
||||
}
|
||||
|
||||
// Alpha returns the number of moduli in in P
|
||||
func (m *Moduli) Alpha() uint64 {
|
||||
return m.PiCount()
|
||||
}
|
||||
|
||||
// Beta returns the number of element in the RNS decomposition basis: Ceil(lenQi / lenPi)
|
||||
func (m *Moduli) Beta() uint64 {
|
||||
if m.Alpha() != 0 {
|
||||
return uint64(math.Ceil(float64(m.QiCount()) / float64(m.Alpha())))
|
||||
}
|
||||
|
||||
return 0
|
||||
Qi []uint64 // Ciphertext prime moduli
|
||||
Pi []uint64 // Keys additional prime moduli
|
||||
}
|
||||
|
||||
// Print prints the moduli in hexadimal
|
||||
func (m *Moduli) Print() {
|
||||
for _, qi := range m.qi {
|
||||
for _, qi := range m.Qi {
|
||||
fmt.Printf("0x%x,\n", qi)
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
for _, pj := range m.pi {
|
||||
for _, pj := range m.Pi {
|
||||
fmt.Printf("0x%x,\n", pj)
|
||||
}
|
||||
fmt.Println()
|
||||
@@ -261,17 +126,19 @@ func (m *Moduli) Print() {
|
||||
// Copy creates a copy of the target Moduli.
|
||||
func (m *Moduli) Copy() Moduli {
|
||||
|
||||
qi := make([]uint64, len(m.qi))
|
||||
copy(qi, m.qi)
|
||||
qi := make([]uint64, len(m.Qi))
|
||||
copy(qi, m.Qi)
|
||||
|
||||
pi := make([]uint64, len(m.pi))
|
||||
copy(pi, m.pi)
|
||||
pi := make([]uint64, len(m.Pi))
|
||||
copy(pi, m.Pi)
|
||||
|
||||
return Moduli{qi, pi}
|
||||
}
|
||||
|
||||
// LogModuli generates a LogModuli struct from the parameters' Moduli struct and returns it.
|
||||
func (p *Parameters) LogModuli() (lm LogModuli) {
|
||||
func (p *Parameters) LogModuli() (lm *LogModuli) {
|
||||
|
||||
lm = new(LogModuli)
|
||||
|
||||
lm.LogQi = make([]uint64, len(p.qi), len(p.qi))
|
||||
for i := range p.qi {
|
||||
@@ -283,7 +150,7 @@ func (p *Parameters) LogModuli() (lm LogModuli) {
|
||||
lm.LogPi[i] = uint64(math.Round(math.Log2(float64(p.pi[i]))))
|
||||
}
|
||||
|
||||
return lm
|
||||
return
|
||||
}
|
||||
|
||||
// LogModuli stores the bit-length of the NTT primes of the RNS representation.
|
||||
@@ -306,7 +173,8 @@ func (m *LogModuli) Copy() LogModuli {
|
||||
|
||||
// Parameters represents a given parameter set for the BFV cryptosystem.
|
||||
type Parameters struct {
|
||||
Moduli
|
||||
qi []uint64
|
||||
pi []uint64
|
||||
logN uint64 // Ring degree (power of 2)
|
||||
logSlots uint64
|
||||
scale float64
|
||||
@@ -314,7 +182,7 @@ type Parameters struct {
|
||||
}
|
||||
|
||||
// NewParametersFromModuli creates a new Parameters struct and returns a pointer to it.
|
||||
func NewParametersFromModuli(logN uint64, m Moduli) (p *Parameters, err error) {
|
||||
func NewParametersFromModuli(logN uint64, m *Moduli) (p *Parameters, err error) {
|
||||
p = new(Parameters)
|
||||
|
||||
if (logN < 3) || (logN > MaxLogN) {
|
||||
@@ -327,7 +195,11 @@ func NewParametersFromModuli(logN uint64, m Moduli) (p *Parameters, err error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p.Moduli = m.Copy()
|
||||
p.qi = make([]uint64, len(m.Qi), len(m.Qi))
|
||||
copy(p.qi, m.Qi)
|
||||
p.pi = make([]uint64, len(m.Pi), len(m.Pi))
|
||||
copy(p.pi, m.Pi)
|
||||
|
||||
p.sigma = DefaultSigma
|
||||
|
||||
return p, nil
|
||||
@@ -335,7 +207,7 @@ func NewParametersFromModuli(logN uint64, m Moduli) (p *Parameters, err error) {
|
||||
}
|
||||
|
||||
// NewParametersFromLogModuli creates a new Parameters struct and returns a pointer to it.
|
||||
func NewParametersFromLogModuli(logN uint64, lm LogModuli) (p *Parameters, err error) {
|
||||
func NewParametersFromLogModuli(logN uint64, lm *LogModuli) (p *Parameters, err error) {
|
||||
|
||||
if err = checkLogModuli(lm); err != nil {
|
||||
return nil, err
|
||||
@@ -431,6 +303,140 @@ func (p *Parameters) SetSigma(sigma float64) {
|
||||
p.sigma = sigma
|
||||
}
|
||||
|
||||
// Moduli returns a struct Moduli with the moduli of the parameters
|
||||
func (p *Parameters) Moduli() (m *Moduli) {
|
||||
m = new(Moduli)
|
||||
m.Qi = make([]uint64, p.QiCount(), p.QiCount())
|
||||
m.Pi = make([]uint64, p.PiCount(), p.PiCount())
|
||||
copy(m.Qi, p.qi)
|
||||
copy(m.Pi, p.pi)
|
||||
return
|
||||
}
|
||||
|
||||
// Qi returns a new slice with the factors of the ciphertext modulus q
|
||||
func (p *Parameters) Qi() []uint64 {
|
||||
qi := make([]uint64, len(p.qi))
|
||||
copy(qi, p.qi)
|
||||
return qi
|
||||
}
|
||||
|
||||
// QiCount returns the number of factors of the ciphertext modulus Q
|
||||
func (p *Parameters) QiCount() uint64 {
|
||||
return uint64(len(p.qi))
|
||||
}
|
||||
|
||||
// Pi returns a new slice with the factors of the ciphertext modulus extention P
|
||||
func (p *Parameters) Pi() []uint64 {
|
||||
pi := make([]uint64, len(p.pi))
|
||||
copy(pi, p.pi)
|
||||
return pi
|
||||
}
|
||||
|
||||
// PiCount returns the number of factors of the ciphertext modulus extention P
|
||||
func (p *Parameters) PiCount() uint64 {
|
||||
return uint64(len(p.pi))
|
||||
}
|
||||
|
||||
// QPiCount returns the number of factors of the ciphertext modulus + the extention modulus P
|
||||
func (p *Parameters) QPiCount() uint64 {
|
||||
return uint64(len(p.qi) + len(p.pi))
|
||||
}
|
||||
|
||||
// LogQP returns the size of the extended modulus QP in bits
|
||||
func (p *Parameters) LogQP() uint64 {
|
||||
tmp := ring.NewUint(1)
|
||||
for _, qi := range p.qi {
|
||||
tmp.Mul(tmp, ring.NewUint(qi))
|
||||
}
|
||||
for _, pi := range p.pi {
|
||||
tmp.Mul(tmp, ring.NewUint(pi))
|
||||
}
|
||||
return uint64(tmp.BitLen())
|
||||
}
|
||||
|
||||
// LogQLvl returns the size of the modulus Q in bits at a specific level
|
||||
func (p *Parameters) LogQLvl(level uint64) uint64 {
|
||||
tmp := p.QLvl(level)
|
||||
return uint64(tmp.BitLen())
|
||||
}
|
||||
|
||||
// QLvl returns the product of the moduli at the given level as a big.Int
|
||||
func (p *Parameters) QLvl(level uint64) *big.Int {
|
||||
tmp := ring.NewUint(1)
|
||||
for _, qi := range p.qi[:level+1] {
|
||||
tmp.Mul(tmp, ring.NewUint(qi))
|
||||
}
|
||||
return tmp
|
||||
}
|
||||
|
||||
// LogQ returns the size of the modulus Q in bits
|
||||
func (p *Parameters) LogQ() uint64 {
|
||||
return p.LogQLvl(p.QiCount() - 1)
|
||||
}
|
||||
|
||||
// Q returns the product of all the moduli as a big.Int
|
||||
func (p *Parameters) Q() *big.Int {
|
||||
return p.QLvl(p.QiCount() - 1)
|
||||
}
|
||||
|
||||
// LogP returns the size of the modulus P in bits
|
||||
func (p *Parameters) LogP() uint64 {
|
||||
tmp := ring.NewUint(1)
|
||||
for _, pi := range p.pi {
|
||||
tmp.Mul(tmp, ring.NewUint(pi))
|
||||
}
|
||||
return uint64(tmp.BitLen())
|
||||
}
|
||||
|
||||
// LogQAlpha returns the size in bits of the sum of the norm of
|
||||
// each element of the special RNS decomposition basis for the
|
||||
// key-switching.
|
||||
// LogQAlpha is the size of the element that is multipled by the
|
||||
// error during the keyswitching and then divided by P.
|
||||
// LogQAlpha should be smaller than P or the error added during
|
||||
// the key-switching wont be negligible.
|
||||
func (p *Parameters) LogQAlpha() uint64 {
|
||||
|
||||
alpha := p.PiCount()
|
||||
|
||||
if alpha == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
res := ring.NewUint(0)
|
||||
var j uint64
|
||||
for i := uint64(0); i < p.QiCount(); i = i + alpha {
|
||||
|
||||
j = i + alpha
|
||||
if j > p.QiCount() {
|
||||
j = p.QiCount()
|
||||
}
|
||||
|
||||
tmp := ring.NewUint(1)
|
||||
for _, qi := range p.pi[i:j] {
|
||||
tmp.Mul(tmp, ring.NewUint(qi))
|
||||
}
|
||||
|
||||
res.Add(res, tmp)
|
||||
}
|
||||
|
||||
return uint64(res.BitLen())
|
||||
}
|
||||
|
||||
// Alpha returns the number of moduli in in P
|
||||
func (p *Parameters) Alpha() uint64 {
|
||||
return p.PiCount()
|
||||
}
|
||||
|
||||
// Beta returns the number of element in the RNS decomposition basis: Ceil(lenQi / lenPi)
|
||||
func (p *Parameters) Beta() uint64 {
|
||||
if p.Alpha() != 0 {
|
||||
return uint64(math.Ceil(float64(p.QiCount()) / float64(p.Alpha())))
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// Copy creates a copy of the target parameters.
|
||||
func (p *Parameters) Copy() (paramsCopy *Parameters) {
|
||||
|
||||
@@ -439,7 +445,10 @@ func (p *Parameters) Copy() (paramsCopy *Parameters) {
|
||||
paramsCopy.logSlots = p.logSlots
|
||||
paramsCopy.scale = p.scale
|
||||
paramsCopy.sigma = p.sigma
|
||||
paramsCopy.Moduli = p.Moduli.Copy()
|
||||
paramsCopy.qi = make([]uint64, len(p.qi), len(p.qi))
|
||||
copy(paramsCopy.qi, p.qi)
|
||||
paramsCopy.pi = make([]uint64, len(p.pi), len(p.pi))
|
||||
copy(paramsCopy.pi, p.pi)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -512,30 +521,30 @@ func (p *Parameters) UnmarshalBinary(data []byte) (err error) {
|
||||
b.ReadUint64Slice(p.qi)
|
||||
b.ReadUint64Slice(p.pi)
|
||||
|
||||
if err = checkModuli(p.Moduli, p.logN); err != nil {
|
||||
if err = checkModuli(p.Moduli(), p.logN); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkModuli(m Moduli, logN uint64) error {
|
||||
func checkModuli(m *Moduli, logN uint64) error {
|
||||
|
||||
if len(m.qi) > MaxModuliCount {
|
||||
if len(m.Qi) > MaxModuliCount {
|
||||
return fmt.Errorf("#Qi is larger than %d", MaxModuliCount)
|
||||
}
|
||||
|
||||
if len(m.pi) > MaxModuliCount {
|
||||
if len(m.Pi) > MaxModuliCount {
|
||||
return fmt.Errorf("#Pi is larger than %d", MaxModuliCount)
|
||||
}
|
||||
|
||||
for i, qi := range m.qi {
|
||||
for i, qi := range m.Qi {
|
||||
if uint64(bits.Len64(qi)-1) > MaxModuliSize+1 {
|
||||
return fmt.Errorf("Qi bit-size (i=%d) is larger than %d", i, MaxModuliSize)
|
||||
}
|
||||
}
|
||||
|
||||
for i, pi := range m.pi {
|
||||
for i, pi := range m.Pi {
|
||||
if uint64(bits.Len64(pi)-1) > MaxModuliSize+2 {
|
||||
return fmt.Errorf("Pi bit-size (i=%d) is larger than %d", i, MaxModuliSize)
|
||||
}
|
||||
@@ -543,13 +552,13 @@ func checkModuli(m Moduli, logN uint64) error {
|
||||
|
||||
N := uint64(1 << logN)
|
||||
|
||||
for i, qi := range m.qi {
|
||||
for i, qi := range m.Qi {
|
||||
if !ring.IsPrime(qi) || qi&((N<<1)-1) != 1 {
|
||||
return fmt.Errorf("Qi (i=%d) is not an NTT prime", i)
|
||||
}
|
||||
}
|
||||
|
||||
for i, pi := range m.pi {
|
||||
for i, pi := range m.Pi {
|
||||
if !ring.IsPrime(pi) || pi&((N<<1)-1) != 1 {
|
||||
return fmt.Errorf("Pi (i=%d) is not an NTT prime", i)
|
||||
}
|
||||
@@ -558,7 +567,7 @@ func checkModuli(m Moduli, logN uint64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkLogModuli(m LogModuli) error {
|
||||
func checkLogModuli(m *LogModuli) error {
|
||||
|
||||
if len(m.LogQi) > MaxModuliCount {
|
||||
return fmt.Errorf("#LogQi is larger than %d", MaxModuliCount)
|
||||
@@ -583,7 +592,9 @@ func checkLogModuli(m LogModuli) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func genModuli(lm LogModuli, logN uint64) (m Moduli) {
|
||||
func genModuli(lm *LogModuli, logN uint64) (m *Moduli) {
|
||||
|
||||
m = new(Moduli)
|
||||
|
||||
// Extracts all the different primes bit size and maps their number
|
||||
primesbitlen := make(map[uint64]uint64)
|
||||
@@ -602,16 +613,16 @@ func genModuli(lm LogModuli, logN uint64) (m Moduli) {
|
||||
}
|
||||
|
||||
// Assigns the primes to the ckks moduli chain
|
||||
m.qi = make([]uint64, len(lm.LogQi))
|
||||
m.Qi = make([]uint64, len(lm.LogQi))
|
||||
for i, qi := range lm.LogQi {
|
||||
m.qi[i] = primes[qi][0]
|
||||
m.Qi[i] = primes[qi][0]
|
||||
primes[qi] = primes[qi][1:]
|
||||
}
|
||||
|
||||
// Assigns the primes to the special primes list for the extended ring
|
||||
m.pi = make([]uint64, len(lm.LogPi))
|
||||
m.Pi = make([]uint64, len(lm.LogPi))
|
||||
for i, pj := range lm.LogPi {
|
||||
m.pi[i] = primes[pj][0]
|
||||
m.Pi[i] = primes[pj][0]
|
||||
primes[pj] = primes[pj][1:]
|
||||
}
|
||||
|
||||
|
||||
@@ -35,8 +35,8 @@ func main() {
|
||||
// LogSlots is hardcoded to 15 in the parameters, but can be changed from 1 to 15.
|
||||
// When changing logSlots make sure that the number of levels allocated to CtS and StC is
|
||||
// smaller or equal to logSlots.
|
||||
params := ckks.DefaultBootstrappSchemeParams[5]
|
||||
btpParams := ckks.DefaultBootstrappParams[5]
|
||||
params := ckks.DefaultBootstrappSchemeParams[0]
|
||||
btpParams := ckks.DefaultBootstrappParams[0]
|
||||
|
||||
fmt.Println()
|
||||
fmt.Printf("CKKS parameters : logN = %d, logSlots = %d, h = %d, logQP = %d, levels = %d, scale= 2^%f, sigma = %f \n", params.LogN(), params.LogSlots(), btpParams.H, params.LogQP(), params.Levels(), math.Log2(params.Scale()), params.Sigma())
|
||||
|
||||
@@ -24,7 +24,7 @@ func example() {
|
||||
|
||||
Scale := float64(1 << 40)
|
||||
|
||||
params, err := ckks.NewParametersFromLogModuli(LogN, LogModuli)
|
||||
params, err := ckks.NewParametersFromLogModuli(LogN, &LogModuli)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user