1 package oprf
2
3 import (
4 "crypto/rand"
5
6 "github.com/cloudflare/circl/group"
7 "github.com/cloudflare/circl/zk/dleq"
8 )
9
10 type client struct{ params }
11
12 type Client struct {
13 client
14 }
15
16 type VerifiableClient struct {
17 client
18 pkS *PublicKey
19 }
20
21 type PartialObliviousClient struct {
22 client
23 pkS *PublicKey
24 }
25
26 func (c client) Blind(inputs [][]byte) (*FinalizeData, *EvaluationRequest, error) {
27 if len(inputs) == 0 {
28 return nil, nil, ErrInvalidInput
29 }
30
31 blinds := make([]Blind, len(inputs))
32 for i := range inputs {
33 blinds[i] = c.params.group.RandomScalar(rand.Reader)
34 }
35
36 return c.blind(inputs, blinds)
37 }
38
39 func (c client) DeterministicBlind(inputs [][]byte, blinds []Blind) (*FinalizeData, *EvaluationRequest, error) {
40 if len(inputs) == 0 {
41 return nil, nil, ErrInvalidInput
42 }
43 if len(inputs) != len(blinds) {
44 return nil, nil, ErrInvalidInput
45 }
46
47 return c.blind(inputs, blinds)
48 }
49
50 func (c client) blind(inputs [][]byte, blinds []Blind) (*FinalizeData, *EvaluationRequest, error) {
51 blindedElements := make([]Blinded, len(inputs))
52 dst := c.params.getDST(hashToGroupDST)
53 for i := range inputs {
54 point := c.params.group.HashToElement(inputs[i], dst)
55 if point.IsIdentity() {
56 return nil, nil, ErrInvalidInput
57 }
58 blindedElements[i] = c.params.group.NewElement().Mul(point, blinds[i])
59 }
60
61 evalReq := &EvaluationRequest{blindedElements}
62 finData := &FinalizeData{inputs, blinds, evalReq}
63
64 return finData, evalReq, nil
65 }
66
67 func (c client) unblind(serUnblindeds [][]byte, blindeds []group.Element, blind []Blind) (err error) {
68 invBlind := c.params.group.NewScalar()
69 U := c.params.group.NewElement()
70
71 for i := range blindeds {
72 invBlind.Inv(blind[i])
73 U.Mul(blindeds[i], invBlind)
74 serUnblindeds[i], err = U.MarshalBinaryCompress()
75 if err != nil {
76 return err
77 }
78 }
79
80 return nil
81 }
82
83 func (c client) validate(f *FinalizeData, e *Evaluation) (err error) {
84 if l := len(f.blinds); len(f.evalReq.Elements) != l || len(e.Elements) != l {
85 err = ErrInvalidInput
86 }
87
88 return
89 }
90
91 func (c client) finalize(f *FinalizeData, e *Evaluation, info []byte) ([][]byte, error) {
92 unblindedElements := make([][]byte, len(f.blinds))
93 err := c.unblind(unblindedElements, e.Elements, f.blinds)
94 if err != nil {
95 return nil, err
96 }
97
98 h := c.params.hash.New()
99 outputs := make([][]byte, len(f.inputs))
100 for i := range f.inputs {
101 outputs[i] = c.params.finalizeHash(h, f.inputs[i], info, unblindedElements[i])
102 }
103
104 return outputs, nil
105 }
106
107 func (c Client) Finalize(f *FinalizeData, e *Evaluation) (outputs [][]byte, err error) {
108 if err = c.validate(f, e); err != nil {
109 return nil, err
110 }
111
112 return c.client.finalize(f, e, nil)
113 }
114
115 func (c VerifiableClient) Finalize(f *FinalizeData, e *Evaluation) (outputs [][]byte, err error) {
116 if err := c.validate(f, e); err != nil {
117 return nil, err
118 }
119
120 if !(dleq.Verifier{Params: c.getDLEQParams()}).VerifyBatch(
121 c.params.group.Generator(),
122 c.pkS.e,
123 f.evalReq.Elements,
124 e.Elements,
125 e.Proof,
126 ) {
127 return nil, ErrInvalidProof
128 }
129
130 return c.client.finalize(f, e, nil)
131 }
132
133 func (c PartialObliviousClient) Finalize(f *FinalizeData, e *Evaluation, info []byte) (outputs [][]byte, err error) {
134 if err = c.validate(f, e); err != nil {
135 return nil, err
136 }
137
138 tweakedKey, err := c.pointFromInfo(info)
139 if err != nil {
140 return nil, err
141 }
142
143 if !(dleq.Verifier{Params: c.getDLEQParams()}).VerifyBatch(
144 c.params.group.Generator(),
145 tweakedKey,
146 e.Elements,
147 f.evalReq.Elements,
148 e.Proof,
149 ) {
150 return nil, ErrInvalidProof
151 }
152
153 return c.client.finalize(f, e, info)
154 }
155
156 func (c PartialObliviousClient) pointFromInfo(info []byte) (group.Element, error) {
157 m, err := c.params.scalarFromInfo(info)
158 if err != nil {
159 return nil, err
160 }
161
162 T := c.params.group.NewElement().MulGen(m)
163 tweakedKey := c.params.group.NewElement().Add(T, c.pkS.e)
164 if tweakedKey.IsIdentity() {
165 return nil, ErrInvalidInfo
166 }
167
168 return tweakedKey, nil
169 }
170
View as plain text