improvements on bfv/params.go

This commit is contained in:
Christian Mouchet
2019-08-14 21:54:29 -07:00
committed by ChristianMct
parent 1f3d2e829b
commit 925c1de364
11 changed files with 224 additions and 22 deletions

View File

@@ -13,7 +13,7 @@ type BfvContext struct {
// Plaintext Modulus
t uint64
// floor(Q/t) mod each Qi in montgomeryform
// floor(Q/T) mod each Qi in montgomeryform
DeltaMont []uint64
Delta []uint64
@@ -39,7 +39,7 @@ type BfvContext struct {
galElRotColLeft []uint64
galElRotColRight []uint64
// Checksum of [n, [modulies]]
// Checksum of [N, [modulies]]
checksum []byte
}

View File

@@ -7,7 +7,7 @@ import (
func BenchmarkBFVScheme(b *testing.B) {
paramSets := ParamSets60
paramSets := DefaultParams
bitDecomps := []uint64{60}

View File

@@ -22,7 +22,7 @@ func Test_BFV(t *testing.T) {
var err error
paramSets := ParamSets60[1:2]
paramSets := DefaultParams[1:2]
bitDecomps := []uint64{16}

View File

@@ -1,19 +1,39 @@
package bfv
import "github.com/lca1/lattigo/ring"
import (
"errors"
"fmt"
"github.com/lca1/lattigo/ring"
"github.com/lca1/lattigo/utils"
"math"
"math/bits"
)
//https://projects.csail.mit.edu/HEWorkshop/HomomorphicEncryptionStandard2018.pdf
// MaxN is the largest supported polynomial modulus degree
const MaxN = 1 << 15
// MaxModuliCount is the largest supported number of 60 moduli in the RNS representation
const MaxModuliCount = 256
// Power of 2 plaintext modulus
var Tpow2 = []uint64{2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, 2147483648, 4294967296}
var Tpow2 = []uint64{2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144,
524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864, 134217728, 268435456, 536870912,
1073741824, 2147483648, 4294967296}
// Plaintext modulus allowing batching for the corresponding N in ascending bitsize.
var TBatching4096 = []uint64{40961, 114689, 188417, 417793, 1032193, 2056193, 4169729, 8380417, 16760833, 33538049, 67084289, 134176769, 268369921, 536813569, 1073692673, 2147377153, 4294828033}
var TBatching8192 = []uint64{65537, 114689, 163841, 1032193, 1785857, 4079617, 8273921, 16760833, 33538049, 67043329, 133857281, 268369921, 536690689, 1073692673, 2147352577, 4294475777}
var TBatching16384 = []uint64{65537, 163841, 786433, 1769473, 3735553, 8257537, 16580609, 33292289, 67043329, 133857281, 268369921, 536641537, 1073643521, 2147352577, 4294475777}
var TBatching32768 = []uint64{65537, 786433, 1769473, 3735553, 8257537, 16580609, 33292289, 67043329, 132710401, 268369921, 536608769, 1073479681, 2147352577, 4293918721}
var TBatching = map[uint64][]uint64{
4096: {40961, 114689, 188417, 417793, 1032193, 2056193, 4169729, 8380417, 16760833, 33538049, 67084289, 134176769,
268369921, 536813569, 1073692673, 2147377153, 4294828033},
8192: {65537, 114689, 163841, 1032193, 1785857, 4079617, 8273921, 16760833, 33538049, 67043329, 133857281,
268369921, 536690689, 1073692673, 2147352577, 4294475777},
16384: {65537, 163841, 786433, 1769473, 3735553, 8257537, 16580609, 33292289, 67043329, 133857281, 268369921,
536641537, 1073643521, 2147352577, 4294475777},
32768: {65537, 786433, 1769473, 3735553, 8257537, 16580609, 33292289, 67043329, 132710401, 268369921, 536608769,
1073479681, 2147352577, 4293918721},
}
type Params struct {
// Parameters represents a given parameter set for the BFV cryptosystem.
type Parameters struct {
N uint64
T uint64
Qi []uint64
@@ -21,10 +41,63 @@ type Params struct {
Sigma float64
}
// ~128 bit security with sigma = 3.19 and secret with ternary distribution
var ParamSets60 = []Params{
// DefaultParams is an array default parameters with increasing homomorphic capacity.
// These parameters correspond to 128 bit security level for secret keys in the ternary distribution
// (see //https://projects.csail.mit.edu/HEWorkshop/HomomorphicEncryptionStandard2018.pdf).
var DefaultParams = []Parameters{
{4096, 65537, ring.Qi60[len(ring.Qi60)-2:], ring.Pi60[len(ring.Pi60)-3:], 3.19},
{8192, 65537, ring.Qi60[len(ring.Qi60)-4:], ring.Pi60[len(ring.Pi60)-5:], 3.19},
{16384, 65537, ring.Qi60[len(ring.Qi60)-8:], ring.Pi60[len(ring.Pi60)-9:], 3.19},
{32768, 65537, ring.Qi60[len(ring.Qi60)-16:], ring.Pi60[len(ring.Pi60)-17:], 3.19},
}
// Equals compares two sets of parameters for equality
func (p *Parameters) Equals(other *Parameters) bool {
if p == other {
return true
}
return p.N == other.N && EqualSlice(p.Qi, other.Qi) && EqualSlice(p.Pi, other.Pi) && p.Sigma == other.Sigma
}
// MarshalBinary returns a []byte representation of the parameter set
func (p *Parameters) MarshalBinary() ([]byte, error) {
if p.N == 0 { // if N is 0, then p is the zero value
return []byte{}, nil
}
b := utils.NewBuffer(make([]byte, 0, 3+((2+len(p.Qi)+len(p.Pi))<<3)))
b.WriteUint8(uint8(bits.Len64(p.N) - 1))
b.WriteUint8(uint8(len(p.Qi)))
b.WriteUint8(uint8(len(p.Pi)))
b.WriteUint64(p.T)
b.WriteUint64(uint64(p.Sigma * (1 << 32)))
b.WriteUint64Slice(p.Qi)
b.WriteUint64Slice(p.Pi)
return b.Bytes(), nil
}
// UnMarshalBinary decodes a []byte into a parameter set struct
func (p *Parameters) UnMarshalBinary(data []byte) error {
if len(data) < 3 {
return errors.New("invalid parameters encoding")
}
b := utils.NewBuffer(data)
p.N = 1 << uint64(b.ReadUint8())
if p.N > MaxN {
return errors.New("polynomial degree is too large")
}
lenQi := uint64(b.ReadUint8())
if lenQi > MaxModuliCount {
return fmt.Errorf("len(Qi) is larger than %d", MaxModuliCount)
}
lenPi := uint64(b.ReadUint8())
if lenPi > MaxModuliCount {
return fmt.Errorf("len(Pi) is larger than %d", MaxModuliCount)
}
p.T = b.ReadUint64()
p.Sigma = math.Round((float64(b.ReadUint64())/float64(1<<32))*100) / 100
p.Qi = make([]uint64, lenQi, lenQi)
p.Pi = make([]uint64, lenPi, lenPi)
b.ReadUint64Slice(p.Qi)
b.ReadUint64Slice(p.Pi)
return nil
}

27
bfv/params_test.go Normal file
View File

@@ -0,0 +1,27 @@
package bfv
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestParams_BinaryMarshaller(t *testing.T) {
t.Run("ZeroValue", func(t *testing.T) {
bytes, err := (&Parameters{}).MarshalBinary()
assert.Nil(t, err)
assert.Equal(t, []byte{}, bytes)
var p Parameters
err = p.UnMarshalBinary(bytes)
assert.NotNil(t, err)
})
t.Run("SupportedParams", func(t *testing.T) {
for _, params := range DefaultParams {
bytes, err := params.MarshalBinary()
assert.Nil(t, err)
var p Parameters
err = p.UnMarshalBinary(bytes)
assert.Nil(t, err)
assert.Equal(t, params, p)
}
})
}

View File

@@ -10,7 +10,7 @@ import (
func Benchmark_DBFVScheme(b *testing.B) {
paramSets := bfv.ParamSets60[3:4]
paramSets := bfv.DefaultParams[3:4]
bitDecomps := []uint64{60}
nParties := []int{2}

View File

@@ -10,7 +10,7 @@ import (
func Test_DBFVScheme(t *testing.T) {
paramSets := bfv.ParamSets60[0:1]
paramSets := bfv.DefaultParams[0:1]
bitDecomps := []uint64{60}
nParties := []int{5}

9
go.mod
View File

@@ -2,7 +2,8 @@ module github.com/lca1/lattigo
go 1.12
require (
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4
golang.org/x/lint v0.0.0-20190409202823-959b441ac422 // indirect
)
require golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4
require golang.org/x/lint v0.0.0-20190409202823-959b441ac422
require github.com/stretchr/testify v0.0.0-20190311161405-34c6fa2dc709

10
go.sum
View File

@@ -1,7 +1,14 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v0.0.0-20190311161405-34c6fa2dc709 h1:zN7m1FsHm1PeW8oJ3JvZPC5Cc1lWnEiHtS1i6DpXcm0=
github.com/stretchr/testify v0.0.0-20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422 h1:QzoH/1pFpZguR8NrRHLcO6jKqfv2zpuSqZLgdm7ZmjI=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -9,5 +16,4 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd h1:/e+gpKk9r3dJobndpTytxS2gOy6m5uvpg+ISQoEcusQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=

56
utils/buffer.go Normal file
View File

@@ -0,0 +1,56 @@
// Package containing helper structures and function
package utils
// Buffer is a simple wrapper around a []byte to facilitate efficient marshaling of lattigo's objects
type Buffer struct {
buf []byte
}
// NewBuffer creates a new buffer from the provided backing slice
func NewBuffer(s []byte) *Buffer {
return &Buffer{s}
}
func (b *Buffer) WriteUint8(c byte) {
b.buf = append(b.buf, c)
}
func (b *Buffer) WriteUint64(v uint64) {
b.buf = append(b.buf, byte(v>>56),
byte(v>>48),
byte(v>>40),
byte(v>>32),
byte(v>>24),
byte(v>>16),
byte(v>>8),
byte(v))
}
func (b *Buffer) WriteUint64Slice(s []uint64) {
for _, v := range s {
b.WriteUint64(v)
}
}
func (b *Buffer) ReadUint8() byte {
v := b.buf[0]
b.buf = b.buf[1:]
return v
}
func (b *Buffer) ReadUint64() uint64 {
v := b.buf[:8]
b.buf = b.buf[8:]
return uint64(v[7]) | uint64(v[6])<<8 | uint64(v[5])<<16 | uint64(v[4])<<24 |
uint64(v[3])<<32 | uint64(v[2])<<40 | uint64(v[1])<<48 | uint64(v[0])<<56
}
func (b *Buffer) ReadUint64Slice(rec []uint64) {
for i := range rec {
rec[i] = b.ReadUint64()
}
}
func (b *Buffer) Bytes() []byte {
return b.buf
}

39
utils/buffer_test.go Normal file
View File

@@ -0,0 +1,39 @@
// Package containing helper structures and function
package utils
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestNewBuffer(t *testing.T) {
assert.Equal(t, []byte(nil), NewBuffer(nil).Bytes())
assert.Equal(t, []byte{}, NewBuffer([]byte{}).Bytes())
assert.Equal(t, []byte{1, 2, 3}, NewBuffer([]byte{1, 2, 3}).Bytes())
}
func TestBuffer_WriteReadUint8(t *testing.T) {
b := NewBuffer(make([]byte, 0, 1))
b.WriteUint8(0xff)
assert.Equal(t, []byte{0xff}, b.Bytes())
assert.Equal(t, byte(0xff), b.ReadUint8())
assert.Equal(t, []byte{}, b.Bytes())
}
func TestBuffer_WriteReadUint64(t *testing.T) {
b := NewBuffer(make([]byte, 0, 8))
b.WriteUint64(0x1122334455667788)
assert.Equal(t, []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}, b.Bytes())
assert.Equal(t, uint64(0x1122334455667788), b.ReadUint64())
assert.Equal(t, []byte{}, b.Bytes())
}
func TestBuffer_WriteReadUint64Slice(t *testing.T) {
b := NewBuffer(make([]byte, 0, 8))
b.WriteUint64Slice([]uint64{0x1122334455667788})
assert.Equal(t, []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}, b.Bytes())
s := make([]uint64, 1, 1)
b.ReadUint64Slice(s)
assert.Equal(t, []uint64{0x1122334455667788}, s)
assert.Equal(t, []byte{}, b.Bytes())
}