Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move commitment verification into verifier #1051

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 0 additions & 59 deletions api/clients/v2/verification/verification_utils.go

This file was deleted.

125 changes: 0 additions & 125 deletions api/clients/v2/verification/verification_utils_test.go

This file was deleted.

42 changes: 42 additions & 0 deletions encoding/kzg/verifier/verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -329,3 +329,45 @@ func PairingsVerify(a1 *bn254.G1Affine, a2 *bn254.G2Affine, b1 *bn254.G1Affine,

return nil
}

// GenerateBlobCommitment computes a kzg-bn254 commitment of blob data using SRS
func (v *Verifier) GenerateBlobCommitment(blob []byte) (*encoding.G1Commitment, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this need to be public?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have any particular external use cases in mind. My tendency would be to keep it public, since it's a general purpose method to compute commitment from bytes, with likelihood of being used elsewhere in the future. But I'd have no strong objection to making it private

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can rework the API later but I find it a bit weird that this method is on a strict called Verifier. I might want to compute a kzg commitment without verifying anything.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see your point. We could create a new type Committer, which would accept a kzg configuration, and just produce the commitments.

inputFr, err := rs.ToFrArray(blob)
if err != nil {
return nil, fmt.Errorf("convert bytes to field elements, %w", err)
}

if len(v.Srs.G1) < len(inputFr) {
return nil, fmt.Errorf(
"insufficient SRS in memory: have %v, need %v",
len(v.Srs.G1),
len(inputFr))
}

var commitment bn254.G1Affine
_, err = commitment.MultiExp(v.Srs.G1[:len(inputFr)], inputFr, ecc.MultiExpConfig{})
if err != nil {
return nil, fmt.Errorf("MultiExp: %w", err)
}

return &encoding.G1Commitment{X: commitment.X, Y: commitment.Y}, nil
}

// GenerateAndCompareBlobCommitment generates the kzg-bn254 commitment of the blob, and compares it with a claimed
// commitment. An error is returned if there is a problem generating the commitment, or if the comparison fails.
func (v *Verifier) GenerateAndCompareBlobCommitment(claimedCommitment *encoding.G1Commitment, blobBytes []byte) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this need to be public?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this will be called by the v2 client


computedCommitment, err := v.GenerateBlobCommitment(blobBytes)
if err != nil {
return fmt.Errorf("compute commitment: %w", err)
}

if claimedCommitment.X.Equal(&computedCommitment.X) &&
claimedCommitment.Y.Equal(&computedCommitment.Y) {
return nil
}

return fmt.Errorf(
"commitment field elements do not match. computed commitment: (x: %x, y: %x), claimed commitment (x: %x, y: %x)",
computedCommitment.X, computedCommitment.Y, claimedCommitment.X, claimedCommitment.Y)
}
96 changes: 96 additions & 0 deletions encoding/kzg/verifier/verifier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package verifier_test
import (
"crypto/rand"
"fmt"
"github.com/Layr-Labs/eigenda/common/testutils/random"
"log"
"os"
"runtime"
Expand Down Expand Up @@ -57,6 +58,16 @@ func teardown() {
os.RemoveAll("./data")
}

// randomlyModifyBytes picks a random byte from the input array, and increments it
func randomlyModifyBytes(testRandom *random.TestRandom, inputBytes []byte) {
indexToModify := testRandom.Intn(len(inputBytes))
inputBytes[indexToModify] = inputBytes[indexToModify] + 1
}

func getRandomPaddedBytes(testRandom *random.TestRandom, count int) []byte {
return codec.ConvertByPaddingEmptyByte(testRandom.Bytes(count))
}

// var control interface{ Stop() }

func TestBenchmarkVerifyChunks(t *testing.T) {
Expand Down Expand Up @@ -146,3 +157,88 @@ func BenchmarkVerifyBlob(b *testing.B) {
}

}

func TestComputeAndCompareKzgCommitmentSuccess(t *testing.T) {
testRandom := random.NewTestRandom(t)
randomBytes := getRandomPaddedBytes(testRandom, 1000)

kzgVerifier, err := verifier.NewVerifier(kzgConfig, nil)
require.NotNil(t, kzgVerifier)
require.NoError(t, err)

commitment, err := kzgVerifier.GenerateBlobCommitment(randomBytes)
require.NotNil(t, commitment)
require.NoError(t, err)

// make sure the commitment verifies correctly
err = kzgVerifier.GenerateAndCompareBlobCommitment(commitment, randomBytes)
require.NoError(t, err)
}

func TestComputeAndCompareKzgCommitmentFailure(t *testing.T) {
testRandom := random.NewTestRandom(t)
randomBytes := getRandomPaddedBytes(testRandom, 1000)

kzgVerifier, err := verifier.NewVerifier(kzgConfig, nil)
require.NotNil(t, kzgVerifier)
require.NoError(t, err)

commitment, err := kzgVerifier.GenerateBlobCommitment(randomBytes)
require.NotNil(t, commitment)
require.NoError(t, err)

// randomly modify the bytes, and make sure the commitment verification fails
randomlyModifyBytes(testRandom, randomBytes)
err = kzgVerifier.GenerateAndCompareBlobCommitment(commitment, randomBytes)
require.NotNil(t, err)
}

func TestGenerateBlobCommitmentEquality(t *testing.T) {
testRandom := random.NewTestRandom(t)
randomBytes := getRandomPaddedBytes(testRandom, 1000)

kzgVerifier, err := verifier.NewVerifier(kzgConfig, nil)
require.NotNil(t, kzgVerifier)
require.NoError(t, err)

// generate two identical commitments
commitment1, err := kzgVerifier.GenerateBlobCommitment(randomBytes)
require.NotNil(t, commitment1)
require.NoError(t, err)
commitment2, err := kzgVerifier.GenerateBlobCommitment(randomBytes)
require.NotNil(t, commitment2)
require.NoError(t, err)

// commitments to identical bytes should be equal
require.Equal(t, commitment1, commitment2)

// randomly modify a byte
randomlyModifyBytes(testRandom, randomBytes)
commitmentA, err := kzgVerifier.GenerateBlobCommitment(randomBytes)
require.NotNil(t, commitmentA)
require.NoError(t, err)

// commitments to non-identical bytes should not be equal
require.NotEqual(t, commitment1, commitmentA)
}

func TestGenerateBlobCommitmentTooLong(t *testing.T) {
kzgVerifier, err := verifier.NewVerifier(kzgConfig, nil)
require.NotNil(t, kzgVerifier)
require.NoError(t, err)

// this is the absolute maximum number of bytes we can handle, given how the verifier was configured
almostTooLongByteCount := 2900 * 32

// an array of exactly this size should be fine
almostTooLongBytes := make([]byte, almostTooLongByteCount)
commitment1, err := kzgVerifier.GenerateBlobCommitment(almostTooLongBytes)
require.NotNil(t, commitment1)
require.NoError(t, err)

// but 1 more byte is more than we can handle
tooLongBytes := make([]byte, almostTooLongByteCount+1)
commitment2, err := kzgVerifier.GenerateBlobCommitment(tooLongBytes)
require.Nil(t, commitment2)
require.NotNil(t, err)
}
Loading