forked from taurushq-io/multi-party-sig
-
Notifications
You must be signed in to change notification settings - Fork 0
/
additive.go
163 lines (148 loc) · 5.72 KB
/
additive.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
package ot
import (
"github.com/capsule-org/multi-party-sig/pkg/hash"
"github.com/capsule-org/multi-party-sig/pkg/math/curve"
"github.com/capsule-org/multi-party-sig/pkg/math/sample"
"github.com/zeebo/blake3"
)
// AdditiveOTSendRound1Message is the first message by the Sender in the Additive OT protocol.
type AdditiveOTSendRound1Message struct {
CombinedPads [][2][]byte
}
// AdditiveOTSendResult is the result of running the Additive OT protocol.
//
// The sender receives a collection of random pads.
type AdditiveOTSendResult [][2]curve.Scalar
// AdditiveOTSender holds the Sender's state for the Additive OT Protocol.
type AdditiveOTSender struct {
ctxHash *hash.Hash
group curve.Curve
// The setup used for the underlying correlated OT.
setup *CorreOTSendSetup
// The number of transfers to perform
batchSize int
// The constant adjust that will be conditionally added to the pads.
alpha [2]curve.Scalar
}
// NewAdditiveOTSender initializes the sender of an Additive OT.
//
// This follows Protocol 9 of https://eprint.iacr.org/2018/499 to a certain extent.
// The main difference is that we strictly conform to the underlying extended OT,
// removing Doerner's modifications to the check.
//
// The goal of this protocol is for the Sender to learn random pads, each pad being two scalars,
// and for the Receiver to receive choice_j * alpha_j - pad_j for each of the pads, and their choices.
//
// A single setup can be used for multiple protocol executions, but should be initialized with a nonce.
func NewAdditiveOTSender(ctxHash *hash.Hash, setup *CorreOTSendSetup, batchSize int, alpha [2]curve.Scalar) *AdditiveOTSender {
return &AdditiveOTSender{
ctxHash: ctxHash,
setup: setup,
batchSize: batchSize,
group: alpha[0].Curve(),
alpha: alpha,
}
}
func (r *AdditiveOTSender) Round1(msg *AdditiveOTReceiveRound1Message) (*AdditiveOTSendRound1Message, AdditiveOTSendResult, error) {
extendedResult, err := ExtendedOTSend(r.ctxHash, r.setup, r.batchSize, msg.Msg)
if err != nil {
return nil, nil, err
}
prg := blake3.New()
outMsg := new(AdditiveOTSendRound1Message)
outMsg.CombinedPads = make([][2][]byte, r.batchSize)
result := make([][2]curve.Scalar, r.batchSize)
var combinedPads [2]curve.Scalar
for i := 0; i < r.batchSize; i++ {
prg.Reset()
_, _ = prg.Write(extendedResult._V0[i][:])
digest := prg.Digest()
result[i][0] = sample.Scalar(digest, r.group)
result[i][1] = sample.Scalar(digest, r.group)
prg.Reset()
_, _ = prg.Write(extendedResult._V1[i][:])
digest = prg.Digest()
combinedPads[0] = sample.Scalar(digest, r.group)
combinedPads[1] = sample.Scalar(digest, r.group)
combinedPads[0].Sub(result[i][0]).Add(r.alpha[0])
combinedPads[1].Sub(result[i][1]).Add(r.alpha[1])
var err error
outMsg.CombinedPads[i][0], err = combinedPads[0].MarshalBinary()
if err != nil {
return nil, nil, err
}
outMsg.CombinedPads[i][1], err = combinedPads[1].MarshalBinary()
if err != nil {
return nil, nil, err
}
}
return outMsg, result, nil
}
// AdditiveOTReceiver holds the Receiver's state for the Additive OT Protocol.
type AdditiveOTReceiver struct {
// After setup
ctxHash *hash.Hash
group curve.Curve
setup *CorreOTReceiveSetup
choices []byte
// After round 1
result *ExtendedOTReceiveResult
}
// NewAdditiveOTReceiver initializes the receiver of an Additive OT.
//
// This follows Protocol 9 of https://eprint.iacr.org/2018/499 to a certain extent.
// The main difference is that we strictly conform to the underlying extended OT,
// removing Doerner's modifications to the check.
//
// The goal of this protocol is for the Sender to learn random pads, each pad being two scalars,
// and for the Receiver to receive choice_j * alpha_j - pad_j for each of the pads, and their choices.
//
// A single setup can be used for multiple protocol executions, but should be initialized with a nonce.
func NewAdditiveOTReceiver(ctxHash *hash.Hash, setup *CorreOTReceiveSetup, group curve.Curve, choices []byte) *AdditiveOTReceiver {
return &AdditiveOTReceiver{ctxHash: ctxHash, setup: setup, group: group, choices: choices}
}
// AdditiveOTReceiveRound1Message is the first message sent by the Receiver in an Additive OT.
type AdditiveOTReceiveRound1Message struct {
Msg *ExtendedOTReceiveMessage
}
// Round1 executes the Receiver's first round of an Additive OT.
func (r *AdditiveOTReceiver) Round1() *AdditiveOTReceiveRound1Message {
msg, result := ExtendedOTReceive(r.ctxHash, r.setup, r.choices)
r.result = result
return &AdditiveOTReceiveRound1Message{Msg: msg}
}
// AdditiveOTReceiveResult is the Receiver's result for an Additive OT.
//
// For each choice_j, we receive choice_j * alpha - pad.
type AdditiveOTReceiveResult [][2]curve.Scalar
// Round2 executes the Receiver's second round of an Additive OT.
func (r *AdditiveOTReceiver) Round2(msg *AdditiveOTSendRound1Message) (AdditiveOTReceiveResult, error) {
batchSize := 8 * len(r.choices)
result := make([][2]curve.Scalar, batchSize)
prg := blake3.New()
for i := 0; i < batchSize; i++ {
mask := -bitAt(i, r.choices)
prg.Reset()
_, _ = prg.Write(r.result._VChoices[i][:])
digest := prg.Digest()
result[i][0] = sample.Scalar(digest, r.group).Negate()
result[i][1] = sample.Scalar(digest, r.group).Negate()
for j := 0; j < len(msg.CombinedPads[j][0]); j++ {
msg.CombinedPads[i][0][j] &= mask
}
for j := 0; j < len(msg.CombinedPads[j][1]); j++ {
msg.CombinedPads[i][1][j] &= mask
}
combinedPad0 := r.group.NewScalar()
if err := combinedPad0.UnmarshalBinary(msg.CombinedPads[i][0]); err != nil {
return nil, err
}
combinedPad1 := r.group.NewScalar()
if err := combinedPad1.UnmarshalBinary(msg.CombinedPads[i][1]); err != nil {
return nil, err
}
result[i][0].Add(combinedPad0)
result[i][1].Add(combinedPad1)
}
return result, nil
}