-
Notifications
You must be signed in to change notification settings - Fork 0
/
sig_session.go
190 lines (179 loc) · 5 KB
/
sig_session.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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
package tcecdsa
import (
"fmt"
"github.com/niclabs/tcecdsa/l2fhe"
"math/big"
)
// Status represents the current state of a SigSession
type Status uint8
// The following consts represent the different status a session could be.
const (
NotInited Status = iota // Session was created.
Round1 // Session has passed Round 1.
Round2 // Session has passed Round 2.
Round3 // Session has passed Round 3.
Finished // Session is finished.
Undefined Status = iota // Undefined status.
)
// SigSession represents a set of values saved and used by the participants
// to generate an specific Signature.
// It is an ephimeral structure and it lives only while the Signature is being created.
type SigSession struct {
status Status // Session status
r, s *big.Int // Final Signature
share *KeyShare // KeyShare related to the current signing process
meta *KeyMeta // KeyMeta related to the current signing process
sigma, z *l2fhe.EncryptedL2 // Values needed to check ZKProofs
m []byte // Hashed message
encM *l2fhe.EncryptedL1 // Encrypted hashed message
u *l2fhe.EncryptedL1 // Value used between rounds 2 and 3 in signing process
}
// Round1 starts the signing process generating a set of random values and the ZKProof of them.
// It represents Round 1 and Round 2 in paper, because our implementation doesn't consider the usage of commits.
func (state *SigSession) Round1() (msg *Round1Message, err error) {
if state.status != NotInited {
err = fmt.Errorf("status should be \"Not Inited\" to use this method")
}
// choose rho_i, k_i random from Z_q, and c_i from [-q^6, q^6]
rho, err := RandomInRange(zero, state.meta.Q())
if err != nil {
return
}
k, err := RandomInRange(zero, state.meta.Q())
if err != nil {
return
}
qToSix := new(big.Int).Exp(state.meta.Q(), big.NewInt(6), nil)
ci, err := RandomInRange(zero, qToSix)
if err != nil {
return
}
ri := NewZero().BaseMul(state.meta.Curve(), k)
ui, rui, err := state.meta.Encrypt(rho)
if err != nil {
return
}
vi, rvi, err := state.meta.Encrypt(k)
if err != nil {
return
}
wi, rwi, err := state.meta.Encrypt(ci)
if err != nil {
return
}
proofParams := &SigZKProofParams{
Eta1: k,
Eta2: rho,
Eta3: ci,
Ri: ri,
EncUi: ui,
EncVi: vi,
EncWi: wi,
RandUi: rui,
RandVi: rvi,
RandWi: rwi,
}
proof, err := NewSigZKProof(state.meta, proofParams)
msg = &Round1Message{
Ri: ri,
Ui: ui,
Vi: vi,
Wi: wi,
Proof: proof,
}
state.status = Round1
return
}
// Round2 uses the values generated in Round1 to generate R and u, a value that is needed for GetSignature
// It is Round 3 in paper.
func (state *SigSession) Round2(msgs Round1MessageList) (msg *Round2Message, err error) {
if state.status != Round1 {
err = fmt.Errorf("status should be \"Round1\" to use this method")
}
R, u, v, w, err := msgs.Join(state.meta)
uv, err := state.meta.Mul(v, u)
if err != nil {
return
}
qw, err := state.meta.MulConstL1(w, state.meta.Q())
if err != nil {
return
}
qwL2, err := qw.ToL2(state.meta.PubKey)
if err != nil {
return
}
z, err := state.meta.AddL2(uv, qwL2)
if err != nil {
return
}
pdZ, zkp, err := state.meta.PartialDecryptL2(state.share.PaillierShare, z)
r := R.X
msg = &Round2Message{
PDZ: pdZ,
Proof: zkp,
}
state.z = z
state.status = Round2
state.u, state.r = u, r
return
}
// Round3 joins the partially decrypted Z of the last round and generates a partial decryption of sigma.
// It is Round 4 in paper
func (state *SigSession) Round3(msgs Round2MessageList) (msg *Round3Message, err error) {
if state.status != Round2 {
err = fmt.Errorf("status should be \"Round2\" to use this method")
}
nu, err := msgs.Join(state.meta, state.z)
if err != nil {
return
}
psi := new(big.Int).ModInverse(nu, state.meta.Q())
vHat, err := state.meta.MulConstL1(state.u, psi)
if err != nil {
return
}
rAlpha, err := state.meta.MulConstL1(state.share.Alpha, state.r)
if err != nil {
return
}
rAlphaPlusEncM, err := state.meta.AddL1(rAlpha, state.encM)
if err != nil {
return
}
sigma, err := state.meta.Mul(rAlphaPlusEncM, vHat)
if err != nil {
return
}
pdSigma, zkp, err := state.meta.PartialDecryptL2(state.share.PaillierShare, sigma)
if err != nil {
return
}
msg = &Round3Message{
PDSigma: pdSigma,
Proof: zkp,
}
state.sigma = sigma
state.status = Round3
return
}
// GetSignature joins the last values and returns the Signature.
// It is described in the paper as the joining process of partially decrypted values.
func (state *SigSession) GetSignature(msgs Round3MessageList) (r, s *big.Int, err error) {
if state.status == Finished {
// Ri and S already calculated, return them.
r, s = state.r, state.s
return
}
if state.status != Round3 {
err = fmt.Errorf("status should be \"Round3\" to use this method")
}
s, err = msgs.Join(state.meta, state.sigma)
if err != nil {
return
}
r = state.r
state.s = s
state.status = Finished
return
}