diff --git a/backend/groth16/bls12-377/marshal.go b/backend/groth16/bls12-377/marshal.go index 525315efc2..ee8facd1e6 100644 --- a/backend/groth16/bls12-377/marshal.go +++ b/backend/groth16/bls12-377/marshal.go @@ -20,6 +20,7 @@ import ( curve "github.com/consensys/gnark-crypto/ecc/bls12-377" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/pedersen" + "github.com/consensys/gnark-crypto/utils/unsafe" "github.com/consensys/gnark/internal/utils" "io" ) @@ -372,3 +373,165 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) return n + dec.BytesRead(), nil } + +// WriteDump behaves like WriteRawTo, excepts, the slices of points are "dumped" using gnark-crypto/utils/unsafe +// Output is compatible with ReadDump, with the caveat that, not only the points are not checked for +// correctness, but the raw bytes are platform dependent (endianness, etc.) +func (pk *ProvingKey) WriteDump(w io.Writer) error { + // it behaves like WriteRawTo, excepts, the slices of points are "dumped" using gnark-crypto/utils/unsafe + + // start by writing an unsafe marker to fail early. + if err := unsafe.WriteMarker(w); err != nil { + return err + } + + if _, err := pk.Domain.WriteTo(w); err != nil { + return err + } + + enc := curve.NewEncoder(w, curve.RawEncoding()) + nbWires := uint64(len(pk.InfinityA)) + + toEncode := []interface{}{ + &pk.G1.Alpha, + &pk.G1.Beta, + &pk.G1.Delta, + // pk.G1.A, + // pk.G1.B, + // pk.G1.Z, + // pk.G1.K, + &pk.G2.Beta, + &pk.G2.Delta, + // pk.G2.B, + nbWires, + pk.NbInfinityA, + pk.NbInfinityB, + pk.InfinityA, + pk.InfinityB, + uint32(len(pk.CommitmentKeys)), + } + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return err + } + } + + // dump slices of points + if err := unsafe.WriteSlice(w, pk.G1.A); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G1.B); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G1.Z); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G1.K); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G2.B); err != nil { + return err + } + + for i := range pk.CommitmentKeys { + if err := unsafe.WriteSlice(w, pk.CommitmentKeys[i].Basis); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.CommitmentKeys[i].BasisExpSigma); err != nil { + return err + } + } + + return nil +} + +// ReadDump reads a ProvingKey from a dump written by WriteDump. +// This is platform dependent and very unsafe (no checks, no endianness translation, etc.) +func (pk *ProvingKey) ReadDump(r io.Reader) error { + // read the marker to fail early in case of malformed input + if err := unsafe.ReadMarker(r); err != nil { + return err + } + + if _, err := pk.Domain.ReadFrom(r); err != nil { + return err + } + + dec := curve.NewDecoder(r, curve.NoSubgroupChecks()) + + var nbWires uint64 + var nbCommitments uint32 + + toDecode := []interface{}{ + &pk.G1.Alpha, + &pk.G1.Beta, + &pk.G1.Delta, + // &pk.G1.A, + // &pk.G1.B, + // &pk.G1.Z, + // &pk.G1.K, + &pk.G2.Beta, + &pk.G2.Delta, + // &pk.G2.B, + &nbWires, + &pk.NbInfinityA, + &pk.NbInfinityB, + } + + for _, v := range toDecode { + if err := dec.Decode(v); err != nil { + return err + } + } + pk.InfinityA = make([]bool, nbWires) + pk.InfinityB = make([]bool, nbWires) + + if err := dec.Decode(&pk.InfinityA); err != nil { + return err + } + if err := dec.Decode(&pk.InfinityB); err != nil { + return err + } + if err := dec.Decode(&nbCommitments); err != nil { + return err + } + + // read slices of points + var err error + pk.G1.A, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G1.B, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G1.Z, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G1.K, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G2.B, _, err = unsafe.ReadSlice[[]curve.G2Affine](r) + if err != nil { + return err + } + + pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitments) + for i := range pk.CommitmentKeys { + pk.CommitmentKeys[i].Basis, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.CommitmentKeys[i].BasisExpSigma, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + } + + return nil + +} diff --git a/backend/groth16/bls12-377/marshal_test.go b/backend/groth16/bls12-377/marshal_test.go index c84d78180a..156ae2228d 100644 --- a/backend/groth16/bls12-377/marshal_test.go +++ b/backend/groth16/bls12-377/marshal_test.go @@ -187,9 +187,16 @@ func TestProvingKeySerialization(t *testing.T) { require.NoError(t, err) } - err := io.RoundTripCheck(&pk, func() any { return new(ProvingKey) }) - return err == nil + if err := io.RoundTripCheck(&pk, func() any { return new(ProvingKey) }); err != nil { + t.Log(err) + return false + } + if err := io.DumpRoundTripCheck(&pk, func() any { return new(ProvingKey) }); err != nil { + t.Log(err) + return false + } + return true }, GenG1(), GenG2(), diff --git a/backend/groth16/bls12-381/marshal.go b/backend/groth16/bls12-381/marshal.go index 9b0e59446b..ff47b52ad4 100644 --- a/backend/groth16/bls12-381/marshal.go +++ b/backend/groth16/bls12-381/marshal.go @@ -20,6 +20,7 @@ import ( curve "github.com/consensys/gnark-crypto/ecc/bls12-381" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/pedersen" + "github.com/consensys/gnark-crypto/utils/unsafe" "github.com/consensys/gnark/internal/utils" "io" ) @@ -372,3 +373,165 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) return n + dec.BytesRead(), nil } + +// WriteDump behaves like WriteRawTo, excepts, the slices of points are "dumped" using gnark-crypto/utils/unsafe +// Output is compatible with ReadDump, with the caveat that, not only the points are not checked for +// correctness, but the raw bytes are platform dependent (endianness, etc.) +func (pk *ProvingKey) WriteDump(w io.Writer) error { + // it behaves like WriteRawTo, excepts, the slices of points are "dumped" using gnark-crypto/utils/unsafe + + // start by writing an unsafe marker to fail early. + if err := unsafe.WriteMarker(w); err != nil { + return err + } + + if _, err := pk.Domain.WriteTo(w); err != nil { + return err + } + + enc := curve.NewEncoder(w, curve.RawEncoding()) + nbWires := uint64(len(pk.InfinityA)) + + toEncode := []interface{}{ + &pk.G1.Alpha, + &pk.G1.Beta, + &pk.G1.Delta, + // pk.G1.A, + // pk.G1.B, + // pk.G1.Z, + // pk.G1.K, + &pk.G2.Beta, + &pk.G2.Delta, + // pk.G2.B, + nbWires, + pk.NbInfinityA, + pk.NbInfinityB, + pk.InfinityA, + pk.InfinityB, + uint32(len(pk.CommitmentKeys)), + } + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return err + } + } + + // dump slices of points + if err := unsafe.WriteSlice(w, pk.G1.A); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G1.B); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G1.Z); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G1.K); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G2.B); err != nil { + return err + } + + for i := range pk.CommitmentKeys { + if err := unsafe.WriteSlice(w, pk.CommitmentKeys[i].Basis); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.CommitmentKeys[i].BasisExpSigma); err != nil { + return err + } + } + + return nil +} + +// ReadDump reads a ProvingKey from a dump written by WriteDump. +// This is platform dependent and very unsafe (no checks, no endianness translation, etc.) +func (pk *ProvingKey) ReadDump(r io.Reader) error { + // read the marker to fail early in case of malformed input + if err := unsafe.ReadMarker(r); err != nil { + return err + } + + if _, err := pk.Domain.ReadFrom(r); err != nil { + return err + } + + dec := curve.NewDecoder(r, curve.NoSubgroupChecks()) + + var nbWires uint64 + var nbCommitments uint32 + + toDecode := []interface{}{ + &pk.G1.Alpha, + &pk.G1.Beta, + &pk.G1.Delta, + // &pk.G1.A, + // &pk.G1.B, + // &pk.G1.Z, + // &pk.G1.K, + &pk.G2.Beta, + &pk.G2.Delta, + // &pk.G2.B, + &nbWires, + &pk.NbInfinityA, + &pk.NbInfinityB, + } + + for _, v := range toDecode { + if err := dec.Decode(v); err != nil { + return err + } + } + pk.InfinityA = make([]bool, nbWires) + pk.InfinityB = make([]bool, nbWires) + + if err := dec.Decode(&pk.InfinityA); err != nil { + return err + } + if err := dec.Decode(&pk.InfinityB); err != nil { + return err + } + if err := dec.Decode(&nbCommitments); err != nil { + return err + } + + // read slices of points + var err error + pk.G1.A, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G1.B, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G1.Z, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G1.K, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G2.B, _, err = unsafe.ReadSlice[[]curve.G2Affine](r) + if err != nil { + return err + } + + pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitments) + for i := range pk.CommitmentKeys { + pk.CommitmentKeys[i].Basis, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.CommitmentKeys[i].BasisExpSigma, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + } + + return nil + +} diff --git a/backend/groth16/bls12-381/marshal_test.go b/backend/groth16/bls12-381/marshal_test.go index 7b0e6a56cd..93e98ac44e 100644 --- a/backend/groth16/bls12-381/marshal_test.go +++ b/backend/groth16/bls12-381/marshal_test.go @@ -187,9 +187,16 @@ func TestProvingKeySerialization(t *testing.T) { require.NoError(t, err) } - err := io.RoundTripCheck(&pk, func() any { return new(ProvingKey) }) - return err == nil + if err := io.RoundTripCheck(&pk, func() any { return new(ProvingKey) }); err != nil { + t.Log(err) + return false + } + if err := io.DumpRoundTripCheck(&pk, func() any { return new(ProvingKey) }); err != nil { + t.Log(err) + return false + } + return true }, GenG1(), GenG2(), diff --git a/backend/groth16/bls24-315/marshal.go b/backend/groth16/bls24-315/marshal.go index efbb31d620..614647c775 100644 --- a/backend/groth16/bls24-315/marshal.go +++ b/backend/groth16/bls24-315/marshal.go @@ -20,6 +20,7 @@ import ( curve "github.com/consensys/gnark-crypto/ecc/bls24-315" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/pedersen" + "github.com/consensys/gnark-crypto/utils/unsafe" "github.com/consensys/gnark/internal/utils" "io" ) @@ -372,3 +373,165 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) return n + dec.BytesRead(), nil } + +// WriteDump behaves like WriteRawTo, excepts, the slices of points are "dumped" using gnark-crypto/utils/unsafe +// Output is compatible with ReadDump, with the caveat that, not only the points are not checked for +// correctness, but the raw bytes are platform dependent (endianness, etc.) +func (pk *ProvingKey) WriteDump(w io.Writer) error { + // it behaves like WriteRawTo, excepts, the slices of points are "dumped" using gnark-crypto/utils/unsafe + + // start by writing an unsafe marker to fail early. + if err := unsafe.WriteMarker(w); err != nil { + return err + } + + if _, err := pk.Domain.WriteTo(w); err != nil { + return err + } + + enc := curve.NewEncoder(w, curve.RawEncoding()) + nbWires := uint64(len(pk.InfinityA)) + + toEncode := []interface{}{ + &pk.G1.Alpha, + &pk.G1.Beta, + &pk.G1.Delta, + // pk.G1.A, + // pk.G1.B, + // pk.G1.Z, + // pk.G1.K, + &pk.G2.Beta, + &pk.G2.Delta, + // pk.G2.B, + nbWires, + pk.NbInfinityA, + pk.NbInfinityB, + pk.InfinityA, + pk.InfinityB, + uint32(len(pk.CommitmentKeys)), + } + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return err + } + } + + // dump slices of points + if err := unsafe.WriteSlice(w, pk.G1.A); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G1.B); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G1.Z); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G1.K); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G2.B); err != nil { + return err + } + + for i := range pk.CommitmentKeys { + if err := unsafe.WriteSlice(w, pk.CommitmentKeys[i].Basis); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.CommitmentKeys[i].BasisExpSigma); err != nil { + return err + } + } + + return nil +} + +// ReadDump reads a ProvingKey from a dump written by WriteDump. +// This is platform dependent and very unsafe (no checks, no endianness translation, etc.) +func (pk *ProvingKey) ReadDump(r io.Reader) error { + // read the marker to fail early in case of malformed input + if err := unsafe.ReadMarker(r); err != nil { + return err + } + + if _, err := pk.Domain.ReadFrom(r); err != nil { + return err + } + + dec := curve.NewDecoder(r, curve.NoSubgroupChecks()) + + var nbWires uint64 + var nbCommitments uint32 + + toDecode := []interface{}{ + &pk.G1.Alpha, + &pk.G1.Beta, + &pk.G1.Delta, + // &pk.G1.A, + // &pk.G1.B, + // &pk.G1.Z, + // &pk.G1.K, + &pk.G2.Beta, + &pk.G2.Delta, + // &pk.G2.B, + &nbWires, + &pk.NbInfinityA, + &pk.NbInfinityB, + } + + for _, v := range toDecode { + if err := dec.Decode(v); err != nil { + return err + } + } + pk.InfinityA = make([]bool, nbWires) + pk.InfinityB = make([]bool, nbWires) + + if err := dec.Decode(&pk.InfinityA); err != nil { + return err + } + if err := dec.Decode(&pk.InfinityB); err != nil { + return err + } + if err := dec.Decode(&nbCommitments); err != nil { + return err + } + + // read slices of points + var err error + pk.G1.A, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G1.B, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G1.Z, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G1.K, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G2.B, _, err = unsafe.ReadSlice[[]curve.G2Affine](r) + if err != nil { + return err + } + + pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitments) + for i := range pk.CommitmentKeys { + pk.CommitmentKeys[i].Basis, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.CommitmentKeys[i].BasisExpSigma, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + } + + return nil + +} diff --git a/backend/groth16/bls24-315/marshal_test.go b/backend/groth16/bls24-315/marshal_test.go index 9b5efcade2..6bf286b39e 100644 --- a/backend/groth16/bls24-315/marshal_test.go +++ b/backend/groth16/bls24-315/marshal_test.go @@ -187,9 +187,16 @@ func TestProvingKeySerialization(t *testing.T) { require.NoError(t, err) } - err := io.RoundTripCheck(&pk, func() any { return new(ProvingKey) }) - return err == nil + if err := io.RoundTripCheck(&pk, func() any { return new(ProvingKey) }); err != nil { + t.Log(err) + return false + } + if err := io.DumpRoundTripCheck(&pk, func() any { return new(ProvingKey) }); err != nil { + t.Log(err) + return false + } + return true }, GenG1(), GenG2(), diff --git a/backend/groth16/bls24-317/marshal.go b/backend/groth16/bls24-317/marshal.go index b16d681254..00e0222422 100644 --- a/backend/groth16/bls24-317/marshal.go +++ b/backend/groth16/bls24-317/marshal.go @@ -20,6 +20,7 @@ import ( curve "github.com/consensys/gnark-crypto/ecc/bls24-317" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/pedersen" + "github.com/consensys/gnark-crypto/utils/unsafe" "github.com/consensys/gnark/internal/utils" "io" ) @@ -372,3 +373,165 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) return n + dec.BytesRead(), nil } + +// WriteDump behaves like WriteRawTo, excepts, the slices of points are "dumped" using gnark-crypto/utils/unsafe +// Output is compatible with ReadDump, with the caveat that, not only the points are not checked for +// correctness, but the raw bytes are platform dependent (endianness, etc.) +func (pk *ProvingKey) WriteDump(w io.Writer) error { + // it behaves like WriteRawTo, excepts, the slices of points are "dumped" using gnark-crypto/utils/unsafe + + // start by writing an unsafe marker to fail early. + if err := unsafe.WriteMarker(w); err != nil { + return err + } + + if _, err := pk.Domain.WriteTo(w); err != nil { + return err + } + + enc := curve.NewEncoder(w, curve.RawEncoding()) + nbWires := uint64(len(pk.InfinityA)) + + toEncode := []interface{}{ + &pk.G1.Alpha, + &pk.G1.Beta, + &pk.G1.Delta, + // pk.G1.A, + // pk.G1.B, + // pk.G1.Z, + // pk.G1.K, + &pk.G2.Beta, + &pk.G2.Delta, + // pk.G2.B, + nbWires, + pk.NbInfinityA, + pk.NbInfinityB, + pk.InfinityA, + pk.InfinityB, + uint32(len(pk.CommitmentKeys)), + } + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return err + } + } + + // dump slices of points + if err := unsafe.WriteSlice(w, pk.G1.A); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G1.B); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G1.Z); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G1.K); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G2.B); err != nil { + return err + } + + for i := range pk.CommitmentKeys { + if err := unsafe.WriteSlice(w, pk.CommitmentKeys[i].Basis); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.CommitmentKeys[i].BasisExpSigma); err != nil { + return err + } + } + + return nil +} + +// ReadDump reads a ProvingKey from a dump written by WriteDump. +// This is platform dependent and very unsafe (no checks, no endianness translation, etc.) +func (pk *ProvingKey) ReadDump(r io.Reader) error { + // read the marker to fail early in case of malformed input + if err := unsafe.ReadMarker(r); err != nil { + return err + } + + if _, err := pk.Domain.ReadFrom(r); err != nil { + return err + } + + dec := curve.NewDecoder(r, curve.NoSubgroupChecks()) + + var nbWires uint64 + var nbCommitments uint32 + + toDecode := []interface{}{ + &pk.G1.Alpha, + &pk.G1.Beta, + &pk.G1.Delta, + // &pk.G1.A, + // &pk.G1.B, + // &pk.G1.Z, + // &pk.G1.K, + &pk.G2.Beta, + &pk.G2.Delta, + // &pk.G2.B, + &nbWires, + &pk.NbInfinityA, + &pk.NbInfinityB, + } + + for _, v := range toDecode { + if err := dec.Decode(v); err != nil { + return err + } + } + pk.InfinityA = make([]bool, nbWires) + pk.InfinityB = make([]bool, nbWires) + + if err := dec.Decode(&pk.InfinityA); err != nil { + return err + } + if err := dec.Decode(&pk.InfinityB); err != nil { + return err + } + if err := dec.Decode(&nbCommitments); err != nil { + return err + } + + // read slices of points + var err error + pk.G1.A, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G1.B, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G1.Z, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G1.K, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G2.B, _, err = unsafe.ReadSlice[[]curve.G2Affine](r) + if err != nil { + return err + } + + pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitments) + for i := range pk.CommitmentKeys { + pk.CommitmentKeys[i].Basis, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.CommitmentKeys[i].BasisExpSigma, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + } + + return nil + +} diff --git a/backend/groth16/bls24-317/marshal_test.go b/backend/groth16/bls24-317/marshal_test.go index 2e984257dc..4110b35746 100644 --- a/backend/groth16/bls24-317/marshal_test.go +++ b/backend/groth16/bls24-317/marshal_test.go @@ -187,9 +187,16 @@ func TestProvingKeySerialization(t *testing.T) { require.NoError(t, err) } - err := io.RoundTripCheck(&pk, func() any { return new(ProvingKey) }) - return err == nil + if err := io.RoundTripCheck(&pk, func() any { return new(ProvingKey) }); err != nil { + t.Log(err) + return false + } + if err := io.DumpRoundTripCheck(&pk, func() any { return new(ProvingKey) }); err != nil { + t.Log(err) + return false + } + return true }, GenG1(), GenG2(), diff --git a/backend/groth16/bn254/marshal.go b/backend/groth16/bn254/marshal.go index c6539a7ba2..90dd38d8ad 100644 --- a/backend/groth16/bn254/marshal.go +++ b/backend/groth16/bn254/marshal.go @@ -20,6 +20,7 @@ import ( curve "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr/pedersen" + "github.com/consensys/gnark-crypto/utils/unsafe" "github.com/consensys/gnark/internal/utils" "io" ) @@ -372,3 +373,165 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) return n + dec.BytesRead(), nil } + +// WriteDump behaves like WriteRawTo, excepts, the slices of points are "dumped" using gnark-crypto/utils/unsafe +// Output is compatible with ReadDump, with the caveat that, not only the points are not checked for +// correctness, but the raw bytes are platform dependent (endianness, etc.) +func (pk *ProvingKey) WriteDump(w io.Writer) error { + // it behaves like WriteRawTo, excepts, the slices of points are "dumped" using gnark-crypto/utils/unsafe + + // start by writing an unsafe marker to fail early. + if err := unsafe.WriteMarker(w); err != nil { + return err + } + + if _, err := pk.Domain.WriteTo(w); err != nil { + return err + } + + enc := curve.NewEncoder(w, curve.RawEncoding()) + nbWires := uint64(len(pk.InfinityA)) + + toEncode := []interface{}{ + &pk.G1.Alpha, + &pk.G1.Beta, + &pk.G1.Delta, + // pk.G1.A, + // pk.G1.B, + // pk.G1.Z, + // pk.G1.K, + &pk.G2.Beta, + &pk.G2.Delta, + // pk.G2.B, + nbWires, + pk.NbInfinityA, + pk.NbInfinityB, + pk.InfinityA, + pk.InfinityB, + uint32(len(pk.CommitmentKeys)), + } + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return err + } + } + + // dump slices of points + if err := unsafe.WriteSlice(w, pk.G1.A); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G1.B); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G1.Z); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G1.K); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G2.B); err != nil { + return err + } + + for i := range pk.CommitmentKeys { + if err := unsafe.WriteSlice(w, pk.CommitmentKeys[i].Basis); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.CommitmentKeys[i].BasisExpSigma); err != nil { + return err + } + } + + return nil +} + +// ReadDump reads a ProvingKey from a dump written by WriteDump. +// This is platform dependent and very unsafe (no checks, no endianness translation, etc.) +func (pk *ProvingKey) ReadDump(r io.Reader) error { + // read the marker to fail early in case of malformed input + if err := unsafe.ReadMarker(r); err != nil { + return err + } + + if _, err := pk.Domain.ReadFrom(r); err != nil { + return err + } + + dec := curve.NewDecoder(r, curve.NoSubgroupChecks()) + + var nbWires uint64 + var nbCommitments uint32 + + toDecode := []interface{}{ + &pk.G1.Alpha, + &pk.G1.Beta, + &pk.G1.Delta, + // &pk.G1.A, + // &pk.G1.B, + // &pk.G1.Z, + // &pk.G1.K, + &pk.G2.Beta, + &pk.G2.Delta, + // &pk.G2.B, + &nbWires, + &pk.NbInfinityA, + &pk.NbInfinityB, + } + + for _, v := range toDecode { + if err := dec.Decode(v); err != nil { + return err + } + } + pk.InfinityA = make([]bool, nbWires) + pk.InfinityB = make([]bool, nbWires) + + if err := dec.Decode(&pk.InfinityA); err != nil { + return err + } + if err := dec.Decode(&pk.InfinityB); err != nil { + return err + } + if err := dec.Decode(&nbCommitments); err != nil { + return err + } + + // read slices of points + var err error + pk.G1.A, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G1.B, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G1.Z, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G1.K, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G2.B, _, err = unsafe.ReadSlice[[]curve.G2Affine](r) + if err != nil { + return err + } + + pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitments) + for i := range pk.CommitmentKeys { + pk.CommitmentKeys[i].Basis, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.CommitmentKeys[i].BasisExpSigma, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + } + + return nil + +} diff --git a/backend/groth16/bn254/marshal_test.go b/backend/groth16/bn254/marshal_test.go index ae007c3668..170bac74c0 100644 --- a/backend/groth16/bn254/marshal_test.go +++ b/backend/groth16/bn254/marshal_test.go @@ -187,9 +187,16 @@ func TestProvingKeySerialization(t *testing.T) { require.NoError(t, err) } - err := io.RoundTripCheck(&pk, func() any { return new(ProvingKey) }) - return err == nil + if err := io.RoundTripCheck(&pk, func() any { return new(ProvingKey) }); err != nil { + t.Log(err) + return false + } + if err := io.DumpRoundTripCheck(&pk, func() any { return new(ProvingKey) }); err != nil { + t.Log(err) + return false + } + return true }, GenG1(), GenG2(), diff --git a/backend/groth16/bw6-633/marshal.go b/backend/groth16/bw6-633/marshal.go index d5c2339407..a801462c9f 100644 --- a/backend/groth16/bw6-633/marshal.go +++ b/backend/groth16/bw6-633/marshal.go @@ -20,6 +20,7 @@ import ( curve "github.com/consensys/gnark-crypto/ecc/bw6-633" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/pedersen" + "github.com/consensys/gnark-crypto/utils/unsafe" "github.com/consensys/gnark/internal/utils" "io" ) @@ -372,3 +373,165 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) return n + dec.BytesRead(), nil } + +// WriteDump behaves like WriteRawTo, excepts, the slices of points are "dumped" using gnark-crypto/utils/unsafe +// Output is compatible with ReadDump, with the caveat that, not only the points are not checked for +// correctness, but the raw bytes are platform dependent (endianness, etc.) +func (pk *ProvingKey) WriteDump(w io.Writer) error { + // it behaves like WriteRawTo, excepts, the slices of points are "dumped" using gnark-crypto/utils/unsafe + + // start by writing an unsafe marker to fail early. + if err := unsafe.WriteMarker(w); err != nil { + return err + } + + if _, err := pk.Domain.WriteTo(w); err != nil { + return err + } + + enc := curve.NewEncoder(w, curve.RawEncoding()) + nbWires := uint64(len(pk.InfinityA)) + + toEncode := []interface{}{ + &pk.G1.Alpha, + &pk.G1.Beta, + &pk.G1.Delta, + // pk.G1.A, + // pk.G1.B, + // pk.G1.Z, + // pk.G1.K, + &pk.G2.Beta, + &pk.G2.Delta, + // pk.G2.B, + nbWires, + pk.NbInfinityA, + pk.NbInfinityB, + pk.InfinityA, + pk.InfinityB, + uint32(len(pk.CommitmentKeys)), + } + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return err + } + } + + // dump slices of points + if err := unsafe.WriteSlice(w, pk.G1.A); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G1.B); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G1.Z); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G1.K); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G2.B); err != nil { + return err + } + + for i := range pk.CommitmentKeys { + if err := unsafe.WriteSlice(w, pk.CommitmentKeys[i].Basis); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.CommitmentKeys[i].BasisExpSigma); err != nil { + return err + } + } + + return nil +} + +// ReadDump reads a ProvingKey from a dump written by WriteDump. +// This is platform dependent and very unsafe (no checks, no endianness translation, etc.) +func (pk *ProvingKey) ReadDump(r io.Reader) error { + // read the marker to fail early in case of malformed input + if err := unsafe.ReadMarker(r); err != nil { + return err + } + + if _, err := pk.Domain.ReadFrom(r); err != nil { + return err + } + + dec := curve.NewDecoder(r, curve.NoSubgroupChecks()) + + var nbWires uint64 + var nbCommitments uint32 + + toDecode := []interface{}{ + &pk.G1.Alpha, + &pk.G1.Beta, + &pk.G1.Delta, + // &pk.G1.A, + // &pk.G1.B, + // &pk.G1.Z, + // &pk.G1.K, + &pk.G2.Beta, + &pk.G2.Delta, + // &pk.G2.B, + &nbWires, + &pk.NbInfinityA, + &pk.NbInfinityB, + } + + for _, v := range toDecode { + if err := dec.Decode(v); err != nil { + return err + } + } + pk.InfinityA = make([]bool, nbWires) + pk.InfinityB = make([]bool, nbWires) + + if err := dec.Decode(&pk.InfinityA); err != nil { + return err + } + if err := dec.Decode(&pk.InfinityB); err != nil { + return err + } + if err := dec.Decode(&nbCommitments); err != nil { + return err + } + + // read slices of points + var err error + pk.G1.A, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G1.B, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G1.Z, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G1.K, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G2.B, _, err = unsafe.ReadSlice[[]curve.G2Affine](r) + if err != nil { + return err + } + + pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitments) + for i := range pk.CommitmentKeys { + pk.CommitmentKeys[i].Basis, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.CommitmentKeys[i].BasisExpSigma, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + } + + return nil + +} diff --git a/backend/groth16/bw6-633/marshal_test.go b/backend/groth16/bw6-633/marshal_test.go index 31b93fe801..05d9637e2a 100644 --- a/backend/groth16/bw6-633/marshal_test.go +++ b/backend/groth16/bw6-633/marshal_test.go @@ -187,9 +187,16 @@ func TestProvingKeySerialization(t *testing.T) { require.NoError(t, err) } - err := io.RoundTripCheck(&pk, func() any { return new(ProvingKey) }) - return err == nil + if err := io.RoundTripCheck(&pk, func() any { return new(ProvingKey) }); err != nil { + t.Log(err) + return false + } + if err := io.DumpRoundTripCheck(&pk, func() any { return new(ProvingKey) }); err != nil { + t.Log(err) + return false + } + return true }, GenG1(), GenG2(), diff --git a/backend/groth16/bw6-761/marshal.go b/backend/groth16/bw6-761/marshal.go index b9de7f8d90..b89105e280 100644 --- a/backend/groth16/bw6-761/marshal.go +++ b/backend/groth16/bw6-761/marshal.go @@ -20,6 +20,7 @@ import ( curve "github.com/consensys/gnark-crypto/ecc/bw6-761" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/pedersen" + "github.com/consensys/gnark-crypto/utils/unsafe" "github.com/consensys/gnark/internal/utils" "io" ) @@ -372,3 +373,165 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) return n + dec.BytesRead(), nil } + +// WriteDump behaves like WriteRawTo, excepts, the slices of points are "dumped" using gnark-crypto/utils/unsafe +// Output is compatible with ReadDump, with the caveat that, not only the points are not checked for +// correctness, but the raw bytes are platform dependent (endianness, etc.) +func (pk *ProvingKey) WriteDump(w io.Writer) error { + // it behaves like WriteRawTo, excepts, the slices of points are "dumped" using gnark-crypto/utils/unsafe + + // start by writing an unsafe marker to fail early. + if err := unsafe.WriteMarker(w); err != nil { + return err + } + + if _, err := pk.Domain.WriteTo(w); err != nil { + return err + } + + enc := curve.NewEncoder(w, curve.RawEncoding()) + nbWires := uint64(len(pk.InfinityA)) + + toEncode := []interface{}{ + &pk.G1.Alpha, + &pk.G1.Beta, + &pk.G1.Delta, + // pk.G1.A, + // pk.G1.B, + // pk.G1.Z, + // pk.G1.K, + &pk.G2.Beta, + &pk.G2.Delta, + // pk.G2.B, + nbWires, + pk.NbInfinityA, + pk.NbInfinityB, + pk.InfinityA, + pk.InfinityB, + uint32(len(pk.CommitmentKeys)), + } + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return err + } + } + + // dump slices of points + if err := unsafe.WriteSlice(w, pk.G1.A); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G1.B); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G1.Z); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G1.K); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G2.B); err != nil { + return err + } + + for i := range pk.CommitmentKeys { + if err := unsafe.WriteSlice(w, pk.CommitmentKeys[i].Basis); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.CommitmentKeys[i].BasisExpSigma); err != nil { + return err + } + } + + return nil +} + +// ReadDump reads a ProvingKey from a dump written by WriteDump. +// This is platform dependent and very unsafe (no checks, no endianness translation, etc.) +func (pk *ProvingKey) ReadDump(r io.Reader) error { + // read the marker to fail early in case of malformed input + if err := unsafe.ReadMarker(r); err != nil { + return err + } + + if _, err := pk.Domain.ReadFrom(r); err != nil { + return err + } + + dec := curve.NewDecoder(r, curve.NoSubgroupChecks()) + + var nbWires uint64 + var nbCommitments uint32 + + toDecode := []interface{}{ + &pk.G1.Alpha, + &pk.G1.Beta, + &pk.G1.Delta, + // &pk.G1.A, + // &pk.G1.B, + // &pk.G1.Z, + // &pk.G1.K, + &pk.G2.Beta, + &pk.G2.Delta, + // &pk.G2.B, + &nbWires, + &pk.NbInfinityA, + &pk.NbInfinityB, + } + + for _, v := range toDecode { + if err := dec.Decode(v); err != nil { + return err + } + } + pk.InfinityA = make([]bool, nbWires) + pk.InfinityB = make([]bool, nbWires) + + if err := dec.Decode(&pk.InfinityA); err != nil { + return err + } + if err := dec.Decode(&pk.InfinityB); err != nil { + return err + } + if err := dec.Decode(&nbCommitments); err != nil { + return err + } + + // read slices of points + var err error + pk.G1.A, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G1.B, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G1.Z, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G1.K, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G2.B, _, err = unsafe.ReadSlice[[]curve.G2Affine](r) + if err != nil { + return err + } + + pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitments) + for i := range pk.CommitmentKeys { + pk.CommitmentKeys[i].Basis, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.CommitmentKeys[i].BasisExpSigma, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + } + + return nil + +} diff --git a/backend/groth16/bw6-761/marshal_test.go b/backend/groth16/bw6-761/marshal_test.go index 61bd28a632..7f59bf90e8 100644 --- a/backend/groth16/bw6-761/marshal_test.go +++ b/backend/groth16/bw6-761/marshal_test.go @@ -187,9 +187,16 @@ func TestProvingKeySerialization(t *testing.T) { require.NoError(t, err) } - err := io.RoundTripCheck(&pk, func() any { return new(ProvingKey) }) - return err == nil + if err := io.RoundTripCheck(&pk, func() any { return new(ProvingKey) }); err != nil { + t.Log(err) + return false + } + if err := io.DumpRoundTripCheck(&pk, func() any { return new(ProvingKey) }); err != nil { + t.Log(err) + return false + } + return true }, GenG1(), GenG2(), diff --git a/backend/groth16/groth16.go b/backend/groth16/groth16.go index ca5b8bdc61..3b542f2afa 100644 --- a/backend/groth16/groth16.go +++ b/backend/groth16/groth16.go @@ -74,6 +74,7 @@ type Proof interface { type ProvingKey interface { groth16Object gnarkio.UnsafeReaderFrom + gnarkio.BinaryDumper // NbG1 returns the number of G1 elements in the ProvingKey NbG1() int diff --git a/go.mod b/go.mod index f71dd3b666..4805c741f0 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 github.com/consensys/compress v0.2.5 - github.com/consensys/gnark-crypto v0.12.2-0.20240423164836-7edca0e476c5 + github.com/consensys/gnark-crypto v0.12.2-0.20240504013751-564b6f724c3b github.com/fxamacker/cbor/v2 v2.5.0 github.com/google/go-cmp v0.5.9 github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b diff --git a/go.sum b/go.sum index b4599176c1..99806d860f 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,8 @@ github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/Yj github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= github.com/consensys/compress v0.2.5 h1:gJr1hKzbOD36JFsF1AN8lfXz1yevnJi1YolffY19Ntk= github.com/consensys/compress v0.2.5/go.mod h1:pyM+ZXiNUh7/0+AUjUf9RKUM6vSH7T/fsn5LLS0j1Tk= -github.com/consensys/gnark-crypto v0.12.2-0.20240423164836-7edca0e476c5 h1:qdtFrv6MlqK4IBrlm56ZQRiDK2sfPRXXvgmkvjzFiSI= -github.com/consensys/gnark-crypto v0.12.2-0.20240423164836-7edca0e476c5/go.mod h1:wKqwsieaKPThcFkHe0d0zMsbHEUWFmZcG7KBCse210o= +github.com/consensys/gnark-crypto v0.12.2-0.20240504013751-564b6f724c3b h1:tu0NaVr64o6vXzy9rYSK/LCZXmS+u/k9eP1F8OtRUWQ= +github.com/consensys/gnark-crypto v0.12.2-0.20240504013751-564b6f724c3b/go.mod h1:wKqwsieaKPThcFkHe0d0zMsbHEUWFmZcG7KBCse210o= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl index bb22840950..4199f6cf47 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.marshal.go.tmpl @@ -2,6 +2,7 @@ import ( {{ template "import_curve" . }} {{ template "import_pedersen" . }} "github.com/consensys/gnark/internal/utils" + "github.com/consensys/gnark-crypto/utils/unsafe" "io" ) @@ -361,3 +362,164 @@ func (pk *ProvingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) } +// WriteDump behaves like WriteRawTo, excepts, the slices of points are "dumped" using gnark-crypto/utils/unsafe +// Output is compatible with ReadDump, with the caveat that, not only the points are not checked for +// correctness, but the raw bytes are platform dependent (endianness, etc.) +func (pk *ProvingKey) WriteDump(w io.Writer) error { + // it behaves like WriteRawTo, excepts, the slices of points are "dumped" using gnark-crypto/utils/unsafe + + // start by writing an unsafe marker to fail early. + if err := unsafe.WriteMarker(w); err != nil { + return err + } + + if _, err := pk.Domain.WriteTo(w); err != nil { + return err + } + + enc := curve.NewEncoder(w, curve.RawEncoding()) + nbWires := uint64(len(pk.InfinityA)) + + toEncode := []interface{}{ + &pk.G1.Alpha, + &pk.G1.Beta, + &pk.G1.Delta, + // pk.G1.A, + // pk.G1.B, + // pk.G1.Z, + // pk.G1.K, + &pk.G2.Beta, + &pk.G2.Delta, + // pk.G2.B, + nbWires, + pk.NbInfinityA, + pk.NbInfinityB, + pk.InfinityA, + pk.InfinityB, + uint32(len(pk.CommitmentKeys)), + } + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return err + } + } + + // dump slices of points + if err := unsafe.WriteSlice(w, pk.G1.A); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G1.B); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G1.Z); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G1.K); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.G2.B); err != nil { + return err + } + + for i := range pk.CommitmentKeys { + if err := unsafe.WriteSlice(w, pk.CommitmentKeys[i].Basis); err != nil { + return err + } + if err := unsafe.WriteSlice(w, pk.CommitmentKeys[i].BasisExpSigma); err != nil { + return err + } + } + + return nil +} + +// ReadDump reads a ProvingKey from a dump written by WriteDump. +// This is platform dependent and very unsafe (no checks, no endianness translation, etc.) +func (pk *ProvingKey) ReadDump(r io.Reader) error { + // read the marker to fail early in case of malformed input + if err := unsafe.ReadMarker(r); err != nil { + return err + } + + if _, err := pk.Domain.ReadFrom(r); err != nil { + return err + } + + dec := curve.NewDecoder(r, curve.NoSubgroupChecks()) + + var nbWires uint64 + var nbCommitments uint32 + + toDecode := []interface{}{ + &pk.G1.Alpha, + &pk.G1.Beta, + &pk.G1.Delta, + // &pk.G1.A, + // &pk.G1.B, + // &pk.G1.Z, + // &pk.G1.K, + &pk.G2.Beta, + &pk.G2.Delta, + // &pk.G2.B, + &nbWires, + &pk.NbInfinityA, + &pk.NbInfinityB, + } + + for _, v := range toDecode { + if err := dec.Decode(v); err != nil { + return err + } + } + pk.InfinityA = make([]bool, nbWires) + pk.InfinityB = make([]bool, nbWires) + + if err := dec.Decode(&pk.InfinityA); err != nil { + return err + } + if err := dec.Decode(&pk.InfinityB); err != nil { + return err + } + if err := dec.Decode(&nbCommitments); err != nil { + return err + } + + // read slices of points + var err error + pk.G1.A, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G1.B, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G1.Z, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G1.K, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.G2.B, _, err = unsafe.ReadSlice[[]curve.G2Affine](r) + if err != nil { + return err + } + + pk.CommitmentKeys = make([]pedersen.ProvingKey, nbCommitments) + for i := range pk.CommitmentKeys { + pk.CommitmentKeys[i].Basis, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + pk.CommitmentKeys[i].BasisExpSigma, _, err = unsafe.ReadSlice[[]curve.G1Affine](r) + if err != nil { + return err + } + } + + return nil + +} \ No newline at end of file diff --git a/internal/generator/backend/template/zkpschemes/groth16/tests/groth16.marshal.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/tests/groth16.marshal.go.tmpl index 5fb72b55c4..a5bc1d73ea 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/tests/groth16.marshal.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/tests/groth16.marshal.go.tmpl @@ -173,9 +173,16 @@ func TestProvingKeySerialization(t *testing.T) { require.NoError(t, err) } - err := io.RoundTripCheck(&pk, func() any {return new(ProvingKey)}) - return err == nil + if err := io.RoundTripCheck(&pk, func() any {return new(ProvingKey)}); err != nil { + t.Log(err) + return false + } + if err := io.DumpRoundTripCheck(&pk, func() any {return new(ProvingKey)}); err != nil { + t.Log(err) + return false + } + return true }, GenG1(), GenG2(), diff --git a/io/io.go b/io/io.go index 268e0f84ba..3d6847f35e 100644 --- a/io/io.go +++ b/io/io.go @@ -39,3 +39,11 @@ type WriterRawTo interface { type UnsafeReaderFrom interface { UnsafeReadFrom(r io.Reader) (int64, error) } + +// BinaryDumper is the interface that wraps the WriteDump and ReadDump methods. +// WriteDump writes the object to w, ReadDump reads the object from r. +// The object is serialized in binary format, in a very fast, very unsafe way. +type BinaryDumper interface { + WriteDump(w io.Writer) error + ReadDump(r io.Reader) error +} diff --git a/io/roundtrip.go b/io/roundtrip.go index 92bb038cfc..ecac78afaf 100644 --- a/io/roundtrip.go +++ b/io/roundtrip.go @@ -73,3 +73,20 @@ func RoundTripCheck(from any, to func() any) error { return nil } + +func DumpRoundTripCheck(from any, to func() any) error { + var buf bytes.Buffer + + if err := from.(BinaryDumper).WriteDump(&buf); err != nil { + return err + } + + r := to().(BinaryDumper) + if err := r.ReadDump(bytes.NewReader(buf.Bytes())); err != nil { + return err + } + if !reflect.DeepEqual(from, r) { + return errors.New("reconstructed object don't match original (ReadDump)") + } + return nil +}