Skip to content

Commit fa152d9

Browse files
authored
Merge branch 'master' into master
2 parents 6a1b2eb + 53bbb0c commit fa152d9

4 files changed

Lines changed: 94 additions & 12 deletions

File tree

banderwagon/element.go

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package banderwagon
22

33
import (
4+
"bytes"
45
"errors"
56
"fmt"
67
"math/big"
@@ -58,8 +59,10 @@ func (p Element) Bytes() [CompressedSize]byte {
5859
return affineX.Bytes()
5960
}
6061

61-
// BytesUncompressed returns the uncompressed serialized version of the element.
62-
func (p Element) BytesUncompressed() [UncompressedSize]byte {
62+
// BytesUncompressedTrusted returns the uncompressed serialized version of the element.
63+
// The returned bytes can only be used with SetBytesUncompressed with the trusted flag on.
64+
// This is because this method doesn't do any (x, y) transformation regarding the sign of y.
65+
func (p Element) BytesUncompressedTrusted() [UncompressedSize]byte {
6366
// Convert underlying point to affine representation
6467
var affine bandersnatch.PointAffine
6568
affine.FromProj(&p.inner)
@@ -243,17 +246,27 @@ func (p *Element) SetBytesUncompressed(buf []byte, trusted bool) error {
243246
var x fp.Element
244247
x.SetBytes(buf[:coordinateSize])
245248

246-
// subgroup check
249+
var y fp.Element
250+
// point in curve & subgroup check
247251
if !trusted {
252+
point := bandersnatch.GetPointFromX(&x, true)
253+
if point == nil {
254+
return fmt.Errorf("point not in the curve")
255+
}
256+
calculatedYBytes := point.Y.Bytes()
257+
if !bytes.Equal(calculatedYBytes[:], buf[coordinateSize:]) {
258+
return fmt.Errorf("provided Y coordinate doesn't correspond to X")
259+
}
260+
y = point.Y
261+
248262
err := subgroupCheck(x)
249263
if err != nil {
250264
return err
251265
}
266+
} else {
267+
y.SetBytes(buf[coordinateSize:])
252268
}
253269

254-
var y fp.Element
255-
y.SetBytes(buf[coordinateSize:])
256-
257270
*p = Element{inner: bandersnatch.PointProj{
258271
X: x,
259272
Y: y,

banderwagon/element_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,75 @@ func TestBatchNormalize(t *testing.T) {
327327
})
328328
}
329329

330+
func TestBytesUncompressSerializeDeserialize(t *testing.T) {
331+
t.Parallel()
332+
333+
var point Element
334+
point.Add(&Generator, &Generator)
335+
point.Double(&Generator)
336+
337+
bytesUncompressed := point.BytesUncompressedTrusted()
338+
339+
var point2 Element
340+
341+
// Trying to deserialize the from an untrusted source would mean that the Y coordinate would be checked from
342+
// the EC formula. This would reject the point since BytesUncompressedTrusted() doesn't consider the Y coordinate sign.
343+
if err := point2.SetBytesUncompressed(bytesUncompressed[:], false); err == nil {
344+
t.Fatalf("the point must be rejected since the serialized bytes didn't consider the Y coordinate sign")
345+
}
346+
347+
// Deserializing with the trusted flag, must succeed since it's simply deserializing the x and y coordinate directly
348+
// without subgroup or lexicographic checks.
349+
if err := point2.SetBytesUncompressed(bytesUncompressed[:], true); err != nil {
350+
t.Fatalf("could not deserialize point: %s", err)
351+
}
352+
if !point.Equal(&point2) {
353+
t.Fatalf("deserialized point does not match original point")
354+
}
355+
}
356+
357+
func TestSetUncompressedFail(t *testing.T) {
358+
t.Parallel()
359+
one := fp.One()
360+
361+
t.Run("X not in curve", func(t *testing.T) {
362+
startX := one
363+
// Find in startX a point that isn't in the curve
364+
for {
365+
point := bandersnatch.GetPointFromX(&startX, true)
366+
if point == nil {
367+
break
368+
}
369+
startX.Add(&startX, &one)
370+
continue
371+
}
372+
var serializedPoint [UncompressedSize]byte
373+
xBytes := startX.Bytes()
374+
yBytes := Generator.inner.Y.Bytes() // Use some valid-ish Y, but this shouldn't matter much.
375+
copy(serializedPoint[:], xBytes[:])
376+
copy(serializedPoint[CompressedSize:], yBytes[:])
377+
378+
var point2 Element
379+
if err := point2.SetBytesUncompressed(serializedPoint[:], false); err == nil {
380+
t.Fatalf("the point must be rejected")
381+
}
382+
})
383+
384+
t.Run("wrong Y", func(t *testing.T) {
385+
gen := Generator
386+
// Despite X would lead to a point in the curve,
387+
// we modify Y+1 to check the provided (serialized) Y
388+
// coordinate isn't trusted blindly.
389+
gen.inner.Y.Add(&gen.inner.Y, &one)
390+
391+
pointBytes := gen.BytesUncompressedTrusted()
392+
var point2 Element
393+
if err := point2.SetBytesUncompressed(pointBytes[:], false); err == nil {
394+
t.Fatalf("the point must be rejected")
395+
}
396+
})
397+
}
398+
330399
func FuzzDeserializationCompressed(f *testing.F) {
331400
f.Fuzz(func(t *testing.T, serializedpoint []byte) {
332401
var point Element

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ module github.com/crate-crypto/go-ipa
33
go 1.18
44

55
require (
6-
github.com/consensys/gnark-crypto v0.12.1
6+
github.com/consensys/gnark-crypto v0.13.0
77
github.com/leanovate/gopter v0.2.9
88
golang.org/x/sync v0.1.0
9-
golang.org/x/sys v0.9.0
9+
golang.org/x/sys v0.15.0
1010
)
1111

1212
require (

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ github.com/bits-and-blooms/bitset v1.7.0 h1:YjAGVd3XmtK9ktAbX8Zg2g2PwLIMjGREZJHl
22
github.com/bits-and-blooms/bitset v1.7.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
33
github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ=
44
github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI=
5-
github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M=
6-
github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY=
5+
github.com/consensys/gnark-crypto v0.13.0 h1:VPULb/v6bbYELAPTDFINEVaMTTybV5GLxDdcjnS+4oc=
6+
github.com/consensys/gnark-crypto v0.13.0/go.mod h1:wKqwsieaKPThcFkHe0d0zMsbHEUWFmZcG7KBCse210o=
77
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
88
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
99
github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c=
@@ -15,8 +15,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
1515
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
1616
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
1717
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
18-
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
19-
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
18+
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
19+
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
2020
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
2121
rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU=
2222
rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA=

0 commit comments

Comments
 (0)