Skip to content

Commit 10a0004

Browse files
committed
Adds conditional move and select to group.
1 parent c8971c0 commit 10a0004

File tree

6 files changed

+227
-12
lines changed

6 files changed

+227
-12
lines changed

go.mod

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module github.com/cloudflare/circl
33
go 1.16
44

55
require (
6-
github.com/bwesterb/go-ristretto v1.2.1
7-
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
8-
golang.org/x/sys v0.0.0-20220624220833-87e55d714810
6+
github.com/bwesterb/go-ristretto v1.2.2
7+
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa
8+
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10
99
)

go.sum

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
github.com/bwesterb/go-ristretto v1.2.1 h1:Xd9ZXmjKE2aY8Ub7+4bX7tXsIPsV1pIZaUlJUjI1toE=
2-
github.com/bwesterb/go-ristretto v1.2.1/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
3-
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
4-
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
1+
github.com/bwesterb/go-ristretto v1.2.2 h1:S2C0mmSjCLS3H9+zfXoIoKzl+cOncvBvt6pE+zTm5Ms=
2+
github.com/bwesterb/go-ristretto v1.2.2/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
3+
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
4+
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
55
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
66
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
77
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
88
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
9-
golang.org/x/sys v0.0.0-20220624220833-87e55d714810 h1:rHZQSjJdAI4Xf5Qzeh2bBc5YJIkPFVM6oDtMFYmgws0=
10-
golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
9+
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg=
10+
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1111
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
1212
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
1313
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

group/group.go

