diff --git a/ecc/bls12-377/kzg/kzg.go b/ecc/bls12-377/kzg/kzg.go index d6c4c5b475..7e7404294b 100644 --- a/ecc/bls12-377/kzg/kzg.go +++ b/ecc/bls12-377/kzg/kzg.go @@ -26,6 +26,8 @@ var ( ErrVerifyOpeningProof = errors.New("can't verify opening proof") ErrVerifyBatchOpeningSinglePoint = errors.New("can't verify batch opening proof at single point") ErrMinSRSSize = errors.New("minimum srs size is 2") + ErrCommitmentNotInSubgroup = errors.New("commitment is not in the correct subgroup") + ErrQuotientNotNotInSubgroup = errors.New("proof quotient is not in the correct subgroup") ) // Digest commitment of a polynomial. @@ -55,8 +57,7 @@ type SRS struct { func eval(p []fr.Element, point fr.Element) fr.Element { var res fr.Element n := len(p) - res.Set(&p[n-1]) - for i := n - 2; i >= 0; i-- { + for i := n - 1; i >= 0; i-- { res.Mul(&res, &point).Add(&res, &p[i]) } return res @@ -158,7 +159,7 @@ type BatchOpeningProof struct { // It is assumed that the polynomial is in canonical form, in Montgomery form. func Commit(p []fr.Element, pk ProvingKey, nbTasks ...int) (Digest, error) { - if len(p) == 0 || len(p) > len(pk.G1) { + if len(p) > len(pk.G1) { return Digest{}, ErrInvalidPolynomialSize } @@ -178,7 +179,7 @@ func Commit(p []fr.Element, pk ProvingKey, nbTasks ...int) (Digest, error) { // Open computes an opening proof of polynomial p at given point. // fft.Domain Cardinality must be larger than p.Degree() func Open(p []fr.Element, point fr.Element, pk ProvingKey) (OpeningProof, error) { - if len(p) == 0 || len(p) > len(pk.G1) { + if len(p) > len(pk.G1) { return OpeningProof{}, ErrInvalidPolynomialSize } @@ -206,6 +207,14 @@ func Open(p []fr.Element, point fr.Element, pk ProvingKey) (OpeningProof, error) // Verify verifies a KZG opening proof at a single point func Verify(commitment *Digest, proof *OpeningProof, point fr.Element, vk VerifyingKey) error { + // check that the commitment and the proof are on the curve + if !commitment.IsInSubGroup() { + return ErrCommitmentNotInSubgroup + } + if !proof.H.IsInSubGroup() { + return ErrQuotientNotNotInSubgroup + } + // [f(a)]G₁ + [-a]([H(α)]G₁) = [f(a) - a*H(α)]G₁ var totalG1 bls12377.G1Jac var pointNeg fr.Element @@ -254,7 +263,7 @@ func BatchOpenSinglePoint(polynomials [][]fr.Element, digests []Digest, point fr // TODO ensure the polynomials are of the same size largestPoly := -1 for _, p := range polynomials { - if len(p) == 0 || len(p) > len(pk.G1) { + if len(p) > len(pk.G1) { return BatchOpeningProof{}, ErrInvalidPolynomialSize } if len(p) > largestPoly { @@ -384,6 +393,15 @@ func FoldProof(digests []Digest, batchOpeningProof *BatchOpeningProof, point fr. // * dataTranscript extra data that might be needed to derive the challenge used for the folding func BatchVerifySinglePoint(digests []Digest, batchOpeningProof *BatchOpeningProof, point fr.Element, hf hash.Hash, vk VerifyingKey, dataTranscript ...[]byte) error { + for i := 0; i < len(digests); i++ { + if !digests[i].IsInSubGroup() { + return ErrCommitmentNotInSubgroup + } + } + if !batchOpeningProof.H.IsInSubGroup() { + return ErrQuotientNotNotInSubgroup + } + // fold the proof foldedProof, foldedDigest, err := FoldProof(digests, batchOpeningProof, point, hf, dataTranscript...) if err != nil { @@ -404,6 +422,17 @@ func BatchVerifySinglePoint(digests []Digest, batchOpeningProof *BatchOpeningPro // * points the list of points at which the opening are done func BatchVerifyMultiPoints(digests []Digest, proofs []OpeningProof, points []fr.Element, vk VerifyingKey) error { + for i := 0; i < len(digests); i++ { + if !digests[i].IsInSubGroup() { + return ErrCommitmentNotInSubgroup + } + } + for i := 0; i < len(proofs); i++ { + if !proofs[i].H.IsInSubGroup() { + return ErrQuotientNotNotInSubgroup + } + } + // check consistency nb proogs vs nb digests if len(digests) != len(proofs) || len(digests) != len(points) { return ErrInvalidNbDigests @@ -565,6 +594,10 @@ func deriveGamma(point fr.Element, digests []Digest, claimedValues []fr.Element, // f memory is re-used for the result func dividePolyByXminusA(f []fr.Element, fa, a fr.Element) []fr.Element { + if len(f) == 0 { + return []fr.Element{} + } + // first we compute f-f(a) f[0].Sub(&f[0], &fa) diff --git a/ecc/bls12-377/kzg/kzg_test.go b/ecc/bls12-377/kzg/kzg_test.go index df2527ff50..a1449f8680 100644 --- a/ecc/bls12-377/kzg/kzg_test.go +++ b/ecc/bls12-377/kzg/kzg_test.go @@ -273,7 +273,9 @@ func TestVerifySinglePoint(t *testing.T) { { // verify wrong proof - proof.ClaimedValue.Double(&proof.ClaimedValue) + var one fr.Element + one.SetOne() + proof.ClaimedValue.Add(&proof.ClaimedValue, &one) err = Verify(&digest, &proof, point, srs.Vk) if err == nil { t.Fatal("verifying wrong proof should have failed") @@ -293,6 +295,12 @@ func TestVerifySinglePoint(t *testing.T) { } t.Run("unsafe", test(testSrs)) t.Run("mpcsetup", test(mpcGetSrs(t))) + // size 0 polynomial + f = randomPolynomial(0) + t.Run("unsafe", test(testSrs)) + // size 1 polynomial + f = randomPolynomial(1) + t.Run("unsafe", test(testSrs)) } func TestVerifySinglePointQuickSRS(t *testing.T) { diff --git a/ecc/bls12-381/kzg/kzg.go b/ecc/bls12-381/kzg/kzg.go index 571f9beb92..0381aec750 100644 --- a/ecc/bls12-381/kzg/kzg.go +++ b/ecc/bls12-381/kzg/kzg.go @@ -26,6 +26,8 @@ var ( ErrVerifyOpeningProof = errors.New("can't verify opening proof") ErrVerifyBatchOpeningSinglePoint = errors.New("can't verify batch opening proof at single point") ErrMinSRSSize = errors.New("minimum srs size is 2") + ErrCommitmentNotInSubgroup = errors.New("commitment is not in the correct subgroup") + ErrQuotientNotNotInSubgroup = errors.New("proof quotient is not in the correct subgroup") ) // Digest commitment of a polynomial. @@ -55,8 +57,7 @@ type SRS struct { func eval(p []fr.Element, point fr.Element) fr.Element { var res fr.Element n := len(p) - res.Set(&p[n-1]) - for i := n - 2; i >= 0; i-- { + for i := n - 1; i >= 0; i-- { res.Mul(&res, &point).Add(&res, &p[i]) } return res @@ -158,7 +159,7 @@ type BatchOpeningProof struct { // It is assumed that the polynomial is in canonical form, in Montgomery form. func Commit(p []fr.Element, pk ProvingKey, nbTasks ...int) (Digest, error) { - if len(p) == 0 || len(p) > len(pk.G1) { + if len(p) > len(pk.G1) { return Digest{}, ErrInvalidPolynomialSize } @@ -178,7 +179,7 @@ func Commit(p []fr.Element, pk ProvingKey, nbTasks ...int) (Digest, error) { // Open computes an opening proof of polynomial p at given point. // fft.Domain Cardinality must be larger than p.Degree() func Open(p []fr.Element, point fr.Element, pk ProvingKey) (OpeningProof, error) { - if len(p) == 0 || len(p) > len(pk.G1) { + if len(p) > len(pk.G1) { return OpeningProof{}, ErrInvalidPolynomialSize } @@ -206,6 +207,14 @@ func Open(p []fr.Element, point fr.Element, pk ProvingKey) (OpeningProof, error) // Verify verifies a KZG opening proof at a single point func Verify(commitment *Digest, proof *OpeningProof, point fr.Element, vk VerifyingKey) error { + // check that the commitment and the proof are on the curve + if !commitment.IsInSubGroup() { + return ErrCommitmentNotInSubgroup + } + if !proof.H.IsInSubGroup() { + return ErrQuotientNotNotInSubgroup + } + // [f(a)]G₁ + [-a]([H(α)]G₁) = [f(a) - a*H(α)]G₁ var totalG1 bls12381.G1Jac var pointNeg fr.Element @@ -254,7 +263,7 @@ func BatchOpenSinglePoint(polynomials [][]fr.Element, digests []Digest, point fr // TODO ensure the polynomials are of the same size largestPoly := -1 for _, p := range polynomials { - if len(p) == 0 || len(p) > len(pk.G1) { + if len(p) > len(pk.G1) { return BatchOpeningProof{}, ErrInvalidPolynomialSize } if len(p) > largestPoly { @@ -384,6 +393,15 @@ func FoldProof(digests []Digest, batchOpeningProof *BatchOpeningProof, point fr. // * dataTranscript extra data that might be needed to derive the challenge used for the folding func BatchVerifySinglePoint(digests []Digest, batchOpeningProof *BatchOpeningProof, point fr.Element, hf hash.Hash, vk VerifyingKey, dataTranscript ...[]byte) error { + for i := 0; i < len(digests); i++ { + if !digests[i].IsInSubGroup() { + return ErrCommitmentNotInSubgroup + } + } + if !batchOpeningProof.H.IsInSubGroup() { + return ErrQuotientNotNotInSubgroup + } + // fold the proof foldedProof, foldedDigest, err := FoldProof(digests, batchOpeningProof, point, hf, dataTranscript...) if err != nil { @@ -404,6 +422,17 @@ func BatchVerifySinglePoint(digests []Digest, batchOpeningProof *BatchOpeningPro // * points the list of points at which the opening are done func BatchVerifyMultiPoints(digests []Digest, proofs []OpeningProof, points []fr.Element, vk VerifyingKey) error { + for i := 0; i < len(digests); i++ { + if !digests[i].IsInSubGroup() { + return ErrCommitmentNotInSubgroup + } + } + for i := 0; i < len(proofs); i++ { + if !proofs[i].H.IsInSubGroup() { + return ErrQuotientNotNotInSubgroup + } + } + // check consistency nb proogs vs nb digests if len(digests) != len(proofs) || len(digests) != len(points) { return ErrInvalidNbDigests @@ -565,6 +594,10 @@ func deriveGamma(point fr.Element, digests []Digest, claimedValues []fr.Element, // f memory is re-used for the result func dividePolyByXminusA(f []fr.Element, fa, a fr.Element) []fr.Element { + if len(f) == 0 { + return []fr.Element{} + } + // first we compute f-f(a) f[0].Sub(&f[0], &fa) diff --git a/ecc/bls12-381/kzg/kzg_test.go b/ecc/bls12-381/kzg/kzg_test.go index 7e29fe1cdb..fc2d7632ea 100644 --- a/ecc/bls12-381/kzg/kzg_test.go +++ b/ecc/bls12-381/kzg/kzg_test.go @@ -273,7 +273,9 @@ func TestVerifySinglePoint(t *testing.T) { { // verify wrong proof - proof.ClaimedValue.Double(&proof.ClaimedValue) + var one fr.Element + one.SetOne() + proof.ClaimedValue.Add(&proof.ClaimedValue, &one) err = Verify(&digest, &proof, point, srs.Vk) if err == nil { t.Fatal("verifying wrong proof should have failed") @@ -293,6 +295,12 @@ func TestVerifySinglePoint(t *testing.T) { } t.Run("unsafe", test(testSrs)) t.Run("mpcsetup", test(mpcGetSrs(t))) + // size 0 polynomial + f = randomPolynomial(0) + t.Run("unsafe", test(testSrs)) + // size 1 polynomial + f = randomPolynomial(1) + t.Run("unsafe", test(testSrs)) } func TestVerifySinglePointQuickSRS(t *testing.T) { diff --git a/ecc/bls24-315/kzg/kzg.go b/ecc/bls24-315/kzg/kzg.go index 6872ccfce8..3f353c3f4f 100644 --- a/ecc/bls24-315/kzg/kzg.go +++ b/ecc/bls24-315/kzg/kzg.go @@ -26,6 +26,8 @@ var ( ErrVerifyOpeningProof = errors.New("can't verify opening proof") ErrVerifyBatchOpeningSinglePoint = errors.New("can't verify batch opening proof at single point") ErrMinSRSSize = errors.New("minimum srs size is 2") + ErrCommitmentNotInSubgroup = errors.New("commitment is not in the correct subgroup") + ErrQuotientNotNotInSubgroup = errors.New("proof quotient is not in the correct subgroup") ) // Digest commitment of a polynomial. @@ -55,8 +57,7 @@ type SRS struct { func eval(p []fr.Element, point fr.Element) fr.Element { var res fr.Element n := len(p) - res.Set(&p[n-1]) - for i := n - 2; i >= 0; i-- { + for i := n - 1; i >= 0; i-- { res.Mul(&res, &point).Add(&res, &p[i]) } return res @@ -158,7 +159,7 @@ type BatchOpeningProof struct { // It is assumed that the polynomial is in canonical form, in Montgomery form. func Commit(p []fr.Element, pk ProvingKey, nbTasks ...int) (Digest, error) { - if len(p) == 0 || len(p) > len(pk.G1) { + if len(p) > len(pk.G1) { return Digest{}, ErrInvalidPolynomialSize } @@ -178,7 +179,7 @@ func Commit(p []fr.Element, pk ProvingKey, nbTasks ...int) (Digest, error) { // Open computes an opening proof of polynomial p at given point. // fft.Domain Cardinality must be larger than p.Degree() func Open(p []fr.Element, point fr.Element, pk ProvingKey) (OpeningProof, error) { - if len(p) == 0 || len(p) > len(pk.G1) { + if len(p) > len(pk.G1) { return OpeningProof{}, ErrInvalidPolynomialSize } @@ -206,6 +207,14 @@ func Open(p []fr.Element, point fr.Element, pk ProvingKey) (OpeningProof, error) // Verify verifies a KZG opening proof at a single point func Verify(commitment *Digest, proof *OpeningProof, point fr.Element, vk VerifyingKey) error { + // check that the commitment and the proof are on the curve + if !commitment.IsInSubGroup() { + return ErrCommitmentNotInSubgroup + } + if !proof.H.IsInSubGroup() { + return ErrQuotientNotNotInSubgroup + } + // [f(a)]G₁ + [-a]([H(α)]G₁) = [f(a) - a*H(α)]G₁ var totalG1 bls24315.G1Jac var pointNeg fr.Element @@ -254,7 +263,7 @@ func BatchOpenSinglePoint(polynomials [][]fr.Element, digests []Digest, point fr // TODO ensure the polynomials are of the same size largestPoly := -1 for _, p := range polynomials { - if len(p) == 0 || len(p) > len(pk.G1) { + if len(p) > len(pk.G1) { return BatchOpeningProof{}, ErrInvalidPolynomialSize } if len(p) > largestPoly { @@ -384,6 +393,15 @@ func FoldProof(digests []Digest, batchOpeningProof *BatchOpeningProof, point fr. // * dataTranscript extra data that might be needed to derive the challenge used for the folding func BatchVerifySinglePoint(digests []Digest, batchOpeningProof *BatchOpeningProof, point fr.Element, hf hash.Hash, vk VerifyingKey, dataTranscript ...[]byte) error { + for i := 0; i < len(digests); i++ { + if !digests[i].IsInSubGroup() { + return ErrCommitmentNotInSubgroup + } + } + if !batchOpeningProof.H.IsInSubGroup() { + return ErrQuotientNotNotInSubgroup + } + // fold the proof foldedProof, foldedDigest, err := FoldProof(digests, batchOpeningProof, point, hf, dataTranscript...) if err != nil { @@ -404,6 +422,17 @@ func BatchVerifySinglePoint(digests []Digest, batchOpeningProof *BatchOpeningPro // * points the list of points at which the opening are done func BatchVerifyMultiPoints(digests []Digest, proofs []OpeningProof, points []fr.Element, vk VerifyingKey) error { + for i := 0; i < len(digests); i++ { + if !digests[i].IsInSubGroup() { + return ErrCommitmentNotInSubgroup + } + } + for i := 0; i < len(proofs); i++ { + if !proofs[i].H.IsInSubGroup() { + return ErrQuotientNotNotInSubgroup + } + } + // check consistency nb proogs vs nb digests if len(digests) != len(proofs) || len(digests) != len(points) { return ErrInvalidNbDigests @@ -565,6 +594,10 @@ func deriveGamma(point fr.Element, digests []Digest, claimedValues []fr.Element, // f memory is re-used for the result func dividePolyByXminusA(f []fr.Element, fa, a fr.Element) []fr.Element { + if len(f) == 0 { + return []fr.Element{} + } + // first we compute f-f(a) f[0].Sub(&f[0], &fa) diff --git a/ecc/bls24-315/kzg/kzg_test.go b/ecc/bls24-315/kzg/kzg_test.go index e33ae4a72a..89655764ee 100644 --- a/ecc/bls24-315/kzg/kzg_test.go +++ b/ecc/bls24-315/kzg/kzg_test.go @@ -273,7 +273,9 @@ func TestVerifySinglePoint(t *testing.T) { { // verify wrong proof - proof.ClaimedValue.Double(&proof.ClaimedValue) + var one fr.Element + one.SetOne() + proof.ClaimedValue.Add(&proof.ClaimedValue, &one) err = Verify(&digest, &proof, point, srs.Vk) if err == nil { t.Fatal("verifying wrong proof should have failed") @@ -293,6 +295,12 @@ func TestVerifySinglePoint(t *testing.T) { } t.Run("unsafe", test(testSrs)) t.Run("mpcsetup", test(mpcGetSrs(t))) + // size 0 polynomial + f = randomPolynomial(0) + t.Run("unsafe", test(testSrs)) + // size 1 polynomial + f = randomPolynomial(1) + t.Run("unsafe", test(testSrs)) } func TestVerifySinglePointQuickSRS(t *testing.T) { diff --git a/ecc/bls24-317/kzg/kzg.go b/ecc/bls24-317/kzg/kzg.go index 2cd246edfd..e2a2686be0 100644 --- a/ecc/bls24-317/kzg/kzg.go +++ b/ecc/bls24-317/kzg/kzg.go @@ -26,6 +26,8 @@ var ( ErrVerifyOpeningProof = errors.New("can't verify opening proof") ErrVerifyBatchOpeningSinglePoint = errors.New("can't verify batch opening proof at single point") ErrMinSRSSize = errors.New("minimum srs size is 2") + ErrCommitmentNotInSubgroup = errors.New("commitment is not in the correct subgroup") + ErrQuotientNotNotInSubgroup = errors.New("proof quotient is not in the correct subgroup") ) // Digest commitment of a polynomial. @@ -55,8 +57,7 @@ type SRS struct { func eval(p []fr.Element, point fr.Element) fr.Element { var res fr.Element n := len(p) - res.Set(&p[n-1]) - for i := n - 2; i >= 0; i-- { + for i := n - 1; i >= 0; i-- { res.Mul(&res, &point).Add(&res, &p[i]) } return res @@ -158,7 +159,7 @@ type BatchOpeningProof struct { // It is assumed that the polynomial is in canonical form, in Montgomery form. func Commit(p []fr.Element, pk ProvingKey, nbTasks ...int) (Digest, error) { - if len(p) == 0 || len(p) > len(pk.G1) { + if len(p) > len(pk.G1) { return Digest{}, ErrInvalidPolynomialSize } @@ -178,7 +179,7 @@ func Commit(p []fr.Element, pk ProvingKey, nbTasks ...int) (Digest, error) { // Open computes an opening proof of polynomial p at given point. // fft.Domain Cardinality must be larger than p.Degree() func Open(p []fr.Element, point fr.Element, pk ProvingKey) (OpeningProof, error) { - if len(p) == 0 || len(p) > len(pk.G1) { + if len(p) > len(pk.G1) { return OpeningProof{}, ErrInvalidPolynomialSize } @@ -206,6 +207,14 @@ func Open(p []fr.Element, point fr.Element, pk ProvingKey) (OpeningProof, error) // Verify verifies a KZG opening proof at a single point func Verify(commitment *Digest, proof *OpeningProof, point fr.Element, vk VerifyingKey) error { + // check that the commitment and the proof are on the curve + if !commitment.IsInSubGroup() { + return ErrCommitmentNotInSubgroup + } + if !proof.H.IsInSubGroup() { + return ErrQuotientNotNotInSubgroup + } + // [f(a)]G₁ + [-a]([H(α)]G₁) = [f(a) - a*H(α)]G₁ var totalG1 bls24317.G1Jac var pointNeg fr.Element @@ -254,7 +263,7 @@ func BatchOpenSinglePoint(polynomials [][]fr.Element, digests []Digest, point fr // TODO ensure the polynomials are of the same size largestPoly := -1 for _, p := range polynomials { - if len(p) == 0 || len(p) > len(pk.G1) { + if len(p) > len(pk.G1) { return BatchOpeningProof{}, ErrInvalidPolynomialSize } if len(p) > largestPoly { @@ -384,6 +393,15 @@ func FoldProof(digests []Digest, batchOpeningProof *BatchOpeningProof, point fr. // * dataTranscript extra data that might be needed to derive the challenge used for the folding func BatchVerifySinglePoint(digests []Digest, batchOpeningProof *BatchOpeningProof, point fr.Element, hf hash.Hash, vk VerifyingKey, dataTranscript ...[]byte) error { + for i := 0; i < len(digests); i++ { + if !digests[i].IsInSubGroup() { + return ErrCommitmentNotInSubgroup + } + } + if !batchOpeningProof.H.IsInSubGroup() { + return ErrQuotientNotNotInSubgroup + } + // fold the proof foldedProof, foldedDigest, err := FoldProof(digests, batchOpeningProof, point, hf, dataTranscript...) if err != nil { @@ -404,6 +422,17 @@ func BatchVerifySinglePoint(digests []Digest, batchOpeningProof *BatchOpeningPro // * points the list of points at which the opening are done func BatchVerifyMultiPoints(digests []Digest, proofs []OpeningProof, points []fr.Element, vk VerifyingKey) error { + for i := 0; i < len(digests); i++ { + if !digests[i].IsInSubGroup() { + return ErrCommitmentNotInSubgroup + } + } + for i := 0; i < len(proofs); i++ { + if !proofs[i].H.IsInSubGroup() { + return ErrQuotientNotNotInSubgroup + } + } + // check consistency nb proogs vs nb digests if len(digests) != len(proofs) || len(digests) != len(points) { return ErrInvalidNbDigests @@ -565,6 +594,10 @@ func deriveGamma(point fr.Element, digests []Digest, claimedValues []fr.Element, // f memory is re-used for the result func dividePolyByXminusA(f []fr.Element, fa, a fr.Element) []fr.Element { + if len(f) == 0 { + return []fr.Element{} + } + // first we compute f-f(a) f[0].Sub(&f[0], &fa) diff --git a/ecc/bls24-317/kzg/kzg_test.go b/ecc/bls24-317/kzg/kzg_test.go index be55d4d6e6..9c9750f47c 100644 --- a/ecc/bls24-317/kzg/kzg_test.go +++ b/ecc/bls24-317/kzg/kzg_test.go @@ -273,7 +273,9 @@ func TestVerifySinglePoint(t *testing.T) { { // verify wrong proof - proof.ClaimedValue.Double(&proof.ClaimedValue) + var one fr.Element + one.SetOne() + proof.ClaimedValue.Add(&proof.ClaimedValue, &one) err = Verify(&digest, &proof, point, srs.Vk) if err == nil { t.Fatal("verifying wrong proof should have failed") @@ -293,6 +295,12 @@ func TestVerifySinglePoint(t *testing.T) { } t.Run("unsafe", test(testSrs)) t.Run("mpcsetup", test(mpcGetSrs(t))) + // size 0 polynomial + f = randomPolynomial(0) + t.Run("unsafe", test(testSrs)) + // size 1 polynomial + f = randomPolynomial(1) + t.Run("unsafe", test(testSrs)) } func TestVerifySinglePointQuickSRS(t *testing.T) { diff --git a/ecc/bn254/kzg/kzg.go b/ecc/bn254/kzg/kzg.go index b888c74d14..d0264db5bd 100644 --- a/ecc/bn254/kzg/kzg.go +++ b/ecc/bn254/kzg/kzg.go @@ -26,6 +26,8 @@ var ( ErrVerifyOpeningProof = errors.New("can't verify opening proof") ErrVerifyBatchOpeningSinglePoint = errors.New("can't verify batch opening proof at single point") ErrMinSRSSize = errors.New("minimum srs size is 2") + ErrCommitmentNotInSubgroup = errors.New("commitment is not in the correct subgroup") + ErrQuotientNotNotInSubgroup = errors.New("proof quotient is not in the correct subgroup") ) // Digest commitment of a polynomial. @@ -55,8 +57,7 @@ type SRS struct { func eval(p []fr.Element, point fr.Element) fr.Element { var res fr.Element n := len(p) - res.Set(&p[n-1]) - for i := n - 2; i >= 0; i-- { + for i := n - 1; i >= 0; i-- { res.Mul(&res, &point).Add(&res, &p[i]) } return res @@ -158,7 +159,7 @@ type BatchOpeningProof struct { // It is assumed that the polynomial is in canonical form, in Montgomery form. func Commit(p []fr.Element, pk ProvingKey, nbTasks ...int) (Digest, error) { - if len(p) == 0 || len(p) > len(pk.G1) { + if len(p) > len(pk.G1) { return Digest{}, ErrInvalidPolynomialSize } @@ -178,7 +179,7 @@ func Commit(p []fr.Element, pk ProvingKey, nbTasks ...int) (Digest, error) { // Open computes an opening proof of polynomial p at given point. // fft.Domain Cardinality must be larger than p.Degree() func Open(p []fr.Element, point fr.Element, pk ProvingKey) (OpeningProof, error) { - if len(p) == 0 || len(p) > len(pk.G1) { + if len(p) > len(pk.G1) { return OpeningProof{}, ErrInvalidPolynomialSize } @@ -206,6 +207,14 @@ func Open(p []fr.Element, point fr.Element, pk ProvingKey) (OpeningProof, error) // Verify verifies a KZG opening proof at a single point func Verify(commitment *Digest, proof *OpeningProof, point fr.Element, vk VerifyingKey) error { + // check that the commitment and the proof are on the curve + if !commitment.IsInSubGroup() { + return ErrCommitmentNotInSubgroup + } + if !proof.H.IsInSubGroup() { + return ErrQuotientNotNotInSubgroup + } + // [f(a)]G₁ + [-a]([H(α)]G₁) = [f(a) - a*H(α)]G₁ var totalG1 bn254.G1Jac var pointNeg fr.Element @@ -254,7 +263,7 @@ func BatchOpenSinglePoint(polynomials [][]fr.Element, digests []Digest, point fr // TODO ensure the polynomials are of the same size largestPoly := -1 for _, p := range polynomials { - if len(p) == 0 || len(p) > len(pk.G1) { + if len(p) > len(pk.G1) { return BatchOpeningProof{}, ErrInvalidPolynomialSize } if len(p) > largestPoly { @@ -384,6 +393,15 @@ func FoldProof(digests []Digest, batchOpeningProof *BatchOpeningProof, point fr. // * dataTranscript extra data that might be needed to derive the challenge used for the folding func BatchVerifySinglePoint(digests []Digest, batchOpeningProof *BatchOpeningProof, point fr.Element, hf hash.Hash, vk VerifyingKey, dataTranscript ...[]byte) error { + for i := 0; i < len(digests); i++ { + if !digests[i].IsInSubGroup() { + return ErrCommitmentNotInSubgroup + } + } + if !batchOpeningProof.H.IsInSubGroup() { + return ErrQuotientNotNotInSubgroup + } + // fold the proof foldedProof, foldedDigest, err := FoldProof(digests, batchOpeningProof, point, hf, dataTranscript...) if err != nil { @@ -404,6 +422,17 @@ func BatchVerifySinglePoint(digests []Digest, batchOpeningProof *BatchOpeningPro // * points the list of points at which the opening are done func BatchVerifyMultiPoints(digests []Digest, proofs []OpeningProof, points []fr.Element, vk VerifyingKey) error { + for i := 0; i < len(digests); i++ { + if !digests[i].IsInSubGroup() { + return ErrCommitmentNotInSubgroup + } + } + for i := 0; i < len(proofs); i++ { + if !proofs[i].H.IsInSubGroup() { + return ErrQuotientNotNotInSubgroup + } + } + // check consistency nb proogs vs nb digests if len(digests) != len(proofs) || len(digests) != len(points) { return ErrInvalidNbDigests @@ -565,6 +594,10 @@ func deriveGamma(point fr.Element, digests []Digest, claimedValues []fr.Element, // f memory is re-used for the result func dividePolyByXminusA(f []fr.Element, fa, a fr.Element) []fr.Element { + if len(f) == 0 { + return []fr.Element{} + } + // first we compute f-f(a) f[0].Sub(&f[0], &fa) diff --git a/ecc/bn254/kzg/kzg_test.go b/ecc/bn254/kzg/kzg_test.go index 830c69371a..dd334df0fa 100644 --- a/ecc/bn254/kzg/kzg_test.go +++ b/ecc/bn254/kzg/kzg_test.go @@ -273,7 +273,9 @@ func TestVerifySinglePoint(t *testing.T) { { // verify wrong proof - proof.ClaimedValue.Double(&proof.ClaimedValue) + var one fr.Element + one.SetOne() + proof.ClaimedValue.Add(&proof.ClaimedValue, &one) err = Verify(&digest, &proof, point, srs.Vk) if err == nil { t.Fatal("verifying wrong proof should have failed") @@ -293,6 +295,12 @@ func TestVerifySinglePoint(t *testing.T) { } t.Run("unsafe", test(testSrs)) t.Run("mpcsetup", test(mpcGetSrs(t))) + // size 0 polynomial + f = randomPolynomial(0) + t.Run("unsafe", test(testSrs)) + // size 1 polynomial + f = randomPolynomial(1) + t.Run("unsafe", test(testSrs)) } func TestVerifySinglePointQuickSRS(t *testing.T) { diff --git a/ecc/bw6-633/kzg/kzg.go b/ecc/bw6-633/kzg/kzg.go index f70d0ed617..42b492bd35 100644 --- a/ecc/bw6-633/kzg/kzg.go +++ b/ecc/bw6-633/kzg/kzg.go @@ -26,6 +26,8 @@ var ( ErrVerifyOpeningProof = errors.New("can't verify opening proof") ErrVerifyBatchOpeningSinglePoint = errors.New("can't verify batch opening proof at single point") ErrMinSRSSize = errors.New("minimum srs size is 2") + ErrCommitmentNotInSubgroup = errors.New("commitment is not in the correct subgroup") + ErrQuotientNotNotInSubgroup = errors.New("proof quotient is not in the correct subgroup") ) // Digest commitment of a polynomial. @@ -55,8 +57,7 @@ type SRS struct { func eval(p []fr.Element, point fr.Element) fr.Element { var res fr.Element n := len(p) - res.Set(&p[n-1]) - for i := n - 2; i >= 0; i-- { + for i := n - 1; i >= 0; i-- { res.Mul(&res, &point).Add(&res, &p[i]) } return res @@ -158,7 +159,7 @@ type BatchOpeningProof struct { // It is assumed that the polynomial is in canonical form, in Montgomery form. func Commit(p []fr.Element, pk ProvingKey, nbTasks ...int) (Digest, error) { - if len(p) == 0 || len(p) > len(pk.G1) { + if len(p) > len(pk.G1) { return Digest{}, ErrInvalidPolynomialSize } @@ -178,7 +179,7 @@ func Commit(p []fr.Element, pk ProvingKey, nbTasks ...int) (Digest, error) { // Open computes an opening proof of polynomial p at given point. // fft.Domain Cardinality must be larger than p.Degree() func Open(p []fr.Element, point fr.Element, pk ProvingKey) (OpeningProof, error) { - if len(p) == 0 || len(p) > len(pk.G1) { + if len(p) > len(pk.G1) { return OpeningProof{}, ErrInvalidPolynomialSize } @@ -206,6 +207,14 @@ func Open(p []fr.Element, point fr.Element, pk ProvingKey) (OpeningProof, error) // Verify verifies a KZG opening proof at a single point func Verify(commitment *Digest, proof *OpeningProof, point fr.Element, vk VerifyingKey) error { + // check that the commitment and the proof are on the curve + if !commitment.IsInSubGroup() { + return ErrCommitmentNotInSubgroup + } + if !proof.H.IsInSubGroup() { + return ErrQuotientNotNotInSubgroup + } + // [f(a)]G₁ + [-a]([H(α)]G₁) = [f(a) - a*H(α)]G₁ var totalG1 bw6633.G1Jac var pointNeg fr.Element @@ -254,7 +263,7 @@ func BatchOpenSinglePoint(polynomials [][]fr.Element, digests []Digest, point fr // TODO ensure the polynomials are of the same size largestPoly := -1 for _, p := range polynomials { - if len(p) == 0 || len(p) > len(pk.G1) { + if len(p) > len(pk.G1) { return BatchOpeningProof{}, ErrInvalidPolynomialSize } if len(p) > largestPoly { @@ -384,6 +393,15 @@ func FoldProof(digests []Digest, batchOpeningProof *BatchOpeningProof, point fr. // * dataTranscript extra data that might be needed to derive the challenge used for the folding func BatchVerifySinglePoint(digests []Digest, batchOpeningProof *BatchOpeningProof, point fr.Element, hf hash.Hash, vk VerifyingKey, dataTranscript ...[]byte) error { + for i := 0; i < len(digests); i++ { + if !digests[i].IsInSubGroup() { + return ErrCommitmentNotInSubgroup + } + } + if !batchOpeningProof.H.IsInSubGroup() { + return ErrQuotientNotNotInSubgroup + } + // fold the proof foldedProof, foldedDigest, err := FoldProof(digests, batchOpeningProof, point, hf, dataTranscript...) if err != nil { @@ -404,6 +422,17 @@ func BatchVerifySinglePoint(digests []Digest, batchOpeningProof *BatchOpeningPro // * points the list of points at which the opening are done func BatchVerifyMultiPoints(digests []Digest, proofs []OpeningProof, points []fr.Element, vk VerifyingKey) error { + for i := 0; i < len(digests); i++ { + if !digests[i].IsInSubGroup() { + return ErrCommitmentNotInSubgroup + } + } + for i := 0; i < len(proofs); i++ { + if !proofs[i].H.IsInSubGroup() { + return ErrQuotientNotNotInSubgroup + } + } + // check consistency nb proogs vs nb digests if len(digests) != len(proofs) || len(digests) != len(points) { return ErrInvalidNbDigests @@ -565,6 +594,10 @@ func deriveGamma(point fr.Element, digests []Digest, claimedValues []fr.Element, // f memory is re-used for the result func dividePolyByXminusA(f []fr.Element, fa, a fr.Element) []fr.Element { + if len(f) == 0 { + return []fr.Element{} + } + // first we compute f-f(a) f[0].Sub(&f[0], &fa) diff --git a/ecc/bw6-633/kzg/kzg_test.go b/ecc/bw6-633/kzg/kzg_test.go index 6701bb2043..50ce257d2f 100644 --- a/ecc/bw6-633/kzg/kzg_test.go +++ b/ecc/bw6-633/kzg/kzg_test.go @@ -273,7 +273,9 @@ func TestVerifySinglePoint(t *testing.T) { { // verify wrong proof - proof.ClaimedValue.Double(&proof.ClaimedValue) + var one fr.Element + one.SetOne() + proof.ClaimedValue.Add(&proof.ClaimedValue, &one) err = Verify(&digest, &proof, point, srs.Vk) if err == nil { t.Fatal("verifying wrong proof should have failed") @@ -293,6 +295,12 @@ func TestVerifySinglePoint(t *testing.T) { } t.Run("unsafe", test(testSrs)) t.Run("mpcsetup", test(mpcGetSrs(t))) + // size 0 polynomial + f = randomPolynomial(0) + t.Run("unsafe", test(testSrs)) + // size 1 polynomial + f = randomPolynomial(1) + t.Run("unsafe", test(testSrs)) } func TestVerifySinglePointQuickSRS(t *testing.T) { diff --git a/ecc/bw6-761/kzg/kzg.go b/ecc/bw6-761/kzg/kzg.go index cb986386a7..ee0e2a4630 100644 --- a/ecc/bw6-761/kzg/kzg.go +++ b/ecc/bw6-761/kzg/kzg.go @@ -26,6 +26,8 @@ var ( ErrVerifyOpeningProof = errors.New("can't verify opening proof") ErrVerifyBatchOpeningSinglePoint = errors.New("can't verify batch opening proof at single point") ErrMinSRSSize = errors.New("minimum srs size is 2") + ErrCommitmentNotInSubgroup = errors.New("commitment is not in the correct subgroup") + ErrQuotientNotNotInSubgroup = errors.New("proof quotient is not in the correct subgroup") ) // Digest commitment of a polynomial. @@ -55,8 +57,7 @@ type SRS struct { func eval(p []fr.Element, point fr.Element) fr.Element { var res fr.Element n := len(p) - res.Set(&p[n-1]) - for i := n - 2; i >= 0; i-- { + for i := n - 1; i >= 0; i-- { res.Mul(&res, &point).Add(&res, &p[i]) } return res @@ -158,7 +159,7 @@ type BatchOpeningProof struct { // It is assumed that the polynomial is in canonical form, in Montgomery form. func Commit(p []fr.Element, pk ProvingKey, nbTasks ...int) (Digest, error) { - if len(p) == 0 || len(p) > len(pk.G1) { + if len(p) > len(pk.G1) { return Digest{}, ErrInvalidPolynomialSize } @@ -178,7 +179,7 @@ func Commit(p []fr.Element, pk ProvingKey, nbTasks ...int) (Digest, error) { // Open computes an opening proof of polynomial p at given point. // fft.Domain Cardinality must be larger than p.Degree() func Open(p []fr.Element, point fr.Element, pk ProvingKey) (OpeningProof, error) { - if len(p) == 0 || len(p) > len(pk.G1) { + if len(p) > len(pk.G1) { return OpeningProof{}, ErrInvalidPolynomialSize } @@ -206,6 +207,14 @@ func Open(p []fr.Element, point fr.Element, pk ProvingKey) (OpeningProof, error) // Verify verifies a KZG opening proof at a single point func Verify(commitment *Digest, proof *OpeningProof, point fr.Element, vk VerifyingKey) error { + // check that the commitment and the proof are on the curve + if !commitment.IsInSubGroup() { + return ErrCommitmentNotInSubgroup + } + if !proof.H.IsInSubGroup() { + return ErrQuotientNotNotInSubgroup + } + // [f(a)]G₁ + [-a]([H(α)]G₁) = [f(a) - a*H(α)]G₁ var totalG1 bw6761.G1Jac var pointNeg fr.Element @@ -254,7 +263,7 @@ func BatchOpenSinglePoint(polynomials [][]fr.Element, digests []Digest, point fr // TODO ensure the polynomials are of the same size largestPoly := -1 for _, p := range polynomials { - if len(p) == 0 || len(p) > len(pk.G1) { + if len(p) > len(pk.G1) { return BatchOpeningProof{}, ErrInvalidPolynomialSize } if len(p) > largestPoly { @@ -384,6 +393,15 @@ func FoldProof(digests []Digest, batchOpeningProof *BatchOpeningProof, point fr. // * dataTranscript extra data that might be needed to derive the challenge used for the folding func BatchVerifySinglePoint(digests []Digest, batchOpeningProof *BatchOpeningProof, point fr.Element, hf hash.Hash, vk VerifyingKey, dataTranscript ...[]byte) error { + for i := 0; i < len(digests); i++ { + if !digests[i].IsInSubGroup() { + return ErrCommitmentNotInSubgroup + } + } + if !batchOpeningProof.H.IsInSubGroup() { + return ErrQuotientNotNotInSubgroup + } + // fold the proof foldedProof, foldedDigest, err := FoldProof(digests, batchOpeningProof, point, hf, dataTranscript...) if err != nil { @@ -404,6 +422,17 @@ func BatchVerifySinglePoint(digests []Digest, batchOpeningProof *BatchOpeningPro // * points the list of points at which the opening are done func BatchVerifyMultiPoints(digests []Digest, proofs []OpeningProof, points []fr.Element, vk VerifyingKey) error { + for i := 0; i < len(digests); i++ { + if !digests[i].IsInSubGroup() { + return ErrCommitmentNotInSubgroup + } + } + for i := 0; i < len(proofs); i++ { + if !proofs[i].H.IsInSubGroup() { + return ErrQuotientNotNotInSubgroup + } + } + // check consistency nb proogs vs nb digests if len(digests) != len(proofs) || len(digests) != len(points) { return ErrInvalidNbDigests @@ -565,6 +594,10 @@ func deriveGamma(point fr.Element, digests []Digest, claimedValues []fr.Element, // f memory is re-used for the result func dividePolyByXminusA(f []fr.Element, fa, a fr.Element) []fr.Element { + if len(f) == 0 { + return []fr.Element{} + } + // first we compute f-f(a) f[0].Sub(&f[0], &fa) diff --git a/ecc/bw6-761/kzg/kzg_test.go b/ecc/bw6-761/kzg/kzg_test.go index 804b9793c3..a088360698 100644 --- a/ecc/bw6-761/kzg/kzg_test.go +++ b/ecc/bw6-761/kzg/kzg_test.go @@ -273,7 +273,9 @@ func TestVerifySinglePoint(t *testing.T) { { // verify wrong proof - proof.ClaimedValue.Double(&proof.ClaimedValue) + var one fr.Element + one.SetOne() + proof.ClaimedValue.Add(&proof.ClaimedValue, &one) err = Verify(&digest, &proof, point, srs.Vk) if err == nil { t.Fatal("verifying wrong proof should have failed") @@ -293,6 +295,12 @@ func TestVerifySinglePoint(t *testing.T) { } t.Run("unsafe", test(testSrs)) t.Run("mpcsetup", test(mpcGetSrs(t))) + // size 0 polynomial + f = randomPolynomial(0) + t.Run("unsafe", test(testSrs)) + // size 1 polynomial + f = randomPolynomial(1) + t.Run("unsafe", test(testSrs)) } func TestVerifySinglePointQuickSRS(t *testing.T) { diff --git a/internal/generator/kzg/template/kzg.go.tmpl b/internal/generator/kzg/template/kzg.go.tmpl index b8f699fe8e..2b1bde6780 100644 --- a/internal/generator/kzg/template/kzg.go.tmpl +++ b/internal/generator/kzg/template/kzg.go.tmpl @@ -19,6 +19,8 @@ var ( ErrVerifyOpeningProof = errors.New("can't verify opening proof") ErrVerifyBatchOpeningSinglePoint = errors.New("can't verify batch opening proof at single point") ErrMinSRSSize = errors.New("minimum srs size is 2") + ErrCommitmentNotInSubgroup = errors.New("commitment is not in the correct subgroup") + ErrQuotientNotNotInSubgroup = errors.New("proof quotient is not in the correct subgroup") ) // Digest commitment of a polynomial. @@ -52,8 +54,7 @@ type SRS struct { func eval(p []fr.Element, point fr.Element) fr.Element { var res fr.Element n := len(p) - res.Set(&p[n-1]) - for i := n - 2; i >= 0; i-- { + for i := n - 1; i >= 0; i-- { res.Mul(&res, &point).Add(&res, &p[i]) } return res @@ -155,7 +156,7 @@ type BatchOpeningProof struct { // It is assumed that the polynomial is in canonical form, in Montgomery form. func Commit(p []fr.Element, pk ProvingKey, nbTasks ...int) (Digest, error) { - if len(p) == 0 || len(p) > len(pk.G1) { + if len(p) > len(pk.G1) { return Digest{}, ErrInvalidPolynomialSize } @@ -176,7 +177,7 @@ func Commit(p []fr.Element, pk ProvingKey, nbTasks ...int) (Digest, error) { // Open computes an opening proof of polynomial p at given point. // fft.Domain Cardinality must be larger than p.Degree() func Open(p []fr.Element, point fr.Element, pk ProvingKey) (OpeningProof, error) { - if len(p) == 0 || len(p) > len(pk.G1) { + if len(p) > len(pk.G1) { return OpeningProof{}, ErrInvalidPolynomialSize } @@ -204,6 +205,14 @@ func Open(p []fr.Element, point fr.Element, pk ProvingKey) (OpeningProof, error) // Verify verifies a KZG opening proof at a single point func Verify(commitment *Digest, proof *OpeningProof, point fr.Element, vk VerifyingKey) error { + // check that the commitment and the proof are on the curve + if !commitment.IsInSubGroup() { + return ErrCommitmentNotInSubgroup + } + if !proof.H.IsInSubGroup() { + return ErrQuotientNotNotInSubgroup + } + // [f(a)]G₁ + [-a]([H(α)]G₁) = [f(a) - a*H(α)]G₁ var totalG1 {{ .CurvePackage }}.G1Jac var pointNeg fr.Element @@ -252,7 +261,7 @@ func BatchOpenSinglePoint(polynomials [][]fr.Element, digests []Digest, point fr // TODO ensure the polynomials are of the same size largestPoly := -1 for _, p := range polynomials { - if len(p) == 0 || len(p) > len(pk.G1) { + if len(p) > len(pk.G1) { return BatchOpeningProof{}, ErrInvalidPolynomialSize } if len(p) > largestPoly { @@ -382,6 +391,15 @@ func FoldProof(digests []Digest, batchOpeningProof *BatchOpeningProof, point fr. // * dataTranscript extra data that might be needed to derive the challenge used for the folding func BatchVerifySinglePoint(digests []Digest, batchOpeningProof *BatchOpeningProof, point fr.Element, hf hash.Hash, vk VerifyingKey, dataTranscript ...[]byte) error { + for i := 0; i < len(digests); i++ { + if !digests[i].IsInSubGroup() { + return ErrCommitmentNotInSubgroup + } + } + if !batchOpeningProof.H.IsInSubGroup() { + return ErrQuotientNotNotInSubgroup + } + // fold the proof foldedProof, foldedDigest, err := FoldProof(digests, batchOpeningProof, point, hf, dataTranscript...) if err != nil { @@ -402,6 +420,17 @@ func BatchVerifySinglePoint(digests []Digest, batchOpeningProof *BatchOpeningPro // * points the list of points at which the opening are done func BatchVerifyMultiPoints(digests []Digest, proofs []OpeningProof, points []fr.Element, vk VerifyingKey) error { + for i := 0; i < len(digests); i++ { + if !digests[i].IsInSubGroup() { + return ErrCommitmentNotInSubgroup + } + } + for i := 0; i < len(proofs); i++ { + if !proofs[i].H.IsInSubGroup() { + return ErrQuotientNotNotInSubgroup + } + } + // check consistency nb proogs vs nb digests if len(digests) != len(proofs) || len(digests) != len(points) { return ErrInvalidNbDigests @@ -563,6 +592,10 @@ func deriveGamma(point fr.Element, digests []Digest, claimedValues []fr.Element, // f memory is re-used for the result func dividePolyByXminusA(f []fr.Element, fa, a fr.Element) []fr.Element { + if len(f)==0 { + return []fr.Element{} + } + // first we compute f-f(a) f[0].Sub(&f[0], &fa) diff --git a/internal/generator/kzg/template/kzg.test.go.tmpl b/internal/generator/kzg/template/kzg.test.go.tmpl index cba22ed2e7..b37958f736 100644 --- a/internal/generator/kzg/template/kzg.test.go.tmpl +++ b/internal/generator/kzg/template/kzg.test.go.tmpl @@ -266,7 +266,9 @@ func TestVerifySinglePoint(t *testing.T) { { // verify wrong proof - proof.ClaimedValue.Double(&proof.ClaimedValue) + var one fr.Element + one.SetOne() + proof.ClaimedValue.Add(&proof.ClaimedValue, &one) err = Verify(&digest, &proof, point, srs.Vk) if err == nil { t.Fatal("verifying wrong proof should have failed") @@ -286,6 +288,12 @@ func TestVerifySinglePoint(t *testing.T) { } t.Run("unsafe", test(testSrs)) t.Run("mpcsetup", test(mpcGetSrs(t))) + // size 0 polynomial + f = randomPolynomial(0) + t.Run("unsafe", test(testSrs)) + // size 1 polynomial + f = randomPolynomial(1) + t.Run("unsafe", test(testSrs)) } func TestVerifySinglePointQuickSRS(t *testing.T) {