From 19dec7a01a19ca1ba073e5c2be731f1ba39f2432 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 20 Apr 2023 11:41:36 -0500 Subject: [PATCH] refactor: break pedersen key into proving (committing) and verifying --- ecc/bls12-377/fr/pedersen/pedersen.go | 123 ++++++++++++----- ecc/bls12-377/fr/pedersen/pedersen_test.go | 60 ++++++--- ecc/bls12-378/fr/pedersen/pedersen.go | 123 ++++++++++++----- ecc/bls12-378/fr/pedersen/pedersen_test.go | 60 ++++++--- ecc/bls12-381/fr/pedersen/pedersen.go | 123 ++++++++++++----- ecc/bls12-381/fr/pedersen/pedersen_test.go | 60 ++++++--- ecc/bls24-315/fr/pedersen/pedersen.go | 123 ++++++++++++----- ecc/bls24-315/fr/pedersen/pedersen_test.go | 60 ++++++--- ecc/bls24-317/fr/pedersen/pedersen.go | 123 ++++++++++++----- ecc/bls24-317/fr/pedersen/pedersen_test.go | 60 ++++++--- ecc/bn254/fr/pedersen/pedersen.go | 123 ++++++++++++----- ecc/bn254/fr/pedersen/pedersen_test.go | 60 ++++++--- ecc/bw6-633/fr/pedersen/pedersen.go | 123 ++++++++++++----- ecc/bw6-633/fr/pedersen/pedersen_test.go | 60 ++++++--- ecc/bw6-756/fr/pedersen/pedersen.go | 123 ++++++++++++----- ecc/bw6-756/fr/pedersen/pedersen_test.go | 60 ++++++--- ecc/bw6-761/fr/pedersen/pedersen.go | 123 ++++++++++++----- ecc/bw6-761/fr/pedersen/pedersen_test.go | 60 ++++++--- .../pedersen/template/pedersen.go.tmpl | 124 +++++++++++++----- .../pedersen/template/pedersen.test.go.tmpl | 62 ++++++--- 20 files changed, 1332 insertions(+), 501 deletions(-) diff --git a/ecc/bls12-377/fr/pedersen/pedersen.go b/ecc/bls12-377/fr/pedersen/pedersen.go index 18c130742b..cee17840b3 100644 --- a/ecc/bls12-377/fr/pedersen/pedersen.go +++ b/ecc/bls12-377/fr/pedersen/pedersen.go @@ -20,62 +20,68 @@ import ( "crypto/rand" "fmt" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/ecc/bls12-377" + curve "github.com/consensys/gnark-crypto/ecc/bls12-377" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "io" "math/big" ) -// Key for proof and verification -type Key struct { - g bls12377.G2Affine // TODO @tabaie: does this really have to be randomized? - gRootSigmaNeg bls12377.G2Affine //gRootSigmaNeg = g^{-1/σ} - basis []bls12377.G1Affine - basisExpSigma []bls12377.G1Affine +// ProvingKey for committing and proofs of knowledge +type ProvingKey struct { + basis []curve.G1Affine + basisExpSigma []curve.G1Affine } -func randomOnG2() (bls12377.G2Affine, error) { // TODO: Add to G2.go? - gBytes := make([]byte, fr.Bytes) - if _, err := rand.Read(gBytes); err != nil { - return bls12377.G2Affine{}, err +type VerifyingKey struct { + 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 +} + +func randomOnG2() (curve.G2Affine, error) { // TODO: Add to G2.go? + if gBytes, err := randomFrSizedBytes(); err != nil { + return curve.G2Affine{}, err + } else { + return curve.HashToG2(gBytes, []byte("random on g2")) } - return bls12377.HashToG2(gBytes, []byte("random on g2")) } -func Setup(basis []bls12377.G1Affine) (Key, error) { - var ( - k Key - err error - ) +func Setup(basis []curve.G1Affine) (pk ProvingKey, vk VerifyingKey, err error) { - if k.g, err = randomOnG2(); err != nil { - return k, err + 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 k, err + return } sigma.Add(sigma, big.NewInt(1)) var sigmaInvNeg big.Int sigmaInvNeg.ModInverse(sigma, fr.Modulus()) sigmaInvNeg.Sub(fr.Modulus(), &sigmaInvNeg) - k.gRootSigmaNeg.ScalarMultiplication(&k.g, &sigmaInvNeg) + vk.gRootSigmaNeg.ScalarMultiplication(&vk.g, &sigmaInvNeg) - k.basisExpSigma = make([]bls12377.G1Affine, len(basis)) + pk.basisExpSigma = make([]curve.G1Affine, len(basis)) for i := range basis { - k.basisExpSigma[i].ScalarMultiplication(&basis[i], sigma) + pk.basisExpSigma[i].ScalarMultiplication(&basis[i], sigma) } - k.basis = basis - return k, err + pk.basis = basis + return } -func (k *Key) Commit(values []fr.Element) (commitment bls12377.G1Affine, knowledgeProof bls12377.G1Affine, err error) { +func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, knowledgeProof curve.G1Affine, err error) { - if len(values) != len(k.basis) { + if len(values) != len(pk.basis) { err = fmt.Errorf("unexpected number of values") return } @@ -86,23 +92,23 @@ func (k *Key) Commit(values []fr.Element) (commitment bls12377.G1Affine, knowled NbTasks: 1, // TODO Experiment } - if _, err = commitment.MultiExp(k.basis, values, config); err != nil { + if _, err = commitment.MultiExp(pk.basis, values, config); err != nil { return } - _, err = knowledgeProof.MultiExp(k.basisExpSigma, values, config) + _, err = knowledgeProof.MultiExp(pk.basisExpSigma, values, config) return } -// VerifyKnowledgeProof checks if the proof of knowledge is valid -func (k *Key) VerifyKnowledgeProof(commitment bls12377.G1Affine, knowledgeProof bls12377.G1Affine) error { +// 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") } - product, err := bls12377.Pair([]bls12377.G1Affine{commitment, knowledgeProof}, []bls12377.G2Affine{k.g, k.gRootSigmaNeg}) + product, err := curve.Pair([]curve.G1Affine{commitment, knowledgeProof}, []curve.G2Affine{vk.g, vk.gRootSigmaNeg}) if err != nil { return err } @@ -111,3 +117,56 @@ func (k *Key) VerifyKnowledgeProof(commitment bls12377.G1Affine, knowledgeProof } return fmt.Errorf("proof rejected") } + +// Marshal + +func (pk *ProvingKey) WriteTo(w io.Writer) (int64, error) { + enc := curve.NewEncoder(w) + + if err := enc.Encode(pk.basis); err != nil { + return enc.BytesWritten(), err + } + + err := enc.Encode(pk.basisExpSigma) + + return enc.BytesWritten(), err +} + +func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { + dec := curve.NewDecoder(r) + + 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 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 +} + +func (vk *VerifyingKey) WriteTo(w io.Writer) (int64, error) { + enc := curve.NewEncoder(w) + var err error + + if err = enc.Encode(&vk.g); err != nil { + return enc.BytesWritten(), err + } + err = enc.Encode(&vk.gRootSigmaNeg) + return enc.BytesWritten(), err +} + +func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { + dec := curve.NewDecoder(r) + var err error + + if err = dec.Decode(&vk.g); err != nil { + return dec.BytesRead(), err + } + err = dec.Decode(&vk.gRootSigmaNeg) + return dec.BytesRead(), err +} diff --git a/ecc/bls12-377/fr/pedersen/pedersen_test.go b/ecc/bls12-377/fr/pedersen/pedersen_test.go index 51a14eef4c..9396424882 100644 --- a/ecc/bls12-377/fr/pedersen/pedersen_test.go +++ b/ecc/bls12-377/fr/pedersen/pedersen_test.go @@ -17,10 +17,10 @@ package pedersen import ( - "github.com/consensys/gnark-crypto/ecc/bls12-377" + curve "github.com/consensys/gnark-crypto/ecc/bls12-377" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/consensys/gnark-crypto/utils" "github.com/stretchr/testify/assert" - "math/rand" "testing" ) @@ -44,37 +44,43 @@ func randomFrSlice(t *testing.T, size int) []interface{} { return res } -func randomOnG1() (bls12377.G1Affine, error) { // TODO: Add to G1.go? - gBytes := make([]byte, fr.Bytes) - if _, err := rand.Read(gBytes); err != nil { - return bls12377.G1Affine{}, err +func randomOnG1() (curve.G1Affine, error) { // TODO: Add to G1.go? + if gBytes, err := randomFrSizedBytes(); err != nil { + return curve.G1Affine{}, err + } else { + return curve.HashToG1(gBytes, []byte("random on g1")) } - return bls12377.HashToG1(gBytes, []byte("random on g2")) } -func testCommit(t *testing.T, values ...interface{}) { - - basis := make([]bls12377.G1Affine, len(values)) - for i := range basis { +func randomG1Slice(t *testing.T, size int) []curve.G1Affine { + res := make([]curve.G1Affine, size) + for i := range res { var err error - basis[i], err = randomOnG1() + res[i], err = randomOnG1() assert.NoError(t, err) } + return res +} + +func testCommit(t *testing.T, values ...interface{}) { + + basis := randomG1Slice(t, len(values)) var ( - key Key + pk ProvingKey + vk VerifyingKey err error - commitment, pok bls12377.G1Affine + commitment, pok curve.G1Affine ) - key, err = Setup(basis) + pk, vk, err = Setup(basis) assert.NoError(t, err) - commitment, pok, err = key.Commit(interfaceSliceToFrSlice(t, values...)) + commitment, pok, err = pk.Commit(interfaceSliceToFrSlice(t, values...)) assert.NoError(t, err) - assert.NoError(t, key.VerifyKnowledgeProof(commitment, pok)) + assert.NoError(t, vk.Verify(commitment, pok)) pok.Neg(&pok) - assert.NotNil(t, key.VerifyKnowledgeProof(commitment, pok)) + assert.NotNil(t, vk.Verify(commitment, pok)) } func TestCommitToOne(t *testing.T) { @@ -88,3 +94,21 @@ func TestCommitSingle(t *testing.T) { func TestCommitFiveElements(t *testing.T) { testCommit(t, randomFrSlice(t, 5)...) } + +func TestMarshal(t *testing.T) { + var pk ProvingKey + pk.basisExpSigma = randomG1Slice(t, 5) + pk.basis = randomG1Slice(t, 5) + + var ( + vk VerifyingKey + err error + ) + vk.g, err = randomOnG2() + assert.NoError(t, err) + vk.gRootSigmaNeg, err = randomOnG2() + assert.NoError(t, err) + + t.Run("ProvingKey -> Bytes -> ProvingKey must remain identical.", utils.SerializationRoundTrip(&pk)) + t.Run("VerifyingKey -> Bytes -> VerifyingKey must remain identical.", utils.SerializationRoundTrip(&vk)) +} diff --git a/ecc/bls12-378/fr/pedersen/pedersen.go b/ecc/bls12-378/fr/pedersen/pedersen.go index 3508d51d01..a526dd71c0 100644 --- a/ecc/bls12-378/fr/pedersen/pedersen.go +++ b/ecc/bls12-378/fr/pedersen/pedersen.go @@ -20,62 +20,68 @@ import ( "crypto/rand" "fmt" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/ecc/bls12-378" + curve "github.com/consensys/gnark-crypto/ecc/bls12-378" "github.com/consensys/gnark-crypto/ecc/bls12-378/fr" + "io" "math/big" ) -// Key for proof and verification -type Key struct { - g bls12378.G2Affine // TODO @tabaie: does this really have to be randomized? - gRootSigmaNeg bls12378.G2Affine //gRootSigmaNeg = g^{-1/σ} - basis []bls12378.G1Affine - basisExpSigma []bls12378.G1Affine +// ProvingKey for committing and proofs of knowledge +type ProvingKey struct { + basis []curve.G1Affine + basisExpSigma []curve.G1Affine } -func randomOnG2() (bls12378.G2Affine, error) { // TODO: Add to G2.go? - gBytes := make([]byte, fr.Bytes) - if _, err := rand.Read(gBytes); err != nil { - return bls12378.G2Affine{}, err +type VerifyingKey struct { + 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 +} + +func randomOnG2() (curve.G2Affine, error) { // TODO: Add to G2.go? + if gBytes, err := randomFrSizedBytes(); err != nil { + return curve.G2Affine{}, err + } else { + return curve.HashToG2(gBytes, []byte("random on g2")) } - return bls12378.HashToG2(gBytes, []byte("random on g2")) } -func Setup(basis []bls12378.G1Affine) (Key, error) { - var ( - k Key - err error - ) +func Setup(basis []curve.G1Affine) (pk ProvingKey, vk VerifyingKey, err error) { - if k.g, err = randomOnG2(); err != nil { - return k, err + 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 k, err + return } sigma.Add(sigma, big.NewInt(1)) var sigmaInvNeg big.Int sigmaInvNeg.ModInverse(sigma, fr.Modulus()) sigmaInvNeg.Sub(fr.Modulus(), &sigmaInvNeg) - k.gRootSigmaNeg.ScalarMultiplication(&k.g, &sigmaInvNeg) + vk.gRootSigmaNeg.ScalarMultiplication(&vk.g, &sigmaInvNeg) - k.basisExpSigma = make([]bls12378.G1Affine, len(basis)) + pk.basisExpSigma = make([]curve.G1Affine, len(basis)) for i := range basis { - k.basisExpSigma[i].ScalarMultiplication(&basis[i], sigma) + pk.basisExpSigma[i].ScalarMultiplication(&basis[i], sigma) } - k.basis = basis - return k, err + pk.basis = basis + return } -func (k *Key) Commit(values []fr.Element) (commitment bls12378.G1Affine, knowledgeProof bls12378.G1Affine, err error) { +func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, knowledgeProof curve.G1Affine, err error) { - if len(values) != len(k.basis) { + if len(values) != len(pk.basis) { err = fmt.Errorf("unexpected number of values") return } @@ -86,23 +92,23 @@ func (k *Key) Commit(values []fr.Element) (commitment bls12378.G1Affine, knowled NbTasks: 1, // TODO Experiment } - if _, err = commitment.MultiExp(k.basis, values, config); err != nil { + if _, err = commitment.MultiExp(pk.basis, values, config); err != nil { return } - _, err = knowledgeProof.MultiExp(k.basisExpSigma, values, config) + _, err = knowledgeProof.MultiExp(pk.basisExpSigma, values, config) return } -// VerifyKnowledgeProof checks if the proof of knowledge is valid -func (k *Key) VerifyKnowledgeProof(commitment bls12378.G1Affine, knowledgeProof bls12378.G1Affine) error { +// 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") } - product, err := bls12378.Pair([]bls12378.G1Affine{commitment, knowledgeProof}, []bls12378.G2Affine{k.g, k.gRootSigmaNeg}) + product, err := curve.Pair([]curve.G1Affine{commitment, knowledgeProof}, []curve.G2Affine{vk.g, vk.gRootSigmaNeg}) if err != nil { return err } @@ -111,3 +117,56 @@ func (k *Key) VerifyKnowledgeProof(commitment bls12378.G1Affine, knowledgeProof } return fmt.Errorf("proof rejected") } + +// Marshal + +func (pk *ProvingKey) WriteTo(w io.Writer) (int64, error) { + enc := curve.NewEncoder(w) + + if err := enc.Encode(pk.basis); err != nil { + return enc.BytesWritten(), err + } + + err := enc.Encode(pk.basisExpSigma) + + return enc.BytesWritten(), err +} + +func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { + dec := curve.NewDecoder(r) + + 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 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 +} + +func (vk *VerifyingKey) WriteTo(w io.Writer) (int64, error) { + enc := curve.NewEncoder(w) + var err error + + if err = enc.Encode(&vk.g); err != nil { + return enc.BytesWritten(), err + } + err = enc.Encode(&vk.gRootSigmaNeg) + return enc.BytesWritten(), err +} + +func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { + dec := curve.NewDecoder(r) + var err error + + if err = dec.Decode(&vk.g); err != nil { + return dec.BytesRead(), err + } + err = dec.Decode(&vk.gRootSigmaNeg) + return dec.BytesRead(), err +} diff --git a/ecc/bls12-378/fr/pedersen/pedersen_test.go b/ecc/bls12-378/fr/pedersen/pedersen_test.go index 745d063342..b2119020d8 100644 --- a/ecc/bls12-378/fr/pedersen/pedersen_test.go +++ b/ecc/bls12-378/fr/pedersen/pedersen_test.go @@ -17,10 +17,10 @@ package pedersen import ( - "github.com/consensys/gnark-crypto/ecc/bls12-378" + curve "github.com/consensys/gnark-crypto/ecc/bls12-378" "github.com/consensys/gnark-crypto/ecc/bls12-378/fr" + "github.com/consensys/gnark-crypto/utils" "github.com/stretchr/testify/assert" - "math/rand" "testing" ) @@ -44,37 +44,43 @@ func randomFrSlice(t *testing.T, size int) []interface{} { return res } -func randomOnG1() (bls12378.G1Affine, error) { // TODO: Add to G1.go? - gBytes := make([]byte, fr.Bytes) - if _, err := rand.Read(gBytes); err != nil { - return bls12378.G1Affine{}, err +func randomOnG1() (curve.G1Affine, error) { // TODO: Add to G1.go? + if gBytes, err := randomFrSizedBytes(); err != nil { + return curve.G1Affine{}, err + } else { + return curve.HashToG1(gBytes, []byte("random on g1")) } - return bls12378.HashToG1(gBytes, []byte("random on g2")) } -func testCommit(t *testing.T, values ...interface{}) { - - basis := make([]bls12378.G1Affine, len(values)) - for i := range basis { +func randomG1Slice(t *testing.T, size int) []curve.G1Affine { + res := make([]curve.G1Affine, size) + for i := range res { var err error - basis[i], err = randomOnG1() + res[i], err = randomOnG1() assert.NoError(t, err) } + return res +} + +func testCommit(t *testing.T, values ...interface{}) { + + basis := randomG1Slice(t, len(values)) var ( - key Key + pk ProvingKey + vk VerifyingKey err error - commitment, pok bls12378.G1Affine + commitment, pok curve.G1Affine ) - key, err = Setup(basis) + pk, vk, err = Setup(basis) assert.NoError(t, err) - commitment, pok, err = key.Commit(interfaceSliceToFrSlice(t, values...)) + commitment, pok, err = pk.Commit(interfaceSliceToFrSlice(t, values...)) assert.NoError(t, err) - assert.NoError(t, key.VerifyKnowledgeProof(commitment, pok)) + assert.NoError(t, vk.Verify(commitment, pok)) pok.Neg(&pok) - assert.NotNil(t, key.VerifyKnowledgeProof(commitment, pok)) + assert.NotNil(t, vk.Verify(commitment, pok)) } func TestCommitToOne(t *testing.T) { @@ -88,3 +94,21 @@ func TestCommitSingle(t *testing.T) { func TestCommitFiveElements(t *testing.T) { testCommit(t, randomFrSlice(t, 5)...) } + +func TestMarshal(t *testing.T) { + var pk ProvingKey + pk.basisExpSigma = randomG1Slice(t, 5) + pk.basis = randomG1Slice(t, 5) + + var ( + vk VerifyingKey + err error + ) + vk.g, err = randomOnG2() + assert.NoError(t, err) + vk.gRootSigmaNeg, err = randomOnG2() + assert.NoError(t, err) + + t.Run("ProvingKey -> Bytes -> ProvingKey must remain identical.", utils.SerializationRoundTrip(&pk)) + t.Run("VerifyingKey -> Bytes -> VerifyingKey must remain identical.", utils.SerializationRoundTrip(&vk)) +} diff --git a/ecc/bls12-381/fr/pedersen/pedersen.go b/ecc/bls12-381/fr/pedersen/pedersen.go index 38cc4d32c4..e9efb6008c 100644 --- a/ecc/bls12-381/fr/pedersen/pedersen.go +++ b/ecc/bls12-381/fr/pedersen/pedersen.go @@ -20,62 +20,68 @@ import ( "crypto/rand" "fmt" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/ecc/bls12-381" + curve "github.com/consensys/gnark-crypto/ecc/bls12-381" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + "io" "math/big" ) -// Key for proof and verification -type Key struct { - g bls12381.G2Affine // TODO @tabaie: does this really have to be randomized? - gRootSigmaNeg bls12381.G2Affine //gRootSigmaNeg = g^{-1/σ} - basis []bls12381.G1Affine - basisExpSigma []bls12381.G1Affine +// ProvingKey for committing and proofs of knowledge +type ProvingKey struct { + basis []curve.G1Affine + basisExpSigma []curve.G1Affine } -func randomOnG2() (bls12381.G2Affine, error) { // TODO: Add to G2.go? - gBytes := make([]byte, fr.Bytes) - if _, err := rand.Read(gBytes); err != nil { - return bls12381.G2Affine{}, err +type VerifyingKey struct { + 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 +} + +func randomOnG2() (curve.G2Affine, error) { // TODO: Add to G2.go? + if gBytes, err := randomFrSizedBytes(); err != nil { + return curve.G2Affine{}, err + } else { + return curve.HashToG2(gBytes, []byte("random on g2")) } - return bls12381.HashToG2(gBytes, []byte("random on g2")) } -func Setup(basis []bls12381.G1Affine) (Key, error) { - var ( - k Key - err error - ) +func Setup(basis []curve.G1Affine) (pk ProvingKey, vk VerifyingKey, err error) { - if k.g, err = randomOnG2(); err != nil { - return k, err + 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 k, err + return } sigma.Add(sigma, big.NewInt(1)) var sigmaInvNeg big.Int sigmaInvNeg.ModInverse(sigma, fr.Modulus()) sigmaInvNeg.Sub(fr.Modulus(), &sigmaInvNeg) - k.gRootSigmaNeg.ScalarMultiplication(&k.g, &sigmaInvNeg) + vk.gRootSigmaNeg.ScalarMultiplication(&vk.g, &sigmaInvNeg) - k.basisExpSigma = make([]bls12381.G1Affine, len(basis)) + pk.basisExpSigma = make([]curve.G1Affine, len(basis)) for i := range basis { - k.basisExpSigma[i].ScalarMultiplication(&basis[i], sigma) + pk.basisExpSigma[i].ScalarMultiplication(&basis[i], sigma) } - k.basis = basis - return k, err + pk.basis = basis + return } -func (k *Key) Commit(values []fr.Element) (commitment bls12381.G1Affine, knowledgeProof bls12381.G1Affine, err error) { +func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, knowledgeProof curve.G1Affine, err error) { - if len(values) != len(k.basis) { + if len(values) != len(pk.basis) { err = fmt.Errorf("unexpected number of values") return } @@ -86,23 +92,23 @@ func (k *Key) Commit(values []fr.Element) (commitment bls12381.G1Affine, knowled NbTasks: 1, // TODO Experiment } - if _, err = commitment.MultiExp(k.basis, values, config); err != nil { + if _, err = commitment.MultiExp(pk.basis, values, config); err != nil { return } - _, err = knowledgeProof.MultiExp(k.basisExpSigma, values, config) + _, err = knowledgeProof.MultiExp(pk.basisExpSigma, values, config) return } -// VerifyKnowledgeProof checks if the proof of knowledge is valid -func (k *Key) VerifyKnowledgeProof(commitment bls12381.G1Affine, knowledgeProof bls12381.G1Affine) error { +// 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") } - product, err := bls12381.Pair([]bls12381.G1Affine{commitment, knowledgeProof}, []bls12381.G2Affine{k.g, k.gRootSigmaNeg}) + product, err := curve.Pair([]curve.G1Affine{commitment, knowledgeProof}, []curve.G2Affine{vk.g, vk.gRootSigmaNeg}) if err != nil { return err } @@ -111,3 +117,56 @@ func (k *Key) VerifyKnowledgeProof(commitment bls12381.G1Affine, knowledgeProof } return fmt.Errorf("proof rejected") } + +// Marshal + +func (pk *ProvingKey) WriteTo(w io.Writer) (int64, error) { + enc := curve.NewEncoder(w) + + if err := enc.Encode(pk.basis); err != nil { + return enc.BytesWritten(), err + } + + err := enc.Encode(pk.basisExpSigma) + + return enc.BytesWritten(), err +} + +func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { + dec := curve.NewDecoder(r) + + 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 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 +} + +func (vk *VerifyingKey) WriteTo(w io.Writer) (int64, error) { + enc := curve.NewEncoder(w) + var err error + + if err = enc.Encode(&vk.g); err != nil { + return enc.BytesWritten(), err + } + err = enc.Encode(&vk.gRootSigmaNeg) + return enc.BytesWritten(), err +} + +func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { + dec := curve.NewDecoder(r) + var err error + + if err = dec.Decode(&vk.g); err != nil { + return dec.BytesRead(), err + } + err = dec.Decode(&vk.gRootSigmaNeg) + return dec.BytesRead(), err +} diff --git a/ecc/bls12-381/fr/pedersen/pedersen_test.go b/ecc/bls12-381/fr/pedersen/pedersen_test.go index 111f63590b..78e04273e0 100644 --- a/ecc/bls12-381/fr/pedersen/pedersen_test.go +++ b/ecc/bls12-381/fr/pedersen/pedersen_test.go @@ -17,10 +17,10 @@ package pedersen import ( - "github.com/consensys/gnark-crypto/ecc/bls12-381" + curve "github.com/consensys/gnark-crypto/ecc/bls12-381" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + "github.com/consensys/gnark-crypto/utils" "github.com/stretchr/testify/assert" - "math/rand" "testing" ) @@ -44,37 +44,43 @@ func randomFrSlice(t *testing.T, size int) []interface{} { return res } -func randomOnG1() (bls12381.G1Affine, error) { // TODO: Add to G1.go? - gBytes := make([]byte, fr.Bytes) - if _, err := rand.Read(gBytes); err != nil { - return bls12381.G1Affine{}, err +func randomOnG1() (curve.G1Affine, error) { // TODO: Add to G1.go? + if gBytes, err := randomFrSizedBytes(); err != nil { + return curve.G1Affine{}, err + } else { + return curve.HashToG1(gBytes, []byte("random on g1")) } - return bls12381.HashToG1(gBytes, []byte("random on g2")) } -func testCommit(t *testing.T, values ...interface{}) { - - basis := make([]bls12381.G1Affine, len(values)) - for i := range basis { +func randomG1Slice(t *testing.T, size int) []curve.G1Affine { + res := make([]curve.G1Affine, size) + for i := range res { var err error - basis[i], err = randomOnG1() + res[i], err = randomOnG1() assert.NoError(t, err) } + return res +} + +func testCommit(t *testing.T, values ...interface{}) { + + basis := randomG1Slice(t, len(values)) var ( - key Key + pk ProvingKey + vk VerifyingKey err error - commitment, pok bls12381.G1Affine + commitment, pok curve.G1Affine ) - key, err = Setup(basis) + pk, vk, err = Setup(basis) assert.NoError(t, err) - commitment, pok, err = key.Commit(interfaceSliceToFrSlice(t, values...)) + commitment, pok, err = pk.Commit(interfaceSliceToFrSlice(t, values...)) assert.NoError(t, err) - assert.NoError(t, key.VerifyKnowledgeProof(commitment, pok)) + assert.NoError(t, vk.Verify(commitment, pok)) pok.Neg(&pok) - assert.NotNil(t, key.VerifyKnowledgeProof(commitment, pok)) + assert.NotNil(t, vk.Verify(commitment, pok)) } func TestCommitToOne(t *testing.T) { @@ -88,3 +94,21 @@ func TestCommitSingle(t *testing.T) { func TestCommitFiveElements(t *testing.T) { testCommit(t, randomFrSlice(t, 5)...) } + +func TestMarshal(t *testing.T) { + var pk ProvingKey + pk.basisExpSigma = randomG1Slice(t, 5) + pk.basis = randomG1Slice(t, 5) + + var ( + vk VerifyingKey + err error + ) + vk.g, err = randomOnG2() + assert.NoError(t, err) + vk.gRootSigmaNeg, err = randomOnG2() + assert.NoError(t, err) + + t.Run("ProvingKey -> Bytes -> ProvingKey must remain identical.", utils.SerializationRoundTrip(&pk)) + t.Run("VerifyingKey -> Bytes -> VerifyingKey must remain identical.", utils.SerializationRoundTrip(&vk)) +} diff --git a/ecc/bls24-315/fr/pedersen/pedersen.go b/ecc/bls24-315/fr/pedersen/pedersen.go index 09e19bea10..0580e8449a 100644 --- a/ecc/bls24-315/fr/pedersen/pedersen.go +++ b/ecc/bls24-315/fr/pedersen/pedersen.go @@ -20,62 +20,68 @@ import ( "crypto/rand" "fmt" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/ecc/bls24-315" + curve "github.com/consensys/gnark-crypto/ecc/bls24-315" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" + "io" "math/big" ) -// Key for proof and verification -type Key struct { - g bls24315.G2Affine // TODO @tabaie: does this really have to be randomized? - gRootSigmaNeg bls24315.G2Affine //gRootSigmaNeg = g^{-1/σ} - basis []bls24315.G1Affine - basisExpSigma []bls24315.G1Affine +// ProvingKey for committing and proofs of knowledge +type ProvingKey struct { + basis []curve.G1Affine + basisExpSigma []curve.G1Affine } -func randomOnG2() (bls24315.G2Affine, error) { // TODO: Add to G2.go? - gBytes := make([]byte, fr.Bytes) - if _, err := rand.Read(gBytes); err != nil { - return bls24315.G2Affine{}, err +type VerifyingKey struct { + 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 +} + +func randomOnG2() (curve.G2Affine, error) { // TODO: Add to G2.go? + if gBytes, err := randomFrSizedBytes(); err != nil { + return curve.G2Affine{}, err + } else { + return curve.HashToG2(gBytes, []byte("random on g2")) } - return bls24315.HashToG2(gBytes, []byte("random on g2")) } -func Setup(basis []bls24315.G1Affine) (Key, error) { - var ( - k Key - err error - ) +func Setup(basis []curve.G1Affine) (pk ProvingKey, vk VerifyingKey, err error) { - if k.g, err = randomOnG2(); err != nil { - return k, err + 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 k, err + return } sigma.Add(sigma, big.NewInt(1)) var sigmaInvNeg big.Int sigmaInvNeg.ModInverse(sigma, fr.Modulus()) sigmaInvNeg.Sub(fr.Modulus(), &sigmaInvNeg) - k.gRootSigmaNeg.ScalarMultiplication(&k.g, &sigmaInvNeg) + vk.gRootSigmaNeg.ScalarMultiplication(&vk.g, &sigmaInvNeg) - k.basisExpSigma = make([]bls24315.G1Affine, len(basis)) + pk.basisExpSigma = make([]curve.G1Affine, len(basis)) for i := range basis { - k.basisExpSigma[i].ScalarMultiplication(&basis[i], sigma) + pk.basisExpSigma[i].ScalarMultiplication(&basis[i], sigma) } - k.basis = basis - return k, err + pk.basis = basis + return } -func (k *Key) Commit(values []fr.Element) (commitment bls24315.G1Affine, knowledgeProof bls24315.G1Affine, err error) { +func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, knowledgeProof curve.G1Affine, err error) { - if len(values) != len(k.basis) { + if len(values) != len(pk.basis) { err = fmt.Errorf("unexpected number of values") return } @@ -86,23 +92,23 @@ func (k *Key) Commit(values []fr.Element) (commitment bls24315.G1Affine, knowled NbTasks: 1, // TODO Experiment } - if _, err = commitment.MultiExp(k.basis, values, config); err != nil { + if _, err = commitment.MultiExp(pk.basis, values, config); err != nil { return } - _, err = knowledgeProof.MultiExp(k.basisExpSigma, values, config) + _, err = knowledgeProof.MultiExp(pk.basisExpSigma, values, config) return } -// VerifyKnowledgeProof checks if the proof of knowledge is valid -func (k *Key) VerifyKnowledgeProof(commitment bls24315.G1Affine, knowledgeProof bls24315.G1Affine) error { +// 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") } - product, err := bls24315.Pair([]bls24315.G1Affine{commitment, knowledgeProof}, []bls24315.G2Affine{k.g, k.gRootSigmaNeg}) + product, err := curve.Pair([]curve.G1Affine{commitment, knowledgeProof}, []curve.G2Affine{vk.g, vk.gRootSigmaNeg}) if err != nil { return err } @@ -111,3 +117,56 @@ func (k *Key) VerifyKnowledgeProof(commitment bls24315.G1Affine, knowledgeProof } return fmt.Errorf("proof rejected") } + +// Marshal + +func (pk *ProvingKey) WriteTo(w io.Writer) (int64, error) { + enc := curve.NewEncoder(w) + + if err := enc.Encode(pk.basis); err != nil { + return enc.BytesWritten(), err + } + + err := enc.Encode(pk.basisExpSigma) + + return enc.BytesWritten(), err +} + +func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { + dec := curve.NewDecoder(r) + + 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 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 +} + +func (vk *VerifyingKey) WriteTo(w io.Writer) (int64, error) { + enc := curve.NewEncoder(w) + var err error + + if err = enc.Encode(&vk.g); err != nil { + return enc.BytesWritten(), err + } + err = enc.Encode(&vk.gRootSigmaNeg) + return enc.BytesWritten(), err +} + +func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { + dec := curve.NewDecoder(r) + var err error + + if err = dec.Decode(&vk.g); err != nil { + return dec.BytesRead(), err + } + err = dec.Decode(&vk.gRootSigmaNeg) + return dec.BytesRead(), err +} diff --git a/ecc/bls24-315/fr/pedersen/pedersen_test.go b/ecc/bls24-315/fr/pedersen/pedersen_test.go index 8418968946..475026061c 100644 --- a/ecc/bls24-315/fr/pedersen/pedersen_test.go +++ b/ecc/bls24-315/fr/pedersen/pedersen_test.go @@ -17,10 +17,10 @@ package pedersen import ( - "github.com/consensys/gnark-crypto/ecc/bls24-315" + curve "github.com/consensys/gnark-crypto/ecc/bls24-315" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" + "github.com/consensys/gnark-crypto/utils" "github.com/stretchr/testify/assert" - "math/rand" "testing" ) @@ -44,37 +44,43 @@ func randomFrSlice(t *testing.T, size int) []interface{} { return res } -func randomOnG1() (bls24315.G1Affine, error) { // TODO: Add to G1.go? - gBytes := make([]byte, fr.Bytes) - if _, err := rand.Read(gBytes); err != nil { - return bls24315.G1Affine{}, err +func randomOnG1() (curve.G1Affine, error) { // TODO: Add to G1.go? + if gBytes, err := randomFrSizedBytes(); err != nil { + return curve.G1Affine{}, err + } else { + return curve.HashToG1(gBytes, []byte("random on g1")) } - return bls24315.HashToG1(gBytes, []byte("random on g2")) } -func testCommit(t *testing.T, values ...interface{}) { - - basis := make([]bls24315.G1Affine, len(values)) - for i := range basis { +func randomG1Slice(t *testing.T, size int) []curve.G1Affine { + res := make([]curve.G1Affine, size) + for i := range res { var err error - basis[i], err = randomOnG1() + res[i], err = randomOnG1() assert.NoError(t, err) } + return res +} + +func testCommit(t *testing.T, values ...interface{}) { + + basis := randomG1Slice(t, len(values)) var ( - key Key + pk ProvingKey + vk VerifyingKey err error - commitment, pok bls24315.G1Affine + commitment, pok curve.G1Affine ) - key, err = Setup(basis) + pk, vk, err = Setup(basis) assert.NoError(t, err) - commitment, pok, err = key.Commit(interfaceSliceToFrSlice(t, values...)) + commitment, pok, err = pk.Commit(interfaceSliceToFrSlice(t, values...)) assert.NoError(t, err) - assert.NoError(t, key.VerifyKnowledgeProof(commitment, pok)) + assert.NoError(t, vk.Verify(commitment, pok)) pok.Neg(&pok) - assert.NotNil(t, key.VerifyKnowledgeProof(commitment, pok)) + assert.NotNil(t, vk.Verify(commitment, pok)) } func TestCommitToOne(t *testing.T) { @@ -88,3 +94,21 @@ func TestCommitSingle(t *testing.T) { func TestCommitFiveElements(t *testing.T) { testCommit(t, randomFrSlice(t, 5)...) } + +func TestMarshal(t *testing.T) { + var pk ProvingKey + pk.basisExpSigma = randomG1Slice(t, 5) + pk.basis = randomG1Slice(t, 5) + + var ( + vk VerifyingKey + err error + ) + vk.g, err = randomOnG2() + assert.NoError(t, err) + vk.gRootSigmaNeg, err = randomOnG2() + assert.NoError(t, err) + + t.Run("ProvingKey -> Bytes -> ProvingKey must remain identical.", utils.SerializationRoundTrip(&pk)) + t.Run("VerifyingKey -> Bytes -> VerifyingKey must remain identical.", utils.SerializationRoundTrip(&vk)) +} diff --git a/ecc/bls24-317/fr/pedersen/pedersen.go b/ecc/bls24-317/fr/pedersen/pedersen.go index 9b6777fa87..3b8fc25093 100644 --- a/ecc/bls24-317/fr/pedersen/pedersen.go +++ b/ecc/bls24-317/fr/pedersen/pedersen.go @@ -20,62 +20,68 @@ import ( "crypto/rand" "fmt" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/ecc/bls24-317" + curve "github.com/consensys/gnark-crypto/ecc/bls24-317" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" + "io" "math/big" ) -// Key for proof and verification -type Key struct { - g bls24317.G2Affine // TODO @tabaie: does this really have to be randomized? - gRootSigmaNeg bls24317.G2Affine //gRootSigmaNeg = g^{-1/σ} - basis []bls24317.G1Affine - basisExpSigma []bls24317.G1Affine +// ProvingKey for committing and proofs of knowledge +type ProvingKey struct { + basis []curve.G1Affine + basisExpSigma []curve.G1Affine } -func randomOnG2() (bls24317.G2Affine, error) { // TODO: Add to G2.go? - gBytes := make([]byte, fr.Bytes) - if _, err := rand.Read(gBytes); err != nil { - return bls24317.G2Affine{}, err +type VerifyingKey struct { + 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 +} + +func randomOnG2() (curve.G2Affine, error) { // TODO: Add to G2.go? + if gBytes, err := randomFrSizedBytes(); err != nil { + return curve.G2Affine{}, err + } else { + return curve.HashToG2(gBytes, []byte("random on g2")) } - return bls24317.HashToG2(gBytes, []byte("random on g2")) } -func Setup(basis []bls24317.G1Affine) (Key, error) { - var ( - k Key - err error - ) +func Setup(basis []curve.G1Affine) (pk ProvingKey, vk VerifyingKey, err error) { - if k.g, err = randomOnG2(); err != nil { - return k, err + 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 k, err + return } sigma.Add(sigma, big.NewInt(1)) var sigmaInvNeg big.Int sigmaInvNeg.ModInverse(sigma, fr.Modulus()) sigmaInvNeg.Sub(fr.Modulus(), &sigmaInvNeg) - k.gRootSigmaNeg.ScalarMultiplication(&k.g, &sigmaInvNeg) + vk.gRootSigmaNeg.ScalarMultiplication(&vk.g, &sigmaInvNeg) - k.basisExpSigma = make([]bls24317.G1Affine, len(basis)) + pk.basisExpSigma = make([]curve.G1Affine, len(basis)) for i := range basis { - k.basisExpSigma[i].ScalarMultiplication(&basis[i], sigma) + pk.basisExpSigma[i].ScalarMultiplication(&basis[i], sigma) } - k.basis = basis - return k, err + pk.basis = basis + return } -func (k *Key) Commit(values []fr.Element) (commitment bls24317.G1Affine, knowledgeProof bls24317.G1Affine, err error) { +func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, knowledgeProof curve.G1Affine, err error) { - if len(values) != len(k.basis) { + if len(values) != len(pk.basis) { err = fmt.Errorf("unexpected number of values") return } @@ -86,23 +92,23 @@ func (k *Key) Commit(values []fr.Element) (commitment bls24317.G1Affine, knowled NbTasks: 1, // TODO Experiment } - if _, err = commitment.MultiExp(k.basis, values, config); err != nil { + if _, err = commitment.MultiExp(pk.basis, values, config); err != nil { return } - _, err = knowledgeProof.MultiExp(k.basisExpSigma, values, config) + _, err = knowledgeProof.MultiExp(pk.basisExpSigma, values, config) return } -// VerifyKnowledgeProof checks if the proof of knowledge is valid -func (k *Key) VerifyKnowledgeProof(commitment bls24317.G1Affine, knowledgeProof bls24317.G1Affine) error { +// 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") } - product, err := bls24317.Pair([]bls24317.G1Affine{commitment, knowledgeProof}, []bls24317.G2Affine{k.g, k.gRootSigmaNeg}) + product, err := curve.Pair([]curve.G1Affine{commitment, knowledgeProof}, []curve.G2Affine{vk.g, vk.gRootSigmaNeg}) if err != nil { return err } @@ -111,3 +117,56 @@ func (k *Key) VerifyKnowledgeProof(commitment bls24317.G1Affine, knowledgeProof } return fmt.Errorf("proof rejected") } + +// Marshal + +func (pk *ProvingKey) WriteTo(w io.Writer) (int64, error) { + enc := curve.NewEncoder(w) + + if err := enc.Encode(pk.basis); err != nil { + return enc.BytesWritten(), err + } + + err := enc.Encode(pk.basisExpSigma) + + return enc.BytesWritten(), err +} + +func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { + dec := curve.NewDecoder(r) + + 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 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 +} + +func (vk *VerifyingKey) WriteTo(w io.Writer) (int64, error) { + enc := curve.NewEncoder(w) + var err error + + if err = enc.Encode(&vk.g); err != nil { + return enc.BytesWritten(), err + } + err = enc.Encode(&vk.gRootSigmaNeg) + return enc.BytesWritten(), err +} + +func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { + dec := curve.NewDecoder(r) + var err error + + if err = dec.Decode(&vk.g); err != nil { + return dec.BytesRead(), err + } + err = dec.Decode(&vk.gRootSigmaNeg) + return dec.BytesRead(), err +} diff --git a/ecc/bls24-317/fr/pedersen/pedersen_test.go b/ecc/bls24-317/fr/pedersen/pedersen_test.go index fe0f0b48f6..ee64c9aa3c 100644 --- a/ecc/bls24-317/fr/pedersen/pedersen_test.go +++ b/ecc/bls24-317/fr/pedersen/pedersen_test.go @@ -17,10 +17,10 @@ package pedersen import ( - "github.com/consensys/gnark-crypto/ecc/bls24-317" + curve "github.com/consensys/gnark-crypto/ecc/bls24-317" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" + "github.com/consensys/gnark-crypto/utils" "github.com/stretchr/testify/assert" - "math/rand" "testing" ) @@ -44,37 +44,43 @@ func randomFrSlice(t *testing.T, size int) []interface{} { return res } -func randomOnG1() (bls24317.G1Affine, error) { // TODO: Add to G1.go? - gBytes := make([]byte, fr.Bytes) - if _, err := rand.Read(gBytes); err != nil { - return bls24317.G1Affine{}, err +func randomOnG1() (curve.G1Affine, error) { // TODO: Add to G1.go? + if gBytes, err := randomFrSizedBytes(); err != nil { + return curve.G1Affine{}, err + } else { + return curve.HashToG1(gBytes, []byte("random on g1")) } - return bls24317.HashToG1(gBytes, []byte("random on g2")) } -func testCommit(t *testing.T, values ...interface{}) { - - basis := make([]bls24317.G1Affine, len(values)) - for i := range basis { +func randomG1Slice(t *testing.T, size int) []curve.G1Affine { + res := make([]curve.G1Affine, size) + for i := range res { var err error - basis[i], err = randomOnG1() + res[i], err = randomOnG1() assert.NoError(t, err) } + return res +} + +func testCommit(t *testing.T, values ...interface{}) { + + basis := randomG1Slice(t, len(values)) var ( - key Key + pk ProvingKey + vk VerifyingKey err error - commitment, pok bls24317.G1Affine + commitment, pok curve.G1Affine ) - key, err = Setup(basis) + pk, vk, err = Setup(basis) assert.NoError(t, err) - commitment, pok, err = key.Commit(interfaceSliceToFrSlice(t, values...)) + commitment, pok, err = pk.Commit(interfaceSliceToFrSlice(t, values...)) assert.NoError(t, err) - assert.NoError(t, key.VerifyKnowledgeProof(commitment, pok)) + assert.NoError(t, vk.Verify(commitment, pok)) pok.Neg(&pok) - assert.NotNil(t, key.VerifyKnowledgeProof(commitment, pok)) + assert.NotNil(t, vk.Verify(commitment, pok)) } func TestCommitToOne(t *testing.T) { @@ -88,3 +94,21 @@ func TestCommitSingle(t *testing.T) { func TestCommitFiveElements(t *testing.T) { testCommit(t, randomFrSlice(t, 5)...) } + +func TestMarshal(t *testing.T) { + var pk ProvingKey + pk.basisExpSigma = randomG1Slice(t, 5) + pk.basis = randomG1Slice(t, 5) + + var ( + vk VerifyingKey + err error + ) + vk.g, err = randomOnG2() + assert.NoError(t, err) + vk.gRootSigmaNeg, err = randomOnG2() + assert.NoError(t, err) + + t.Run("ProvingKey -> Bytes -> ProvingKey must remain identical.", utils.SerializationRoundTrip(&pk)) + t.Run("VerifyingKey -> Bytes -> VerifyingKey must remain identical.", utils.SerializationRoundTrip(&vk)) +} diff --git a/ecc/bn254/fr/pedersen/pedersen.go b/ecc/bn254/fr/pedersen/pedersen.go index 475644705e..b7f60bf2eb 100644 --- a/ecc/bn254/fr/pedersen/pedersen.go +++ b/ecc/bn254/fr/pedersen/pedersen.go @@ -20,62 +20,68 @@ import ( "crypto/rand" "fmt" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/ecc/bn254" + curve "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "io" "math/big" ) -// Key for proof and verification -type Key struct { - g bn254.G2Affine // TODO @tabaie: does this really have to be randomized? - gRootSigmaNeg bn254.G2Affine //gRootSigmaNeg = g^{-1/σ} - basis []bn254.G1Affine - basisExpSigma []bn254.G1Affine +// ProvingKey for committing and proofs of knowledge +type ProvingKey struct { + basis []curve.G1Affine + basisExpSigma []curve.G1Affine } -func randomOnG2() (bn254.G2Affine, error) { // TODO: Add to G2.go? - gBytes := make([]byte, fr.Bytes) - if _, err := rand.Read(gBytes); err != nil { - return bn254.G2Affine{}, err +type VerifyingKey struct { + 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 +} + +func randomOnG2() (curve.G2Affine, error) { // TODO: Add to G2.go? + if gBytes, err := randomFrSizedBytes(); err != nil { + return curve.G2Affine{}, err + } else { + return curve.HashToG2(gBytes, []byte("random on g2")) } - return bn254.HashToG2(gBytes, []byte("random on g2")) } -func Setup(basis []bn254.G1Affine) (Key, error) { - var ( - k Key - err error - ) +func Setup(basis []curve.G1Affine) (pk ProvingKey, vk VerifyingKey, err error) { - if k.g, err = randomOnG2(); err != nil { - return k, err + 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 k, err + return } sigma.Add(sigma, big.NewInt(1)) var sigmaInvNeg big.Int sigmaInvNeg.ModInverse(sigma, fr.Modulus()) sigmaInvNeg.Sub(fr.Modulus(), &sigmaInvNeg) - k.gRootSigmaNeg.ScalarMultiplication(&k.g, &sigmaInvNeg) + vk.gRootSigmaNeg.ScalarMultiplication(&vk.g, &sigmaInvNeg) - k.basisExpSigma = make([]bn254.G1Affine, len(basis)) + pk.basisExpSigma = make([]curve.G1Affine, len(basis)) for i := range basis { - k.basisExpSigma[i].ScalarMultiplication(&basis[i], sigma) + pk.basisExpSigma[i].ScalarMultiplication(&basis[i], sigma) } - k.basis = basis - return k, err + pk.basis = basis + return } -func (k *Key) Commit(values []fr.Element) (commitment bn254.G1Affine, knowledgeProof bn254.G1Affine, err error) { +func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, knowledgeProof curve.G1Affine, err error) { - if len(values) != len(k.basis) { + if len(values) != len(pk.basis) { err = fmt.Errorf("unexpected number of values") return } @@ -86,23 +92,23 @@ func (k *Key) Commit(values []fr.Element) (commitment bn254.G1Affine, knowledgeP NbTasks: 1, // TODO Experiment } - if _, err = commitment.MultiExp(k.basis, values, config); err != nil { + if _, err = commitment.MultiExp(pk.basis, values, config); err != nil { return } - _, err = knowledgeProof.MultiExp(k.basisExpSigma, values, config) + _, err = knowledgeProof.MultiExp(pk.basisExpSigma, values, config) return } -// VerifyKnowledgeProof checks if the proof of knowledge is valid -func (k *Key) VerifyKnowledgeProof(commitment bn254.G1Affine, knowledgeProof bn254.G1Affine) error { +// 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") } - product, err := bn254.Pair([]bn254.G1Affine{commitment, knowledgeProof}, []bn254.G2Affine{k.g, k.gRootSigmaNeg}) + product, err := curve.Pair([]curve.G1Affine{commitment, knowledgeProof}, []curve.G2Affine{vk.g, vk.gRootSigmaNeg}) if err != nil { return err } @@ -111,3 +117,56 @@ func (k *Key) VerifyKnowledgeProof(commitment bn254.G1Affine, knowledgeProof bn2 } return fmt.Errorf("proof rejected") } + +// Marshal + +func (pk *ProvingKey) WriteTo(w io.Writer) (int64, error) { + enc := curve.NewEncoder(w) + + if err := enc.Encode(pk.basis); err != nil { + return enc.BytesWritten(), err + } + + err := enc.Encode(pk.basisExpSigma) + + return enc.BytesWritten(), err +} + +func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { + dec := curve.NewDecoder(r) + + 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 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 +} + +func (vk *VerifyingKey) WriteTo(w io.Writer) (int64, error) { + enc := curve.NewEncoder(w) + var err error + + if err = enc.Encode(&vk.g); err != nil { + return enc.BytesWritten(), err + } + err = enc.Encode(&vk.gRootSigmaNeg) + return enc.BytesWritten(), err +} + +func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { + dec := curve.NewDecoder(r) + var err error + + if err = dec.Decode(&vk.g); err != nil { + return dec.BytesRead(), err + } + err = dec.Decode(&vk.gRootSigmaNeg) + return dec.BytesRead(), err +} diff --git a/ecc/bn254/fr/pedersen/pedersen_test.go b/ecc/bn254/fr/pedersen/pedersen_test.go index eac9cebe6c..14fa00d83f 100644 --- a/ecc/bn254/fr/pedersen/pedersen_test.go +++ b/ecc/bn254/fr/pedersen/pedersen_test.go @@ -17,10 +17,10 @@ package pedersen import ( - "github.com/consensys/gnark-crypto/ecc/bn254" + curve "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark-crypto/utils" "github.com/stretchr/testify/assert" - "math/rand" "testing" ) @@ -44,37 +44,43 @@ func randomFrSlice(t *testing.T, size int) []interface{} { return res } -func randomOnG1() (bn254.G1Affine, error) { // TODO: Add to G1.go? - gBytes := make([]byte, fr.Bytes) - if _, err := rand.Read(gBytes); err != nil { - return bn254.G1Affine{}, err +func randomOnG1() (curve.G1Affine, error) { // TODO: Add to G1.go? + if gBytes, err := randomFrSizedBytes(); err != nil { + return curve.G1Affine{}, err + } else { + return curve.HashToG1(gBytes, []byte("random on g1")) } - return bn254.HashToG1(gBytes, []byte("random on g2")) } -func testCommit(t *testing.T, values ...interface{}) { - - basis := make([]bn254.G1Affine, len(values)) - for i := range basis { +func randomG1Slice(t *testing.T, size int) []curve.G1Affine { + res := make([]curve.G1Affine, size) + for i := range res { var err error - basis[i], err = randomOnG1() + res[i], err = randomOnG1() assert.NoError(t, err) } + return res +} + +func testCommit(t *testing.T, values ...interface{}) { + + basis := randomG1Slice(t, len(values)) var ( - key Key + pk ProvingKey + vk VerifyingKey err error - commitment, pok bn254.G1Affine + commitment, pok curve.G1Affine ) - key, err = Setup(basis) + pk, vk, err = Setup(basis) assert.NoError(t, err) - commitment, pok, err = key.Commit(interfaceSliceToFrSlice(t, values...)) + commitment, pok, err = pk.Commit(interfaceSliceToFrSlice(t, values...)) assert.NoError(t, err) - assert.NoError(t, key.VerifyKnowledgeProof(commitment, pok)) + assert.NoError(t, vk.Verify(commitment, pok)) pok.Neg(&pok) - assert.NotNil(t, key.VerifyKnowledgeProof(commitment, pok)) + assert.NotNil(t, vk.Verify(commitment, pok)) } func TestCommitToOne(t *testing.T) { @@ -88,3 +94,21 @@ func TestCommitSingle(t *testing.T) { func TestCommitFiveElements(t *testing.T) { testCommit(t, randomFrSlice(t, 5)...) } + +func TestMarshal(t *testing.T) { + var pk ProvingKey + pk.basisExpSigma = randomG1Slice(t, 5) + pk.basis = randomG1Slice(t, 5) + + var ( + vk VerifyingKey + err error + ) + vk.g, err = randomOnG2() + assert.NoError(t, err) + vk.gRootSigmaNeg, err = randomOnG2() + assert.NoError(t, err) + + t.Run("ProvingKey -> Bytes -> ProvingKey must remain identical.", utils.SerializationRoundTrip(&pk)) + t.Run("VerifyingKey -> Bytes -> VerifyingKey must remain identical.", utils.SerializationRoundTrip(&vk)) +} diff --git a/ecc/bw6-633/fr/pedersen/pedersen.go b/ecc/bw6-633/fr/pedersen/pedersen.go index 1c5f269bf0..a680a17c66 100644 --- a/ecc/bw6-633/fr/pedersen/pedersen.go +++ b/ecc/bw6-633/fr/pedersen/pedersen.go @@ -20,62 +20,68 @@ import ( "crypto/rand" "fmt" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/ecc/bw6-633" + curve "github.com/consensys/gnark-crypto/ecc/bw6-633" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" + "io" "math/big" ) -// Key for proof and verification -type Key struct { - g bw6633.G2Affine // TODO @tabaie: does this really have to be randomized? - gRootSigmaNeg bw6633.G2Affine //gRootSigmaNeg = g^{-1/σ} - basis []bw6633.G1Affine - basisExpSigma []bw6633.G1Affine +// ProvingKey for committing and proofs of knowledge +type ProvingKey struct { + basis []curve.G1Affine + basisExpSigma []curve.G1Affine } -func randomOnG2() (bw6633.G2Affine, error) { // TODO: Add to G2.go? - gBytes := make([]byte, fr.Bytes) - if _, err := rand.Read(gBytes); err != nil { - return bw6633.G2Affine{}, err +type VerifyingKey struct { + 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 +} + +func randomOnG2() (curve.G2Affine, error) { // TODO: Add to G2.go? + if gBytes, err := randomFrSizedBytes(); err != nil { + return curve.G2Affine{}, err + } else { + return curve.HashToG2(gBytes, []byte("random on g2")) } - return bw6633.HashToG2(gBytes, []byte("random on g2")) } -func Setup(basis []bw6633.G1Affine) (Key, error) { - var ( - k Key - err error - ) +func Setup(basis []curve.G1Affine) (pk ProvingKey, vk VerifyingKey, err error) { - if k.g, err = randomOnG2(); err != nil { - return k, err + 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 k, err + return } sigma.Add(sigma, big.NewInt(1)) var sigmaInvNeg big.Int sigmaInvNeg.ModInverse(sigma, fr.Modulus()) sigmaInvNeg.Sub(fr.Modulus(), &sigmaInvNeg) - k.gRootSigmaNeg.ScalarMultiplication(&k.g, &sigmaInvNeg) + vk.gRootSigmaNeg.ScalarMultiplication(&vk.g, &sigmaInvNeg) - k.basisExpSigma = make([]bw6633.G1Affine, len(basis)) + pk.basisExpSigma = make([]curve.G1Affine, len(basis)) for i := range basis { - k.basisExpSigma[i].ScalarMultiplication(&basis[i], sigma) + pk.basisExpSigma[i].ScalarMultiplication(&basis[i], sigma) } - k.basis = basis - return k, err + pk.basis = basis + return } -func (k *Key) Commit(values []fr.Element) (commitment bw6633.G1Affine, knowledgeProof bw6633.G1Affine, err error) { +func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, knowledgeProof curve.G1Affine, err error) { - if len(values) != len(k.basis) { + if len(values) != len(pk.basis) { err = fmt.Errorf("unexpected number of values") return } @@ -86,23 +92,23 @@ func (k *Key) Commit(values []fr.Element) (commitment bw6633.G1Affine, knowledge NbTasks: 1, // TODO Experiment } - if _, err = commitment.MultiExp(k.basis, values, config); err != nil { + if _, err = commitment.MultiExp(pk.basis, values, config); err != nil { return } - _, err = knowledgeProof.MultiExp(k.basisExpSigma, values, config) + _, err = knowledgeProof.MultiExp(pk.basisExpSigma, values, config) return } -// VerifyKnowledgeProof checks if the proof of knowledge is valid -func (k *Key) VerifyKnowledgeProof(commitment bw6633.G1Affine, knowledgeProof bw6633.G1Affine) error { +// 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") } - product, err := bw6633.Pair([]bw6633.G1Affine{commitment, knowledgeProof}, []bw6633.G2Affine{k.g, k.gRootSigmaNeg}) + product, err := curve.Pair([]curve.G1Affine{commitment, knowledgeProof}, []curve.G2Affine{vk.g, vk.gRootSigmaNeg}) if err != nil { return err } @@ -111,3 +117,56 @@ func (k *Key) VerifyKnowledgeProof(commitment bw6633.G1Affine, knowledgeProof bw } return fmt.Errorf("proof rejected") } + +// Marshal + +func (pk *ProvingKey) WriteTo(w io.Writer) (int64, error) { + enc := curve.NewEncoder(w) + + if err := enc.Encode(pk.basis); err != nil { + return enc.BytesWritten(), err + } + + err := enc.Encode(pk.basisExpSigma) + + return enc.BytesWritten(), err +} + +func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { + dec := curve.NewDecoder(r) + + 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 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 +} + +func (vk *VerifyingKey) WriteTo(w io.Writer) (int64, error) { + enc := curve.NewEncoder(w) + var err error + + if err = enc.Encode(&vk.g); err != nil { + return enc.BytesWritten(), err + } + err = enc.Encode(&vk.gRootSigmaNeg) + return enc.BytesWritten(), err +} + +func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { + dec := curve.NewDecoder(r) + var err error + + if err = dec.Decode(&vk.g); err != nil { + return dec.BytesRead(), err + } + err = dec.Decode(&vk.gRootSigmaNeg) + return dec.BytesRead(), err +} diff --git a/ecc/bw6-633/fr/pedersen/pedersen_test.go b/ecc/bw6-633/fr/pedersen/pedersen_test.go index 17c1f9aa2b..f2b9bb6e47 100644 --- a/ecc/bw6-633/fr/pedersen/pedersen_test.go +++ b/ecc/bw6-633/fr/pedersen/pedersen_test.go @@ -17,10 +17,10 @@ package pedersen import ( - "github.com/consensys/gnark-crypto/ecc/bw6-633" + curve "github.com/consensys/gnark-crypto/ecc/bw6-633" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" + "github.com/consensys/gnark-crypto/utils" "github.com/stretchr/testify/assert" - "math/rand" "testing" ) @@ -44,37 +44,43 @@ func randomFrSlice(t *testing.T, size int) []interface{} { return res } -func randomOnG1() (bw6633.G1Affine, error) { // TODO: Add to G1.go? - gBytes := make([]byte, fr.Bytes) - if _, err := rand.Read(gBytes); err != nil { - return bw6633.G1Affine{}, err +func randomOnG1() (curve.G1Affine, error) { // TODO: Add to G1.go? + if gBytes, err := randomFrSizedBytes(); err != nil { + return curve.G1Affine{}, err + } else { + return curve.HashToG1(gBytes, []byte("random on g1")) } - return bw6633.HashToG1(gBytes, []byte("random on g2")) } -func testCommit(t *testing.T, values ...interface{}) { - - basis := make([]bw6633.G1Affine, len(values)) - for i := range basis { +func randomG1Slice(t *testing.T, size int) []curve.G1Affine { + res := make([]curve.G1Affine, size) + for i := range res { var err error - basis[i], err = randomOnG1() + res[i], err = randomOnG1() assert.NoError(t, err) } + return res +} + +func testCommit(t *testing.T, values ...interface{}) { + + basis := randomG1Slice(t, len(values)) var ( - key Key + pk ProvingKey + vk VerifyingKey err error - commitment, pok bw6633.G1Affine + commitment, pok curve.G1Affine ) - key, err = Setup(basis) + pk, vk, err = Setup(basis) assert.NoError(t, err) - commitment, pok, err = key.Commit(interfaceSliceToFrSlice(t, values...)) + commitment, pok, err = pk.Commit(interfaceSliceToFrSlice(t, values...)) assert.NoError(t, err) - assert.NoError(t, key.VerifyKnowledgeProof(commitment, pok)) + assert.NoError(t, vk.Verify(commitment, pok)) pok.Neg(&pok) - assert.NotNil(t, key.VerifyKnowledgeProof(commitment, pok)) + assert.NotNil(t, vk.Verify(commitment, pok)) } func TestCommitToOne(t *testing.T) { @@ -88,3 +94,21 @@ func TestCommitSingle(t *testing.T) { func TestCommitFiveElements(t *testing.T) { testCommit(t, randomFrSlice(t, 5)...) } + +func TestMarshal(t *testing.T) { + var pk ProvingKey + pk.basisExpSigma = randomG1Slice(t, 5) + pk.basis = randomG1Slice(t, 5) + + var ( + vk VerifyingKey + err error + ) + vk.g, err = randomOnG2() + assert.NoError(t, err) + vk.gRootSigmaNeg, err = randomOnG2() + assert.NoError(t, err) + + t.Run("ProvingKey -> Bytes -> ProvingKey must remain identical.", utils.SerializationRoundTrip(&pk)) + t.Run("VerifyingKey -> Bytes -> VerifyingKey must remain identical.", utils.SerializationRoundTrip(&vk)) +} diff --git a/ecc/bw6-756/fr/pedersen/pedersen.go b/ecc/bw6-756/fr/pedersen/pedersen.go index a670f6ac5f..e6377e1366 100644 --- a/ecc/bw6-756/fr/pedersen/pedersen.go +++ b/ecc/bw6-756/fr/pedersen/pedersen.go @@ -20,62 +20,68 @@ import ( "crypto/rand" "fmt" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/ecc/bw6-756" + curve "github.com/consensys/gnark-crypto/ecc/bw6-756" "github.com/consensys/gnark-crypto/ecc/bw6-756/fr" + "io" "math/big" ) -// Key for proof and verification -type Key struct { - g bw6756.G2Affine // TODO @tabaie: does this really have to be randomized? - gRootSigmaNeg bw6756.G2Affine //gRootSigmaNeg = g^{-1/σ} - basis []bw6756.G1Affine - basisExpSigma []bw6756.G1Affine +// ProvingKey for committing and proofs of knowledge +type ProvingKey struct { + basis []curve.G1Affine + basisExpSigma []curve.G1Affine } -func randomOnG2() (bw6756.G2Affine, error) { // TODO: Add to G2.go? - gBytes := make([]byte, fr.Bytes) - if _, err := rand.Read(gBytes); err != nil { - return bw6756.G2Affine{}, err +type VerifyingKey struct { + 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 +} + +func randomOnG2() (curve.G2Affine, error) { // TODO: Add to G2.go? + if gBytes, err := randomFrSizedBytes(); err != nil { + return curve.G2Affine{}, err + } else { + return curve.HashToG2(gBytes, []byte("random on g2")) } - return bw6756.HashToG2(gBytes, []byte("random on g2")) } -func Setup(basis []bw6756.G1Affine) (Key, error) { - var ( - k Key - err error - ) +func Setup(basis []curve.G1Affine) (pk ProvingKey, vk VerifyingKey, err error) { - if k.g, err = randomOnG2(); err != nil { - return k, err + 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 k, err + return } sigma.Add(sigma, big.NewInt(1)) var sigmaInvNeg big.Int sigmaInvNeg.ModInverse(sigma, fr.Modulus()) sigmaInvNeg.Sub(fr.Modulus(), &sigmaInvNeg) - k.gRootSigmaNeg.ScalarMultiplication(&k.g, &sigmaInvNeg) + vk.gRootSigmaNeg.ScalarMultiplication(&vk.g, &sigmaInvNeg) - k.basisExpSigma = make([]bw6756.G1Affine, len(basis)) + pk.basisExpSigma = make([]curve.G1Affine, len(basis)) for i := range basis { - k.basisExpSigma[i].ScalarMultiplication(&basis[i], sigma) + pk.basisExpSigma[i].ScalarMultiplication(&basis[i], sigma) } - k.basis = basis - return k, err + pk.basis = basis + return } -func (k *Key) Commit(values []fr.Element) (commitment bw6756.G1Affine, knowledgeProof bw6756.G1Affine, err error) { +func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, knowledgeProof curve.G1Affine, err error) { - if len(values) != len(k.basis) { + if len(values) != len(pk.basis) { err = fmt.Errorf("unexpected number of values") return } @@ -86,23 +92,23 @@ func (k *Key) Commit(values []fr.Element) (commitment bw6756.G1Affine, knowledge NbTasks: 1, // TODO Experiment } - if _, err = commitment.MultiExp(k.basis, values, config); err != nil { + if _, err = commitment.MultiExp(pk.basis, values, config); err != nil { return } - _, err = knowledgeProof.MultiExp(k.basisExpSigma, values, config) + _, err = knowledgeProof.MultiExp(pk.basisExpSigma, values, config) return } -// VerifyKnowledgeProof checks if the proof of knowledge is valid -func (k *Key) VerifyKnowledgeProof(commitment bw6756.G1Affine, knowledgeProof bw6756.G1Affine) error { +// 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") } - product, err := bw6756.Pair([]bw6756.G1Affine{commitment, knowledgeProof}, []bw6756.G2Affine{k.g, k.gRootSigmaNeg}) + product, err := curve.Pair([]curve.G1Affine{commitment, knowledgeProof}, []curve.G2Affine{vk.g, vk.gRootSigmaNeg}) if err != nil { return err } @@ -111,3 +117,56 @@ func (k *Key) VerifyKnowledgeProof(commitment bw6756.G1Affine, knowledgeProof bw } return fmt.Errorf("proof rejected") } + +// Marshal + +func (pk *ProvingKey) WriteTo(w io.Writer) (int64, error) { + enc := curve.NewEncoder(w) + + if err := enc.Encode(pk.basis); err != nil { + return enc.BytesWritten(), err + } + + err := enc.Encode(pk.basisExpSigma) + + return enc.BytesWritten(), err +} + +func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { + dec := curve.NewDecoder(r) + + 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 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 +} + +func (vk *VerifyingKey) WriteTo(w io.Writer) (int64, error) { + enc := curve.NewEncoder(w) + var err error + + if err = enc.Encode(&vk.g); err != nil { + return enc.BytesWritten(), err + } + err = enc.Encode(&vk.gRootSigmaNeg) + return enc.BytesWritten(), err +} + +func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { + dec := curve.NewDecoder(r) + var err error + + if err = dec.Decode(&vk.g); err != nil { + return dec.BytesRead(), err + } + err = dec.Decode(&vk.gRootSigmaNeg) + return dec.BytesRead(), err +} diff --git a/ecc/bw6-756/fr/pedersen/pedersen_test.go b/ecc/bw6-756/fr/pedersen/pedersen_test.go index a4b5387c5e..62319db8ab 100644 --- a/ecc/bw6-756/fr/pedersen/pedersen_test.go +++ b/ecc/bw6-756/fr/pedersen/pedersen_test.go @@ -17,10 +17,10 @@ package pedersen import ( - "github.com/consensys/gnark-crypto/ecc/bw6-756" + curve "github.com/consensys/gnark-crypto/ecc/bw6-756" "github.com/consensys/gnark-crypto/ecc/bw6-756/fr" + "github.com/consensys/gnark-crypto/utils" "github.com/stretchr/testify/assert" - "math/rand" "testing" ) @@ -44,37 +44,43 @@ func randomFrSlice(t *testing.T, size int) []interface{} { return res } -func randomOnG1() (bw6756.G1Affine, error) { // TODO: Add to G1.go? - gBytes := make([]byte, fr.Bytes) - if _, err := rand.Read(gBytes); err != nil { - return bw6756.G1Affine{}, err +func randomOnG1() (curve.G1Affine, error) { // TODO: Add to G1.go? + if gBytes, err := randomFrSizedBytes(); err != nil { + return curve.G1Affine{}, err + } else { + return curve.HashToG1(gBytes, []byte("random on g1")) } - return bw6756.HashToG1(gBytes, []byte("random on g2")) } -func testCommit(t *testing.T, values ...interface{}) { - - basis := make([]bw6756.G1Affine, len(values)) - for i := range basis { +func randomG1Slice(t *testing.T, size int) []curve.G1Affine { + res := make([]curve.G1Affine, size) + for i := range res { var err error - basis[i], err = randomOnG1() + res[i], err = randomOnG1() assert.NoError(t, err) } + return res +} + +func testCommit(t *testing.T, values ...interface{}) { + + basis := randomG1Slice(t, len(values)) var ( - key Key + pk ProvingKey + vk VerifyingKey err error - commitment, pok bw6756.G1Affine + commitment, pok curve.G1Affine ) - key, err = Setup(basis) + pk, vk, err = Setup(basis) assert.NoError(t, err) - commitment, pok, err = key.Commit(interfaceSliceToFrSlice(t, values...)) + commitment, pok, err = pk.Commit(interfaceSliceToFrSlice(t, values...)) assert.NoError(t, err) - assert.NoError(t, key.VerifyKnowledgeProof(commitment, pok)) + assert.NoError(t, vk.Verify(commitment, pok)) pok.Neg(&pok) - assert.NotNil(t, key.VerifyKnowledgeProof(commitment, pok)) + assert.NotNil(t, vk.Verify(commitment, pok)) } func TestCommitToOne(t *testing.T) { @@ -88,3 +94,21 @@ func TestCommitSingle(t *testing.T) { func TestCommitFiveElements(t *testing.T) { testCommit(t, randomFrSlice(t, 5)...) } + +func TestMarshal(t *testing.T) { + var pk ProvingKey + pk.basisExpSigma = randomG1Slice(t, 5) + pk.basis = randomG1Slice(t, 5) + + var ( + vk VerifyingKey + err error + ) + vk.g, err = randomOnG2() + assert.NoError(t, err) + vk.gRootSigmaNeg, err = randomOnG2() + assert.NoError(t, err) + + t.Run("ProvingKey -> Bytes -> ProvingKey must remain identical.", utils.SerializationRoundTrip(&pk)) + t.Run("VerifyingKey -> Bytes -> VerifyingKey must remain identical.", utils.SerializationRoundTrip(&vk)) +} diff --git a/ecc/bw6-761/fr/pedersen/pedersen.go b/ecc/bw6-761/fr/pedersen/pedersen.go index 4af6559c91..f22b499701 100644 --- a/ecc/bw6-761/fr/pedersen/pedersen.go +++ b/ecc/bw6-761/fr/pedersen/pedersen.go @@ -20,62 +20,68 @@ import ( "crypto/rand" "fmt" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/ecc/bw6-761" + curve "github.com/consensys/gnark-crypto/ecc/bw6-761" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" + "io" "math/big" ) -// Key for proof and verification -type Key struct { - g bw6761.G2Affine // TODO @tabaie: does this really have to be randomized? - gRootSigmaNeg bw6761.G2Affine //gRootSigmaNeg = g^{-1/σ} - basis []bw6761.G1Affine - basisExpSigma []bw6761.G1Affine +// ProvingKey for committing and proofs of knowledge +type ProvingKey struct { + basis []curve.G1Affine + basisExpSigma []curve.G1Affine } -func randomOnG2() (bw6761.G2Affine, error) { // TODO: Add to G2.go? - gBytes := make([]byte, fr.Bytes) - if _, err := rand.Read(gBytes); err != nil { - return bw6761.G2Affine{}, err +type VerifyingKey struct { + 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 +} + +func randomOnG2() (curve.G2Affine, error) { // TODO: Add to G2.go? + if gBytes, err := randomFrSizedBytes(); err != nil { + return curve.G2Affine{}, err + } else { + return curve.HashToG2(gBytes, []byte("random on g2")) } - return bw6761.HashToG2(gBytes, []byte("random on g2")) } -func Setup(basis []bw6761.G1Affine) (Key, error) { - var ( - k Key - err error - ) +func Setup(basis []curve.G1Affine) (pk ProvingKey, vk VerifyingKey, err error) { - if k.g, err = randomOnG2(); err != nil { - return k, err + 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 k, err + return } sigma.Add(sigma, big.NewInt(1)) var sigmaInvNeg big.Int sigmaInvNeg.ModInverse(sigma, fr.Modulus()) sigmaInvNeg.Sub(fr.Modulus(), &sigmaInvNeg) - k.gRootSigmaNeg.ScalarMultiplication(&k.g, &sigmaInvNeg) + vk.gRootSigmaNeg.ScalarMultiplication(&vk.g, &sigmaInvNeg) - k.basisExpSigma = make([]bw6761.G1Affine, len(basis)) + pk.basisExpSigma = make([]curve.G1Affine, len(basis)) for i := range basis { - k.basisExpSigma[i].ScalarMultiplication(&basis[i], sigma) + pk.basisExpSigma[i].ScalarMultiplication(&basis[i], sigma) } - k.basis = basis - return k, err + pk.basis = basis + return } -func (k *Key) Commit(values []fr.Element) (commitment bw6761.G1Affine, knowledgeProof bw6761.G1Affine, err error) { +func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, knowledgeProof curve.G1Affine, err error) { - if len(values) != len(k.basis) { + if len(values) != len(pk.basis) { err = fmt.Errorf("unexpected number of values") return } @@ -86,23 +92,23 @@ func (k *Key) Commit(values []fr.Element) (commitment bw6761.G1Affine, knowledge NbTasks: 1, // TODO Experiment } - if _, err = commitment.MultiExp(k.basis, values, config); err != nil { + if _, err = commitment.MultiExp(pk.basis, values, config); err != nil { return } - _, err = knowledgeProof.MultiExp(k.basisExpSigma, values, config) + _, err = knowledgeProof.MultiExp(pk.basisExpSigma, values, config) return } -// VerifyKnowledgeProof checks if the proof of knowledge is valid -func (k *Key) VerifyKnowledgeProof(commitment bw6761.G1Affine, knowledgeProof bw6761.G1Affine) error { +// 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") } - product, err := bw6761.Pair([]bw6761.G1Affine{commitment, knowledgeProof}, []bw6761.G2Affine{k.g, k.gRootSigmaNeg}) + product, err := curve.Pair([]curve.G1Affine{commitment, knowledgeProof}, []curve.G2Affine{vk.g, vk.gRootSigmaNeg}) if err != nil { return err } @@ -111,3 +117,56 @@ func (k *Key) VerifyKnowledgeProof(commitment bw6761.G1Affine, knowledgeProof bw } return fmt.Errorf("proof rejected") } + +// Marshal + +func (pk *ProvingKey) WriteTo(w io.Writer) (int64, error) { + enc := curve.NewEncoder(w) + + if err := enc.Encode(pk.basis); err != nil { + return enc.BytesWritten(), err + } + + err := enc.Encode(pk.basisExpSigma) + + return enc.BytesWritten(), err +} + +func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { + dec := curve.NewDecoder(r) + + 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 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 +} + +func (vk *VerifyingKey) WriteTo(w io.Writer) (int64, error) { + enc := curve.NewEncoder(w) + var err error + + if err = enc.Encode(&vk.g); err != nil { + return enc.BytesWritten(), err + } + err = enc.Encode(&vk.gRootSigmaNeg) + return enc.BytesWritten(), err +} + +func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { + dec := curve.NewDecoder(r) + var err error + + if err = dec.Decode(&vk.g); err != nil { + return dec.BytesRead(), err + } + err = dec.Decode(&vk.gRootSigmaNeg) + return dec.BytesRead(), err +} diff --git a/ecc/bw6-761/fr/pedersen/pedersen_test.go b/ecc/bw6-761/fr/pedersen/pedersen_test.go index 1747d3a0b8..646cf0e9be 100644 --- a/ecc/bw6-761/fr/pedersen/pedersen_test.go +++ b/ecc/bw6-761/fr/pedersen/pedersen_test.go @@ -17,10 +17,10 @@ package pedersen import ( - "github.com/consensys/gnark-crypto/ecc/bw6-761" + curve "github.com/consensys/gnark-crypto/ecc/bw6-761" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" + "github.com/consensys/gnark-crypto/utils" "github.com/stretchr/testify/assert" - "math/rand" "testing" ) @@ -44,37 +44,43 @@ func randomFrSlice(t *testing.T, size int) []interface{} { return res } -func randomOnG1() (bw6761.G1Affine, error) { // TODO: Add to G1.go? - gBytes := make([]byte, fr.Bytes) - if _, err := rand.Read(gBytes); err != nil { - return bw6761.G1Affine{}, err +func randomOnG1() (curve.G1Affine, error) { // TODO: Add to G1.go? + if gBytes, err := randomFrSizedBytes(); err != nil { + return curve.G1Affine{}, err + } else { + return curve.HashToG1(gBytes, []byte("random on g1")) } - return bw6761.HashToG1(gBytes, []byte("random on g2")) } -func testCommit(t *testing.T, values ...interface{}) { - - basis := make([]bw6761.G1Affine, len(values)) - for i := range basis { +func randomG1Slice(t *testing.T, size int) []curve.G1Affine { + res := make([]curve.G1Affine, size) + for i := range res { var err error - basis[i], err = randomOnG1() + res[i], err = randomOnG1() assert.NoError(t, err) } + return res +} + +func testCommit(t *testing.T, values ...interface{}) { + + basis := randomG1Slice(t, len(values)) var ( - key Key + pk ProvingKey + vk VerifyingKey err error - commitment, pok bw6761.G1Affine + commitment, pok curve.G1Affine ) - key, err = Setup(basis) + pk, vk, err = Setup(basis) assert.NoError(t, err) - commitment, pok, err = key.Commit(interfaceSliceToFrSlice(t, values...)) + commitment, pok, err = pk.Commit(interfaceSliceToFrSlice(t, values...)) assert.NoError(t, err) - assert.NoError(t, key.VerifyKnowledgeProof(commitment, pok)) + assert.NoError(t, vk.Verify(commitment, pok)) pok.Neg(&pok) - assert.NotNil(t, key.VerifyKnowledgeProof(commitment, pok)) + assert.NotNil(t, vk.Verify(commitment, pok)) } func TestCommitToOne(t *testing.T) { @@ -88,3 +94,21 @@ func TestCommitSingle(t *testing.T) { func TestCommitFiveElements(t *testing.T) { testCommit(t, randomFrSlice(t, 5)...) } + +func TestMarshal(t *testing.T) { + var pk ProvingKey + pk.basisExpSigma = randomG1Slice(t, 5) + pk.basis = randomG1Slice(t, 5) + + var ( + vk VerifyingKey + err error + ) + vk.g, err = randomOnG2() + assert.NoError(t, err) + vk.gRootSigmaNeg, err = randomOnG2() + assert.NoError(t, err) + + t.Run("ProvingKey -> Bytes -> ProvingKey must remain identical.", utils.SerializationRoundTrip(&pk)) + t.Run("VerifyingKey -> Bytes -> VerifyingKey must remain identical.", utils.SerializationRoundTrip(&vk)) +} diff --git a/internal/generator/pedersen/template/pedersen.go.tmpl b/internal/generator/pedersen/template/pedersen.go.tmpl index 19f6c6b9cb..6957402e15 100644 --- a/internal/generator/pedersen/template/pedersen.go.tmpl +++ b/internal/generator/pedersen/template/pedersen.go.tmpl @@ -2,62 +2,68 @@ import ( "crypto/rand" "fmt" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/ecc/{{.Name}}" + curve "github.com/consensys/gnark-crypto/ecc/{{.Name}}" "github.com/consensys/gnark-crypto/ecc/{{.Name}}/fr" + "io" "math/big" ) -// Key for proof and verification -type Key struct { - g {{.CurvePackage}}.G2Affine // TODO @tabaie: does this really have to be randomized? - gRootSigmaNeg {{.CurvePackage}}.G2Affine //gRootSigmaNeg = g^{-1/σ} - basis []{{.CurvePackage}}.G1Affine - basisExpSigma []{{.CurvePackage}}.G1Affine +// ProvingKey for committing and proofs of knowledge +type ProvingKey struct { + basis []curve.G1Affine + basisExpSigma []curve.G1Affine } -func randomOnG2() ({{.CurvePackage}}.G2Affine, error) { // TODO: Add to G2.go? - gBytes := make([]byte, fr.Bytes) - if _, err := rand.Read(gBytes); err != nil { - return {{.CurvePackage}}.G2Affine{}, err +type VerifyingKey struct { + 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 +} + +func randomOnG2() (curve.G2Affine, error) { // TODO: Add to G2.go? + if gBytes, err := randomFrSizedBytes(); err != nil { + return curve.G2Affine{}, err + } else { + return curve.HashToG2(gBytes, []byte("random on g2")) } - return {{.CurvePackage}}.HashToG2(gBytes, []byte("random on g2")) } -func Setup(basis []{{.CurvePackage}}.G1Affine) (Key, error) { - var ( - k Key - err error - ) +func Setup(basis []curve.G1Affine) (pk ProvingKey, vk VerifyingKey, err error) { - if k.g, err = randomOnG2(); err != nil { - return k, err + 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 k, err + return } sigma.Add(sigma, big.NewInt(1)) var sigmaInvNeg big.Int sigmaInvNeg.ModInverse(sigma, fr.Modulus()) sigmaInvNeg.Sub(fr.Modulus(), &sigmaInvNeg) - k.gRootSigmaNeg.ScalarMultiplication(&k.g, &sigmaInvNeg) + vk.gRootSigmaNeg.ScalarMultiplication(&vk.g, &sigmaInvNeg) - k.basisExpSigma = make([]{{.CurvePackage}}.G1Affine, len(basis)) + pk.basisExpSigma = make([]curve.G1Affine, len(basis)) for i := range basis { - k.basisExpSigma[i].ScalarMultiplication(&basis[i], sigma) + pk.basisExpSigma[i].ScalarMultiplication(&basis[i], sigma) } - k.basis = basis - return k, err + pk.basis = basis + return } -func (k *Key) Commit(values []fr.Element) (commitment {{.CurvePackage}}.G1Affine, knowledgeProof {{.CurvePackage}}.G1Affine, err error) { +func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, knowledgeProof curve.G1Affine, err error) { - if len(values) != len(k.basis) { + if len(values) != len(pk.basis) { err = fmt.Errorf("unexpected number of values") return } @@ -68,23 +74,23 @@ func (k *Key) Commit(values []fr.Element) (commitment {{.CurvePackage}}.G1Affine NbTasks: 1, // TODO Experiment } - if _, err = commitment.MultiExp(k.basis, values, config); err != nil { + if _, err = commitment.MultiExp(pk.basis, values, config); err != nil { return } - _, err = knowledgeProof.MultiExp(k.basisExpSigma, values, config) + _, err = knowledgeProof.MultiExp(pk.basisExpSigma, values, config) return } -// VerifyKnowledgeProof checks if the proof of knowledge is valid -func (k *Key) VerifyKnowledgeProof(commitment {{.CurvePackage}}.G1Affine, knowledgeProof {{.CurvePackage}}.G1Affine) error { +// 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") } - product, err := {{.CurvePackage}}.Pair([]{{.CurvePackage}}.G1Affine{commitment, knowledgeProof}, []{{.CurvePackage}}.G2Affine{k.g, k.gRootSigmaNeg}) + product, err := curve.Pair([]curve.G1Affine{commitment, knowledgeProof}, []curve.G2Affine{vk.g, vk.gRootSigmaNeg}) if err != nil { return err } @@ -93,3 +99,57 @@ func (k *Key) VerifyKnowledgeProof(commitment {{.CurvePackage}}.G1Affine, knowle } return fmt.Errorf("proof rejected") } + + +// Marshal + +func (pk *ProvingKey) WriteTo(w io.Writer) (int64, error) { + enc := curve.NewEncoder(w) + + if err := enc.Encode(pk.basis); err != nil { + return enc.BytesWritten(), err + } + + err := enc.Encode(pk.basisExpSigma) + + return enc.BytesWritten(), err +} + +func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { + dec := curve.NewDecoder(r) + + 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 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 +} + +func (vk *VerifyingKey) WriteTo(w io.Writer) (int64, error) { + enc := curve.NewEncoder(w) + var err error + + if err = enc.Encode(&vk.g); err != nil { + return enc.BytesWritten(), err + } + err = enc.Encode(&vk.gRootSigmaNeg) + return enc.BytesWritten(), err +} + +func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { + dec := curve.NewDecoder(r) + var err error + + if err = dec.Decode(&vk.g); err != nil { + return dec.BytesRead(), err + } + err = dec.Decode(&vk.gRootSigmaNeg) + return dec.BytesRead(), err +} \ No newline at end of file diff --git a/internal/generator/pedersen/template/pedersen.test.go.tmpl b/internal/generator/pedersen/template/pedersen.test.go.tmpl index 1df98e4f5d..12f6f80023 100644 --- a/internal/generator/pedersen/template/pedersen.test.go.tmpl +++ b/internal/generator/pedersen/template/pedersen.test.go.tmpl @@ -1,8 +1,8 @@ import ( - "github.com/consensys/gnark-crypto/ecc/{{.Name}}" + curve "github.com/consensys/gnark-crypto/ecc/{{.Name}}" "github.com/consensys/gnark-crypto/ecc/{{.Name}}/fr" + "github.com/consensys/gnark-crypto/utils" "github.com/stretchr/testify/assert" - "math/rand" "testing" ) @@ -26,37 +26,43 @@ func randomFrSlice(t *testing.T, size int) []interface{} { return res } -func randomOnG1() ({{.CurvePackage}}.G1Affine, error) { // TODO: Add to G1.go? - gBytes := make([]byte, fr.Bytes) - if _, err := rand.Read(gBytes); err != nil { - return {{.CurvePackage}}.G1Affine{}, err +func randomOnG1() (curve.G1Affine, error) { // TODO: Add to G1.go? + if gBytes, err := randomFrSizedBytes(); err != nil { + return curve.G1Affine{}, err + } else { + return curve.HashToG1(gBytes, []byte("random on g1")) } - return {{.CurvePackage}}.HashToG1(gBytes, []byte("random on g2")) } -func testCommit(t *testing.T, values ...interface{}) { - - basis := make([]{{.CurvePackage}}.G1Affine, len(values)) - for i := range basis { +func randomG1Slice(t *testing.T, size int) []curve.G1Affine { + res := make([]curve.G1Affine, size) + for i := range res { var err error - basis[i], err = randomOnG1() + res[i], err = randomOnG1() assert.NoError(t, err) } + return res +} + +func testCommit(t *testing.T, values ...interface{}) { + + basis := randomG1Slice(t, len(values)) var ( - key Key - err error - commitment, pok {{.CurvePackage}}.G1Affine + pk ProvingKey + vk VerifyingKey + err error + commitment, pok curve.G1Affine ) - key, err = Setup(basis) + pk, vk, err = Setup(basis) assert.NoError(t, err) - commitment, pok, err = key.Commit(interfaceSliceToFrSlice(t, values...)) + commitment, pok, err = pk.Commit(interfaceSliceToFrSlice(t, values...)) assert.NoError(t, err) - assert.NoError(t, key.VerifyKnowledgeProof(commitment, pok)) + assert.NoError(t, vk.Verify(commitment, pok)) pok.Neg(&pok) - assert.NotNil(t, key.VerifyKnowledgeProof(commitment, pok)) + assert.NotNil(t, vk.Verify(commitment, pok)) } func TestCommitToOne(t *testing.T) { @@ -70,3 +76,21 @@ func TestCommitSingle(t *testing.T) { func TestCommitFiveElements(t *testing.T) { testCommit(t, randomFrSlice(t, 5)...) } + +func TestMarshal(t *testing.T) { + var pk ProvingKey + pk.basisExpSigma = randomG1Slice(t, 5) + pk.basis = randomG1Slice(t, 5) + + var ( + vk VerifyingKey + err error + ) + vk.g, err = randomOnG2() + assert.NoError(t, err) + vk.gRootSigmaNeg, err = randomOnG2() + assert.NoError(t, err) + + t.Run("ProvingKey -> Bytes -> ProvingKey must remain identical.", utils.SerializationRoundTrip(&pk)) + t.Run("VerifyingKey -> Bytes -> VerifyingKey must remain identical.", utils.SerializationRoundTrip(&vk)) +} \ No newline at end of file