From 0bc272a0513b727fad98cccc5078425af3932fdb Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Thu, 2 May 2024 15:42:29 -0500 Subject: [PATCH 1/3] refactor: expose pedersen basis slices --- ecc/bls12-377/fr/pedersen/pedersen.go | 36 +-- ecc/bls12-377/fr/pedersen/pedersen_test.go | 4 +- ecc/bls12-378/fr/pedersen/pedersen.go | 36 +-- ecc/bls12-378/fr/pedersen/pedersen_test.go | 4 +- ecc/bls12-381/fr/pedersen/pedersen.go | 36 +-- ecc/bls12-381/fr/pedersen/pedersen_test.go | 4 +- ecc/bls24-315/fr/pedersen/pedersen.go | 36 +-- ecc/bls24-315/fr/pedersen/pedersen_test.go | 4 +- ecc/bls24-317/fr/pedersen/pedersen.go | 36 +-- ecc/bls24-317/fr/pedersen/pedersen_test.go | 4 +- ecc/bn254/fr/pedersen/pedersen.go | 36 +-- ecc/bn254/fr/pedersen/pedersen_test.go | 4 +- ecc/bw6-633/fr/pedersen/pedersen.go | 36 +-- ecc/bw6-633/fr/pedersen/pedersen_test.go | 4 +- ecc/bw6-756/fr/pedersen/pedersen.go | 36 +-- ecc/bw6-756/fr/pedersen/pedersen_test.go | 4 +- ecc/bw6-761/fr/pedersen/pedersen.go | 36 +-- ecc/bw6-761/fr/pedersen/pedersen_test.go | 4 +- .../pedersen/template/pedersen.go.tmpl | 300 +++++++++--------- .../pedersen/template/pedersen.test.go.tmpl | 8 +- 20 files changed, 334 insertions(+), 334 deletions(-) diff --git a/ecc/bls12-377/fr/pedersen/pedersen.go b/ecc/bls12-377/fr/pedersen/pedersen.go index b09acbd223..1bbf3a0a24 100644 --- a/ecc/bls12-377/fr/pedersen/pedersen.go +++ b/ecc/bls12-377/fr/pedersen/pedersen.go @@ -30,8 +30,8 @@ import ( // ProvingKey for committing and proofs of knowledge type ProvingKey struct { - basis []curve.G1Affine - basisExpSigma []curve.G1Affine + Basis []curve.G1Affine + BasisExpSigma []curve.G1Affine } type VerifyingKey struct { @@ -74,17 +74,17 @@ func Setup(bases ...[]curve.G1Affine) (pk []ProvingKey, vk VerifyingKey, err err pk = make([]ProvingKey, len(bases)) for i := range bases { - pk[i].basisExpSigma = make([]curve.G1Affine, len(bases[i])) + pk[i].BasisExpSigma = make([]curve.G1Affine, len(bases[i])) for j := range bases[i] { - pk[i].basisExpSigma[j].ScalarMultiplication(&bases[i][j], sigma) + pk[i].BasisExpSigma[j].ScalarMultiplication(&bases[i][j], sigma) } - pk[i].basis = bases[i] + pk[i].Basis = bases[i] } return } func (pk *ProvingKey) ProveKnowledge(values []fr.Element) (pok curve.G1Affine, err error) { - if len(values) != len(pk.basis) { + if len(values) != len(pk.Basis) { err = fmt.Errorf("must have as many values as basis elements") return } @@ -95,13 +95,13 @@ func (pk *ProvingKey) ProveKnowledge(values []fr.Element) (pok curve.G1Affine, e NbTasks: 1, // TODO Experiment } - _, err = pok.MultiExp(pk.basisExpSigma, values, config) + _, err = pok.MultiExp(pk.BasisExpSigma, values, config) return } func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, err error) { - if len(values) != len(pk.basis) { + if len(values) != len(pk.Basis) { err = fmt.Errorf("must have as many values as basis elements") return } @@ -111,7 +111,7 @@ func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, er config := ecc.MultiExpConfig{ NbTasks: 1, } - _, err = commitment.MultiExp(pk.basis, values, config) + _, err = commitment.MultiExp(pk.Basis, values, config) return } @@ -131,7 +131,7 @@ func BatchProve(pk []ProvingKey, values [][]fr.Element, fiatshamirSeeds ...[]byt offset := 0 for i := range pk { - if len(values[i]) != len(pk[i].basis) { + if len(values[i]) != len(pk[i].Basis) { err = fmt.Errorf("must have as many values as basis elements") return } @@ -147,14 +147,14 @@ func BatchProve(pk []ProvingKey, values [][]fr.Element, fiatshamirSeeds ...[]byt scaledValues := make([]fr.Element, offset) basis := make([]curve.G1Affine, offset) - copy(basis, pk[0].basisExpSigma) + copy(basis, pk[0].BasisExpSigma) copy(scaledValues, values[0]) offset = len(values[0]) rI := r for i := 1; i < len(pk); i++ { - copy(basis[offset:], pk[i].basisExpSigma) - for j := range pk[i].basis { + copy(basis[offset:], pk[i].BasisExpSigma) + for j := range pk[i].Basis { scaledValues[offset].Mul(&values[i][j], &rI) offset++ } @@ -245,11 +245,11 @@ func getChallenge(fiatshamirSeeds [][]byte) (r fr.Element, err error) { // Marshal func (pk *ProvingKey) writeTo(enc *curve.Encoder) (int64, error) { - if err := enc.Encode(pk.basis); err != nil { + if err := enc.Encode(pk.Basis); err != nil { return enc.BytesWritten(), err } - err := enc.Encode(pk.basisExpSigma) + err := enc.Encode(pk.BasisExpSigma) return enc.BytesWritten(), err } @@ -265,14 +265,14 @@ func (pk *ProvingKey) WriteRawTo(w io.Writer) (int64, error) { func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { dec := curve.NewDecoder(r) - if err := dec.Decode(&pk.basis); err != nil { + if err := dec.Decode(&pk.Basis); err != nil { return dec.BytesRead(), err } - if err := dec.Decode(&pk.basisExpSigma); err != nil { + if err := dec.Decode(&pk.BasisExpSigma); err != nil { return dec.BytesRead(), err } - if cL, pL := len(pk.basis), len(pk.basisExpSigma); cL != pL { + if cL, pL := len(pk.Basis), len(pk.BasisExpSigma); cL != pL { return dec.BytesRead(), fmt.Errorf("commitment basis size (%d) doesn't match proof basis size (%d)", cL, pL) } diff --git a/ecc/bls12-377/fr/pedersen/pedersen_test.go b/ecc/bls12-377/fr/pedersen/pedersen_test.go index 75c11fdae0..aeed60ac2d 100644 --- a/ecc/bls12-377/fr/pedersen/pedersen_test.go +++ b/ecc/bls12-377/fr/pedersen/pedersen_test.go @@ -166,8 +166,8 @@ func TestCommitFiveElements(t *testing.T) { func TestMarshal(t *testing.T) { var pk ProvingKey - pk.basisExpSigma = randomG1Slice(t, 5) - pk.basis = randomG1Slice(t, 5) + pk.BasisExpSigma = randomG1Slice(t, 5) + pk.Basis = randomG1Slice(t, 5) var ( vk VerifyingKey diff --git a/ecc/bls12-378/fr/pedersen/pedersen.go b/ecc/bls12-378/fr/pedersen/pedersen.go index be32bdca46..80ffed40ba 100644 --- a/ecc/bls12-378/fr/pedersen/pedersen.go +++ b/ecc/bls12-378/fr/pedersen/pedersen.go @@ -30,8 +30,8 @@ import ( // ProvingKey for committing and proofs of knowledge type ProvingKey struct { - basis []curve.G1Affine - basisExpSigma []curve.G1Affine + Basis []curve.G1Affine + BasisExpSigma []curve.G1Affine } type VerifyingKey struct { @@ -74,17 +74,17 @@ func Setup(bases ...[]curve.G1Affine) (pk []ProvingKey, vk VerifyingKey, err err pk = make([]ProvingKey, len(bases)) for i := range bases { - pk[i].basisExpSigma = make([]curve.G1Affine, len(bases[i])) + pk[i].BasisExpSigma = make([]curve.G1Affine, len(bases[i])) for j := range bases[i] { - pk[i].basisExpSigma[j].ScalarMultiplication(&bases[i][j], sigma) + pk[i].BasisExpSigma[j].ScalarMultiplication(&bases[i][j], sigma) } - pk[i].basis = bases[i] + pk[i].Basis = bases[i] } return } func (pk *ProvingKey) ProveKnowledge(values []fr.Element) (pok curve.G1Affine, err error) { - if len(values) != len(pk.basis) { + if len(values) != len(pk.Basis) { err = fmt.Errorf("must have as many values as basis elements") return } @@ -95,13 +95,13 @@ func (pk *ProvingKey) ProveKnowledge(values []fr.Element) (pok curve.G1Affine, e NbTasks: 1, // TODO Experiment } - _, err = pok.MultiExp(pk.basisExpSigma, values, config) + _, err = pok.MultiExp(pk.BasisExpSigma, values, config) return } func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, err error) { - if len(values) != len(pk.basis) { + if len(values) != len(pk.Basis) { err = fmt.Errorf("must have as many values as basis elements") return } @@ -111,7 +111,7 @@ func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, er config := ecc.MultiExpConfig{ NbTasks: 1, } - _, err = commitment.MultiExp(pk.basis, values, config) + _, err = commitment.MultiExp(pk.Basis, values, config) return } @@ -131,7 +131,7 @@ func BatchProve(pk []ProvingKey, values [][]fr.Element, fiatshamirSeeds ...[]byt offset := 0 for i := range pk { - if len(values[i]) != len(pk[i].basis) { + if len(values[i]) != len(pk[i].Basis) { err = fmt.Errorf("must have as many values as basis elements") return } @@ -147,14 +147,14 @@ func BatchProve(pk []ProvingKey, values [][]fr.Element, fiatshamirSeeds ...[]byt scaledValues := make([]fr.Element, offset) basis := make([]curve.G1Affine, offset) - copy(basis, pk[0].basisExpSigma) + copy(basis, pk[0].BasisExpSigma) copy(scaledValues, values[0]) offset = len(values[0]) rI := r for i := 1; i < len(pk); i++ { - copy(basis[offset:], pk[i].basisExpSigma) - for j := range pk[i].basis { + copy(basis[offset:], pk[i].BasisExpSigma) + for j := range pk[i].Basis { scaledValues[offset].Mul(&values[i][j], &rI) offset++ } @@ -245,11 +245,11 @@ func getChallenge(fiatshamirSeeds [][]byte) (r fr.Element, err error) { // Marshal func (pk *ProvingKey) writeTo(enc *curve.Encoder) (int64, error) { - if err := enc.Encode(pk.basis); err != nil { + if err := enc.Encode(pk.Basis); err != nil { return enc.BytesWritten(), err } - err := enc.Encode(pk.basisExpSigma) + err := enc.Encode(pk.BasisExpSigma) return enc.BytesWritten(), err } @@ -265,14 +265,14 @@ func (pk *ProvingKey) WriteRawTo(w io.Writer) (int64, error) { func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { dec := curve.NewDecoder(r) - if err := dec.Decode(&pk.basis); err != nil { + if err := dec.Decode(&pk.Basis); err != nil { return dec.BytesRead(), err } - if err := dec.Decode(&pk.basisExpSigma); err != nil { + if err := dec.Decode(&pk.BasisExpSigma); err != nil { return dec.BytesRead(), err } - if cL, pL := len(pk.basis), len(pk.basisExpSigma); cL != pL { + if cL, pL := len(pk.Basis), len(pk.BasisExpSigma); cL != pL { return dec.BytesRead(), fmt.Errorf("commitment basis size (%d) doesn't match proof basis size (%d)", cL, pL) } diff --git a/ecc/bls12-378/fr/pedersen/pedersen_test.go b/ecc/bls12-378/fr/pedersen/pedersen_test.go index d94ac20ef6..f5c5493633 100644 --- a/ecc/bls12-378/fr/pedersen/pedersen_test.go +++ b/ecc/bls12-378/fr/pedersen/pedersen_test.go @@ -166,8 +166,8 @@ func TestCommitFiveElements(t *testing.T) { func TestMarshal(t *testing.T) { var pk ProvingKey - pk.basisExpSigma = randomG1Slice(t, 5) - pk.basis = randomG1Slice(t, 5) + pk.BasisExpSigma = randomG1Slice(t, 5) + pk.Basis = randomG1Slice(t, 5) var ( vk VerifyingKey diff --git a/ecc/bls12-381/fr/pedersen/pedersen.go b/ecc/bls12-381/fr/pedersen/pedersen.go index 6e0f51c3e2..32bc01043f 100644 --- a/ecc/bls12-381/fr/pedersen/pedersen.go +++ b/ecc/bls12-381/fr/pedersen/pedersen.go @@ -30,8 +30,8 @@ import ( // ProvingKey for committing and proofs of knowledge type ProvingKey struct { - basis []curve.G1Affine - basisExpSigma []curve.G1Affine + Basis []curve.G1Affine + BasisExpSigma []curve.G1Affine } type VerifyingKey struct { @@ -74,17 +74,17 @@ func Setup(bases ...[]curve.G1Affine) (pk []ProvingKey, vk VerifyingKey, err err pk = make([]ProvingKey, len(bases)) for i := range bases { - pk[i].basisExpSigma = make([]curve.G1Affine, len(bases[i])) + pk[i].BasisExpSigma = make([]curve.G1Affine, len(bases[i])) for j := range bases[i] { - pk[i].basisExpSigma[j].ScalarMultiplication(&bases[i][j], sigma) + pk[i].BasisExpSigma[j].ScalarMultiplication(&bases[i][j], sigma) } - pk[i].basis = bases[i] + pk[i].Basis = bases[i] } return } func (pk *ProvingKey) ProveKnowledge(values []fr.Element) (pok curve.G1Affine, err error) { - if len(values) != len(pk.basis) { + if len(values) != len(pk.Basis) { err = fmt.Errorf("must have as many values as basis elements") return } @@ -95,13 +95,13 @@ func (pk *ProvingKey) ProveKnowledge(values []fr.Element) (pok curve.G1Affine, e NbTasks: 1, // TODO Experiment } - _, err = pok.MultiExp(pk.basisExpSigma, values, config) + _, err = pok.MultiExp(pk.BasisExpSigma, values, config) return } func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, err error) { - if len(values) != len(pk.basis) { + if len(values) != len(pk.Basis) { err = fmt.Errorf("must have as many values as basis elements") return } @@ -111,7 +111,7 @@ func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, er config := ecc.MultiExpConfig{ NbTasks: 1, } - _, err = commitment.MultiExp(pk.basis, values, config) + _, err = commitment.MultiExp(pk.Basis, values, config) return } @@ -131,7 +131,7 @@ func BatchProve(pk []ProvingKey, values [][]fr.Element, fiatshamirSeeds ...[]byt offset := 0 for i := range pk { - if len(values[i]) != len(pk[i].basis) { + if len(values[i]) != len(pk[i].Basis) { err = fmt.Errorf("must have as many values as basis elements") return } @@ -147,14 +147,14 @@ func BatchProve(pk []ProvingKey, values [][]fr.Element, fiatshamirSeeds ...[]byt scaledValues := make([]fr.Element, offset) basis := make([]curve.G1Affine, offset) - copy(basis, pk[0].basisExpSigma) + copy(basis, pk[0].BasisExpSigma) copy(scaledValues, values[0]) offset = len(values[0]) rI := r for i := 1; i < len(pk); i++ { - copy(basis[offset:], pk[i].basisExpSigma) - for j := range pk[i].basis { + copy(basis[offset:], pk[i].BasisExpSigma) + for j := range pk[i].Basis { scaledValues[offset].Mul(&values[i][j], &rI) offset++ } @@ -245,11 +245,11 @@ func getChallenge(fiatshamirSeeds [][]byte) (r fr.Element, err error) { // Marshal func (pk *ProvingKey) writeTo(enc *curve.Encoder) (int64, error) { - if err := enc.Encode(pk.basis); err != nil { + if err := enc.Encode(pk.Basis); err != nil { return enc.BytesWritten(), err } - err := enc.Encode(pk.basisExpSigma) + err := enc.Encode(pk.BasisExpSigma) return enc.BytesWritten(), err } @@ -265,14 +265,14 @@ func (pk *ProvingKey) WriteRawTo(w io.Writer) (int64, error) { func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { dec := curve.NewDecoder(r) - if err := dec.Decode(&pk.basis); err != nil { + if err := dec.Decode(&pk.Basis); err != nil { return dec.BytesRead(), err } - if err := dec.Decode(&pk.basisExpSigma); err != nil { + if err := dec.Decode(&pk.BasisExpSigma); err != nil { return dec.BytesRead(), err } - if cL, pL := len(pk.basis), len(pk.basisExpSigma); cL != pL { + if cL, pL := len(pk.Basis), len(pk.BasisExpSigma); cL != pL { return dec.BytesRead(), fmt.Errorf("commitment basis size (%d) doesn't match proof basis size (%d)", cL, pL) } diff --git a/ecc/bls12-381/fr/pedersen/pedersen_test.go b/ecc/bls12-381/fr/pedersen/pedersen_test.go index 5356f190ea..ccda545d2d 100644 --- a/ecc/bls12-381/fr/pedersen/pedersen_test.go +++ b/ecc/bls12-381/fr/pedersen/pedersen_test.go @@ -166,8 +166,8 @@ func TestCommitFiveElements(t *testing.T) { func TestMarshal(t *testing.T) { var pk ProvingKey - pk.basisExpSigma = randomG1Slice(t, 5) - pk.basis = randomG1Slice(t, 5) + pk.BasisExpSigma = randomG1Slice(t, 5) + pk.Basis = randomG1Slice(t, 5) var ( vk VerifyingKey diff --git a/ecc/bls24-315/fr/pedersen/pedersen.go b/ecc/bls24-315/fr/pedersen/pedersen.go index 30fcc11d12..8c9a5cc87d 100644 --- a/ecc/bls24-315/fr/pedersen/pedersen.go +++ b/ecc/bls24-315/fr/pedersen/pedersen.go @@ -30,8 +30,8 @@ import ( // ProvingKey for committing and proofs of knowledge type ProvingKey struct { - basis []curve.G1Affine - basisExpSigma []curve.G1Affine + Basis []curve.G1Affine + BasisExpSigma []curve.G1Affine } type VerifyingKey struct { @@ -74,17 +74,17 @@ func Setup(bases ...[]curve.G1Affine) (pk []ProvingKey, vk VerifyingKey, err err pk = make([]ProvingKey, len(bases)) for i := range bases { - pk[i].basisExpSigma = make([]curve.G1Affine, len(bases[i])) + pk[i].BasisExpSigma = make([]curve.G1Affine, len(bases[i])) for j := range bases[i] { - pk[i].basisExpSigma[j].ScalarMultiplication(&bases[i][j], sigma) + pk[i].BasisExpSigma[j].ScalarMultiplication(&bases[i][j], sigma) } - pk[i].basis = bases[i] + pk[i].Basis = bases[i] } return } func (pk *ProvingKey) ProveKnowledge(values []fr.Element) (pok curve.G1Affine, err error) { - if len(values) != len(pk.basis) { + if len(values) != len(pk.Basis) { err = fmt.Errorf("must have as many values as basis elements") return } @@ -95,13 +95,13 @@ func (pk *ProvingKey) ProveKnowledge(values []fr.Element) (pok curve.G1Affine, e NbTasks: 1, // TODO Experiment } - _, err = pok.MultiExp(pk.basisExpSigma, values, config) + _, err = pok.MultiExp(pk.BasisExpSigma, values, config) return } func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, err error) { - if len(values) != len(pk.basis) { + if len(values) != len(pk.Basis) { err = fmt.Errorf("must have as many values as basis elements") return } @@ -111,7 +111,7 @@ func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, er config := ecc.MultiExpConfig{ NbTasks: 1, } - _, err = commitment.MultiExp(pk.basis, values, config) + _, err = commitment.MultiExp(pk.Basis, values, config) return } @@ -131,7 +131,7 @@ func BatchProve(pk []ProvingKey, values [][]fr.Element, fiatshamirSeeds ...[]byt offset := 0 for i := range pk { - if len(values[i]) != len(pk[i].basis) { + if len(values[i]) != len(pk[i].Basis) { err = fmt.Errorf("must have as many values as basis elements") return } @@ -147,14 +147,14 @@ func BatchProve(pk []ProvingKey, values [][]fr.Element, fiatshamirSeeds ...[]byt scaledValues := make([]fr.Element, offset) basis := make([]curve.G1Affine, offset) - copy(basis, pk[0].basisExpSigma) + copy(basis, pk[0].BasisExpSigma) copy(scaledValues, values[0]) offset = len(values[0]) rI := r for i := 1; i < len(pk); i++ { - copy(basis[offset:], pk[i].basisExpSigma) - for j := range pk[i].basis { + copy(basis[offset:], pk[i].BasisExpSigma) + for j := range pk[i].Basis { scaledValues[offset].Mul(&values[i][j], &rI) offset++ } @@ -245,11 +245,11 @@ func getChallenge(fiatshamirSeeds [][]byte) (r fr.Element, err error) { // Marshal func (pk *ProvingKey) writeTo(enc *curve.Encoder) (int64, error) { - if err := enc.Encode(pk.basis); err != nil { + if err := enc.Encode(pk.Basis); err != nil { return enc.BytesWritten(), err } - err := enc.Encode(pk.basisExpSigma) + err := enc.Encode(pk.BasisExpSigma) return enc.BytesWritten(), err } @@ -265,14 +265,14 @@ func (pk *ProvingKey) WriteRawTo(w io.Writer) (int64, error) { func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { dec := curve.NewDecoder(r) - if err := dec.Decode(&pk.basis); err != nil { + if err := dec.Decode(&pk.Basis); err != nil { return dec.BytesRead(), err } - if err := dec.Decode(&pk.basisExpSigma); err != nil { + if err := dec.Decode(&pk.BasisExpSigma); err != nil { return dec.BytesRead(), err } - if cL, pL := len(pk.basis), len(pk.basisExpSigma); cL != pL { + if cL, pL := len(pk.Basis), len(pk.BasisExpSigma); cL != pL { return dec.BytesRead(), fmt.Errorf("commitment basis size (%d) doesn't match proof basis size (%d)", cL, pL) } diff --git a/ecc/bls24-315/fr/pedersen/pedersen_test.go b/ecc/bls24-315/fr/pedersen/pedersen_test.go index 5dda2da1a3..e00bba6ce6 100644 --- a/ecc/bls24-315/fr/pedersen/pedersen_test.go +++ b/ecc/bls24-315/fr/pedersen/pedersen_test.go @@ -166,8 +166,8 @@ func TestCommitFiveElements(t *testing.T) { func TestMarshal(t *testing.T) { var pk ProvingKey - pk.basisExpSigma = randomG1Slice(t, 5) - pk.basis = randomG1Slice(t, 5) + pk.BasisExpSigma = randomG1Slice(t, 5) + pk.Basis = randomG1Slice(t, 5) var ( vk VerifyingKey diff --git a/ecc/bls24-317/fr/pedersen/pedersen.go b/ecc/bls24-317/fr/pedersen/pedersen.go index 86fcc5f37c..4585c6be32 100644 --- a/ecc/bls24-317/fr/pedersen/pedersen.go +++ b/ecc/bls24-317/fr/pedersen/pedersen.go @@ -30,8 +30,8 @@ import ( // ProvingKey for committing and proofs of knowledge type ProvingKey struct { - basis []curve.G1Affine - basisExpSigma []curve.G1Affine + Basis []curve.G1Affine + BasisExpSigma []curve.G1Affine } type VerifyingKey struct { @@ -74,17 +74,17 @@ func Setup(bases ...[]curve.G1Affine) (pk []ProvingKey, vk VerifyingKey, err err pk = make([]ProvingKey, len(bases)) for i := range bases { - pk[i].basisExpSigma = make([]curve.G1Affine, len(bases[i])) + pk[i].BasisExpSigma = make([]curve.G1Affine, len(bases[i])) for j := range bases[i] { - pk[i].basisExpSigma[j].ScalarMultiplication(&bases[i][j], sigma) + pk[i].BasisExpSigma[j].ScalarMultiplication(&bases[i][j], sigma) } - pk[i].basis = bases[i] + pk[i].Basis = bases[i] } return } func (pk *ProvingKey) ProveKnowledge(values []fr.Element) (pok curve.G1Affine, err error) { - if len(values) != len(pk.basis) { + if len(values) != len(pk.Basis) { err = fmt.Errorf("must have as many values as basis elements") return } @@ -95,13 +95,13 @@ func (pk *ProvingKey) ProveKnowledge(values []fr.Element) (pok curve.G1Affine, e NbTasks: 1, // TODO Experiment } - _, err = pok.MultiExp(pk.basisExpSigma, values, config) + _, err = pok.MultiExp(pk.BasisExpSigma, values, config) return } func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, err error) { - if len(values) != len(pk.basis) { + if len(values) != len(pk.Basis) { err = fmt.Errorf("must have as many values as basis elements") return } @@ -111,7 +111,7 @@ func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, er config := ecc.MultiExpConfig{ NbTasks: 1, } - _, err = commitment.MultiExp(pk.basis, values, config) + _, err = commitment.MultiExp(pk.Basis, values, config) return } @@ -131,7 +131,7 @@ func BatchProve(pk []ProvingKey, values [][]fr.Element, fiatshamirSeeds ...[]byt offset := 0 for i := range pk { - if len(values[i]) != len(pk[i].basis) { + if len(values[i]) != len(pk[i].Basis) { err = fmt.Errorf("must have as many values as basis elements") return } @@ -147,14 +147,14 @@ func BatchProve(pk []ProvingKey, values [][]fr.Element, fiatshamirSeeds ...[]byt scaledValues := make([]fr.Element, offset) basis := make([]curve.G1Affine, offset) - copy(basis, pk[0].basisExpSigma) + copy(basis, pk[0].BasisExpSigma) copy(scaledValues, values[0]) offset = len(values[0]) rI := r for i := 1; i < len(pk); i++ { - copy(basis[offset:], pk[i].basisExpSigma) - for j := range pk[i].basis { + copy(basis[offset:], pk[i].BasisExpSigma) + for j := range pk[i].Basis { scaledValues[offset].Mul(&values[i][j], &rI) offset++ } @@ -245,11 +245,11 @@ func getChallenge(fiatshamirSeeds [][]byte) (r fr.Element, err error) { // Marshal func (pk *ProvingKey) writeTo(enc *curve.Encoder) (int64, error) { - if err := enc.Encode(pk.basis); err != nil { + if err := enc.Encode(pk.Basis); err != nil { return enc.BytesWritten(), err } - err := enc.Encode(pk.basisExpSigma) + err := enc.Encode(pk.BasisExpSigma) return enc.BytesWritten(), err } @@ -265,14 +265,14 @@ func (pk *ProvingKey) WriteRawTo(w io.Writer) (int64, error) { func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { dec := curve.NewDecoder(r) - if err := dec.Decode(&pk.basis); err != nil { + if err := dec.Decode(&pk.Basis); err != nil { return dec.BytesRead(), err } - if err := dec.Decode(&pk.basisExpSigma); err != nil { + if err := dec.Decode(&pk.BasisExpSigma); err != nil { return dec.BytesRead(), err } - if cL, pL := len(pk.basis), len(pk.basisExpSigma); cL != pL { + if cL, pL := len(pk.Basis), len(pk.BasisExpSigma); cL != pL { return dec.BytesRead(), fmt.Errorf("commitment basis size (%d) doesn't match proof basis size (%d)", cL, pL) } diff --git a/ecc/bls24-317/fr/pedersen/pedersen_test.go b/ecc/bls24-317/fr/pedersen/pedersen_test.go index c0625afa6b..69f42f641d 100644 --- a/ecc/bls24-317/fr/pedersen/pedersen_test.go +++ b/ecc/bls24-317/fr/pedersen/pedersen_test.go @@ -166,8 +166,8 @@ func TestCommitFiveElements(t *testing.T) { func TestMarshal(t *testing.T) { var pk ProvingKey - pk.basisExpSigma = randomG1Slice(t, 5) - pk.basis = randomG1Slice(t, 5) + pk.BasisExpSigma = randomG1Slice(t, 5) + pk.Basis = randomG1Slice(t, 5) var ( vk VerifyingKey diff --git a/ecc/bn254/fr/pedersen/pedersen.go b/ecc/bn254/fr/pedersen/pedersen.go index d836eeaecb..e550177cba 100644 --- a/ecc/bn254/fr/pedersen/pedersen.go +++ b/ecc/bn254/fr/pedersen/pedersen.go @@ -30,8 +30,8 @@ import ( // ProvingKey for committing and proofs of knowledge type ProvingKey struct { - basis []curve.G1Affine - basisExpSigma []curve.G1Affine + Basis []curve.G1Affine + BasisExpSigma []curve.G1Affine } type VerifyingKey struct { @@ -74,17 +74,17 @@ func Setup(bases ...[]curve.G1Affine) (pk []ProvingKey, vk VerifyingKey, err err pk = make([]ProvingKey, len(bases)) for i := range bases { - pk[i].basisExpSigma = make([]curve.G1Affine, len(bases[i])) + pk[i].BasisExpSigma = make([]curve.G1Affine, len(bases[i])) for j := range bases[i] { - pk[i].basisExpSigma[j].ScalarMultiplication(&bases[i][j], sigma) + pk[i].BasisExpSigma[j].ScalarMultiplication(&bases[i][j], sigma) } - pk[i].basis = bases[i] + pk[i].Basis = bases[i] } return } func (pk *ProvingKey) ProveKnowledge(values []fr.Element) (pok curve.G1Affine, err error) { - if len(values) != len(pk.basis) { + if len(values) != len(pk.Basis) { err = fmt.Errorf("must have as many values as basis elements") return } @@ -95,13 +95,13 @@ func (pk *ProvingKey) ProveKnowledge(values []fr.Element) (pok curve.G1Affine, e NbTasks: 1, // TODO Experiment } - _, err = pok.MultiExp(pk.basisExpSigma, values, config) + _, err = pok.MultiExp(pk.BasisExpSigma, values, config) return } func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, err error) { - if len(values) != len(pk.basis) { + if len(values) != len(pk.Basis) { err = fmt.Errorf("must have as many values as basis elements") return } @@ -111,7 +111,7 @@ func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, er config := ecc.MultiExpConfig{ NbTasks: 1, } - _, err = commitment.MultiExp(pk.basis, values, config) + _, err = commitment.MultiExp(pk.Basis, values, config) return } @@ -131,7 +131,7 @@ func BatchProve(pk []ProvingKey, values [][]fr.Element, fiatshamirSeeds ...[]byt offset := 0 for i := range pk { - if len(values[i]) != len(pk[i].basis) { + if len(values[i]) != len(pk[i].Basis) { err = fmt.Errorf("must have as many values as basis elements") return } @@ -147,14 +147,14 @@ func BatchProve(pk []ProvingKey, values [][]fr.Element, fiatshamirSeeds ...[]byt scaledValues := make([]fr.Element, offset) basis := make([]curve.G1Affine, offset) - copy(basis, pk[0].basisExpSigma) + copy(basis, pk[0].BasisExpSigma) copy(scaledValues, values[0]) offset = len(values[0]) rI := r for i := 1; i < len(pk); i++ { - copy(basis[offset:], pk[i].basisExpSigma) - for j := range pk[i].basis { + copy(basis[offset:], pk[i].BasisExpSigma) + for j := range pk[i].Basis { scaledValues[offset].Mul(&values[i][j], &rI) offset++ } @@ -245,11 +245,11 @@ func getChallenge(fiatshamirSeeds [][]byte) (r fr.Element, err error) { // Marshal func (pk *ProvingKey) writeTo(enc *curve.Encoder) (int64, error) { - if err := enc.Encode(pk.basis); err != nil { + if err := enc.Encode(pk.Basis); err != nil { return enc.BytesWritten(), err } - err := enc.Encode(pk.basisExpSigma) + err := enc.Encode(pk.BasisExpSigma) return enc.BytesWritten(), err } @@ -265,14 +265,14 @@ func (pk *ProvingKey) WriteRawTo(w io.Writer) (int64, error) { func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { dec := curve.NewDecoder(r) - if err := dec.Decode(&pk.basis); err != nil { + if err := dec.Decode(&pk.Basis); err != nil { return dec.BytesRead(), err } - if err := dec.Decode(&pk.basisExpSigma); err != nil { + if err := dec.Decode(&pk.BasisExpSigma); err != nil { return dec.BytesRead(), err } - if cL, pL := len(pk.basis), len(pk.basisExpSigma); cL != pL { + if cL, pL := len(pk.Basis), len(pk.BasisExpSigma); cL != pL { return dec.BytesRead(), fmt.Errorf("commitment basis size (%d) doesn't match proof basis size (%d)", cL, pL) } diff --git a/ecc/bn254/fr/pedersen/pedersen_test.go b/ecc/bn254/fr/pedersen/pedersen_test.go index 53109adfba..57b7e3e0ca 100644 --- a/ecc/bn254/fr/pedersen/pedersen_test.go +++ b/ecc/bn254/fr/pedersen/pedersen_test.go @@ -166,8 +166,8 @@ func TestCommitFiveElements(t *testing.T) { func TestMarshal(t *testing.T) { var pk ProvingKey - pk.basisExpSigma = randomG1Slice(t, 5) - pk.basis = randomG1Slice(t, 5) + pk.BasisExpSigma = randomG1Slice(t, 5) + pk.Basis = randomG1Slice(t, 5) var ( vk VerifyingKey diff --git a/ecc/bw6-633/fr/pedersen/pedersen.go b/ecc/bw6-633/fr/pedersen/pedersen.go index 60964a610e..cf2e80f9f7 100644 --- a/ecc/bw6-633/fr/pedersen/pedersen.go +++ b/ecc/bw6-633/fr/pedersen/pedersen.go @@ -30,8 +30,8 @@ import ( // ProvingKey for committing and proofs of knowledge type ProvingKey struct { - basis []curve.G1Affine - basisExpSigma []curve.G1Affine + Basis []curve.G1Affine + BasisExpSigma []curve.G1Affine } type VerifyingKey struct { @@ -74,17 +74,17 @@ func Setup(bases ...[]curve.G1Affine) (pk []ProvingKey, vk VerifyingKey, err err pk = make([]ProvingKey, len(bases)) for i := range bases { - pk[i].basisExpSigma = make([]curve.G1Affine, len(bases[i])) + pk[i].BasisExpSigma = make([]curve.G1Affine, len(bases[i])) for j := range bases[i] { - pk[i].basisExpSigma[j].ScalarMultiplication(&bases[i][j], sigma) + pk[i].BasisExpSigma[j].ScalarMultiplication(&bases[i][j], sigma) } - pk[i].basis = bases[i] + pk[i].Basis = bases[i] } return } func (pk *ProvingKey) ProveKnowledge(values []fr.Element) (pok curve.G1Affine, err error) { - if len(values) != len(pk.basis) { + if len(values) != len(pk.Basis) { err = fmt.Errorf("must have as many values as basis elements") return } @@ -95,13 +95,13 @@ func (pk *ProvingKey) ProveKnowledge(values []fr.Element) (pok curve.G1Affine, e NbTasks: 1, // TODO Experiment } - _, err = pok.MultiExp(pk.basisExpSigma, values, config) + _, err = pok.MultiExp(pk.BasisExpSigma, values, config) return } func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, err error) { - if len(values) != len(pk.basis) { + if len(values) != len(pk.Basis) { err = fmt.Errorf("must have as many values as basis elements") return } @@ -111,7 +111,7 @@ func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, er config := ecc.MultiExpConfig{ NbTasks: 1, } - _, err = commitment.MultiExp(pk.basis, values, config) + _, err = commitment.MultiExp(pk.Basis, values, config) return } @@ -131,7 +131,7 @@ func BatchProve(pk []ProvingKey, values [][]fr.Element, fiatshamirSeeds ...[]byt offset := 0 for i := range pk { - if len(values[i]) != len(pk[i].basis) { + if len(values[i]) != len(pk[i].Basis) { err = fmt.Errorf("must have as many values as basis elements") return } @@ -147,14 +147,14 @@ func BatchProve(pk []ProvingKey, values [][]fr.Element, fiatshamirSeeds ...[]byt scaledValues := make([]fr.Element, offset) basis := make([]curve.G1Affine, offset) - copy(basis, pk[0].basisExpSigma) + copy(basis, pk[0].BasisExpSigma) copy(scaledValues, values[0]) offset = len(values[0]) rI := r for i := 1; i < len(pk); i++ { - copy(basis[offset:], pk[i].basisExpSigma) - for j := range pk[i].basis { + copy(basis[offset:], pk[i].BasisExpSigma) + for j := range pk[i].Basis { scaledValues[offset].Mul(&values[i][j], &rI) offset++ } @@ -245,11 +245,11 @@ func getChallenge(fiatshamirSeeds [][]byte) (r fr.Element, err error) { // Marshal func (pk *ProvingKey) writeTo(enc *curve.Encoder) (int64, error) { - if err := enc.Encode(pk.basis); err != nil { + if err := enc.Encode(pk.Basis); err != nil { return enc.BytesWritten(), err } - err := enc.Encode(pk.basisExpSigma) + err := enc.Encode(pk.BasisExpSigma) return enc.BytesWritten(), err } @@ -265,14 +265,14 @@ func (pk *ProvingKey) WriteRawTo(w io.Writer) (int64, error) { func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { dec := curve.NewDecoder(r) - if err := dec.Decode(&pk.basis); err != nil { + if err := dec.Decode(&pk.Basis); err != nil { return dec.BytesRead(), err } - if err := dec.Decode(&pk.basisExpSigma); err != nil { + if err := dec.Decode(&pk.BasisExpSigma); err != nil { return dec.BytesRead(), err } - if cL, pL := len(pk.basis), len(pk.basisExpSigma); cL != pL { + if cL, pL := len(pk.Basis), len(pk.BasisExpSigma); cL != pL { return dec.BytesRead(), fmt.Errorf("commitment basis size (%d) doesn't match proof basis size (%d)", cL, pL) } diff --git a/ecc/bw6-633/fr/pedersen/pedersen_test.go b/ecc/bw6-633/fr/pedersen/pedersen_test.go index c644bebd3e..4d266802df 100644 --- a/ecc/bw6-633/fr/pedersen/pedersen_test.go +++ b/ecc/bw6-633/fr/pedersen/pedersen_test.go @@ -166,8 +166,8 @@ func TestCommitFiveElements(t *testing.T) { func TestMarshal(t *testing.T) { var pk ProvingKey - pk.basisExpSigma = randomG1Slice(t, 5) - pk.basis = randomG1Slice(t, 5) + pk.BasisExpSigma = randomG1Slice(t, 5) + pk.Basis = randomG1Slice(t, 5) var ( vk VerifyingKey diff --git a/ecc/bw6-756/fr/pedersen/pedersen.go b/ecc/bw6-756/fr/pedersen/pedersen.go index e33f50d43f..bbe7f9e1d9 100644 --- a/ecc/bw6-756/fr/pedersen/pedersen.go +++ b/ecc/bw6-756/fr/pedersen/pedersen.go @@ -30,8 +30,8 @@ import ( // ProvingKey for committing and proofs of knowledge type ProvingKey struct { - basis []curve.G1Affine - basisExpSigma []curve.G1Affine + Basis []curve.G1Affine + BasisExpSigma []curve.G1Affine } type VerifyingKey struct { @@ -74,17 +74,17 @@ func Setup(bases ...[]curve.G1Affine) (pk []ProvingKey, vk VerifyingKey, err err pk = make([]ProvingKey, len(bases)) for i := range bases { - pk[i].basisExpSigma = make([]curve.G1Affine, len(bases[i])) + pk[i].BasisExpSigma = make([]curve.G1Affine, len(bases[i])) for j := range bases[i] { - pk[i].basisExpSigma[j].ScalarMultiplication(&bases[i][j], sigma) + pk[i].BasisExpSigma[j].ScalarMultiplication(&bases[i][j], sigma) } - pk[i].basis = bases[i] + pk[i].Basis = bases[i] } return } func (pk *ProvingKey) ProveKnowledge(values []fr.Element) (pok curve.G1Affine, err error) { - if len(values) != len(pk.basis) { + if len(values) != len(pk.Basis) { err = fmt.Errorf("must have as many values as basis elements") return } @@ -95,13 +95,13 @@ func (pk *ProvingKey) ProveKnowledge(values []fr.Element) (pok curve.G1Affine, e NbTasks: 1, // TODO Experiment } - _, err = pok.MultiExp(pk.basisExpSigma, values, config) + _, err = pok.MultiExp(pk.BasisExpSigma, values, config) return } func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, err error) { - if len(values) != len(pk.basis) { + if len(values) != len(pk.Basis) { err = fmt.Errorf("must have as many values as basis elements") return } @@ -111,7 +111,7 @@ func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, er config := ecc.MultiExpConfig{ NbTasks: 1, } - _, err = commitment.MultiExp(pk.basis, values, config) + _, err = commitment.MultiExp(pk.Basis, values, config) return } @@ -131,7 +131,7 @@ func BatchProve(pk []ProvingKey, values [][]fr.Element, fiatshamirSeeds ...[]byt offset := 0 for i := range pk { - if len(values[i]) != len(pk[i].basis) { + if len(values[i]) != len(pk[i].Basis) { err = fmt.Errorf("must have as many values as basis elements") return } @@ -147,14 +147,14 @@ func BatchProve(pk []ProvingKey, values [][]fr.Element, fiatshamirSeeds ...[]byt scaledValues := make([]fr.Element, offset) basis := make([]curve.G1Affine, offset) - copy(basis, pk[0].basisExpSigma) + copy(basis, pk[0].BasisExpSigma) copy(scaledValues, values[0]) offset = len(values[0]) rI := r for i := 1; i < len(pk); i++ { - copy(basis[offset:], pk[i].basisExpSigma) - for j := range pk[i].basis { + copy(basis[offset:], pk[i].BasisExpSigma) + for j := range pk[i].Basis { scaledValues[offset].Mul(&values[i][j], &rI) offset++ } @@ -245,11 +245,11 @@ func getChallenge(fiatshamirSeeds [][]byte) (r fr.Element, err error) { // Marshal func (pk *ProvingKey) writeTo(enc *curve.Encoder) (int64, error) { - if err := enc.Encode(pk.basis); err != nil { + if err := enc.Encode(pk.Basis); err != nil { return enc.BytesWritten(), err } - err := enc.Encode(pk.basisExpSigma) + err := enc.Encode(pk.BasisExpSigma) return enc.BytesWritten(), err } @@ -265,14 +265,14 @@ func (pk *ProvingKey) WriteRawTo(w io.Writer) (int64, error) { func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { dec := curve.NewDecoder(r) - if err := dec.Decode(&pk.basis); err != nil { + if err := dec.Decode(&pk.Basis); err != nil { return dec.BytesRead(), err } - if err := dec.Decode(&pk.basisExpSigma); err != nil { + if err := dec.Decode(&pk.BasisExpSigma); err != nil { return dec.BytesRead(), err } - if cL, pL := len(pk.basis), len(pk.basisExpSigma); cL != pL { + if cL, pL := len(pk.Basis), len(pk.BasisExpSigma); cL != pL { return dec.BytesRead(), fmt.Errorf("commitment basis size (%d) doesn't match proof basis size (%d)", cL, pL) } diff --git a/ecc/bw6-756/fr/pedersen/pedersen_test.go b/ecc/bw6-756/fr/pedersen/pedersen_test.go index c91e012b14..9e6e08fe1e 100644 --- a/ecc/bw6-756/fr/pedersen/pedersen_test.go +++ b/ecc/bw6-756/fr/pedersen/pedersen_test.go @@ -166,8 +166,8 @@ func TestCommitFiveElements(t *testing.T) { func TestMarshal(t *testing.T) { var pk ProvingKey - pk.basisExpSigma = randomG1Slice(t, 5) - pk.basis = randomG1Slice(t, 5) + pk.BasisExpSigma = randomG1Slice(t, 5) + pk.Basis = randomG1Slice(t, 5) var ( vk VerifyingKey diff --git a/ecc/bw6-761/fr/pedersen/pedersen.go b/ecc/bw6-761/fr/pedersen/pedersen.go index b77c0724b0..a9a6e56498 100644 --- a/ecc/bw6-761/fr/pedersen/pedersen.go +++ b/ecc/bw6-761/fr/pedersen/pedersen.go @@ -30,8 +30,8 @@ import ( // ProvingKey for committing and proofs of knowledge type ProvingKey struct { - basis []curve.G1Affine - basisExpSigma []curve.G1Affine + Basis []curve.G1Affine + BasisExpSigma []curve.G1Affine } type VerifyingKey struct { @@ -74,17 +74,17 @@ func Setup(bases ...[]curve.G1Affine) (pk []ProvingKey, vk VerifyingKey, err err pk = make([]ProvingKey, len(bases)) for i := range bases { - pk[i].basisExpSigma = make([]curve.G1Affine, len(bases[i])) + pk[i].BasisExpSigma = make([]curve.G1Affine, len(bases[i])) for j := range bases[i] { - pk[i].basisExpSigma[j].ScalarMultiplication(&bases[i][j], sigma) + pk[i].BasisExpSigma[j].ScalarMultiplication(&bases[i][j], sigma) } - pk[i].basis = bases[i] + pk[i].Basis = bases[i] } return } func (pk *ProvingKey) ProveKnowledge(values []fr.Element) (pok curve.G1Affine, err error) { - if len(values) != len(pk.basis) { + if len(values) != len(pk.Basis) { err = fmt.Errorf("must have as many values as basis elements") return } @@ -95,13 +95,13 @@ func (pk *ProvingKey) ProveKnowledge(values []fr.Element) (pok curve.G1Affine, e NbTasks: 1, // TODO Experiment } - _, err = pok.MultiExp(pk.basisExpSigma, values, config) + _, err = pok.MultiExp(pk.BasisExpSigma, values, config) return } func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, err error) { - if len(values) != len(pk.basis) { + if len(values) != len(pk.Basis) { err = fmt.Errorf("must have as many values as basis elements") return } @@ -111,7 +111,7 @@ func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, er config := ecc.MultiExpConfig{ NbTasks: 1, } - _, err = commitment.MultiExp(pk.basis, values, config) + _, err = commitment.MultiExp(pk.Basis, values, config) return } @@ -131,7 +131,7 @@ func BatchProve(pk []ProvingKey, values [][]fr.Element, fiatshamirSeeds ...[]byt offset := 0 for i := range pk { - if len(values[i]) != len(pk[i].basis) { + if len(values[i]) != len(pk[i].Basis) { err = fmt.Errorf("must have as many values as basis elements") return } @@ -147,14 +147,14 @@ func BatchProve(pk []ProvingKey, values [][]fr.Element, fiatshamirSeeds ...[]byt scaledValues := make([]fr.Element, offset) basis := make([]curve.G1Affine, offset) - copy(basis, pk[0].basisExpSigma) + copy(basis, pk[0].BasisExpSigma) copy(scaledValues, values[0]) offset = len(values[0]) rI := r for i := 1; i < len(pk); i++ { - copy(basis[offset:], pk[i].basisExpSigma) - for j := range pk[i].basis { + copy(basis[offset:], pk[i].BasisExpSigma) + for j := range pk[i].Basis { scaledValues[offset].Mul(&values[i][j], &rI) offset++ } @@ -245,11 +245,11 @@ func getChallenge(fiatshamirSeeds [][]byte) (r fr.Element, err error) { // Marshal func (pk *ProvingKey) writeTo(enc *curve.Encoder) (int64, error) { - if err := enc.Encode(pk.basis); err != nil { + if err := enc.Encode(pk.Basis); err != nil { return enc.BytesWritten(), err } - err := enc.Encode(pk.basisExpSigma) + err := enc.Encode(pk.BasisExpSigma) return enc.BytesWritten(), err } @@ -265,14 +265,14 @@ func (pk *ProvingKey) WriteRawTo(w io.Writer) (int64, error) { func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { dec := curve.NewDecoder(r) - if err := dec.Decode(&pk.basis); err != nil { + if err := dec.Decode(&pk.Basis); err != nil { return dec.BytesRead(), err } - if err := dec.Decode(&pk.basisExpSigma); err != nil { + if err := dec.Decode(&pk.BasisExpSigma); err != nil { return dec.BytesRead(), err } - if cL, pL := len(pk.basis), len(pk.basisExpSigma); cL != pL { + if cL, pL := len(pk.Basis), len(pk.BasisExpSigma); cL != pL { return dec.BytesRead(), fmt.Errorf("commitment basis size (%d) doesn't match proof basis size (%d)", cL, pL) } diff --git a/ecc/bw6-761/fr/pedersen/pedersen_test.go b/ecc/bw6-761/fr/pedersen/pedersen_test.go index 32f53f99d1..534b163c30 100644 --- a/ecc/bw6-761/fr/pedersen/pedersen_test.go +++ b/ecc/bw6-761/fr/pedersen/pedersen_test.go @@ -166,8 +166,8 @@ func TestCommitFiveElements(t *testing.T) { func TestMarshal(t *testing.T) { var pk ProvingKey - pk.basisExpSigma = randomG1Slice(t, 5) - pk.basis = randomG1Slice(t, 5) + pk.BasisExpSigma = randomG1Slice(t, 5) + pk.Basis = randomG1Slice(t, 5) var ( vk VerifyingKey diff --git a/internal/generator/pedersen/template/pedersen.go.tmpl b/internal/generator/pedersen/template/pedersen.go.tmpl index af1cdc8a58..db485881af 100644 --- a/internal/generator/pedersen/template/pedersen.go.tmpl +++ b/internal/generator/pedersen/template/pedersen.go.tmpl @@ -1,158 +1,158 @@ import ( - "crypto/rand" + "crypto/rand" "crypto/sha256" - "fmt" - "github.com/consensys/gnark-crypto/ecc" - curve "github.com/consensys/gnark-crypto/ecc/{{.Name}}" - "github.com/consensys/gnark-crypto/ecc/{{.Name}}/fr" + "fmt" + "github.com/consensys/gnark-crypto/ecc" + curve "github.com/consensys/gnark-crypto/ecc/{{.Name}}" + "github.com/consensys/gnark-crypto/ecc/{{.Name}}/fr" fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "io" - "math/big" + "math/big" ) // ProvingKey for committing and proofs of knowledge type ProvingKey struct { - basis []curve.G1Affine - basisExpSigma []curve.G1Affine + Basis []curve.G1Affine + BasisExpSigma []curve.G1Affine } type VerifyingKey struct { - G curve.G2Affine // TODO @tabaie: does this really have to be randomized? - GRootSigmaNeg curve.G2Affine //gRootSigmaNeg = g^{-1/σ} + G curve.G2Affine // TODO @tabaie: does this really have to be randomized? + GRootSigmaNeg curve.G2Affine //gRootSigmaNeg = g^{-1/σ} } func randomFrSizedBytes() ([]byte, error) { - res := make([]byte, fr.Bytes) - _, err := rand.Read(res) - return res, err + res := make([]byte, fr.Bytes) + _, err := rand.Read(res) + return res, err } func randomOnG2() (curve.G2Affine, error) { // TODO: Add to G2.go? if gBytes, err := randomFrSizedBytes(); err != nil { - return curve.G2Affine{}, err + return curve.G2Affine{}, err } else { - return curve.HashToG2(gBytes, []byte("random on g2")) - } + return curve.HashToG2(gBytes, []byte("random on g2")) + } } func Setup(bases ...[]curve.G1Affine) (pk []ProvingKey, vk VerifyingKey, err error) { - if vk.G, err = randomOnG2(); err != nil { - return - } - - var modMinusOne big.Int - modMinusOne.Sub(fr.Modulus(), big.NewInt(1)) - var sigma *big.Int - if sigma, err = rand.Int(rand.Reader, &modMinusOne); err != nil { - return - } - sigma.Add(sigma, big.NewInt(1)) - - var sigmaInvNeg big.Int - sigmaInvNeg.ModInverse(sigma, fr.Modulus()) - sigmaInvNeg.Sub(fr.Modulus(), &sigmaInvNeg) - vk.GRootSigmaNeg.ScalarMultiplication(&vk.G, &sigmaInvNeg) - - pk = make([]ProvingKey, len(bases)) - for i := range bases { - pk[i].basisExpSigma = make([]curve.G1Affine, len(bases[i])) - for j := range bases[i] { - pk[i].basisExpSigma[j].ScalarMultiplication(&bases[i][j], sigma) - } - pk[i].basis = bases[i] - } - return + if vk.G, err = randomOnG2(); err != nil { + return + } + + var modMinusOne big.Int + modMinusOne.Sub(fr.Modulus(), big.NewInt(1)) + var sigma *big.Int + if sigma, err = rand.Int(rand.Reader, &modMinusOne); err != nil { + return + } + sigma.Add(sigma, big.NewInt(1)) + + var sigmaInvNeg big.Int + sigmaInvNeg.ModInverse(sigma, fr.Modulus()) + sigmaInvNeg.Sub(fr.Modulus(), &sigmaInvNeg) + vk.GRootSigmaNeg.ScalarMultiplication(&vk.G, &sigmaInvNeg) + + pk = make([]ProvingKey, len(bases)) + for i := range bases { + pk[i].BasisExpSigma = make([]curve.G1Affine, len(bases[i])) + for j := range bases[i] { + pk[i].BasisExpSigma[j].ScalarMultiplication(&bases[i][j], sigma) + } + pk[i].Basis = bases[i] + } + return } func (pk *ProvingKey) ProveKnowledge(values []fr.Element) (pok curve.G1Affine, err error) { - if len(values) != len(pk.basis) { - err = fmt.Errorf("must have as many values as basis elements") - return - } - - // TODO @gbotrel this will spawn more than one task, see - // https://github.com/ConsenSys/gnark-crypto/issues/269 - config := ecc.MultiExpConfig{ - NbTasks: 1, // TODO Experiment - } - - _, err = pok.MultiExp(pk.basisExpSigma, values, config) - return + if len(values) != len(pk.Basis) { + err = fmt.Errorf("must have as many values as basis elements") + return + } + + // TODO @gbotrel this will spawn more than one task, see + // https://github.com/ConsenSys/gnark-crypto/issues/269 + config := ecc.MultiExpConfig{ + NbTasks: 1, // TODO Experiment + } + + _, err = pok.MultiExp(pk.BasisExpSigma, values, config) + return } func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, err error) { - if len(values) != len(pk.basis) { - err = fmt.Errorf("must have as many values as basis elements") - return - } + if len(values) != len(pk.Basis) { + err = fmt.Errorf("must have as many values as basis elements") + return + } - // TODO @gbotrel this will spawn more than one task, see - // https://github.com/ConsenSys/gnark-crypto/issues/269 - config := ecc.MultiExpConfig{ - NbTasks: 1, - } - _, err = commitment.MultiExp(pk.basis, values, config) + // TODO @gbotrel this will spawn more than one task, see + // https://github.com/ConsenSys/gnark-crypto/issues/269 + config := ecc.MultiExpConfig{ + NbTasks: 1, + } + _, err = commitment.MultiExp(pk.Basis, values, config) - return + return } // BatchProve generates a single proof of knowledge for multiple commitments for faster verification func BatchProve(pk []ProvingKey, values [][]fr.Element, fiatshamirSeeds ...[]byte) (pok curve.G1Affine, err error) { - if len(pk) != len(values) { - err = fmt.Errorf("must have as many value vectors as bases") - return - } - - if len(pk) == 1 { // no need to fold - return pk[0].ProveKnowledge(values[0]) - } else if len(pk) == 0 { // nothing to do at all + if len(pk) != len(values) { + err = fmt.Errorf("must have as many value vectors as bases") + return + } + + if len(pk) == 1 { // no need to fold + return pk[0].ProveKnowledge(values[0]) + } else if len(pk) == 0 { // nothing to do at all + return + } + + offset := 0 + for i := range pk { + if len(values[i]) != len(pk[i].Basis) { + err = fmt.Errorf("must have as many values as basis elements") + return + } + offset += len(values[i]) + } + + var r fr.Element + if r, err = getChallenge(fiatshamirSeeds); err != nil { return - } - - offset := 0 - for i := range pk { - if len(values[i]) != len(pk[i].basis) { - err = fmt.Errorf("must have as many values as basis elements") - return - } - offset += len(values[i]) - } - - var r fr.Element - if r, err = getChallenge(fiatshamirSeeds); err != nil { - return - } - - // prepare one amalgamated MSM - scaledValues := make([]fr.Element, offset) - basis := make([]curve.G1Affine, offset) - - copy(basis, pk[0].basisExpSigma) - copy(scaledValues, values[0]) - - offset = len(values[0]) - rI := r - for i := 1; i < len(pk); i++ { - copy(basis[offset:], pk[i].basisExpSigma) - for j := range pk[i].basis { - scaledValues[offset].Mul(&values[i][j], &rI) - offset++ - } - if i+1 < len(pk) { - rI.Mul(&rI, &r) - } - } - - // TODO @gbotrel this will spawn more than one task, see - // https://github.com/ConsenSys/gnark-crypto/issues/269 - config := ecc.MultiExpConfig{ - NbTasks: 1, - } - - _, err = pok.MultiExp(basis, scaledValues, config) - return + } + + // prepare one amalgamated MSM + scaledValues := make([]fr.Element, offset) + basis := make([]curve.G1Affine, offset) + + copy(basis, pk[0].BasisExpSigma) + copy(scaledValues, values[0]) + + offset = len(values[0]) + rI := r + for i := 1; i < len(pk); i++ { + copy(basis[offset:], pk[i].BasisExpSigma) + for j := range pk[i].Basis { + scaledValues[offset].Mul(&values[i][j], &rI) + offset++ + } + if i+1 < len(pk) { + rI.Mul(&rI, &r) + } + } + + // TODO @gbotrel this will spawn more than one task, see + // https://github.com/ConsenSys/gnark-crypto/issues/269 + config := ecc.MultiExpConfig{ + NbTasks: 1, + } + + _, err = pok.MultiExp(basis, scaledValues, config) + return } // FoldCommitments amalgamates multiple commitments into one, which can be verifier against a folded proof obtained from BatchProve @@ -161,9 +161,9 @@ func FoldCommitments(commitments []curve.G1Affine, fiatshamirSeeds ...[]byte) (c if len(commitments) == 1 { // no need to fold commitment = commitments[0] return - } else if len(commitments) == 0 { // nothing to do at all + } else if len(commitments) == 0 { // nothing to do at all return - } + } r := make([]fr.Element, len(commitments)) r[0].SetOne() @@ -193,9 +193,9 @@ func FoldCommitments(commitments []curve.G1Affine, fiatshamirSeeds ...[]byte) (c // Verify checks if the proof of knowledge is valid func (vk *VerifyingKey) Verify(commitment curve.G1Affine, knowledgeProof curve.G1Affine) error { - if !commitment.IsInSubGroup() || !knowledgeProof.IsInSubGroup() { - return fmt.Errorf("subgroup check failed") - } + if !commitment.IsInSubGroup() || !knowledgeProof.IsInSubGroup() { + return fmt.Errorf("subgroup check failed") + } if isOne, err := curve.PairingCheck([]curve.G1Affine{commitment, knowledgeProof}, []curve.G2Affine{vk.G, vk.GRootSigmaNeg}); err != nil { return err @@ -206,32 +206,32 @@ func (vk *VerifyingKey) Verify(commitment curve.G1Affine, knowledgeProof curve.G } func getChallenge(fiatshamirSeeds [][]byte) (r fr.Element, err error) { - // incorporate user-provided seeds into the transcript - t := fiatshamir.NewTranscript(sha256.New(), "r") - for i := range fiatshamirSeeds { - if err = t.Bind("r", fiatshamirSeeds[i]); err != nil { - return - } - } - - // obtain the challenge - var rBytes []byte - - if rBytes, err = t.ComputeChallenge("r"); err != nil { - return - } - r.SetBytes(rBytes) // TODO @Tabaie Plonk challenge generation done the same way; replace both with hash to fr? - return + // incorporate user-provided seeds into the transcript + t := fiatshamir.NewTranscript(sha256.New(), "r") + for i := range fiatshamirSeeds { + if err = t.Bind("r", fiatshamirSeeds[i]); err != nil { + return + } + } + + // obtain the challenge + var rBytes []byte + + if rBytes, err = t.ComputeChallenge("r"); err != nil { + return + } + r.SetBytes(rBytes) // TODO @Tabaie Plonk challenge generation done the same way; replace both with hash to fr? + return } // Marshal func (pk *ProvingKey) writeTo(enc *curve.Encoder) (int64, error) { - if err := enc.Encode(pk.basis); err != nil { - return enc.BytesWritten(), err - } + if err := enc.Encode(pk.Basis); err != nil { + return enc.BytesWritten(), err + } - err := enc.Encode(pk.basisExpSigma) + err := enc.Encode(pk.BasisExpSigma) return enc.BytesWritten(), err } @@ -247,16 +247,16 @@ func (pk *ProvingKey) WriteRawTo(w io.Writer) (int64, error) { func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { dec := curve.NewDecoder(r) - if err := dec.Decode(&pk.basis); err != nil { + if err := dec.Decode(&pk.Basis); err != nil { + return dec.BytesRead(), err + } + if err := dec.Decode(&pk.BasisExpSigma); err != nil { return dec.BytesRead(), err } - if err := dec.Decode(&pk.basisExpSigma); err != nil { - return dec.BytesRead(), err - } - if cL, pL := len(pk.basis), len(pk.basisExpSigma); cL != pL { - return dec.BytesRead(), fmt.Errorf("commitment basis size (%d) doesn't match proof basis size (%d)", cL, pL) - } + if cL, pL := len(pk.Basis), len(pk.BasisExpSigma); cL != pL { + return dec.BytesRead(), fmt.Errorf("commitment basis size (%d) doesn't match proof basis size (%d)", cL, pL) + } return dec.BytesRead(), nil } diff --git a/internal/generator/pedersen/template/pedersen.test.go.tmpl b/internal/generator/pedersen/template/pedersen.test.go.tmpl index f8556b811a..d2d0f61df0 100644 --- a/internal/generator/pedersen/template/pedersen.test.go.tmpl +++ b/internal/generator/pedersen/template/pedersen.test.go.tmpl @@ -52,7 +52,7 @@ func testCommit(t *testing.T, values ...interface{}) { var ( pk []ProvingKey vk VerifyingKey - err error + err error commitment, pok curve.G1Affine ) valuesFr := interfaceSliceToFrSlice(t, values...) @@ -103,7 +103,7 @@ func TestFoldProofs(t *testing.T) { assert.Equal(t, pok, pokFolded) }) - t.Run("run empty", func (t *testing.T) { + t.Run("run empty", func(t *testing.T) { var foldedCommitment curve.G1Affine pok, err := BatchProve([]ProvingKey{}, [][]fr.Element{}, []byte("test")) assert.NoError(t, err) @@ -148,8 +148,8 @@ func TestCommitFiveElements(t *testing.T) { func TestMarshal(t *testing.T) { var pk ProvingKey - pk.basisExpSigma = randomG1Slice(t, 5) - pk.basis = randomG1Slice(t, 5) + pk.BasisExpSigma = randomG1Slice(t, 5) + pk.Basis = randomG1Slice(t, 5) var ( vk VerifyingKey From 6fe7c4a34943c6b89a55376c4a87f85d9fac6c65 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Thu, 2 May 2024 20:32:56 -0500 Subject: [PATCH 2/3] feat: more elegant solution to mem dump using unsafe and generics --- ecc/bls12-377/kzg/kzg_test.go | 33 ++++--- ecc/bls12-377/kzg/marshal.go | 85 ++++------------ ecc/bls12-378/kzg/kzg_test.go | 33 ++++--- ecc/bls12-378/kzg/marshal.go | 85 ++++------------ ecc/bls12-381/kzg/kzg_test.go | 33 ++++--- ecc/bls12-381/kzg/marshal.go | 85 ++++------------ ecc/bls24-315/kzg/kzg_test.go | 33 ++++--- ecc/bls24-315/kzg/marshal.go | 85 ++++------------ ecc/bls24-317/kzg/kzg_test.go | 33 ++++--- ecc/bls24-317/kzg/marshal.go | 85 ++++------------ ecc/bn254/kzg/kzg_test.go | 33 ++++--- ecc/bn254/kzg/marshal.go | 85 ++++------------ ecc/bw6-633/kzg/kzg_test.go | 33 ++++--- ecc/bw6-633/kzg/marshal.go | 85 ++++------------ ecc/bw6-756/kzg/kzg_test.go | 33 ++++--- ecc/bw6-756/kzg/marshal.go | 85 ++++------------ ecc/bw6-761/kzg/kzg_test.go | 33 ++++--- ecc/bw6-761/kzg/marshal.go | 85 ++++------------ .../generator/kzg/template/kzg.test.go.tmpl | 33 ++++--- .../generator/kzg/template/marshal.go.tmpl | 85 ++++------------ utils/arith.go | 23 ----- utils/testutils/testing.go | 15 +-- utils/unsafe/dump_slice.go | 98 +++++++++++++++++++ utils/unsafe/dump_slice_test.go | 52 ++++++++++ 24 files changed, 548 insertions(+), 820 deletions(-) create mode 100644 utils/unsafe/dump_slice.go create mode 100644 utils/unsafe/dump_slice_test.go diff --git a/ecc/bls12-377/kzg/kzg_test.go b/ecc/bls12-377/kzg/kzg_test.go index c7b21555d0..8110a9be4a 100644 --- a/ecc/bls12-377/kzg/kzg_test.go +++ b/ecc/bls12-377/kzg/kzg_test.go @@ -441,12 +441,15 @@ func TestUnsafeToBytesTruncating(t *testing.T) { assert.NoError(err) // marshal the SRS, but explicitly with less points. - d, err := srs.UnsafeToBytes(1 << 9) + var buf bytes.Buffer + err = srs.WriteDump(&buf, 1<<9) assert.NoError(err) + r := bytes.NewReader(buf.Bytes()) + // unmarshal the SRS var newSRS SRS - err = newSRS.UnsafeFromBytes(d) + err = newSRS.ReadDump(r) assert.NoError(err) // check that the SRS proving key has only 1 << 9 points @@ -457,7 +460,8 @@ func TestUnsafeToBytesTruncating(t *testing.T) { // read even less points. var newSRSPartial SRS - err = newSRSPartial.UnsafeFromBytes(d, 1<<8) + r = bytes.NewReader(buf.Bytes()) + err = newSRSPartial.ReadDump(r, 1<<8) assert.NoError(err) // check that the SRS proving key has only 1 << 8 points @@ -662,7 +666,7 @@ func BenchmarkSerializeSRS(b *testing.B) { b.Fatal(err) } - // now we can benchmark the WriteTo, WriteRawTo and UnsafeToBytes methods + // now we can benchmark the WriteTo, WriteRawTo and WriteDump methods b.Run("WriteTo", func(b *testing.B) { b.ResetTimer() var buf bytes.Buffer @@ -687,17 +691,15 @@ func BenchmarkSerializeSRS(b *testing.B) { } }) - b.Run("UnsafeToBytes", func(b *testing.B) { + b.Run("WriteDump", func(b *testing.B) { b.ResetTimer() - var d []byte - var err error + var buf bytes.Buffer for i := 0; i < b.N; i++ { - d, err = srs.UnsafeToBytes() - if err != nil { + buf.Reset() + if err := srs.WriteDump(&buf); err != nil { b.Fatal(err) } } - _ = d }) } @@ -711,8 +713,7 @@ func BenchmarkDeserializeSRS(b *testing.B) { b.Run("UnsafeReadFrom", func(b *testing.B) { var buf bytes.Buffer - _, err := srs.WriteRawTo(&buf) - if err != nil { + if _, err := srs.WriteRawTo(&buf); err != nil { b.Fatal(err) } b.ResetTimer() @@ -725,15 +726,17 @@ func BenchmarkDeserializeSRS(b *testing.B) { } }) - b.Run("UnsafeFromBytes", func(b *testing.B) { - d, err := srs.UnsafeToBytes() + b.Run("ReadDump", func(b *testing.B) { + var buf bytes.Buffer + err := srs.WriteDump(&buf) if err != nil { b.Fatal(err) } + data := buf.Bytes() b.ResetTimer() for i := 0; i < b.N; i++ { var newSRS SRS - if err := newSRS.UnsafeFromBytes(d); err != nil { + if err := newSRS.ReadDump(bytes.NewReader(data)); err != nil { b.Fatal(err) } } diff --git a/ecc/bls12-377/kzg/marshal.go b/ecc/bls12-377/kzg/marshal.go index 5fc96ba74d..64e344ee4e 100644 --- a/ecc/bls12-377/kzg/marshal.go +++ b/ecc/bls12-377/kzg/marshal.go @@ -17,11 +17,10 @@ package kzg import ( - "bytes" - "encoding/binary" "github.com/consensys/gnark-crypto/ecc/bls12-377" - "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" "io" + + "github.com/consensys/gnark-crypto/utils/unsafe" ) // WriteTo writes binary encoding of the ProvingKey @@ -79,91 +78,49 @@ func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*bls12377.Encoder)) return enc.BytesWritten(), nil } -// UnsafeToBytes returns the binary encoding of the entire SRS memory representation +// WriteDump writes the binary encoding of the entire SRS memory representation // It is meant to be use to achieve fast serialization/deserialization and // is not compatible with WriteTo / ReadFrom. It does not do any validation // and doesn't encode points in a canonical form. +// @unsafe: this is platform dependent and may not be compatible with other platforms // @unstable: the format may change in the future // If maxPkPoints is provided, the number of points in the ProvingKey will be limited to maxPkPoints -func (srs *SRS) UnsafeToBytes(maxPkPoints ...int) ([]byte, error) { +func (srs *SRS) WriteDump(w io.Writer, maxPkPoints ...int) error { maxG1 := len(srs.Pk.G1) if len(maxPkPoints) > 0 && maxPkPoints[0] < maxG1 && maxPkPoints[0] > 0 { maxG1 = maxPkPoints[0] } // first we write the VerifyingKey; it is small so we re-use WriteTo - var buf bytes.Buffer - if _, err := srs.Vk.writeTo(&buf, bls12377.RawEncoding()); err != nil { - return nil, err + if _, err := srs.Vk.writeTo(w, bls12377.RawEncoding()); err != nil { + return err } - buf.Grow(2*maxG1*fp.Bytes + 8) // pre-allocate space for the ProvingKey - - // write nb points we encode. - if err := binary.Write(&buf, binary.LittleEndian, uint64(maxG1)); err != nil { - return nil, err + // write the marker + if err := unsafe.WriteMarker(w); err != nil { + return err } - // write the limbs directly - var bbuf [fp.Bytes * 2]byte - for i := 0; i < maxG1; i++ { - for j := 0; j < fp.Limbs; j++ { - binary.LittleEndian.PutUint64(bbuf[j*8:j*8+8], srs.Pk.G1[i].X[j]) - } - for j := 0; j < fp.Limbs; j++ { - binary.LittleEndian.PutUint64(bbuf[fp.Bytes+j*8:fp.Bytes+j*8+8], srs.Pk.G1[i].Y[j]) - } - if _, err := buf.Write(bbuf[:]); err != nil { - return nil, err - } - } - return buf.Bytes(), nil + // write the slice + return unsafe.WriteSlice(w, srs.Pk.G1[:maxG1]) } -// UnsafeFromBytes deserializes the SRS from a byte slice -// It is meant to be use to achieve fast serialization/deserialization and -// is not compatible with WriteTo / ReadFrom. It does not do any validation -// and doesn't encode points in a canonical form. -// @unstable: the format may change in the future -func (srs *SRS) UnsafeFromBytes(data []byte, maxPkPoints ...int) error { +// ReadDump deserializes the SRS from a reader, as written by WriteDump +func (srs *SRS) ReadDump(r io.Reader, maxPkPoints ...int) error { // first we read the VerifyingKey; it is small so we re-use ReadFrom - n, err := srs.Vk.ReadFrom(bytes.NewReader(data)) + _, err := srs.Vk.ReadFrom(r) if err != nil { return err } - data = data[n:] - if len(data) < 8 { - return io.ErrUnexpectedEOF - } - - // read nb points we encode. - nbPoints := binary.LittleEndian.Uint64(data[:8]) - data = data[8:] - - // check the length of data - if len(data) < int(nbPoints)*2*fp.Bytes { - return io.ErrUnexpectedEOF - } - - if len(maxPkPoints) == 1 && maxPkPoints[0] > 0 && int(nbPoints) > maxPkPoints[0] { - nbPoints = uint64(maxPkPoints[0]) + // read the marker + if err := unsafe.ReadMarker(r); err != nil { + return err } - srs.Pk.G1 = make([]bls12377.G1Affine, nbPoints) - - // read the limbs directly - var bbuf [fp.Bytes * 2]byte - for i := 0; i < int(nbPoints); i++ { - copy(bbuf[:], data[i*2*fp.Bytes:(i+1)*2*fp.Bytes]) - for j := 0; j < fp.Limbs; j++ { - srs.Pk.G1[i].X[j] = binary.LittleEndian.Uint64(bbuf[j*8 : j*8+8]) - } - for j := 0; j < fp.Limbs; j++ { - srs.Pk.G1[i].Y[j] = binary.LittleEndian.Uint64(bbuf[fp.Bytes+j*8 : fp.Bytes+j*8+8]) - } - } - return nil + // read the slice + srs.Pk.G1, _, err = unsafe.ReadSlice[[]bls12377.G1Affine](r, maxPkPoints...) + return err } // WriteTo writes binary encoding of the entire SRS diff --git a/ecc/bls12-378/kzg/kzg_test.go b/ecc/bls12-378/kzg/kzg_test.go index 4ec5c2db65..156a1730de 100644 --- a/ecc/bls12-378/kzg/kzg_test.go +++ b/ecc/bls12-378/kzg/kzg_test.go @@ -441,12 +441,15 @@ func TestUnsafeToBytesTruncating(t *testing.T) { assert.NoError(err) // marshal the SRS, but explicitly with less points. - d, err := srs.UnsafeToBytes(1 << 9) + var buf bytes.Buffer + err = srs.WriteDump(&buf, 1<<9) assert.NoError(err) + r := bytes.NewReader(buf.Bytes()) + // unmarshal the SRS var newSRS SRS - err = newSRS.UnsafeFromBytes(d) + err = newSRS.ReadDump(r) assert.NoError(err) // check that the SRS proving key has only 1 << 9 points @@ -457,7 +460,8 @@ func TestUnsafeToBytesTruncating(t *testing.T) { // read even less points. var newSRSPartial SRS - err = newSRSPartial.UnsafeFromBytes(d, 1<<8) + r = bytes.NewReader(buf.Bytes()) + err = newSRSPartial.ReadDump(r, 1<<8) assert.NoError(err) // check that the SRS proving key has only 1 << 8 points @@ -662,7 +666,7 @@ func BenchmarkSerializeSRS(b *testing.B) { b.Fatal(err) } - // now we can benchmark the WriteTo, WriteRawTo and UnsafeToBytes methods + // now we can benchmark the WriteTo, WriteRawTo and WriteDump methods b.Run("WriteTo", func(b *testing.B) { b.ResetTimer() var buf bytes.Buffer @@ -687,17 +691,15 @@ func BenchmarkSerializeSRS(b *testing.B) { } }) - b.Run("UnsafeToBytes", func(b *testing.B) { + b.Run("WriteDump", func(b *testing.B) { b.ResetTimer() - var d []byte - var err error + var buf bytes.Buffer for i := 0; i < b.N; i++ { - d, err = srs.UnsafeToBytes() - if err != nil { + buf.Reset() + if err := srs.WriteDump(&buf); err != nil { b.Fatal(err) } } - _ = d }) } @@ -711,8 +713,7 @@ func BenchmarkDeserializeSRS(b *testing.B) { b.Run("UnsafeReadFrom", func(b *testing.B) { var buf bytes.Buffer - _, err := srs.WriteRawTo(&buf) - if err != nil { + if _, err := srs.WriteRawTo(&buf); err != nil { b.Fatal(err) } b.ResetTimer() @@ -725,15 +726,17 @@ func BenchmarkDeserializeSRS(b *testing.B) { } }) - b.Run("UnsafeFromBytes", func(b *testing.B) { - d, err := srs.UnsafeToBytes() + b.Run("ReadDump", func(b *testing.B) { + var buf bytes.Buffer + err := srs.WriteDump(&buf) if err != nil { b.Fatal(err) } + data := buf.Bytes() b.ResetTimer() for i := 0; i < b.N; i++ { var newSRS SRS - if err := newSRS.UnsafeFromBytes(d); err != nil { + if err := newSRS.ReadDump(bytes.NewReader(data)); err != nil { b.Fatal(err) } } diff --git a/ecc/bls12-378/kzg/marshal.go b/ecc/bls12-378/kzg/marshal.go index 18caf74b48..f3349849c9 100644 --- a/ecc/bls12-378/kzg/marshal.go +++ b/ecc/bls12-378/kzg/marshal.go @@ -17,11 +17,10 @@ package kzg import ( - "bytes" - "encoding/binary" "github.com/consensys/gnark-crypto/ecc/bls12-378" - "github.com/consensys/gnark-crypto/ecc/bls12-378/fp" "io" + + "github.com/consensys/gnark-crypto/utils/unsafe" ) // WriteTo writes binary encoding of the ProvingKey @@ -79,91 +78,49 @@ func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*bls12378.Encoder)) return enc.BytesWritten(), nil } -// UnsafeToBytes returns the binary encoding of the entire SRS memory representation +// WriteDump writes the binary encoding of the entire SRS memory representation // It is meant to be use to achieve fast serialization/deserialization and // is not compatible with WriteTo / ReadFrom. It does not do any validation // and doesn't encode points in a canonical form. +// @unsafe: this is platform dependent and may not be compatible with other platforms // @unstable: the format may change in the future // If maxPkPoints is provided, the number of points in the ProvingKey will be limited to maxPkPoints -func (srs *SRS) UnsafeToBytes(maxPkPoints ...int) ([]byte, error) { +func (srs *SRS) WriteDump(w io.Writer, maxPkPoints ...int) error { maxG1 := len(srs.Pk.G1) if len(maxPkPoints) > 0 && maxPkPoints[0] < maxG1 && maxPkPoints[0] > 0 { maxG1 = maxPkPoints[0] } // first we write the VerifyingKey; it is small so we re-use WriteTo - var buf bytes.Buffer - if _, err := srs.Vk.writeTo(&buf, bls12378.RawEncoding()); err != nil { - return nil, err + if _, err := srs.Vk.writeTo(w, bls12378.RawEncoding()); err != nil { + return err } - buf.Grow(2*maxG1*fp.Bytes + 8) // pre-allocate space for the ProvingKey - - // write nb points we encode. - if err := binary.Write(&buf, binary.LittleEndian, uint64(maxG1)); err != nil { - return nil, err + // write the marker + if err := unsafe.WriteMarker(w); err != nil { + return err } - // write the limbs directly - var bbuf [fp.Bytes * 2]byte - for i := 0; i < maxG1; i++ { - for j := 0; j < fp.Limbs; j++ { - binary.LittleEndian.PutUint64(bbuf[j*8:j*8+8], srs.Pk.G1[i].X[j]) - } - for j := 0; j < fp.Limbs; j++ { - binary.LittleEndian.PutUint64(bbuf[fp.Bytes+j*8:fp.Bytes+j*8+8], srs.Pk.G1[i].Y[j]) - } - if _, err := buf.Write(bbuf[:]); err != nil { - return nil, err - } - } - return buf.Bytes(), nil + // write the slice + return unsafe.WriteSlice(w, srs.Pk.G1[:maxG1]) } -// UnsafeFromBytes deserializes the SRS from a byte slice -// It is meant to be use to achieve fast serialization/deserialization and -// is not compatible with WriteTo / ReadFrom. It does not do any validation -// and doesn't encode points in a canonical form. -// @unstable: the format may change in the future -func (srs *SRS) UnsafeFromBytes(data []byte, maxPkPoints ...int) error { +// ReadDump deserializes the SRS from a reader, as written by WriteDump +func (srs *SRS) ReadDump(r io.Reader, maxPkPoints ...int) error { // first we read the VerifyingKey; it is small so we re-use ReadFrom - n, err := srs.Vk.ReadFrom(bytes.NewReader(data)) + _, err := srs.Vk.ReadFrom(r) if err != nil { return err } - data = data[n:] - if len(data) < 8 { - return io.ErrUnexpectedEOF - } - - // read nb points we encode. - nbPoints := binary.LittleEndian.Uint64(data[:8]) - data = data[8:] - - // check the length of data - if len(data) < int(nbPoints)*2*fp.Bytes { - return io.ErrUnexpectedEOF - } - - if len(maxPkPoints) == 1 && maxPkPoints[0] > 0 && int(nbPoints) > maxPkPoints[0] { - nbPoints = uint64(maxPkPoints[0]) + // read the marker + if err := unsafe.ReadMarker(r); err != nil { + return err } - srs.Pk.G1 = make([]bls12378.G1Affine, nbPoints) - - // read the limbs directly - var bbuf [fp.Bytes * 2]byte - for i := 0; i < int(nbPoints); i++ { - copy(bbuf[:], data[i*2*fp.Bytes:(i+1)*2*fp.Bytes]) - for j := 0; j < fp.Limbs; j++ { - srs.Pk.G1[i].X[j] = binary.LittleEndian.Uint64(bbuf[j*8 : j*8+8]) - } - for j := 0; j < fp.Limbs; j++ { - srs.Pk.G1[i].Y[j] = binary.LittleEndian.Uint64(bbuf[fp.Bytes+j*8 : fp.Bytes+j*8+8]) - } - } - return nil + // read the slice + srs.Pk.G1, _, err = unsafe.ReadSlice[[]bls12378.G1Affine](r, maxPkPoints...) + return err } // WriteTo writes binary encoding of the entire SRS diff --git a/ecc/bls12-381/kzg/kzg_test.go b/ecc/bls12-381/kzg/kzg_test.go index dc5b8fe63d..cfc72f3878 100644 --- a/ecc/bls12-381/kzg/kzg_test.go +++ b/ecc/bls12-381/kzg/kzg_test.go @@ -441,12 +441,15 @@ func TestUnsafeToBytesTruncating(t *testing.T) { assert.NoError(err) // marshal the SRS, but explicitly with less points. - d, err := srs.UnsafeToBytes(1 << 9) + var buf bytes.Buffer + err = srs.WriteDump(&buf, 1<<9) assert.NoError(err) + r := bytes.NewReader(buf.Bytes()) + // unmarshal the SRS var newSRS SRS - err = newSRS.UnsafeFromBytes(d) + err = newSRS.ReadDump(r) assert.NoError(err) // check that the SRS proving key has only 1 << 9 points @@ -457,7 +460,8 @@ func TestUnsafeToBytesTruncating(t *testing.T) { // read even less points. var newSRSPartial SRS - err = newSRSPartial.UnsafeFromBytes(d, 1<<8) + r = bytes.NewReader(buf.Bytes()) + err = newSRSPartial.ReadDump(r, 1<<8) assert.NoError(err) // check that the SRS proving key has only 1 << 8 points @@ -662,7 +666,7 @@ func BenchmarkSerializeSRS(b *testing.B) { b.Fatal(err) } - // now we can benchmark the WriteTo, WriteRawTo and UnsafeToBytes methods + // now we can benchmark the WriteTo, WriteRawTo and WriteDump methods b.Run("WriteTo", func(b *testing.B) { b.ResetTimer() var buf bytes.Buffer @@ -687,17 +691,15 @@ func BenchmarkSerializeSRS(b *testing.B) { } }) - b.Run("UnsafeToBytes", func(b *testing.B) { + b.Run("WriteDump", func(b *testing.B) { b.ResetTimer() - var d []byte - var err error + var buf bytes.Buffer for i := 0; i < b.N; i++ { - d, err = srs.UnsafeToBytes() - if err != nil { + buf.Reset() + if err := srs.WriteDump(&buf); err != nil { b.Fatal(err) } } - _ = d }) } @@ -711,8 +713,7 @@ func BenchmarkDeserializeSRS(b *testing.B) { b.Run("UnsafeReadFrom", func(b *testing.B) { var buf bytes.Buffer - _, err := srs.WriteRawTo(&buf) - if err != nil { + if _, err := srs.WriteRawTo(&buf); err != nil { b.Fatal(err) } b.ResetTimer() @@ -725,15 +726,17 @@ func BenchmarkDeserializeSRS(b *testing.B) { } }) - b.Run("UnsafeFromBytes", func(b *testing.B) { - d, err := srs.UnsafeToBytes() + b.Run("ReadDump", func(b *testing.B) { + var buf bytes.Buffer + err := srs.WriteDump(&buf) if err != nil { b.Fatal(err) } + data := buf.Bytes() b.ResetTimer() for i := 0; i < b.N; i++ { var newSRS SRS - if err := newSRS.UnsafeFromBytes(d); err != nil { + if err := newSRS.ReadDump(bytes.NewReader(data)); err != nil { b.Fatal(err) } } diff --git a/ecc/bls12-381/kzg/marshal.go b/ecc/bls12-381/kzg/marshal.go index d20556b9b5..bbfe032976 100644 --- a/ecc/bls12-381/kzg/marshal.go +++ b/ecc/bls12-381/kzg/marshal.go @@ -17,11 +17,10 @@ package kzg import ( - "bytes" - "encoding/binary" "github.com/consensys/gnark-crypto/ecc/bls12-381" - "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" "io" + + "github.com/consensys/gnark-crypto/utils/unsafe" ) // WriteTo writes binary encoding of the ProvingKey @@ -79,91 +78,49 @@ func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*bls12381.Encoder)) return enc.BytesWritten(), nil } -// UnsafeToBytes returns the binary encoding of the entire SRS memory representation +// WriteDump writes the binary encoding of the entire SRS memory representation // It is meant to be use to achieve fast serialization/deserialization and // is not compatible with WriteTo / ReadFrom. It does not do any validation // and doesn't encode points in a canonical form. +// @unsafe: this is platform dependent and may not be compatible with other platforms // @unstable: the format may change in the future // If maxPkPoints is provided, the number of points in the ProvingKey will be limited to maxPkPoints -func (srs *SRS) UnsafeToBytes(maxPkPoints ...int) ([]byte, error) { +func (srs *SRS) WriteDump(w io.Writer, maxPkPoints ...int) error { maxG1 := len(srs.Pk.G1) if len(maxPkPoints) > 0 && maxPkPoints[0] < maxG1 && maxPkPoints[0] > 0 { maxG1 = maxPkPoints[0] } // first we write the VerifyingKey; it is small so we re-use WriteTo - var buf bytes.Buffer - if _, err := srs.Vk.writeTo(&buf, bls12381.RawEncoding()); err != nil { - return nil, err + if _, err := srs.Vk.writeTo(w, bls12381.RawEncoding()); err != nil { + return err } - buf.Grow(2*maxG1*fp.Bytes + 8) // pre-allocate space for the ProvingKey - - // write nb points we encode. - if err := binary.Write(&buf, binary.LittleEndian, uint64(maxG1)); err != nil { - return nil, err + // write the marker + if err := unsafe.WriteMarker(w); err != nil { + return err } - // write the limbs directly - var bbuf [fp.Bytes * 2]byte - for i := 0; i < maxG1; i++ { - for j := 0; j < fp.Limbs; j++ { - binary.LittleEndian.PutUint64(bbuf[j*8:j*8+8], srs.Pk.G1[i].X[j]) - } - for j := 0; j < fp.Limbs; j++ { - binary.LittleEndian.PutUint64(bbuf[fp.Bytes+j*8:fp.Bytes+j*8+8], srs.Pk.G1[i].Y[j]) - } - if _, err := buf.Write(bbuf[:]); err != nil { - return nil, err - } - } - return buf.Bytes(), nil + // write the slice + return unsafe.WriteSlice(w, srs.Pk.G1[:maxG1]) } -// UnsafeFromBytes deserializes the SRS from a byte slice -// It is meant to be use to achieve fast serialization/deserialization and -// is not compatible with WriteTo / ReadFrom. It does not do any validation -// and doesn't encode points in a canonical form. -// @unstable: the format may change in the future -func (srs *SRS) UnsafeFromBytes(data []byte, maxPkPoints ...int) error { +// ReadDump deserializes the SRS from a reader, as written by WriteDump +func (srs *SRS) ReadDump(r io.Reader, maxPkPoints ...int) error { // first we read the VerifyingKey; it is small so we re-use ReadFrom - n, err := srs.Vk.ReadFrom(bytes.NewReader(data)) + _, err := srs.Vk.ReadFrom(r) if err != nil { return err } - data = data[n:] - if len(data) < 8 { - return io.ErrUnexpectedEOF - } - - // read nb points we encode. - nbPoints := binary.LittleEndian.Uint64(data[:8]) - data = data[8:] - - // check the length of data - if len(data) < int(nbPoints)*2*fp.Bytes { - return io.ErrUnexpectedEOF - } - - if len(maxPkPoints) == 1 && maxPkPoints[0] > 0 && int(nbPoints) > maxPkPoints[0] { - nbPoints = uint64(maxPkPoints[0]) + // read the marker + if err := unsafe.ReadMarker(r); err != nil { + return err } - srs.Pk.G1 = make([]bls12381.G1Affine, nbPoints) - - // read the limbs directly - var bbuf [fp.Bytes * 2]byte - for i := 0; i < int(nbPoints); i++ { - copy(bbuf[:], data[i*2*fp.Bytes:(i+1)*2*fp.Bytes]) - for j := 0; j < fp.Limbs; j++ { - srs.Pk.G1[i].X[j] = binary.LittleEndian.Uint64(bbuf[j*8 : j*8+8]) - } - for j := 0; j < fp.Limbs; j++ { - srs.Pk.G1[i].Y[j] = binary.LittleEndian.Uint64(bbuf[fp.Bytes+j*8 : fp.Bytes+j*8+8]) - } - } - return nil + // read the slice + srs.Pk.G1, _, err = unsafe.ReadSlice[[]bls12381.G1Affine](r, maxPkPoints...) + return err } // WriteTo writes binary encoding of the entire SRS diff --git a/ecc/bls24-315/kzg/kzg_test.go b/ecc/bls24-315/kzg/kzg_test.go index fbfb97964b..805b6aaed5 100644 --- a/ecc/bls24-315/kzg/kzg_test.go +++ b/ecc/bls24-315/kzg/kzg_test.go @@ -441,12 +441,15 @@ func TestUnsafeToBytesTruncating(t *testing.T) { assert.NoError(err) // marshal the SRS, but explicitly with less points. - d, err := srs.UnsafeToBytes(1 << 9) + var buf bytes.Buffer + err = srs.WriteDump(&buf, 1<<9) assert.NoError(err) + r := bytes.NewReader(buf.Bytes()) + // unmarshal the SRS var newSRS SRS - err = newSRS.UnsafeFromBytes(d) + err = newSRS.ReadDump(r) assert.NoError(err) // check that the SRS proving key has only 1 << 9 points @@ -457,7 +460,8 @@ func TestUnsafeToBytesTruncating(t *testing.T) { // read even less points. var newSRSPartial SRS - err = newSRSPartial.UnsafeFromBytes(d, 1<<8) + r = bytes.NewReader(buf.Bytes()) + err = newSRSPartial.ReadDump(r, 1<<8) assert.NoError(err) // check that the SRS proving key has only 1 << 8 points @@ -662,7 +666,7 @@ func BenchmarkSerializeSRS(b *testing.B) { b.Fatal(err) } - // now we can benchmark the WriteTo, WriteRawTo and UnsafeToBytes methods + // now we can benchmark the WriteTo, WriteRawTo and WriteDump methods b.Run("WriteTo", func(b *testing.B) { b.ResetTimer() var buf bytes.Buffer @@ -687,17 +691,15 @@ func BenchmarkSerializeSRS(b *testing.B) { } }) - b.Run("UnsafeToBytes", func(b *testing.B) { + b.Run("WriteDump", func(b *testing.B) { b.ResetTimer() - var d []byte - var err error + var buf bytes.Buffer for i := 0; i < b.N; i++ { - d, err = srs.UnsafeToBytes() - if err != nil { + buf.Reset() + if err := srs.WriteDump(&buf); err != nil { b.Fatal(err) } } - _ = d }) } @@ -711,8 +713,7 @@ func BenchmarkDeserializeSRS(b *testing.B) { b.Run("UnsafeReadFrom", func(b *testing.B) { var buf bytes.Buffer - _, err := srs.WriteRawTo(&buf) - if err != nil { + if _, err := srs.WriteRawTo(&buf); err != nil { b.Fatal(err) } b.ResetTimer() @@ -725,15 +726,17 @@ func BenchmarkDeserializeSRS(b *testing.B) { } }) - b.Run("UnsafeFromBytes", func(b *testing.B) { - d, err := srs.UnsafeToBytes() + b.Run("ReadDump", func(b *testing.B) { + var buf bytes.Buffer + err := srs.WriteDump(&buf) if err != nil { b.Fatal(err) } + data := buf.Bytes() b.ResetTimer() for i := 0; i < b.N; i++ { var newSRS SRS - if err := newSRS.UnsafeFromBytes(d); err != nil { + if err := newSRS.ReadDump(bytes.NewReader(data)); err != nil { b.Fatal(err) } } diff --git a/ecc/bls24-315/kzg/marshal.go b/ecc/bls24-315/kzg/marshal.go index fdccfa979e..2d5c4ead9f 100644 --- a/ecc/bls24-315/kzg/marshal.go +++ b/ecc/bls24-315/kzg/marshal.go @@ -17,11 +17,10 @@ package kzg import ( - "bytes" - "encoding/binary" "github.com/consensys/gnark-crypto/ecc/bls24-315" - "github.com/consensys/gnark-crypto/ecc/bls24-315/fp" "io" + + "github.com/consensys/gnark-crypto/utils/unsafe" ) // WriteTo writes binary encoding of the ProvingKey @@ -79,91 +78,49 @@ func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*bls24315.Encoder)) return enc.BytesWritten(), nil } -// UnsafeToBytes returns the binary encoding of the entire SRS memory representation +// WriteDump writes the binary encoding of the entire SRS memory representation // It is meant to be use to achieve fast serialization/deserialization and // is not compatible with WriteTo / ReadFrom. It does not do any validation // and doesn't encode points in a canonical form. +// @unsafe: this is platform dependent and may not be compatible with other platforms // @unstable: the format may change in the future // If maxPkPoints is provided, the number of points in the ProvingKey will be limited to maxPkPoints -func (srs *SRS) UnsafeToBytes(maxPkPoints ...int) ([]byte, error) { +func (srs *SRS) WriteDump(w io.Writer, maxPkPoints ...int) error { maxG1 := len(srs.Pk.G1) if len(maxPkPoints) > 0 && maxPkPoints[0] < maxG1 && maxPkPoints[0] > 0 { maxG1 = maxPkPoints[0] } // first we write the VerifyingKey; it is small so we re-use WriteTo - var buf bytes.Buffer - if _, err := srs.Vk.writeTo(&buf, bls24315.RawEncoding()); err != nil { - return nil, err + if _, err := srs.Vk.writeTo(w, bls24315.RawEncoding()); err != nil { + return err } - buf.Grow(2*maxG1*fp.Bytes + 8) // pre-allocate space for the ProvingKey - - // write nb points we encode. - if err := binary.Write(&buf, binary.LittleEndian, uint64(maxG1)); err != nil { - return nil, err + // write the marker + if err := unsafe.WriteMarker(w); err != nil { + return err } - // write the limbs directly - var bbuf [fp.Bytes * 2]byte - for i := 0; i < maxG1; i++ { - for j := 0; j < fp.Limbs; j++ { - binary.LittleEndian.PutUint64(bbuf[j*8:j*8+8], srs.Pk.G1[i].X[j]) - } - for j := 0; j < fp.Limbs; j++ { - binary.LittleEndian.PutUint64(bbuf[fp.Bytes+j*8:fp.Bytes+j*8+8], srs.Pk.G1[i].Y[j]) - } - if _, err := buf.Write(bbuf[:]); err != nil { - return nil, err - } - } - return buf.Bytes(), nil + // write the slice + return unsafe.WriteSlice(w, srs.Pk.G1[:maxG1]) } -// UnsafeFromBytes deserializes the SRS from a byte slice -// It is meant to be use to achieve fast serialization/deserialization and -// is not compatible with WriteTo / ReadFrom. It does not do any validation -// and doesn't encode points in a canonical form. -// @unstable: the format may change in the future -func (srs *SRS) UnsafeFromBytes(data []byte, maxPkPoints ...int) error { +// ReadDump deserializes the SRS from a reader, as written by WriteDump +func (srs *SRS) ReadDump(r io.Reader, maxPkPoints ...int) error { // first we read the VerifyingKey; it is small so we re-use ReadFrom - n, err := srs.Vk.ReadFrom(bytes.NewReader(data)) + _, err := srs.Vk.ReadFrom(r) if err != nil { return err } - data = data[n:] - if len(data) < 8 { - return io.ErrUnexpectedEOF - } - - // read nb points we encode. - nbPoints := binary.LittleEndian.Uint64(data[:8]) - data = data[8:] - - // check the length of data - if len(data) < int(nbPoints)*2*fp.Bytes { - return io.ErrUnexpectedEOF - } - - if len(maxPkPoints) == 1 && maxPkPoints[0] > 0 && int(nbPoints) > maxPkPoints[0] { - nbPoints = uint64(maxPkPoints[0]) + // read the marker + if err := unsafe.ReadMarker(r); err != nil { + return err } - srs.Pk.G1 = make([]bls24315.G1Affine, nbPoints) - - // read the limbs directly - var bbuf [fp.Bytes * 2]byte - for i := 0; i < int(nbPoints); i++ { - copy(bbuf[:], data[i*2*fp.Bytes:(i+1)*2*fp.Bytes]) - for j := 0; j < fp.Limbs; j++ { - srs.Pk.G1[i].X[j] = binary.LittleEndian.Uint64(bbuf[j*8 : j*8+8]) - } - for j := 0; j < fp.Limbs; j++ { - srs.Pk.G1[i].Y[j] = binary.LittleEndian.Uint64(bbuf[fp.Bytes+j*8 : fp.Bytes+j*8+8]) - } - } - return nil + // read the slice + srs.Pk.G1, _, err = unsafe.ReadSlice[[]bls24315.G1Affine](r, maxPkPoints...) + return err } // WriteTo writes binary encoding of the entire SRS diff --git a/ecc/bls24-317/kzg/kzg_test.go b/ecc/bls24-317/kzg/kzg_test.go index ae38a3c2df..ebf4a58f11 100644 --- a/ecc/bls24-317/kzg/kzg_test.go +++ b/ecc/bls24-317/kzg/kzg_test.go @@ -441,12 +441,15 @@ func TestUnsafeToBytesTruncating(t *testing.T) { assert.NoError(err) // marshal the SRS, but explicitly with less points. - d, err := srs.UnsafeToBytes(1 << 9) + var buf bytes.Buffer + err = srs.WriteDump(&buf, 1<<9) assert.NoError(err) + r := bytes.NewReader(buf.Bytes()) + // unmarshal the SRS var newSRS SRS - err = newSRS.UnsafeFromBytes(d) + err = newSRS.ReadDump(r) assert.NoError(err) // check that the SRS proving key has only 1 << 9 points @@ -457,7 +460,8 @@ func TestUnsafeToBytesTruncating(t *testing.T) { // read even less points. var newSRSPartial SRS - err = newSRSPartial.UnsafeFromBytes(d, 1<<8) + r = bytes.NewReader(buf.Bytes()) + err = newSRSPartial.ReadDump(r, 1<<8) assert.NoError(err) // check that the SRS proving key has only 1 << 8 points @@ -662,7 +666,7 @@ func BenchmarkSerializeSRS(b *testing.B) { b.Fatal(err) } - // now we can benchmark the WriteTo, WriteRawTo and UnsafeToBytes methods + // now we can benchmark the WriteTo, WriteRawTo and WriteDump methods b.Run("WriteTo", func(b *testing.B) { b.ResetTimer() var buf bytes.Buffer @@ -687,17 +691,15 @@ func BenchmarkSerializeSRS(b *testing.B) { } }) - b.Run("UnsafeToBytes", func(b *testing.B) { + b.Run("WriteDump", func(b *testing.B) { b.ResetTimer() - var d []byte - var err error + var buf bytes.Buffer for i := 0; i < b.N; i++ { - d, err = srs.UnsafeToBytes() - if err != nil { + buf.Reset() + if err := srs.WriteDump(&buf); err != nil { b.Fatal(err) } } - _ = d }) } @@ -711,8 +713,7 @@ func BenchmarkDeserializeSRS(b *testing.B) { b.Run("UnsafeReadFrom", func(b *testing.B) { var buf bytes.Buffer - _, err := srs.WriteRawTo(&buf) - if err != nil { + if _, err := srs.WriteRawTo(&buf); err != nil { b.Fatal(err) } b.ResetTimer() @@ -725,15 +726,17 @@ func BenchmarkDeserializeSRS(b *testing.B) { } }) - b.Run("UnsafeFromBytes", func(b *testing.B) { - d, err := srs.UnsafeToBytes() + b.Run("ReadDump", func(b *testing.B) { + var buf bytes.Buffer + err := srs.WriteDump(&buf) if err != nil { b.Fatal(err) } + data := buf.Bytes() b.ResetTimer() for i := 0; i < b.N; i++ { var newSRS SRS - if err := newSRS.UnsafeFromBytes(d); err != nil { + if err := newSRS.ReadDump(bytes.NewReader(data)); err != nil { b.Fatal(err) } } diff --git a/ecc/bls24-317/kzg/marshal.go b/ecc/bls24-317/kzg/marshal.go index ea5682e008..3bab6e0062 100644 --- a/ecc/bls24-317/kzg/marshal.go +++ b/ecc/bls24-317/kzg/marshal.go @@ -17,11 +17,10 @@ package kzg import ( - "bytes" - "encoding/binary" "github.com/consensys/gnark-crypto/ecc/bls24-317" - "github.com/consensys/gnark-crypto/ecc/bls24-317/fp" "io" + + "github.com/consensys/gnark-crypto/utils/unsafe" ) // WriteTo writes binary encoding of the ProvingKey @@ -79,91 +78,49 @@ func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*bls24317.Encoder)) return enc.BytesWritten(), nil } -// UnsafeToBytes returns the binary encoding of the entire SRS memory representation +// WriteDump writes the binary encoding of the entire SRS memory representation // It is meant to be use to achieve fast serialization/deserialization and // is not compatible with WriteTo / ReadFrom. It does not do any validation // and doesn't encode points in a canonical form. +// @unsafe: this is platform dependent and may not be compatible with other platforms // @unstable: the format may change in the future // If maxPkPoints is provided, the number of points in the ProvingKey will be limited to maxPkPoints -func (srs *SRS) UnsafeToBytes(maxPkPoints ...int) ([]byte, error) { +func (srs *SRS) WriteDump(w io.Writer, maxPkPoints ...int) error { maxG1 := len(srs.Pk.G1) if len(maxPkPoints) > 0 && maxPkPoints[0] < maxG1 && maxPkPoints[0] > 0 { maxG1 = maxPkPoints[0] } // first we write the VerifyingKey; it is small so we re-use WriteTo - var buf bytes.Buffer - if _, err := srs.Vk.writeTo(&buf, bls24317.RawEncoding()); err != nil { - return nil, err + if _, err := srs.Vk.writeTo(w, bls24317.RawEncoding()); err != nil { + return err } - buf.Grow(2*maxG1*fp.Bytes + 8) // pre-allocate space for the ProvingKey - - // write nb points we encode. - if err := binary.Write(&buf, binary.LittleEndian, uint64(maxG1)); err != nil { - return nil, err + // write the marker + if err := unsafe.WriteMarker(w); err != nil { + return err } - // write the limbs directly - var bbuf [fp.Bytes * 2]byte - for i := 0; i < maxG1; i++ { - for j := 0; j < fp.Limbs; j++ { - binary.LittleEndian.PutUint64(bbuf[j*8:j*8+8], srs.Pk.G1[i].X[j]) - } - for j := 0; j < fp.Limbs; j++ { - binary.LittleEndian.PutUint64(bbuf[fp.Bytes+j*8:fp.Bytes+j*8+8], srs.Pk.G1[i].Y[j]) - } - if _, err := buf.Write(bbuf[:]); err != nil { - return nil, err - } - } - return buf.Bytes(), nil + // write the slice + return unsafe.WriteSlice(w, srs.Pk.G1[:maxG1]) } -// UnsafeFromBytes deserializes the SRS from a byte slice -// It is meant to be use to achieve fast serialization/deserialization and -// is not compatible with WriteTo / ReadFrom. It does not do any validation -// and doesn't encode points in a canonical form. -// @unstable: the format may change in the future -func (srs *SRS) UnsafeFromBytes(data []byte, maxPkPoints ...int) error { +// ReadDump deserializes the SRS from a reader, as written by WriteDump +func (srs *SRS) ReadDump(r io.Reader, maxPkPoints ...int) error { // first we read the VerifyingKey; it is small so we re-use ReadFrom - n, err := srs.Vk.ReadFrom(bytes.NewReader(data)) + _, err := srs.Vk.ReadFrom(r) if err != nil { return err } - data = data[n:] - if len(data) < 8 { - return io.ErrUnexpectedEOF - } - - // read nb points we encode. - nbPoints := binary.LittleEndian.Uint64(data[:8]) - data = data[8:] - - // check the length of data - if len(data) < int(nbPoints)*2*fp.Bytes { - return io.ErrUnexpectedEOF - } - - if len(maxPkPoints) == 1 && maxPkPoints[0] > 0 && int(nbPoints) > maxPkPoints[0] { - nbPoints = uint64(maxPkPoints[0]) + // read the marker + if err := unsafe.ReadMarker(r); err != nil { + return err } - srs.Pk.G1 = make([]bls24317.G1Affine, nbPoints) - - // read the limbs directly - var bbuf [fp.Bytes * 2]byte - for i := 0; i < int(nbPoints); i++ { - copy(bbuf[:], data[i*2*fp.Bytes:(i+1)*2*fp.Bytes]) - for j := 0; j < fp.Limbs; j++ { - srs.Pk.G1[i].X[j] = binary.LittleEndian.Uint64(bbuf[j*8 : j*8+8]) - } - for j := 0; j < fp.Limbs; j++ { - srs.Pk.G1[i].Y[j] = binary.LittleEndian.Uint64(bbuf[fp.Bytes+j*8 : fp.Bytes+j*8+8]) - } - } - return nil + // read the slice + srs.Pk.G1, _, err = unsafe.ReadSlice[[]bls24317.G1Affine](r, maxPkPoints...) + return err } // WriteTo writes binary encoding of the entire SRS diff --git a/ecc/bn254/kzg/kzg_test.go b/ecc/bn254/kzg/kzg_test.go index 389b140905..b9cd530535 100644 --- a/ecc/bn254/kzg/kzg_test.go +++ b/ecc/bn254/kzg/kzg_test.go @@ -441,12 +441,15 @@ func TestUnsafeToBytesTruncating(t *testing.T) { assert.NoError(err) // marshal the SRS, but explicitly with less points. - d, err := srs.UnsafeToBytes(1 << 9) + var buf bytes.Buffer + err = srs.WriteDump(&buf, 1<<9) assert.NoError(err) + r := bytes.NewReader(buf.Bytes()) + // unmarshal the SRS var newSRS SRS - err = newSRS.UnsafeFromBytes(d) + err = newSRS.ReadDump(r) assert.NoError(err) // check that the SRS proving key has only 1 << 9 points @@ -457,7 +460,8 @@ func TestUnsafeToBytesTruncating(t *testing.T) { // read even less points. var newSRSPartial SRS - err = newSRSPartial.UnsafeFromBytes(d, 1<<8) + r = bytes.NewReader(buf.Bytes()) + err = newSRSPartial.ReadDump(r, 1<<8) assert.NoError(err) // check that the SRS proving key has only 1 << 8 points @@ -662,7 +666,7 @@ func BenchmarkSerializeSRS(b *testing.B) { b.Fatal(err) } - // now we can benchmark the WriteTo, WriteRawTo and UnsafeToBytes methods + // now we can benchmark the WriteTo, WriteRawTo and WriteDump methods b.Run("WriteTo", func(b *testing.B) { b.ResetTimer() var buf bytes.Buffer @@ -687,17 +691,15 @@ func BenchmarkSerializeSRS(b *testing.B) { } }) - b.Run("UnsafeToBytes", func(b *testing.B) { + b.Run("WriteDump", func(b *testing.B) { b.ResetTimer() - var d []byte - var err error + var buf bytes.Buffer for i := 0; i < b.N; i++ { - d, err = srs.UnsafeToBytes() - if err != nil { + buf.Reset() + if err := srs.WriteDump(&buf); err != nil { b.Fatal(err) } } - _ = d }) } @@ -711,8 +713,7 @@ func BenchmarkDeserializeSRS(b *testing.B) { b.Run("UnsafeReadFrom", func(b *testing.B) { var buf bytes.Buffer - _, err := srs.WriteRawTo(&buf) - if err != nil { + if _, err := srs.WriteRawTo(&buf); err != nil { b.Fatal(err) } b.ResetTimer() @@ -725,15 +726,17 @@ func BenchmarkDeserializeSRS(b *testing.B) { } }) - b.Run("UnsafeFromBytes", func(b *testing.B) { - d, err := srs.UnsafeToBytes() + b.Run("ReadDump", func(b *testing.B) { + var buf bytes.Buffer + err := srs.WriteDump(&buf) if err != nil { b.Fatal(err) } + data := buf.Bytes() b.ResetTimer() for i := 0; i < b.N; i++ { var newSRS SRS - if err := newSRS.UnsafeFromBytes(d); err != nil { + if err := newSRS.ReadDump(bytes.NewReader(data)); err != nil { b.Fatal(err) } } diff --git a/ecc/bn254/kzg/marshal.go b/ecc/bn254/kzg/marshal.go index 9202cb4a4b..b633b9bcbd 100644 --- a/ecc/bn254/kzg/marshal.go +++ b/ecc/bn254/kzg/marshal.go @@ -17,11 +17,10 @@ package kzg import ( - "bytes" - "encoding/binary" "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark-crypto/ecc/bn254/fp" "io" + + "github.com/consensys/gnark-crypto/utils/unsafe" ) // WriteTo writes binary encoding of the ProvingKey @@ -79,91 +78,49 @@ func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*bn254.Encoder)) (i return enc.BytesWritten(), nil } -// UnsafeToBytes returns the binary encoding of the entire SRS memory representation +// WriteDump writes the binary encoding of the entire SRS memory representation // It is meant to be use to achieve fast serialization/deserialization and // is not compatible with WriteTo / ReadFrom. It does not do any validation // and doesn't encode points in a canonical form. +// @unsafe: this is platform dependent and may not be compatible with other platforms // @unstable: the format may change in the future // If maxPkPoints is provided, the number of points in the ProvingKey will be limited to maxPkPoints -func (srs *SRS) UnsafeToBytes(maxPkPoints ...int) ([]byte, error) { +func (srs *SRS) WriteDump(w io.Writer, maxPkPoints ...int) error { maxG1 := len(srs.Pk.G1) if len(maxPkPoints) > 0 && maxPkPoints[0] < maxG1 && maxPkPoints[0] > 0 { maxG1 = maxPkPoints[0] } // first we write the VerifyingKey; it is small so we re-use WriteTo - var buf bytes.Buffer - if _, err := srs.Vk.writeTo(&buf, bn254.RawEncoding()); err != nil { - return nil, err + if _, err := srs.Vk.writeTo(w, bn254.RawEncoding()); err != nil { + return err } - buf.Grow(2*maxG1*fp.Bytes + 8) // pre-allocate space for the ProvingKey - - // write nb points we encode. - if err := binary.Write(&buf, binary.LittleEndian, uint64(maxG1)); err != nil { - return nil, err + // write the marker + if err := unsafe.WriteMarker(w); err != nil { + return err } - // write the limbs directly - var bbuf [fp.Bytes * 2]byte - for i := 0; i < maxG1; i++ { - for j := 0; j < fp.Limbs; j++ { - binary.LittleEndian.PutUint64(bbuf[j*8:j*8+8], srs.Pk.G1[i].X[j]) - } - for j := 0; j < fp.Limbs; j++ { - binary.LittleEndian.PutUint64(bbuf[fp.Bytes+j*8:fp.Bytes+j*8+8], srs.Pk.G1[i].Y[j]) - } - if _, err := buf.Write(bbuf[:]); err != nil { - return nil, err - } - } - return buf.Bytes(), nil + // write the slice + return unsafe.WriteSlice(w, srs.Pk.G1[:maxG1]) } -// UnsafeFromBytes deserializes the SRS from a byte slice -// It is meant to be use to achieve fast serialization/deserialization and -// is not compatible with WriteTo / ReadFrom. It does not do any validation -// and doesn't encode points in a canonical form. -// @unstable: the format may change in the future -func (srs *SRS) UnsafeFromBytes(data []byte, maxPkPoints ...int) error { +// ReadDump deserializes the SRS from a reader, as written by WriteDump +func (srs *SRS) ReadDump(r io.Reader, maxPkPoints ...int) error { // first we read the VerifyingKey; it is small so we re-use ReadFrom - n, err := srs.Vk.ReadFrom(bytes.NewReader(data)) + _, err := srs.Vk.ReadFrom(r) if err != nil { return err } - data = data[n:] - if len(data) < 8 { - return io.ErrUnexpectedEOF - } - - // read nb points we encode. - nbPoints := binary.LittleEndian.Uint64(data[:8]) - data = data[8:] - - // check the length of data - if len(data) < int(nbPoints)*2*fp.Bytes { - return io.ErrUnexpectedEOF - } - - if len(maxPkPoints) == 1 && maxPkPoints[0] > 0 && int(nbPoints) > maxPkPoints[0] { - nbPoints = uint64(maxPkPoints[0]) + // read the marker + if err := unsafe.ReadMarker(r); err != nil { + return err } - srs.Pk.G1 = make([]bn254.G1Affine, nbPoints) - - // read the limbs directly - var bbuf [fp.Bytes * 2]byte - for i := 0; i < int(nbPoints); i++ { - copy(bbuf[:], data[i*2*fp.Bytes:(i+1)*2*fp.Bytes]) - for j := 0; j < fp.Limbs; j++ { - srs.Pk.G1[i].X[j] = binary.LittleEndian.Uint64(bbuf[j*8 : j*8+8]) - } - for j := 0; j < fp.Limbs; j++ { - srs.Pk.G1[i].Y[j] = binary.LittleEndian.Uint64(bbuf[fp.Bytes+j*8 : fp.Bytes+j*8+8]) - } - } - return nil + // read the slice + srs.Pk.G1, _, err = unsafe.ReadSlice[[]bn254.G1Affine](r, maxPkPoints...) + return err } // WriteTo writes binary encoding of the entire SRS diff --git a/ecc/bw6-633/kzg/kzg_test.go b/ecc/bw6-633/kzg/kzg_test.go index 25d1cb7181..62fad1e7ac 100644 --- a/ecc/bw6-633/kzg/kzg_test.go +++ b/ecc/bw6-633/kzg/kzg_test.go @@ -441,12 +441,15 @@ func TestUnsafeToBytesTruncating(t *testing.T) { assert.NoError(err) // marshal the SRS, but explicitly with less points. - d, err := srs.UnsafeToBytes(1 << 9) + var buf bytes.Buffer + err = srs.WriteDump(&buf, 1<<9) assert.NoError(err) + r := bytes.NewReader(buf.Bytes()) + // unmarshal the SRS var newSRS SRS - err = newSRS.UnsafeFromBytes(d) + err = newSRS.ReadDump(r) assert.NoError(err) // check that the SRS proving key has only 1 << 9 points @@ -457,7 +460,8 @@ func TestUnsafeToBytesTruncating(t *testing.T) { // read even less points. var newSRSPartial SRS - err = newSRSPartial.UnsafeFromBytes(d, 1<<8) + r = bytes.NewReader(buf.Bytes()) + err = newSRSPartial.ReadDump(r, 1<<8) assert.NoError(err) // check that the SRS proving key has only 1 << 8 points @@ -662,7 +666,7 @@ func BenchmarkSerializeSRS(b *testing.B) { b.Fatal(err) } - // now we can benchmark the WriteTo, WriteRawTo and UnsafeToBytes methods + // now we can benchmark the WriteTo, WriteRawTo and WriteDump methods b.Run("WriteTo", func(b *testing.B) { b.ResetTimer() var buf bytes.Buffer @@ -687,17 +691,15 @@ func BenchmarkSerializeSRS(b *testing.B) { } }) - b.Run("UnsafeToBytes", func(b *testing.B) { + b.Run("WriteDump", func(b *testing.B) { b.ResetTimer() - var d []byte - var err error + var buf bytes.Buffer for i := 0; i < b.N; i++ { - d, err = srs.UnsafeToBytes() - if err != nil { + buf.Reset() + if err := srs.WriteDump(&buf); err != nil { b.Fatal(err) } } - _ = d }) } @@ -711,8 +713,7 @@ func BenchmarkDeserializeSRS(b *testing.B) { b.Run("UnsafeReadFrom", func(b *testing.B) { var buf bytes.Buffer - _, err := srs.WriteRawTo(&buf) - if err != nil { + if _, err := srs.WriteRawTo(&buf); err != nil { b.Fatal(err) } b.ResetTimer() @@ -725,15 +726,17 @@ func BenchmarkDeserializeSRS(b *testing.B) { } }) - b.Run("UnsafeFromBytes", func(b *testing.B) { - d, err := srs.UnsafeToBytes() + b.Run("ReadDump", func(b *testing.B) { + var buf bytes.Buffer + err := srs.WriteDump(&buf) if err != nil { b.Fatal(err) } + data := buf.Bytes() b.ResetTimer() for i := 0; i < b.N; i++ { var newSRS SRS - if err := newSRS.UnsafeFromBytes(d); err != nil { + if err := newSRS.ReadDump(bytes.NewReader(data)); err != nil { b.Fatal(err) } } diff --git a/ecc/bw6-633/kzg/marshal.go b/ecc/bw6-633/kzg/marshal.go index 9c5f133700..8cbce1f179 100644 --- a/ecc/bw6-633/kzg/marshal.go +++ b/ecc/bw6-633/kzg/marshal.go @@ -17,11 +17,10 @@ package kzg import ( - "bytes" - "encoding/binary" "github.com/consensys/gnark-crypto/ecc/bw6-633" - "github.com/consensys/gnark-crypto/ecc/bw6-633/fp" "io" + + "github.com/consensys/gnark-crypto/utils/unsafe" ) // WriteTo writes binary encoding of the ProvingKey @@ -79,91 +78,49 @@ func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*bw6633.Encoder)) ( return enc.BytesWritten(), nil } -// UnsafeToBytes returns the binary encoding of the entire SRS memory representation +// WriteDump writes the binary encoding of the entire SRS memory representation // It is meant to be use to achieve fast serialization/deserialization and // is not compatible with WriteTo / ReadFrom. It does not do any validation // and doesn't encode points in a canonical form. +// @unsafe: this is platform dependent and may not be compatible with other platforms // @unstable: the format may change in the future // If maxPkPoints is provided, the number of points in the ProvingKey will be limited to maxPkPoints -func (srs *SRS) UnsafeToBytes(maxPkPoints ...int) ([]byte, error) { +func (srs *SRS) WriteDump(w io.Writer, maxPkPoints ...int) error { maxG1 := len(srs.Pk.G1) if len(maxPkPoints) > 0 && maxPkPoints[0] < maxG1 && maxPkPoints[0] > 0 { maxG1 = maxPkPoints[0] } // first we write the VerifyingKey; it is small so we re-use WriteTo - var buf bytes.Buffer - if _, err := srs.Vk.writeTo(&buf, bw6633.RawEncoding()); err != nil { - return nil, err + if _, err := srs.Vk.writeTo(w, bw6633.RawEncoding()); err != nil { + return err } - buf.Grow(2*maxG1*fp.Bytes + 8) // pre-allocate space for the ProvingKey - - // write nb points we encode. - if err := binary.Write(&buf, binary.LittleEndian, uint64(maxG1)); err != nil { - return nil, err + // write the marker + if err := unsafe.WriteMarker(w); err != nil { + return err } - // write the limbs directly - var bbuf [fp.Bytes * 2]byte - for i := 0; i < maxG1; i++ { - for j := 0; j < fp.Limbs; j++ { - binary.LittleEndian.PutUint64(bbuf[j*8:j*8+8], srs.Pk.G1[i].X[j]) - } - for j := 0; j < fp.Limbs; j++ { - binary.LittleEndian.PutUint64(bbuf[fp.Bytes+j*8:fp.Bytes+j*8+8], srs.Pk.G1[i].Y[j]) - } - if _, err := buf.Write(bbuf[:]); err != nil { - return nil, err - } - } - return buf.Bytes(), nil + // write the slice + return unsafe.WriteSlice(w, srs.Pk.G1[:maxG1]) } -// UnsafeFromBytes deserializes the SRS from a byte slice -// It is meant to be use to achieve fast serialization/deserialization and -// is not compatible with WriteTo / ReadFrom. It does not do any validation -// and doesn't encode points in a canonical form. -// @unstable: the format may change in the future -func (srs *SRS) UnsafeFromBytes(data []byte, maxPkPoints ...int) error { +// ReadDump deserializes the SRS from a reader, as written by WriteDump +func (srs *SRS) ReadDump(r io.Reader, maxPkPoints ...int) error { // first we read the VerifyingKey; it is small so we re-use ReadFrom - n, err := srs.Vk.ReadFrom(bytes.NewReader(data)) + _, err := srs.Vk.ReadFrom(r) if err != nil { return err } - data = data[n:] - if len(data) < 8 { - return io.ErrUnexpectedEOF - } - - // read nb points we encode. - nbPoints := binary.LittleEndian.Uint64(data[:8]) - data = data[8:] - - // check the length of data - if len(data) < int(nbPoints)*2*fp.Bytes { - return io.ErrUnexpectedEOF - } - - if len(maxPkPoints) == 1 && maxPkPoints[0] > 0 && int(nbPoints) > maxPkPoints[0] { - nbPoints = uint64(maxPkPoints[0]) + // read the marker + if err := unsafe.ReadMarker(r); err != nil { + return err } - srs.Pk.G1 = make([]bw6633.G1Affine, nbPoints) - - // read the limbs directly - var bbuf [fp.Bytes * 2]byte - for i := 0; i < int(nbPoints); i++ { - copy(bbuf[:], data[i*2*fp.Bytes:(i+1)*2*fp.Bytes]) - for j := 0; j < fp.Limbs; j++ { - srs.Pk.G1[i].X[j] = binary.LittleEndian.Uint64(bbuf[j*8 : j*8+8]) - } - for j := 0; j < fp.Limbs; j++ { - srs.Pk.G1[i].Y[j] = binary.LittleEndian.Uint64(bbuf[fp.Bytes+j*8 : fp.Bytes+j*8+8]) - } - } - return nil + // read the slice + srs.Pk.G1, _, err = unsafe.ReadSlice[[]bw6633.G1Affine](r, maxPkPoints...) + return err } // WriteTo writes binary encoding of the entire SRS diff --git a/ecc/bw6-756/kzg/kzg_test.go b/ecc/bw6-756/kzg/kzg_test.go index a6139c8744..1d40d4c950 100644 --- a/ecc/bw6-756/kzg/kzg_test.go +++ b/ecc/bw6-756/kzg/kzg_test.go @@ -441,12 +441,15 @@ func TestUnsafeToBytesTruncating(t *testing.T) { assert.NoError(err) // marshal the SRS, but explicitly with less points. - d, err := srs.UnsafeToBytes(1 << 9) + var buf bytes.Buffer + err = srs.WriteDump(&buf, 1<<9) assert.NoError(err) + r := bytes.NewReader(buf.Bytes()) + // unmarshal the SRS var newSRS SRS - err = newSRS.UnsafeFromBytes(d) + err = newSRS.ReadDump(r) assert.NoError(err) // check that the SRS proving key has only 1 << 9 points @@ -457,7 +460,8 @@ func TestUnsafeToBytesTruncating(t *testing.T) { // read even less points. var newSRSPartial SRS - err = newSRSPartial.UnsafeFromBytes(d, 1<<8) + r = bytes.NewReader(buf.Bytes()) + err = newSRSPartial.ReadDump(r, 1<<8) assert.NoError(err) // check that the SRS proving key has only 1 << 8 points @@ -662,7 +666,7 @@ func BenchmarkSerializeSRS(b *testing.B) { b.Fatal(err) } - // now we can benchmark the WriteTo, WriteRawTo and UnsafeToBytes methods + // now we can benchmark the WriteTo, WriteRawTo and WriteDump methods b.Run("WriteTo", func(b *testing.B) { b.ResetTimer() var buf bytes.Buffer @@ -687,17 +691,15 @@ func BenchmarkSerializeSRS(b *testing.B) { } }) - b.Run("UnsafeToBytes", func(b *testing.B) { + b.Run("WriteDump", func(b *testing.B) { b.ResetTimer() - var d []byte - var err error + var buf bytes.Buffer for i := 0; i < b.N; i++ { - d, err = srs.UnsafeToBytes() - if err != nil { + buf.Reset() + if err := srs.WriteDump(&buf); err != nil { b.Fatal(err) } } - _ = d }) } @@ -711,8 +713,7 @@ func BenchmarkDeserializeSRS(b *testing.B) { b.Run("UnsafeReadFrom", func(b *testing.B) { var buf bytes.Buffer - _, err := srs.WriteRawTo(&buf) - if err != nil { + if _, err := srs.WriteRawTo(&buf); err != nil { b.Fatal(err) } b.ResetTimer() @@ -725,15 +726,17 @@ func BenchmarkDeserializeSRS(b *testing.B) { } }) - b.Run("UnsafeFromBytes", func(b *testing.B) { - d, err := srs.UnsafeToBytes() + b.Run("ReadDump", func(b *testing.B) { + var buf bytes.Buffer + err := srs.WriteDump(&buf) if err != nil { b.Fatal(err) } + data := buf.Bytes() b.ResetTimer() for i := 0; i < b.N; i++ { var newSRS SRS - if err := newSRS.UnsafeFromBytes(d); err != nil { + if err := newSRS.ReadDump(bytes.NewReader(data)); err != nil { b.Fatal(err) } } diff --git a/ecc/bw6-756/kzg/marshal.go b/ecc/bw6-756/kzg/marshal.go index 2bc4e67c21..b74a955e20 100644 --- a/ecc/bw6-756/kzg/marshal.go +++ b/ecc/bw6-756/kzg/marshal.go @@ -17,11 +17,10 @@ package kzg import ( - "bytes" - "encoding/binary" "github.com/consensys/gnark-crypto/ecc/bw6-756" - "github.com/consensys/gnark-crypto/ecc/bw6-756/fp" "io" + + "github.com/consensys/gnark-crypto/utils/unsafe" ) // WriteTo writes binary encoding of the ProvingKey @@ -79,91 +78,49 @@ func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*bw6756.Encoder)) ( return enc.BytesWritten(), nil } -// UnsafeToBytes returns the binary encoding of the entire SRS memory representation +// WriteDump writes the binary encoding of the entire SRS memory representation // It is meant to be use to achieve fast serialization/deserialization and // is not compatible with WriteTo / ReadFrom. It does not do any validation // and doesn't encode points in a canonical form. +// @unsafe: this is platform dependent and may not be compatible with other platforms // @unstable: the format may change in the future // If maxPkPoints is provided, the number of points in the ProvingKey will be limited to maxPkPoints -func (srs *SRS) UnsafeToBytes(maxPkPoints ...int) ([]byte, error) { +func (srs *SRS) WriteDump(w io.Writer, maxPkPoints ...int) error { maxG1 := len(srs.Pk.G1) if len(maxPkPoints) > 0 && maxPkPoints[0] < maxG1 && maxPkPoints[0] > 0 { maxG1 = maxPkPoints[0] } // first we write the VerifyingKey; it is small so we re-use WriteTo - var buf bytes.Buffer - if _, err := srs.Vk.writeTo(&buf, bw6756.RawEncoding()); err != nil { - return nil, err + if _, err := srs.Vk.writeTo(w, bw6756.RawEncoding()); err != nil { + return err } - buf.Grow(2*maxG1*fp.Bytes + 8) // pre-allocate space for the ProvingKey - - // write nb points we encode. - if err := binary.Write(&buf, binary.LittleEndian, uint64(maxG1)); err != nil { - return nil, err + // write the marker + if err := unsafe.WriteMarker(w); err != nil { + return err } - // write the limbs directly - var bbuf [fp.Bytes * 2]byte - for i := 0; i < maxG1; i++ { - for j := 0; j < fp.Limbs; j++ { - binary.LittleEndian.PutUint64(bbuf[j*8:j*8+8], srs.Pk.G1[i].X[j]) - } - for j := 0; j < fp.Limbs; j++ { - binary.LittleEndian.PutUint64(bbuf[fp.Bytes+j*8:fp.Bytes+j*8+8], srs.Pk.G1[i].Y[j]) - } - if _, err := buf.Write(bbuf[:]); err != nil { - return nil, err - } - } - return buf.Bytes(), nil + // write the slice + return unsafe.WriteSlice(w, srs.Pk.G1[:maxG1]) } -// UnsafeFromBytes deserializes the SRS from a byte slice -// It is meant to be use to achieve fast serialization/deserialization and -// is not compatible with WriteTo / ReadFrom. It does not do any validation -// and doesn't encode points in a canonical form. -// @unstable: the format may change in the future -func (srs *SRS) UnsafeFromBytes(data []byte, maxPkPoints ...int) error { +// ReadDump deserializes the SRS from a reader, as written by WriteDump +func (srs *SRS) ReadDump(r io.Reader, maxPkPoints ...int) error { // first we read the VerifyingKey; it is small so we re-use ReadFrom - n, err := srs.Vk.ReadFrom(bytes.NewReader(data)) + _, err := srs.Vk.ReadFrom(r) if err != nil { return err } - data = data[n:] - if len(data) < 8 { - return io.ErrUnexpectedEOF - } - - // read nb points we encode. - nbPoints := binary.LittleEndian.Uint64(data[:8]) - data = data[8:] - - // check the length of data - if len(data) < int(nbPoints)*2*fp.Bytes { - return io.ErrUnexpectedEOF - } - - if len(maxPkPoints) == 1 && maxPkPoints[0] > 0 && int(nbPoints) > maxPkPoints[0] { - nbPoints = uint64(maxPkPoints[0]) + // read the marker + if err := unsafe.ReadMarker(r); err != nil { + return err } - srs.Pk.G1 = make([]bw6756.G1Affine, nbPoints) - - // read the limbs directly - var bbuf [fp.Bytes * 2]byte - for i := 0; i < int(nbPoints); i++ { - copy(bbuf[:], data[i*2*fp.Bytes:(i+1)*2*fp.Bytes]) - for j := 0; j < fp.Limbs; j++ { - srs.Pk.G1[i].X[j] = binary.LittleEndian.Uint64(bbuf[j*8 : j*8+8]) - } - for j := 0; j < fp.Limbs; j++ { - srs.Pk.G1[i].Y[j] = binary.LittleEndian.Uint64(bbuf[fp.Bytes+j*8 : fp.Bytes+j*8+8]) - } - } - return nil + // read the slice + srs.Pk.G1, _, err = unsafe.ReadSlice[[]bw6756.G1Affine](r, maxPkPoints...) + return err } // WriteTo writes binary encoding of the entire SRS diff --git a/ecc/bw6-761/kzg/kzg_test.go b/ecc/bw6-761/kzg/kzg_test.go index 46176f3a76..fdec0e1885 100644 --- a/ecc/bw6-761/kzg/kzg_test.go +++ b/ecc/bw6-761/kzg/kzg_test.go @@ -441,12 +441,15 @@ func TestUnsafeToBytesTruncating(t *testing.T) { assert.NoError(err) // marshal the SRS, but explicitly with less points. - d, err := srs.UnsafeToBytes(1 << 9) + var buf bytes.Buffer + err = srs.WriteDump(&buf, 1<<9) assert.NoError(err) + r := bytes.NewReader(buf.Bytes()) + // unmarshal the SRS var newSRS SRS - err = newSRS.UnsafeFromBytes(d) + err = newSRS.ReadDump(r) assert.NoError(err) // check that the SRS proving key has only 1 << 9 points @@ -457,7 +460,8 @@ func TestUnsafeToBytesTruncating(t *testing.T) { // read even less points. var newSRSPartial SRS - err = newSRSPartial.UnsafeFromBytes(d, 1<<8) + r = bytes.NewReader(buf.Bytes()) + err = newSRSPartial.ReadDump(r, 1<<8) assert.NoError(err) // check that the SRS proving key has only 1 << 8 points @@ -662,7 +666,7 @@ func BenchmarkSerializeSRS(b *testing.B) { b.Fatal(err) } - // now we can benchmark the WriteTo, WriteRawTo and UnsafeToBytes methods + // now we can benchmark the WriteTo, WriteRawTo and WriteDump methods b.Run("WriteTo", func(b *testing.B) { b.ResetTimer() var buf bytes.Buffer @@ -687,17 +691,15 @@ func BenchmarkSerializeSRS(b *testing.B) { } }) - b.Run("UnsafeToBytes", func(b *testing.B) { + b.Run("WriteDump", func(b *testing.B) { b.ResetTimer() - var d []byte - var err error + var buf bytes.Buffer for i := 0; i < b.N; i++ { - d, err = srs.UnsafeToBytes() - if err != nil { + buf.Reset() + if err := srs.WriteDump(&buf); err != nil { b.Fatal(err) } } - _ = d }) } @@ -711,8 +713,7 @@ func BenchmarkDeserializeSRS(b *testing.B) { b.Run("UnsafeReadFrom", func(b *testing.B) { var buf bytes.Buffer - _, err := srs.WriteRawTo(&buf) - if err != nil { + if _, err := srs.WriteRawTo(&buf); err != nil { b.Fatal(err) } b.ResetTimer() @@ -725,15 +726,17 @@ func BenchmarkDeserializeSRS(b *testing.B) { } }) - b.Run("UnsafeFromBytes", func(b *testing.B) { - d, err := srs.UnsafeToBytes() + b.Run("ReadDump", func(b *testing.B) { + var buf bytes.Buffer + err := srs.WriteDump(&buf) if err != nil { b.Fatal(err) } + data := buf.Bytes() b.ResetTimer() for i := 0; i < b.N; i++ { var newSRS SRS - if err := newSRS.UnsafeFromBytes(d); err != nil { + if err := newSRS.ReadDump(bytes.NewReader(data)); err != nil { b.Fatal(err) } } diff --git a/ecc/bw6-761/kzg/marshal.go b/ecc/bw6-761/kzg/marshal.go index c076badba5..ca9e1452bb 100644 --- a/ecc/bw6-761/kzg/marshal.go +++ b/ecc/bw6-761/kzg/marshal.go @@ -17,11 +17,10 @@ package kzg import ( - "bytes" - "encoding/binary" "github.com/consensys/gnark-crypto/ecc/bw6-761" - "github.com/consensys/gnark-crypto/ecc/bw6-761/fp" "io" + + "github.com/consensys/gnark-crypto/utils/unsafe" ) // WriteTo writes binary encoding of the ProvingKey @@ -79,91 +78,49 @@ func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*bw6761.Encoder)) ( return enc.BytesWritten(), nil } -// UnsafeToBytes returns the binary encoding of the entire SRS memory representation +// WriteDump writes the binary encoding of the entire SRS memory representation // It is meant to be use to achieve fast serialization/deserialization and // is not compatible with WriteTo / ReadFrom. It does not do any validation // and doesn't encode points in a canonical form. +// @unsafe: this is platform dependent and may not be compatible with other platforms // @unstable: the format may change in the future // If maxPkPoints is provided, the number of points in the ProvingKey will be limited to maxPkPoints -func (srs *SRS) UnsafeToBytes(maxPkPoints ...int) ([]byte, error) { +func (srs *SRS) WriteDump(w io.Writer, maxPkPoints ...int) error { maxG1 := len(srs.Pk.G1) if len(maxPkPoints) > 0 && maxPkPoints[0] < maxG1 && maxPkPoints[0] > 0 { maxG1 = maxPkPoints[0] } // first we write the VerifyingKey; it is small so we re-use WriteTo - var buf bytes.Buffer - if _, err := srs.Vk.writeTo(&buf, bw6761.RawEncoding()); err != nil { - return nil, err + if _, err := srs.Vk.writeTo(w, bw6761.RawEncoding()); err != nil { + return err } - buf.Grow(2*maxG1*fp.Bytes + 8) // pre-allocate space for the ProvingKey - - // write nb points we encode. - if err := binary.Write(&buf, binary.LittleEndian, uint64(maxG1)); err != nil { - return nil, err + // write the marker + if err := unsafe.WriteMarker(w); err != nil { + return err } - // write the limbs directly - var bbuf [fp.Bytes * 2]byte - for i := 0; i < maxG1; i++ { - for j := 0; j < fp.Limbs; j++ { - binary.LittleEndian.PutUint64(bbuf[j*8:j*8+8], srs.Pk.G1[i].X[j]) - } - for j := 0; j < fp.Limbs; j++ { - binary.LittleEndian.PutUint64(bbuf[fp.Bytes+j*8:fp.Bytes+j*8+8], srs.Pk.G1[i].Y[j]) - } - if _, err := buf.Write(bbuf[:]); err != nil { - return nil, err - } - } - return buf.Bytes(), nil + // write the slice + return unsafe.WriteSlice(w, srs.Pk.G1[:maxG1]) } -// UnsafeFromBytes deserializes the SRS from a byte slice -// It is meant to be use to achieve fast serialization/deserialization and -// is not compatible with WriteTo / ReadFrom. It does not do any validation -// and doesn't encode points in a canonical form. -// @unstable: the format may change in the future -func (srs *SRS) UnsafeFromBytes(data []byte, maxPkPoints ...int) error { +// ReadDump deserializes the SRS from a reader, as written by WriteDump +func (srs *SRS) ReadDump(r io.Reader, maxPkPoints ...int) error { // first we read the VerifyingKey; it is small so we re-use ReadFrom - n, err := srs.Vk.ReadFrom(bytes.NewReader(data)) + _, err := srs.Vk.ReadFrom(r) if err != nil { return err } - data = data[n:] - if len(data) < 8 { - return io.ErrUnexpectedEOF - } - - // read nb points we encode. - nbPoints := binary.LittleEndian.Uint64(data[:8]) - data = data[8:] - - // check the length of data - if len(data) < int(nbPoints)*2*fp.Bytes { - return io.ErrUnexpectedEOF - } - - if len(maxPkPoints) == 1 && maxPkPoints[0] > 0 && int(nbPoints) > maxPkPoints[0] { - nbPoints = uint64(maxPkPoints[0]) + // read the marker + if err := unsafe.ReadMarker(r); err != nil { + return err } - srs.Pk.G1 = make([]bw6761.G1Affine, nbPoints) - - // read the limbs directly - var bbuf [fp.Bytes * 2]byte - for i := 0; i < int(nbPoints); i++ { - copy(bbuf[:], data[i*2*fp.Bytes:(i+1)*2*fp.Bytes]) - for j := 0; j < fp.Limbs; j++ { - srs.Pk.G1[i].X[j] = binary.LittleEndian.Uint64(bbuf[j*8 : j*8+8]) - } - for j := 0; j < fp.Limbs; j++ { - srs.Pk.G1[i].Y[j] = binary.LittleEndian.Uint64(bbuf[fp.Bytes+j*8 : fp.Bytes+j*8+8]) - } - } - return nil + // read the slice + srs.Pk.G1, _, err = unsafe.ReadSlice[[]bw6761.G1Affine](r, maxPkPoints...) + return err } // WriteTo writes binary encoding of the entire SRS diff --git a/internal/generator/kzg/template/kzg.test.go.tmpl b/internal/generator/kzg/template/kzg.test.go.tmpl index bf4502cc7f..bc2dce9906 100644 --- a/internal/generator/kzg/template/kzg.test.go.tmpl +++ b/internal/generator/kzg/template/kzg.test.go.tmpl @@ -424,12 +424,15 @@ func TestUnsafeToBytesTruncating(t *testing.T) { assert.NoError(err) // marshal the SRS, but explicitly with less points. - d, err := srs.UnsafeToBytes(1 << 9) + var buf bytes.Buffer + err = srs.WriteDump(&buf, 1 << 9) assert.NoError(err) + r := bytes.NewReader(buf.Bytes()) + // unmarshal the SRS var newSRS SRS - err = newSRS.UnsafeFromBytes(d) + err = newSRS.ReadDump(r) assert.NoError(err) // check that the SRS proving key has only 1 << 9 points @@ -440,7 +443,8 @@ func TestUnsafeToBytesTruncating(t *testing.T) { // read even less points. var newSRSPartial SRS - err = newSRSPartial.UnsafeFromBytes(d, 1 << 8) + r = bytes.NewReader(buf.Bytes()) + err = newSRSPartial.ReadDump(r, 1 << 8) assert.NoError(err) // check that the SRS proving key has only 1 << 8 points @@ -646,7 +650,7 @@ func BenchmarkSerializeSRS(b *testing.B) { b.Fatal(err) } - // now we can benchmark the WriteTo, WriteRawTo and UnsafeToBytes methods + // now we can benchmark the WriteTo, WriteRawTo and WriteDump methods b.Run("WriteTo", func(b *testing.B) { b.ResetTimer() var buf bytes.Buffer @@ -671,17 +675,15 @@ func BenchmarkSerializeSRS(b *testing.B) { } }) - b.Run("UnsafeToBytes", func(b *testing.B) { + b.Run("WriteDump", func(b *testing.B) { b.ResetTimer() - var d []byte - var err error + var buf bytes.Buffer for i := 0; i < b.N; i++ { - d, err = srs.UnsafeToBytes() - if err != nil { + buf.Reset() + if err := srs.WriteDump(&buf); err != nil { b.Fatal(err) } } - _ = d }) } @@ -695,8 +697,7 @@ func BenchmarkDeserializeSRS(b *testing.B) { b.Run("UnsafeReadFrom", func(b *testing.B) { var buf bytes.Buffer - _, err := srs.WriteRawTo(&buf) - if err != nil { + if _, err := srs.WriteRawTo(&buf); err != nil { b.Fatal(err) } b.ResetTimer() @@ -709,15 +710,17 @@ func BenchmarkDeserializeSRS(b *testing.B) { } }) - b.Run("UnsafeFromBytes", func(b *testing.B) { - d, err := srs.UnsafeToBytes() + b.Run("ReadDump", func(b *testing.B) { + var buf bytes.Buffer + err := srs.WriteDump(&buf) if err != nil { b.Fatal(err) } + data := buf.Bytes() b.ResetTimer() for i := 0; i < b.N; i++ { var newSRS SRS - if err := newSRS.UnsafeFromBytes(d); err != nil { + if err := newSRS.ReadDump(bytes.NewReader(data)); err != nil { b.Fatal(err) } } diff --git a/internal/generator/kzg/template/marshal.go.tmpl b/internal/generator/kzg/template/marshal.go.tmpl index c0748dbc46..8798bbf329 100644 --- a/internal/generator/kzg/template/marshal.go.tmpl +++ b/internal/generator/kzg/template/marshal.go.tmpl @@ -1,10 +1,9 @@ import ( "io" - "bytes" - "encoding/binary" "github.com/consensys/gnark-crypto/ecc/{{ .Name }}" - "github.com/consensys/gnark-crypto/ecc/{{ .Name }}/fp" + + "github.com/consensys/gnark-crypto/utils/unsafe" ) // WriteTo writes binary encoding of the ProvingKey @@ -75,92 +74,50 @@ func (vk *VerifyingKey) writeTo(w io.Writer, options ...func(*{{.CurvePackage}}. return enc.BytesWritten(), nil } -// UnsafeToBytes returns the binary encoding of the entire SRS memory representation +// WriteDump writes the binary encoding of the entire SRS memory representation // It is meant to be use to achieve fast serialization/deserialization and // is not compatible with WriteTo / ReadFrom. It does not do any validation // and doesn't encode points in a canonical form. +// @unsafe: this is platform dependent and may not be compatible with other platforms // @unstable: the format may change in the future // If maxPkPoints is provided, the number of points in the ProvingKey will be limited to maxPkPoints -func (srs *SRS) UnsafeToBytes(maxPkPoints ...int) ([]byte, error) { +func (srs *SRS) WriteDump(w io.Writer, maxPkPoints ...int) error { maxG1 := len(srs.Pk.G1) if len(maxPkPoints) > 0 && maxPkPoints[0] < maxG1 && maxPkPoints[0] > 0{ maxG1 = maxPkPoints[0] } // first we write the VerifyingKey; it is small so we re-use WriteTo - var buf bytes.Buffer - if _, err := srs.Vk.writeTo(&buf, {{.CurvePackage}}.RawEncoding()); err != nil { - return nil, err + if _, err := srs.Vk.writeTo(w, {{.CurvePackage}}.RawEncoding()); err != nil { + return err } - buf.Grow(2 * maxG1 * fp.Bytes + 8) // pre-allocate space for the ProvingKey - // write nb points we encode. - if err := binary.Write(&buf, binary.LittleEndian, uint64(maxG1)); err != nil { - return nil, err + // write the marker + if err := unsafe.WriteMarker(w); err != nil { + return err } - // write the limbs directly - var bbuf [fp.Bytes * 2]byte - for i := 0; i < maxG1; i++ { - for j:= 0 ; j < fp.Limbs; j++ { - binary.LittleEndian.PutUint64(bbuf[j*8:j*8+8], srs.Pk.G1[i].X[j]) - } - for j:= 0 ; j < fp.Limbs; j++ { - binary.LittleEndian.PutUint64(bbuf[fp.Bytes + j*8:fp.Bytes + j*8+8], srs.Pk.G1[i].Y[j]) - } - if _, err := buf.Write(bbuf[:]); err != nil { - return nil, err - } - } - return buf.Bytes(), nil + // write the slice + return unsafe.WriteSlice(w, srs.Pk.G1[:maxG1]) } -// UnsafeFromBytes deserializes the SRS from a byte slice -// It is meant to be use to achieve fast serialization/deserialization and -// is not compatible with WriteTo / ReadFrom. It does not do any validation -// and doesn't encode points in a canonical form. -// @unstable: the format may change in the future -func (srs *SRS) UnsafeFromBytes(data []byte, maxPkPoints ...int) error { +// ReadDump deserializes the SRS from a reader, as written by WriteDump +func (srs *SRS) ReadDump(r io.Reader, maxPkPoints ...int) error { // first we read the VerifyingKey; it is small so we re-use ReadFrom - n, err := srs.Vk.ReadFrom(bytes.NewReader(data)) + _, err := srs.Vk.ReadFrom(r) if err != nil { return err } - data = data[n:] - if len(data) < 8 { - return io.ErrUnexpectedEOF - } - - // read nb points we encode. - nbPoints := binary.LittleEndian.Uint64(data[:8]) - data = data[8:] - - // check the length of data - if len(data) < int(nbPoints) * 2 * fp.Bytes { - return io.ErrUnexpectedEOF - } - - - if len(maxPkPoints) == 1 && maxPkPoints[0] > 0 && int(nbPoints) > maxPkPoints[0] { - nbPoints = uint64(maxPkPoints[0]) + // read the marker + if err := unsafe.ReadMarker(r); err != nil { + return err } - srs.Pk.G1 = make([]{{.CurvePackage}}.G1Affine, nbPoints) - - // read the limbs directly - var bbuf [fp.Bytes * 2]byte - for i := 0; i < int(nbPoints); i++ { - copy(bbuf[:], data[i * 2 * fp.Bytes:(i+1) * 2 * fp.Bytes]) - for j:= 0 ; j < fp.Limbs; j++ { - srs.Pk.G1[i].X[j] = binary.LittleEndian.Uint64(bbuf[j*8:j*8+8]) - } - for j:= 0 ; j < fp.Limbs; j++ { - srs.Pk.G1[i].Y[j] = binary.LittleEndian.Uint64(bbuf[fp.Bytes + j*8:fp.Bytes + j*8+8]) - } - } - return nil + // read the slice + srs.Pk.G1, _, err = unsafe.ReadSlice[[]{{.CurvePackage}}.G1Affine](r, maxPkPoints...) + return err } // WriteTo writes binary encoding of the entire SRS diff --git a/utils/arith.go b/utils/arith.go index 521497da2b..d3562eadb7 100644 --- a/utils/arith.go +++ b/utils/arith.go @@ -1,28 +1,5 @@ package utils -// DivCeiling (a, b) = ⌈a/b⌉ -func DivCeiling(a, b uint) uint { - q := a / b - if q*b == a { - return q - } - return q + 1 -} - -func MinU(a, b uint) uint { - if a < b { - return a - } - return b -} - -func Min(a, b int) int { - if a < b { - return a - } - return b -} - func Max(a, b int) int { if a > b { return a diff --git a/utils/testutils/testing.go b/utils/testutils/testing.go index 90f01b0a2d..6af412d2be 100644 --- a/utils/testutils/testing.go +++ b/utils/testutils/testing.go @@ -18,9 +18,9 @@ type RawSerializable interface { WriteRawTo(io.Writer) (int64, error) } -type UnsafeBinaryMarshaler interface { - UnsafeToBytes(maxPkPoints ...int) ([]byte, error) - UnsafeFromBytes(data []byte, maxPkPoints ...int) error +type BinaryDumper interface { + WriteDump(w io.Writer, maxPkPoints ...int) error + ReadDump(r io.Reader, maxPkPoints ...int) error } func SerializationRoundTrip(o Serializable) func(*testing.T) { @@ -57,15 +57,16 @@ func SerializationRoundTripRaw(o RawSerializable) func(*testing.T) { } } -func UnsafeBinaryMarshalerRoundTrip(o UnsafeBinaryMarshaler) func(*testing.T) { +func UnsafeBinaryMarshalerRoundTrip(o BinaryDumper) func(*testing.T) { return func(t *testing.T) { // serialize it... - data, err := o.UnsafeToBytes() + var buf bytes.Buffer + err := o.WriteDump(&buf) assert.NoError(t, err) // reconstruct the object - _o := reflect.New(reflect.TypeOf(o).Elem()).Interface().(UnsafeBinaryMarshaler) - err = _o.UnsafeFromBytes(data) + _o := reflect.New(reflect.TypeOf(o).Elem()).Interface().(BinaryDumper) + err = _o.ReadDump(&buf) assert.NoError(t, err) // compare diff --git a/utils/unsafe/dump_slice.go b/utils/unsafe/dump_slice.go new file mode 100644 index 0000000000..fb26dcc3e1 --- /dev/null +++ b/utils/unsafe/dump_slice.go @@ -0,0 +1,98 @@ +package unsafe + +import ( + "bytes" + "encoding/binary" + "errors" + "io" + "unsafe" +) + +// WriteSlice writes a slice of arbitrary objects to the writer. +// Use with caution, as it writes the raw memory representation of the slice; +// In particular you do not want to use this with slices that contain pointers. +// This architecture dependent and will not work across different architectures +// (e.g. 32 vs 64 bit, big endian vs little endian). +func WriteSlice[S ~[]E, E any](w io.Writer, s S) error { + var e E + size := int(unsafe.Sizeof(e)) + if err := binary.Write(w, binary.LittleEndian, uint64(len(s))); err != nil { + return err + } + + data := unsafe.Slice((*byte)(unsafe.Pointer(&s[0])), size*len(s)) + if _, err := w.Write(data); err != nil { + return err + } + return nil +} + +// ReadSlice reads a slice of arbitrary objects from the reader, written by WriteSlice. +func ReadSlice[S ~[]E, E any](r io.Reader, maxElements ...int) (s S, read int, err error) { + var buf [8]byte + if _, err := io.ReadFull(r, buf[:]); err != nil { + return nil, 0, err + } + read += 8 + + // decode length of the slice + length := binary.LittleEndian.Uint64(buf[:]) + + var e E + size := int(unsafe.Sizeof(e)) + limit := length + if len(maxElements) == 1 && maxElements[0] > 0 && int(length) > maxElements[0] { + limit = uint64(maxElements[0]) + } + + if limit == 0 { + return make(S, 0), read, nil + } + + toReturn := make(S, limit) + + // directly read the bytes from reader into the target memory area + // (slice data) + data := unsafe.Slice((*byte)(unsafe.Pointer(&toReturn[0])), size*int(limit)) + if _, err := io.ReadFull(r, data); err != nil { + return nil, read, err + } + + read += size * int(limit) + + // advance the reader if we had more elements than we wanted + if length > limit { + advance := int(length-limit) * size + if _, err := io.CopyN(io.Discard, r, int64(advance)); err != nil { + return nil, read, err + } + read += advance + } + + return toReturn, read, nil +} + +const marker uint64 = 0xdeadbeef + +// WriteMarker writes the raw memory representation of a fixed marker to the writer. +// This is used to ensure that the dump was written on the same architecture. +func WriteMarker(w io.Writer) error { + marker := marker + _, err := w.Write(unsafe.Slice((*byte)(unsafe.Pointer(&marker)), 8)) + return err +} + +// ReadMarker reads the raw memory representation of a fixed marker from the reader. +// This is used to ensure that the dump was written on the same architecture. +func ReadMarker(r io.Reader) error { + var buf [8]byte + if _, err := io.ReadFull(r, buf[:]); err != nil { + return err + } + marker := marker + d := unsafe.Slice((*byte)(unsafe.Pointer(&marker)), 8) + if !bytes.Equal(d, buf[:]) { + return errors.New("marker mismatch: dump was not written on the same architecture") + } + return nil +} diff --git a/utils/unsafe/dump_slice_test.go b/utils/unsafe/dump_slice_test.go new file mode 100644 index 0000000000..ee2286cec1 --- /dev/null +++ b/utils/unsafe/dump_slice_test.go @@ -0,0 +1,52 @@ +package unsafe_test + +import ( + "bytes" + "math/big" + "testing" + + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/utils/unsafe" + "github.com/stretchr/testify/require" +) + +func TestPointDump(t *testing.T) { + assert := require.New(t) + samplePoints := make([]bn254.G2Affine, 10) + fillBenchBasesG2(samplePoints) + + var buf bytes.Buffer + + err := unsafe.WriteSlice(&buf, samplePoints) + assert.NoError(err) + + readPoints, _, err := unsafe.ReadSlice[[]bn254.G2Affine](&buf) + assert.NoError(err) + + assert.Equal(samplePoints, readPoints) +} + +func TestMarker(t *testing.T) { + assert := require.New(t) + var buf bytes.Buffer + + err := unsafe.WriteMarker(&buf) + assert.NoError(err) + + err = unsafe.ReadMarker(&buf) + assert.NoError(err) +} + +func fillBenchBasesG2(samplePoints []bn254.G2Affine) { + var r big.Int + r.SetString("340444420969191673093399857471996460938405", 10) + samplePoints[0].ScalarMultiplication(&samplePoints[0], &r) + + one := samplePoints[0].X + one.SetOne() + + for i := 1; i < len(samplePoints); i++ { + samplePoints[i].X.Add(&samplePoints[i-1].X, &one) + samplePoints[i].Y.Sub(&samplePoints[i-1].Y, &one) + } +} From f9fac625954552196870b61a509eaee3f65bf6d0 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Thu, 2 May 2024 20:41:24 -0500 Subject: [PATCH 3/3] fix: add BinaryDumper interface in kzg root package --- kzg/kzg.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/kzg/kzg.go b/kzg/kzg.go index a9ee25943c..134b11576d 100644 --- a/kzg/kzg.go +++ b/kzg/kzg.go @@ -22,12 +22,15 @@ import ( type Serializable interface { io.ReaderFrom io.WriterTo + BinaryDumper WriteRawTo(w io.Writer) (n int64, err error) UnsafeReadFrom(r io.Reader) (int64, error) +} - UnsafeToBytes(maxPkPoints ...int) ([]byte, error) - UnsafeFromBytes(data []byte, maxPkPoints ...int) error +type BinaryDumper interface { + WriteDump(w io.Writer, maxPkPoints ...int) error + ReadDump(r io.Reader, maxPkPoints ...int) error } type SRS Serializable