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 package oprf
48
49 import (
50 "crypto"
51 "encoding/binary"
52 "errors"
53 "hash"
54 "io"
55 "math"
56
57 "github.com/cloudflare/circl/group"
58 "github.com/cloudflare/circl/zk/dleq"
59 )
60
61 const (
62 version = "OPRFV1-"
63 finalizeDST = "Finalize"
64 hashToGroupDST = "HashToGroup-"
65 hashToScalarDST = "HashToScalar-"
66 deriveKeyPairDST = "DeriveKeyPair"
67 infoLabel = "Info"
68 )
69
70 type Mode = uint8
71
72 const (
73 BaseMode Mode = 0x00
74 VerifiableMode Mode = 0x01
75 PartialObliviousMode Mode = 0x02
76 )
77
78 func isValidMode(m Mode) bool {
79 return m == BaseMode || m == VerifiableMode || m == PartialObliviousMode
80 }
81
82 type Suite interface {
83 Identifier() string
84 Group() group.Group
85 Hash() crypto.Hash
86 cannotBeImplementedExternally()
87 }
88
89 var (
90
91 SuiteRistretto255 Suite = params{identifier: "ristretto255-SHA512", group: group.Ristretto255, hash: crypto.SHA512}
92
93 SuiteP256 Suite = params{identifier: "P256-SHA256", group: group.P256, hash: crypto.SHA256}
94
95 SuiteP384 Suite = params{identifier: "P384-SHA384", group: group.P384, hash: crypto.SHA384}
96
97 SuiteP521 Suite = params{identifier: "P521-SHA512", group: group.P521, hash: crypto.SHA512}
98 )
99
100 func GetSuite(identifier string) (Suite, error) {
101 for _, suite := range []Suite{SuiteRistretto255, SuiteP256, SuiteP384, SuiteP521} {
102 if suite.Identifier() == identifier {
103 return suite, nil
104 }
105 }
106 return nil, ErrInvalidSuite
107 }
108
109 func NewClient(s Suite) Client {
110 p := s.(params)
111 p.m = BaseMode
112
113 return Client{client{p}}
114 }
115
116 func NewVerifiableClient(s Suite, server *PublicKey) VerifiableClient {
117 p, ok := s.(params)
118 if !ok || server == nil {
119 panic(ErrNoKey)
120 }
121 p.m = VerifiableMode
122
123 return VerifiableClient{client{p}, server}
124 }
125
126 func NewPartialObliviousClient(s Suite, server *PublicKey) PartialObliviousClient {
127 p, ok := s.(params)
128 if !ok || server == nil {
129 panic(ErrNoKey)
130 }
131 p.m = PartialObliviousMode
132
133 return PartialObliviousClient{client{p}, server}
134 }
135
136 func NewServer(s Suite, key *PrivateKey) Server {
137 p, ok := s.(params)
138 if !ok || key == nil {
139 panic(ErrNoKey)
140 }
141 p.m = BaseMode
142
143 return Server{server{p, key}}
144 }
145
146 func NewVerifiableServer(s Suite, key *PrivateKey) VerifiableServer {
147 p, ok := s.(params)
148 if !ok || key == nil {
149 panic(ErrNoKey)
150 }
151 p.m = VerifiableMode
152
153 return VerifiableServer{server{p, key}}
154 }
155
156 func NewPartialObliviousServer(s Suite, key *PrivateKey) PartialObliviousServer {
157 p, ok := s.(params)
158 if !ok || key == nil {
159 panic(ErrNoKey)
160 }
161 p.m = PartialObliviousMode
162
163 return PartialObliviousServer{server{p, key}}
164 }
165
166 type params struct {
167 m Mode
168 group group.Group
169 hash crypto.Hash
170 identifier string
171 }
172
173 func (p params) cannotBeImplementedExternally() {}
174
175 func (p params) String() string { return p.Identifier() }
176 func (p params) Group() group.Group { return p.group }
177 func (p params) Hash() crypto.Hash { return p.hash }
178 func (p params) Identifier() string { return p.identifier }
179
180 func (p params) getDST(name string) []byte {
181 return append(append(append(append(
182 []byte{},
183 []byte(name)...),
184 []byte(version)...),
185 []byte{p.m, byte('-')}...),
186 []byte(p.identifier)...)
187 }
188
189 func (p params) scalarFromInfo(info []byte) (group.Scalar, error) {
190 if len(info) > math.MaxUint16 {
191 return nil, ErrInvalidInfo
192 }
193 lenInfo := []byte{0, 0}
194 binary.BigEndian.PutUint16(lenInfo, uint16(len(info)))
195 framedInfo := append(append(append([]byte{},
196 []byte(infoLabel)...),
197 lenInfo...),
198 info...)
199
200 return p.group.HashToScalar(framedInfo, p.getDST(hashToScalarDST)), nil
201 }
202
203 func (p params) finalizeHash(h hash.Hash, input, info, element []byte) []byte {
204 h.Reset()
205 lenBuf := []byte{0, 0}
206
207 binary.BigEndian.PutUint16(lenBuf, uint16(len(input)))
208 mustWrite(h, lenBuf)
209 mustWrite(h, input)
210
211 if p.m == PartialObliviousMode {
212 binary.BigEndian.PutUint16(lenBuf, uint16(len(info)))
213 mustWrite(h, lenBuf)
214 mustWrite(h, info)
215 }
216
217 binary.BigEndian.PutUint16(lenBuf, uint16(len(element)))
218 mustWrite(h, lenBuf)
219 mustWrite(h, element)
220
221 mustWrite(h, []byte(finalizeDST))
222
223 return h.Sum(nil)
224 }
225
226 func (p params) getDLEQParams() (out dleq.Params) {
227 out.G = p.group
228 out.H = p.hash
229 out.DST = p.getDST("")
230
231 return
232 }
233
234 func mustWrite(h io.Writer, bytes []byte) {
235 bytesLen, err := h.Write(bytes)
236 if err != nil {
237 panic(err)
238 }
239 if len(bytes) != bytesLen {
240 panic("failed to write")
241 }
242 }
243
244 var (
245 ErrInvalidSuite = errors.New("invalid suite")
246 ErrInvalidMode = errors.New("invalid mode")
247 ErrDeriveKeyPairError = errors.New("key pair derivation failed")
248 ErrInvalidInput = errors.New("invalid input")
249 ErrInvalidInfo = errors.New("invalid info")
250 ErrInvalidProof = errors.New("proof verification failed")
251 ErrInverseZero = errors.New("inverting a zero value")
252 ErrNoKey = errors.New("must provide a key")
253 )
254
255 type (
256 Blind = group.Scalar
257 Blinded = group.Element
258 Evaluated = group.Element
259 )
260
261
262 type FinalizeData struct {
263 inputs [][]byte
264 blinds []Blind
265 evalReq *EvaluationRequest
266 }
267
268
269
270 func (f FinalizeData) CopyBlinds() []Blind {
271 out := make([]Blind, len(f.blinds))
272 for i, b := range f.blinds {
273 out[i] = b.Copy()
274 }
275 return out
276 }
277
278
279 type EvaluationRequest struct {
280 Elements []Blinded
281 }
282
283
284
285 type Evaluation struct {
286 Elements []Evaluated
287 Proof *dleq.Proof
288 }
289
View as plain text