Skip to content

Commit

Permalink
fuzz proofs & add errcheck linter (#61)
Browse files Browse the repository at this point in the history
* multiproof: fuzz proof APIs

Signed-off-by: Ignacio Hagopian <[email protected]>

* linter: add errcheck

Signed-off-by: Ignacio Hagopian <[email protected]>

* fuzz: add multiproof testdata

Signed-off-by: Ignacio Hagopian <[email protected]>

* check all errors

Signed-off-by: Ignacio Hagopian <[email protected]>

* multiproof: read Multiproof should expect an exact number of bytes

Signed-off-by: Ignacio Hagopian <[email protected]>

* fr: allow SetBytesLE to check canonical deserialization

Signed-off-by: Ignacio Hagopian <[email protected]>

* improve apis

Signed-off-by: Ignacio Hagopian <[email protected]>

---------

Signed-off-by: Ignacio Hagopian <[email protected]>
  • Loading branch information
jsign authored Sep 14, 2023
1 parent de5e505 commit d1b03fc
Show file tree
Hide file tree
Showing 13 changed files with 200 additions and 20 deletions.
1 change: 1 addition & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
linters:
disable-all: true
enable:
- errcheck
- gofmt
- staticcheck
- unused
Expand Down
4 changes: 3 additions & 1 deletion bandersnatch/fp/sqrt.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ var (

func init() {
sqrtPrecomp_PrimitiveDyadicRoots = func() (ret [BaseField2Adicity + 1]feType_SquareRoot) {
ret[0].SetString("10238227357739495823651030575849232062558860180284477541189508159991286009131")
if _, err := ret[0].SetString("10238227357739495823651030575849232062558860180284477541189508159991286009131"); err != nil {
panic(err)
}
for i := 1; i <= BaseField2Adicity; i++ { // Note <= here
ret[i].Square(&ret[i-1])
}
Expand Down
23 changes: 23 additions & 0 deletions bandersnatch/fr/element.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 6 additions & 2 deletions banderwagon/element_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,9 @@ func TestSerde(t *testing.T) {

var buf bytes.Buffer

bandersnatch.WriteUncompressedPoint(&buf, &point_aff)
if _, err := bandersnatch.WriteUncompressedPoint(&buf, &point_aff); err != nil {
t.Fatalf("could not write uncompressed point: %s", err)
}
got, err := bandersnatch.ReadUncompressedPoint(&buf)
if err != nil {
t.Fatal("could not read uncompressed point")
Expand Down Expand Up @@ -214,7 +216,9 @@ func TestMultiMapToBaseField(t *testing.T) {

var ARes, BRes fr.Element
scalars := []*fr.Element{&ARes, &BRes}
BatchMapToScalarField(scalars, []*Element{&A, &B})
if err := BatchMapToScalarField(scalars, []*Element{&A, &B}); err != nil {
t.Fatalf("could not batch map to scalar field: %s", err)
}

got_a := scalars[0]
got_b := scalars[1]
Expand Down
8 changes: 6 additions & 2 deletions banderwagon/precomp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ func TestPrecompCorrectness(t *testing.T) {
// Generate random scalars.
scalars := make([]fr.Element, len(pointsWagon))
for i := 0; i < len(scalars); i++ {
scalars[i].SetRandom()
if _, err := scalars[i].SetRandom(); err != nil {
t.Fatalf("error generating random scalar: %v", err)
}
}

// Calculate the MSM with our precomputed tables.
Expand Down Expand Up @@ -69,7 +71,9 @@ func BenchmarkPrecompMSM(b *testing.B) {
// Generate random scalars.
scalars := make([]fr.Element, 256)
for i := 0; i < k; i++ {
scalars[i].SetRandom()
if _, err := scalars[i].SetRandom(); err != nil {
b.Fatalf("error generating random scalar: %v", err)
}
}

b.Run("precomp", func(b *testing.B) {
Expand Down
4 changes: 3 additions & 1 deletion common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ func ReadScalar(r io.Reader) (*fr.Element, error) {
return nil, fmt.Errorf("reading scalar: %w", err)
}
var scalar = &fr.Element{}
scalar.SetBytesLE(x)
if _, err := scalar.SetBytesLECanonical(x); err != nil {
return nil, fmt.Errorf("deserializing scalar: %s", err)
}

return scalar, nil
}
12 changes: 9 additions & 3 deletions ipa/ipa_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,9 @@ func TestIPAConsistencySimpleProof(t *testing.T) {
expected := "273395a8febdaed38e94c3d874e99c911a47dd84616d54c55021d5c4131b507e46a4ec2c7e82b77ec2f533994c91ca7edaef212c666a1169b29c323eabb0cf690e0146638d0e2d543f81da4bd597bf3013e1663f340a8f87b845495598d0a3951590b6417f868edaeb3424ff174901d1185a53a3ee127fb7be0af42dda44bf992885bde279ef821a298087717ef3f2b78b2ede7f5d2ea1b60a4195de86a530eb247fd7e456012ae9a070c61635e55d1b7a340dfab8dae991d6273d099d9552815434cc1ba7bcdae341cf7928c6f25102370bdf4b26aad3af654d9dff4b3735661db3177342de5aad774a59d3e1b12754aee641d5f9cd1ecd2751471b308d2d8410add1c9fcc5a2b7371259f0538270832a98d18151f653efbc60895fab8be9650510449081626b5cd24671d1a3253487d44f589c2ff0da3557e307e520cf4e0054bbf8bdffaa24b7e4cce5092ccae5a08281ee24758374f4e65f126cacce64051905b5e2038060ad399c69ca6cb1d596d7c9cb5e161c7dcddc1a7ad62660dd4a5f69b31229b80e6b3df520714e4ea2b5896ebd48d14c7455e91c1ecf4acc5ffb36937c49413b7d1005dd6efbd526f5af5d61131ca3fcdae1218ce81c75e62b39100ec7f474b48a2bee6cef453fa1bc3db95c7c6575bc2d5927cbf7413181ac905766a4038a7b422a8ef2bf7b5059b5c546c19a33c1049482b9a9093f864913ca82290decf6e9a65bf3f66bc3ba4a8ed17b56d890a83bcbe74435a42499dec115"

buf := new(bytes.Buffer)
proof.Write(buf)
if err := proof.Write(buf); err != nil {
t.Fatal("could not serialise proof")
}

bytes := buf.Bytes()
if expected != hex.EncodeToString(bytes) {
Expand Down Expand Up @@ -263,10 +265,14 @@ func TestCRSGeneration(t *testing.T) {

func test_serialize_deserialize_proof(t *testing.T, proof IPAProof) {
buf := new(bytes.Buffer)
proof.Write(buf)
if err := proof.Write(buf); err != nil {
t.Fatal("failed to write proof")
}

var got_proof IPAProof
got_proof.Read(buf)
if err := got_proof.Read(buf); err != nil {
t.Fatal("failed to read proof")
}

if !got_proof.Equal(proof) {
t.Fatal("proof serialization does not match deserialization for IPA")
Expand Down
15 changes: 11 additions & 4 deletions ipa/prover.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,14 +127,21 @@ func CreateIPAProof(transcript *common.Transcript, ic *IPAConfig, commitment ban
}

// Write serializes the IPA proof to the given writer.
func (ip *IPAProof) Write(w io.Writer) {
func (ip *IPAProof) Write(w io.Writer) error {
for _, el := range ip.L {
binary.Write(w, binary.BigEndian, el.Bytes())
if err := binary.Write(w, binary.BigEndian, el.Bytes()); err != nil {
return fmt.Errorf("failed to write L: %w", err)
}
}
for _, ar := range ip.R {
binary.Write(w, binary.BigEndian, ar.Bytes())
if err := binary.Write(w, binary.BigEndian, ar.Bytes()); err != nil {
return fmt.Errorf("failed to write R: %w", err)
}
}
binary.Write(w, binary.BigEndian, ip.A_scalar.BytesLE())
if err := binary.Write(w, binary.BigEndian, ip.A_scalar.BytesLE()); err != nil {
return fmt.Errorf("failed to write A_scalar: %w", err)
}
return nil
}

// Read deserializes the IPA proof from the given reader.
Expand Down
26 changes: 22 additions & 4 deletions multiproof.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ type MultiProof struct {
func CreateMultiProof(transcript *common.Transcript, ipaConf *ipa.IPAConfig, Cs []*banderwagon.Element, fs [][]fr.Element, zs []uint8) (*MultiProof, error) {
transcript.DomainSep("multiproof")

for _, f := range fs {
if len(f) != common.VectorLength {
return nil, fmt.Errorf("polynomial length = %d, while expected length = %d", len(f), common.VectorLength)
}
}

if len(Cs) != len(fs) {
return nil, fmt.Errorf("number of commitments = %d, while number of functions = %d", len(Cs), len(fs))
}
Expand Down Expand Up @@ -232,9 +238,14 @@ func domainToFr(in uint8) fr.Element {
}

// Write serializes a multi-proof to a writer.
func (mp *MultiProof) Write(w io.Writer) {
binary.Write(w, binary.BigEndian, mp.D.Bytes())
mp.IPA.Write(w)
func (mp *MultiProof) Write(w io.Writer) error {
if err := binary.Write(w, binary.BigEndian, mp.D.Bytes()); err != nil {
return fmt.Errorf("failed to write D: %w", err)
}
if err := mp.IPA.Write(w); err != nil {
return fmt.Errorf("failed to write IPA proof: %w", err)
}
return nil
}

// Read deserializes a multi-proof from a reader.
Expand All @@ -244,7 +255,14 @@ func (mp *MultiProof) Read(r io.Reader) error {
return fmt.Errorf("failed to read D: %w", err)
}
mp.D = *D
mp.IPA.Read(r)
if err := mp.IPA.Read(r); err != nil {
return fmt.Errorf("failed to read IPA proof: %w", err)
}
// Check that the next read is EOF.
var buf [1]byte
if _, err := r.Read(buf[:]); err != io.EOF {
return errors.New("expected EOF")
}

return nil
}
Expand Down
113 changes: 110 additions & 3 deletions multiproof_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,9 @@ func TestMultiProofConsistency(t *testing.T) {
expected := "4f53588244efaf07a370ee3f9c467f933eed360d4fbf7a19dfc8bc49b67df4711bf1d0a720717cd6a8c75f1a668cb7cbdd63b48c676b89a7aee4298e71bd7f4013d7657146aa9736817da47051ed6a45fc7b5a61d00eb23e5df82a7f285cc10e67d444e91618465ca68d8ae4f2c916d1942201b7e2aae491ef0f809867d00e83468fb7f9af9b42ede76c1e90d89dd789ff22eb09e8b1d062d8a58b6f88b3cbe80136fc68331178cd45a1df9496ded092d976911b5244b85bc3de41e844ec194256b39aeee4ea55538a36139211e9910ad6b7a74e75d45b869d0a67aa4bf600930a5f760dfb8e4df9938d1f47b743d71c78ba8585e3b80aba26d24b1f50b36fa1458e79d54c05f58049245392bc3e2b5c5f9a1b99d43ed112ca82b201fb143d401741713188e47f1d6682b0bf496a5d4182836121efff0fd3b030fc6bfb5e21d6314a200963fe75cb856d444a813426b2084dfdc49dca2e649cb9da8bcb47859a4c629e97898e3547c591e39764110a224150d579c33fb74fa5eb96427036899c04154feab5344873d36a53a5baefd78c132be419f3f3a8dd8f60f72eb78dd5f43c53226f5ceb68947da3e19a750d760fb31fa8d4c7f53bfef11c4b89158aa56b1f4395430e16a3128f88e234ce1df7ef865f2d2c4975e8c82225f578310c31fd41d265fd530cbfa2b8895b228a510b806c31dff3b1fa5c08bffad443d567ed0e628febdd22775776e0cc9cebcaea9c6df9279a5d91dd0ee5e7a0434e989a160005321c97026cb559f71db23360105460d959bcdf74bee22c4ad8805a1d497507"

var buf = new(bytes.Buffer)
proof.Write(buf)
if err := proof.Write(buf); err != nil {
t.Fatalf("failed to write proof: %s", err)
}

bytes := buf.Bytes()
if expected != hex.EncodeToString(bytes) {
Expand All @@ -127,13 +129,118 @@ func TestMultiProofConsistency(t *testing.T) {

func test_serialize_deserialize_proof(t *testing.T, proof MultiProof) {
var buf = new(bytes.Buffer)
proof.Write(buf)
if err := proof.Write(buf); err != nil {
t.Fatalf("failed to write proof: %s", err)
}

var got_proof MultiProof
got_proof.Read(buf)
if err := got_proof.Read(buf); err != nil {
t.Fatalf("failed to read proof: %s", err)
}

if !got_proof.Equal(proof) {
t.Fatal("proof serialization does not match deserialization for Multiproof")
}
}

func FuzzMultiProofCreateVerify(f *testing.F) {
f.Fuzz(func(t *testing.T, p0_z uint8, p0_0, p0_1, p0_2, p0_3, p0_4, p0_5, p0_6, p0_7, p0_8, p0_9, p0_10 uint64) {
if p0_z > 10 {
return
}

poly_1 := test_helper.TestPoly256(p0_0, p0_1, p0_2, p0_3, p0_4, p0_5, p0_6, p0_7, p0_8, p0_9, p0_10)
prover_transcript := common.NewTranscript("multiproof")
prover_comm_1 := ipaConf.Commit(poly_1)

Cs := []*banderwagon.Element{&prover_comm_1}
fs := [][]fr.Element{poly_1}
zs := []uint8{p0_z}
proof, err := CreateMultiProof(prover_transcript, ipaConf, Cs, fs, zs)
if err != nil {
return
}
if err != nil {
t.Fatalf("failed to create multiproof: %s", err)
}

test_serialize_deserialize_proof(t, *proof)

// Verifier view
verifier_transcript := common.NewTranscript("multiproof")

ys := []*fr.Element{&poly_1[p0_z]}
ok, err := CheckMultiProof(verifier_transcript, ipaConf, proof, Cs, ys, zs)
if err != nil && ok {
t.Fatalf("failing to verify multiproof can't return OK: %s", err)
}
if err != nil {
return
}
if !ok {
t.Fatalf("failed to verify multiproof")
}
})
}

func FuzzMultiProofCreateVerifyOpaqueBytes(f *testing.F) {
f.Fuzz(func(t *testing.T, z uint8, evalPointsBytes []byte) {
if len(evalPointsBytes) != common.VectorLength*32 {
return
}
evalPoints := make([]fr.Element, len(evalPointsBytes)/32)
for i := 0; i < len(evalPointsBytes); i += 32 {
evalPoint := evalPointsBytes[i : i+32]
if err := evalPoints[i/64].SetBytes(evalPoint); err != nil {
return
}
}

poly_1 := evalPoints
prover_transcript := common.NewTranscript("multiproof")
prover_comm_1 := ipaConf.Commit(poly_1)

Cs := []*banderwagon.Element{&prover_comm_1}
fs := [][]fr.Element{poly_1}
zs := []uint8{z}
proof, err := CreateMultiProof(prover_transcript, ipaConf, Cs, fs, zs)
if err != nil {
return
}

test_serialize_deserialize_proof(t, *proof)

// Verifier view
verifier_transcript := common.NewTranscript("multiproof")

ys := []*fr.Element{&poly_1[z]}
ok, err := CheckMultiProof(verifier_transcript, ipaConf, proof, Cs, ys, zs)
if err != nil && ok {
t.Fatalf("failing to verify multiproof can't return OK: %s", err)
}
if err != nil {
return
}
if !ok {
t.Fatalf("failed to verify multiproof")
}
})
}

func FuzzMultiProofDeserialize(f *testing.F) {
f.Fuzz(func(t *testing.T, proofBytes []byte) {
var proof MultiProof
err := proof.Read(bytes.NewReader(proofBytes))
if err != nil {
return
}
var buf = new(bytes.Buffer)
if err := proof.Write(buf); err != nil {
t.Fatalf("failed to write proof: %s", err)
}
a := buf.Bytes()
if !bytes.Equal(a, proofBytes) {
t.Fatalf("proof serialization does not match deserialization for Multiproof")
}
})
}
2 changes: 2 additions & 0 deletions testdata/fuzz/FuzzMultiProofDeserialize/2551f538de792b6d
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
go test fuzz v1
[]byte("20A820010b217a2B70Ab010878C8109720A820010b217a2B70Ab010878C8109720A820010b217a2B70Ab010878C8109720A820010b217a2B70Ab010878C8109720A820010b217a2B70Ab010878C8109720A820010b217a2B70Ab010878C8109720A820010b217a2B70Ab010878C8109720A820010b217a2B70Ab010878C8109720A820010b217a2B70Ab010878C8109720A820010b217a2B70Ab010878C8109720A820010b217a2B70Ab010878C8109720A820010b217a2B70Ab010878C8109720A820010b217a2B70Ab010878C8109720A820010b217a2B70Ab010878C8109720A820010b217a2B70Ab010878C8109720A820010b217a2B70Ab010878C810970201001111020B01002011002222000000000000000000000000000000000000")
2 changes: 2 additions & 0 deletions testdata/fuzz/FuzzMultiProofDeserialize/7c1ab6591fc05ffb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
go test fuzz v1
[]byte("77Z101c210210c7290Z112717120c020")
2 changes: 2 additions & 0 deletions testdata/fuzz/FuzzMultiProofDeserialize/ba29cc29064defca
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
go test fuzz v1
[]byte("10110180102007200002000C0b201B282080A87Y80A021YY8722071ACA2YA10810121BX0120801aZ829A170170Y0A10110121BX0120801aZ829A170170Y0A10110121BX0120801aZ829A170170Y0A10110121BX0120801aZ829A170170Y0A10110121BX0120801aZ829A170170Y0A10110121BX0120801aZ829A170170Y0A10110121BX0120801aZ829A170170Y0A10110121BX0120801aZ829A170170Y0A10110121BX0120801aZ829A170170Y0A10110121BX0120801aZ829A170170Y0A10110121BX0120801aZ829A170170Y0A10110121BX0120801aZ829A170170Y0A10110121BX0120801aZ829A170170Y0A10110121BX0120801aZ829A170170Y0A10110121BX0120801aZ829A170170Y0A101000000000000000000000000000000000")

0 comments on commit d1b03fc

Please sign in to comment.