-
Notifications
You must be signed in to change notification settings - Fork 1
/
keygen_rot.go
164 lines (134 loc) · 4.62 KB
/
keygen_rot.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
package drlwe
import (
"encoding/binary"
"errors"
"math/big"
"github.com/dwkim606/test_lattigo/ring"
"github.com/dwkim606/test_lattigo/rlwe"
"github.com/dwkim606/test_lattigo/utils"
)
// RotationKeyGenerator is an interface for the local operation in the generation of rotation keys
type RotationKeyGenerator interface {
AllocateShares() (rtgShare *RTGShare)
GenShare(sk *rlwe.SecretKey, galEl uint64, crp []*ring.Poly, shareOut *RTGShare)
Aggregate(share1, share2, shareOut *RTGShare)
GenRotationKey(share *RTGShare, crp []*ring.Poly, rotKey *rlwe.SwitchingKey)
}
// RTGShare is represent a Party's share in the RTG protocol
type RTGShare struct {
Value []*ring.Poly
}
// RTGProtocol is the structure storing the parameters for the collective rotation-keys generation.
type RTGProtocol struct { // TODO rename GaloisKeyGen ?
params rlwe.Parameters
ringQP *ring.Ring
pBigInt *big.Int
tmpPoly [2]*ring.Poly
gaussianSampler *ring.GaussianSampler
}
// NewRTGProtocol creates a RTGProtocol instance
func NewRTGProtocol(params rlwe.Parameters) *RTGProtocol {
rtg := new(RTGProtocol)
rtg.params = params
rtg.ringQP = params.RingQP()
rtg.pBigInt = params.PBigInt()
var err error
prng, err := utils.NewPRNG()
if err != nil {
panic(err)
}
rtg.gaussianSampler = ring.NewGaussianSampler(prng, rtg.ringQP, params.Sigma(), int(6*params.Sigma()))
rtg.tmpPoly = [2]*ring.Poly{rtg.ringQP.NewPoly(), rtg.ringQP.NewPoly()}
return rtg
}
// AllocateShares allocates a party's share in the RTG protocol
func (rtg *RTGProtocol) AllocateShares() (rtgShare *RTGShare) {
rtgShare = new(RTGShare)
rtgShare.Value = make([]*ring.Poly, rtg.params.Beta())
for i := range rtgShare.Value {
rtgShare.Value[i] = rtg.ringQP.NewPoly()
}
return
}
// GenShare generates a party's share in the RTG protocol
func (rtg *RTGProtocol) GenShare(sk *rlwe.SecretKey, galEl uint64, crp []*ring.Poly, shareOut *RTGShare) {
twoN := rtg.ringQP.N << 2
galElInv := ring.ModExp(galEl, int(twoN-1), uint64(twoN))
ring.PermuteNTT(sk.Value, galElInv, rtg.tmpPoly[1])
rtg.ringQP.MulScalarBigint(sk.Value, rtg.pBigInt, rtg.tmpPoly[0])
var index int
for i := 0; i < rtg.params.Beta(); i++ {
// e
rtg.gaussianSampler.Read(shareOut.Value[i])
rtg.ringQP.NTTLazy(shareOut.Value[i], shareOut.Value[i])
rtg.ringQP.MForm(shareOut.Value[i], shareOut.Value[i])
// a is the CRP
// e + sk_in * (qiBarre*qiStar) * 2^w
// (qiBarre*qiStar)%qi = 1, else 0
for j := 0; j < rtg.params.PCount(); j++ {
index = i*rtg.params.PCount() + j
qi := rtg.ringQP.Modulus[index]
tmp0 := rtg.tmpPoly[0].Coeffs[index]
tmp1 := shareOut.Value[i].Coeffs[index]
for w := 0; w < rtg.ringQP.N; w++ {
tmp1[w] = ring.CRed(tmp1[w]+tmp0[w], qi)
}
// Handles the case where nb pj does not divides nb qi
if index >= rtg.params.QCount() {
break
}
}
// sk_in * (qiBarre*qiStar) * 2^w - a*sk + e
rtg.ringQP.MulCoeffsMontgomeryAndSub(crp[i], rtg.tmpPoly[1], shareOut.Value[i])
}
rtg.tmpPoly[0].Zero()
rtg.tmpPoly[1].Zero()
return
}
// Aggregate aggregates two shares in the Rotation Key Generation protocol
func (rtg *RTGProtocol) Aggregate(share1, share2, shareOut *RTGShare) {
for i := 0; i < rtg.params.Beta(); i++ {
rtg.ringQP.Add(share1.Value[i], share2.Value[i], shareOut.Value[i])
}
}
// GenRotationKey finalizes the RTG protocol and populates the input RotationKey with the computed collective SwitchingKey.
func (rtg *RTGProtocol) GenRotationKey(share *RTGShare, crp []*ring.Poly, rotKey *rlwe.SwitchingKey) {
for i := 0; i < rtg.params.Beta(); i++ {
ring.CopyValues(share.Value[i], rotKey.Value[i][0])
ring.CopyValues(crp[i], rotKey.Value[i][1])
}
}
// MarshalBinary encode the target element on a slice of byte.
func (share *RTGShare) MarshalBinary() ([]byte, error) {
lenRing := share.Value[0].GetDataLen(true)
data := make([]byte, 8+lenRing*len(share.Value))
binary.BigEndian.PutUint64(data[:8], uint64(lenRing))
ptr := 8
for _, val := range share.Value {
cnt, err := val.WriteTo(data[ptr : ptr+lenRing])
if err != nil {
return []byte{}, err
}
ptr += cnt
}
return data, nil
}
// UnmarshalBinary decodes a slice of bytes on the target element.
func (share *RTGShare) UnmarshalBinary(data []byte) error {
if len(data) <= 8 {
return errors.New("Unsufficient data length")
}
lenRing := binary.BigEndian.Uint64(data[:8])
valLength := uint64(len(data)-8) / lenRing
share.Value = make([]*ring.Poly, valLength)
ptr := uint64(8)
for i := range share.Value {
share.Value[i] = new(ring.Poly)
err := share.Value[i].UnmarshalBinary(data[ptr : ptr+lenRing])
if err != nil {
return err
}
ptr += lenRing
}
return nil
}