+5
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ type Element interface {
3636
Copy() Element
3737
IsIdentity() bool
3838
IsEqual(Element) bool
39+
CMov(int, Element) Element
40+
CSelect(int, Element, Element) Element
3941
Add(Element, Element) Element
4042
Dbl(Element) Element
4143
Neg(Element) Element
@@ -53,6 +55,8 @@ type Scalar interface {
5355
Copy() Scalar
5456
IsEqual(Scalar) bool
5557
SetUint64(uint64)
58+
CMov(int, Scalar) Scalar
59+
CSelect(int, Scalar, Scalar) Scalar
5660
Add(Scalar, Scalar) Scalar
5761
Sub(Scalar, Scalar) Scalar
5862
Mul(Scalar, Scalar) Scalar
@@ -65,4 +69,5 @@ type Scalar interface {
6569
var (
6670
ErrType = errors.New("type mismatch")
6771
ErrUnmarshal = errors.New("error unmarshaling")
72+
ErrSelector = errors.New("group: selector must be 0 or 1")
6873
)

group/group_test.go

+105-3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ func TestGroup(t *testing.T) {
2626
t.Run(n+"/Neg", func(tt *testing.T) { testNeg(tt, testTimes, g) })
2727
t.Run(n+"/Mul", func(tt *testing.T) { testMul(tt, testTimes, g) })
2828
t.Run(n+"/MulGen", func(tt *testing.T) { testMulGen(tt, testTimes, g) })
29+
t.Run(n+"/CMov", func(tt *testing.T) { testCMov(tt, testTimes, g) })
30+
t.Run(n+"/CSelect", func(tt *testing.T) { testCSelect(tt, testTimes, g) })
2931
t.Run(n+"/Order", func(tt *testing.T) { testOrder(tt, testTimes, g) })
3032
t.Run(n+"/Marshal", func(tt *testing.T) { testMarshal(tt, testTimes, g) })
3133
t.Run(n+"/Scalar", func(tt *testing.T) { testScalar(tt, testTimes, g) })
@@ -101,6 +103,66 @@ func testMulGen(t *testing.T, testTimes int, g group.Group) {
101103
}
102104
}
103105

106+
func testCMov(t *testing.T, testTimes int, g group.Group) {
107+
P := g.RandomElement(rand.Reader)
108+
Q := g.RandomElement(rand.Reader)
109+
110+
err := test.CheckPanic(func() { P.CMov(0, Q) })
111+
test.CheckIsErr(t, err, "shouldn't fail with 0")
112+
err = test.CheckPanic(func() { P.CMov(1, Q) })
113+
test.CheckIsErr(t, err, "shouldn't fail with 1")
114+
err = test.CheckPanic(func() { P.CMov(2, Q) })
115+
test.CheckNoErr(t, err, "should fail with dif 0,1")
116+
117+
for i := 0; i < testTimes; i++ {
118+
P = g.RandomElement(rand.Reader)
119+
Q = g.RandomElement(rand.Reader)
120+
121+
want := P.Copy()
122+
got := P.CMov(0, Q)
123+
if !got.IsEqual(want) {
124+
test.ReportError(t, got, want)
125+
}
126+
127+
want = Q.Copy()
128+
got = P.CMov(1, Q)
129+
if !got.IsEqual(want) {
130+
test.ReportError(t, got, want)
131+
}
132+
}
133+
}
134+
135+
func testCSelect(t *testing.T, testTimes int, g group.Group) {
136+
P := g.RandomElement(rand.Reader)
137+
Q := g.RandomElement(rand.Reader)
138+
R := g.RandomElement(rand.Reader)
139+
140+
err := test.CheckPanic(func() { P.CSelect(0, Q, R) })
141+
test.CheckIsErr(t, err, "shouldn't fail with 0")
142+
err = test.CheckPanic(func() { P.CSelect(1, Q, R) })
143+
test.CheckIsErr(t, err, "shouldn't fail with 1")
144+
err = test.CheckPanic(func() { P.CSelect(2, Q, R) })
145+
test.CheckNoErr(t, err, "should fail with dif 0,1")
146+
147+
for i := 0; i < testTimes; i++ {
148+
P := g.RandomElement(rand.Reader)
149+
Q := g.RandomElement(rand.Reader)
150+
R := g.RandomElement(rand.Reader)
151+
152+
want := R.Copy()
153+
got := P.CSelect(0, Q, R)
154+
if !got.IsEqual(want) {
155+
test.ReportError(t, got, want)
156+
}
157+
158+
want = Q.Copy()
159+
got = P.CSelect(1, Q, R)
160+
if !got.IsEqual(want) {
161+
test.ReportError(t, got, want)
162+
}
163+
}
164+
}
165+
104166
func testOrder(t *testing.T, testTimes int, g group.Group) {
105167
Q := g.NewElement()
106168
order := g.Order()
@@ -179,16 +241,33 @@ func testMarshal(t *testing.T, testTimes int, g group.Group) {
179241
}
180242

181243
func testScalar(t *testing.T, testTimes int, g group.Group) {
244+
a := g.RandomScalar(rand.Reader)
245+
b := g.RandomScalar(rand.Reader)
182246
c := g.NewScalar()
183247
d := g.NewScalar()
184248
e := g.NewScalar()
185249
f := g.NewScalar()
186250
one := g.NewScalar()
187251
one.SetUint64(1)
188252
params := g.Params()
253+
254+
err := test.CheckPanic(func() { a.CMov(0, b) })
255+
test.CheckIsErr(t, err, "shouldn't fail with 0")
256+
err = test.CheckPanic(func() { a.CMov(1, b) })
257+
test.CheckIsErr(t, err, "shouldn't fail with 1")
258+
err = test.CheckPanic(func() { a.CMov(2, b) })
259+
test.CheckNoErr(t, err, "should fail with dif 0,1")
260+
261+
err = test.CheckPanic(func() { a.CSelect(0, b, c) })
262+
test.CheckIsErr(t, err, "shouldn't fail with 0")
263+
err = test.CheckPanic(func() { a.CSelect(1, b, c) })
264+
test.CheckIsErr(t, err, "shouldn't fail with 1")
265+
err = test.CheckPanic(func() { a.CSelect(2, b, c) })
266+
test.CheckNoErr(t, err, "should fail with dif 0,1")
267+
189268
for i := 0; i < testTimes; i++ {
190-
a := g.RandomScalar(rand.Reader)
191-
b := g.RandomScalar(rand.Reader)
269+
a = g.RandomScalar(rand.Reader)
270+
b = g.RandomScalar(rand.Reader)
192271
c.Add(a, b)
193272
d.Sub(a, b)
194273
e.Mul(c, d)
@@ -207,9 +286,32 @@ func testScalar(t *testing.T, testTimes int, g group.Group) {
207286
if l := uint(len(enc1)); l != params.ScalarLength {
208287
test.ReportError(t, l, params.ScalarLength)
209288
}
289+
290+
want := c.Copy()
291+
got := c.CMov(0, a)
292+
if !got.IsEqual(want) {
293+
test.ReportError(t, got, want)
294+
}
295+
296+
want = b.Copy()
297+
got = d.CMov(1, b)
298+
if !got.IsEqual(want) {
299+
test.ReportError(t, got, want)
300+
}
301+
302+
want = b.Copy()
303+
got = e.CSelect(0, a, b)
304+
if !got.IsEqual(want) {
305+
test.ReportError(t, got, want)
306+
}
307+
308+
want = a.Copy()
309+
got = f.CSelect(1, a, b)
310+
if !got.IsEqual(want) {
311+
test.ReportError(t, got, want)
312+
}
210313
}
211314

212-
a := g.RandomScalar(rand.Reader)
213315
c.Inv(a)
214316
c.Mul(c, a)
215317
if !one.IsEqual(c) {

group/ristretto255.go

+36
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ func (g ristrettoGroup) HashToScalar(msg, dst []byte) Scalar {
128128

129129
func (e *ristrettoElement) Group() Group { return Ristretto255 }
130130

131+
func (e *ristrettoElement) String() string { return fmt.Sprintf("%x", e.p.Bytes()) }
132+
131133
func (e *ristrettoElement) IsIdentity() bool {
132134
var zero r255.Point
133135
zero.SetZero()
@@ -147,6 +149,23 @@ func (e *ristrettoElement) Copy() Element {
147149
return &ristrettoElement{*new(r255.Point).Set(&e.p)}
148150
}
149151

152+
func (e *ristrettoElement) CMov(v int, x Element) Element {
153+
if !(v == 0 || v == 1) {
154+
panic(ErrSelector)
155+
}
156+
e.p.ConditionalSet(&x.(*ristrettoElement).p, int32(v))
157+
return e
158+
}
159+
160+
func (e *ristrettoElement) CSelect(v int, x Element, y Element) Element {
161+
if !(v == 0 || v == 1) {
162+
panic(ErrSelector)
163+
}
164+
e.p.ConditionalSet(&x.(*ristrettoElement).p, int32(v))
165+
e.p.ConditionalSet(&y.(*ristrettoElement).p, int32(1-v))
166+
return e
167+
}
168+
150169
func (e *ristrettoElement) Add(x Element, y Element) Element {
151170
e.p.Add(&x.(*ristrettoElement).p, &y.(*ristrettoElement).p)
152171
return e
@@ -200,6 +219,23 @@ func (s *ristrettoScalar) Copy() Scalar {
200219
return &ristrettoScalar{*new(r255.Scalar).Set(&s.s)}
201220
}
202221

222+
func (s *ristrettoScalar) CMov(v int, x Scalar) Scalar {
223+
if !(v == 0 || v == 1) {
224+
panic(ErrSelector)
225+
}
226+
s.s.ConditionalSet(&x.(*ristrettoScalar).s, int32(v))
227+
return s
228+
}
229+
230+
func (s *ristrettoScalar) CSelect(v int, x Scalar, y Scalar) Scalar {
231+
if !(v == 0 || v == 1) {
232+
panic(ErrSelector)
233+
}
234+
s.s.ConditionalSet(&x.(*ristrettoScalar).s, int32(v))
235+
s.s.ConditionalSet(&y.(*ristrettoScalar).s, int32(1-v))
236+
return s
237+
}
238+
203239
func (s *ristrettoScalar) Add(x Scalar, y Scalar) Scalar {
204240
s.s.Add(&x.(*ristrettoScalar).s, &y.(*ristrettoScalar).s)
205241
return s

group/short.go

+72
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,57 @@ func (e *wElt) Set(a Element) Element {
141141
}
142142

143143
func (e *wElt) Copy() Element { return e.wG.zeroElement().Set(e) }
144+
145+
func (e *wElt) CMov(v int, a Element) Element {
146+
if !(v == 0 || v == 1) {
147+
panic(ErrSelector)
148+
}
149+
aa := e.cvtElt(a)
150+
l := (e.wG.c.Params().BitSize + 7) / 8
151+
bufE := make([]byte, l)
152+
bufA := make([]byte, l)
153+
e.x.FillBytes(bufE)
154+
aa.x.FillBytes(bufA)
155+
subtle.ConstantTimeCopy(v, bufE, bufA)
156+
e.x.SetBytes(bufE)
157+
158+
e.y.FillBytes(bufE)
159+
aa.y.FillBytes(bufA)
160+
subtle.ConstantTimeCopy(v, bufE, bufA)
161+
e.y.SetBytes(bufE)
162+
163+
return e
164+
}
165+
166+
func (e *wElt) CSelect(v int, a Element, b Element) Element {
167+
if !(v == 0 || v == 1) {
168+
panic(ErrSelector)
169+
}
170+
aa, bb := e.cvtElt(a), e.cvtElt(b)
171+
l := (e.wG.c.Params().BitSize + 7) / 8
172+
bufE := make([]byte, l)
173+
bufA := make([]byte, l)
174+
bufB := make([]byte, l)
175+
176+
e.x.FillBytes(bufE)
177+
aa.x.FillBytes(bufA)
178+
bb.x.FillBytes(bufB)
179+
for i := range bufE {
180+
bufE[i] = byte(subtle.ConstantTimeSelect(v, int(bufA[i]), int(bufB[i])))
181+
}
182+
e.x.SetBytes(bufE)
183+
184+
e.y.FillBytes(bufE)
185+
aa.y.FillBytes(bufA)
186+
bb.y.FillBytes(bufB)
187+
for i := range bufE {
188+
bufE[i] = byte(subtle.ConstantTimeSelect(v, int(bufA[i]), int(bufB[i])))
189+
}
190+
e.y.SetBytes(bufE)
191+
192+
return e
193+
}
194+
144195
func (e *wElt) Add(a, b Element) Element {
145196
aa, bb := e.cvtElt(a), e.cvtElt(b)
146197
e.x, e.y = e.c.Add(aa.x, aa.y, bb.x, bb.y)
@@ -244,6 +295,27 @@ func (s *wScl) Set(a Scalar) Scalar {
244295
}
245296

246297
func (s *wScl) Copy() Scalar { return s.wG.zeroScalar().Set(s) }
298+
299+
func (s *wScl) CMov(v int, a Scalar) Scalar {
300+
if !(v == 0 || v == 1) {
301+
panic(ErrSelector)
302+
}
303+
aa := s.cvtScl(a)
304+
subtle.ConstantTimeCopy(v, s.k, aa.k)
305+
return s
306+
}
307+
308+
func (s *wScl) CSelect(v int, a Scalar, b Scalar) Scalar {
309+
if !(v == 0 || v == 1) {
310+
panic(ErrSelector)
311+
}
312+
aa, bb := s.cvtScl(a), s.cvtScl(b)
313+
for i := range s.k {
314+
s.k[i] = byte(subtle.ConstantTimeSelect(v, int(aa.k[i]), int(bb.k[i])))
315+
}
316+
return s
317+
}
318+
247319
func (s *wScl) Add(a, b Scalar) Scalar {
248320
aa, bb := s.cvtScl(a), s.cvtScl(b)
249321
r := new(big.Int)

0 commit comments

Comments
 (0)