From 6e31deb5b830f7ed0cd15afa602f198ea4ecdc52 Mon Sep 17 00:00:00 2001 From: Eduard S Date: Fri, 22 May 2020 15:39:15 +0200 Subject: [PATCH] Fix binary parser bug, make go.bin format deterministic --- cli/.gitignore | 1 + cli/cli.go | 4 +++- parsers/parsers.go | 28 ++++++++++++++++++++-------- parsers/parsers_test.go | 8 ++++++++ 4 files changed, 32 insertions(+), 9 deletions(-) create mode 100644 cli/.gitignore diff --git a/cli/.gitignore b/cli/.gitignore new file mode 100644 index 0000000..573c0c4 --- /dev/null +++ b/cli/.gitignore @@ -0,0 +1 @@ +cli diff --git a/cli/cli.go b/cli/cli.go index 8c2b88a..e407310 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -159,7 +159,9 @@ func cmdConvert(provingKeyPath, provingKeyBinPath string) error { if err != nil { return err } - err = ioutil.WriteFile(provingKeyBinPath, pkGBin, 0644) + if err = ioutil.WriteFile(provingKeyBinPath, pkGBin, 0644); err != nil { + return err + } return nil } diff --git a/parsers/parsers.go b/parsers/parsers.go index ab33ce0..c207f32 100644 --- a/parsers/parsers.go +++ b/parsers/parsers.go @@ -10,6 +10,7 @@ import ( "io" "math/big" "os" + "sort" "strconv" "strings" @@ -814,9 +815,9 @@ func ParsePkBin(f *os.File) (*types.Pk, error) { if err != nil { return nil, err } - pk.C = append(pk.C, z) // circom behaviour (3x null==["0", "0", "0"]) - pk.C = append(pk.C, z) - pk.C = append(pk.C, z) + for i := 0; i < pk.NPublic+1; i++ { + pk.C = append(pk.C, z) + } for i := pk.NPublic + 1; i < pk.NVars; i++ { b, err = readNBytes(r, 64) if err != nil { @@ -969,6 +970,15 @@ func coordFromMont(u, q *big.Int) *big.Int { ) } +func sortedKeys(m map[int]*big.Int) []int { + keys := make([]int, 0, len(m)) + for k, _ := range m { + keys = append(keys, k) + } + sort.Ints(keys) + return keys +} + // PkToGoBin converts the ProvingKey (*types.Pk) into binary format defined by // go-circom-prover-verifier. PkGoBin is a own go-circom-prover-verifier // binary format that allows to go faster when parsing. @@ -1017,7 +1027,8 @@ func PkToGoBin(pk *types.Pk) ([]byte, error) { binary.LittleEndian.PutUint32(b[:], uint32(len(pk.PolsA[i]))) r = append(r, b[:]...) o += 4 - for j, v := range pk.PolsA[i] { + for _, j := range sortedKeys(pk.PolsA[i]) { + v := pk.PolsA[i][j] binary.LittleEndian.PutUint32(b[:], uint32(j)) r = append(r, b[:]...) r = append(r, addPadding32(v.Bytes())...) @@ -1030,7 +1041,8 @@ func PkToGoBin(pk *types.Pk) ([]byte, error) { binary.LittleEndian.PutUint32(b[:], uint32(len(pk.PolsB[i]))) r = append(r, b[:]...) o += 4 - for j, v := range pk.PolsB[i] { + for _, j := range sortedKeys(pk.PolsB[i]) { + v := pk.PolsB[i][j] binary.LittleEndian.PutUint32(b[:], uint32(j)) r = append(r, b[:]...) r = append(r, addPadding32(v.Bytes())...) @@ -1279,9 +1291,9 @@ func ParsePkGoBin(f *os.File) (*types.Pk, error) { if err != nil { return nil, err } - pk.C = append(pk.C, z) - pk.C = append(pk.C, z) - pk.C = append(pk.C, z) + for i := 0; i < pk.NPublic+1; i++ { + pk.C = append(pk.C, z) + } for i := pk.NPublic + 1; i < pk.NVars; i++ { b, err = readNBytes(r, 64) if err != nil { diff --git a/parsers/parsers_test.go b/parsers/parsers_test.go index 0f0b3d4..529ceb3 100644 --- a/parsers/parsers_test.go +++ b/parsers/parsers_test.go @@ -238,6 +238,10 @@ func testCircuitParsePkBin(t *testing.T, circuit string) { assert.Equal(t, pkJ.B2, pk.B2) assert.Equal(t, pkJ.C, pk.C) assert.Equal(t, pkJ.HExps[:pkJ.DomainSize], pk.HExps[:pk.DomainSize]) // circom behaviour + + assert.Equal(t, pkJ.NVars, pk.NVars) + assert.Equal(t, pkJ.NPublic, pk.NPublic) + assert.Equal(t, pkJ.DomainSize, pk.DomainSize) } func TestParsePkBin(t *testing.T) { @@ -274,6 +278,10 @@ func testGoCircomPkFormat(t *testing.T, circuit string) { assert.Equal(t, pk.HExps, pkG.HExps) assert.Equal(t, pk.PolsA, pkG.PolsA) assert.Equal(t, pk.PolsB, pkG.PolsB) + + assert.Equal(t, pk.NVars, pkG.NVars) + assert.Equal(t, pk.NPublic, pkG.NPublic) + assert.Equal(t, pk.DomainSize, pkG.DomainSize) } func TestGoCircomPkFormat(t *testing.T) {