diff --git a/api/clients/v2/verification/verification_utils.go b/api/clients/v2/verification/verification_utils.go deleted file mode 100644 index 3246e26b25..0000000000 --- a/api/clients/v2/verification/verification_utils.go +++ /dev/null @@ -1,59 +0,0 @@ -package verification - -import ( - "fmt" - "github.com/Layr-Labs/eigenda/encoding" - "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/ecc/bn254" - - "github.com/Layr-Labs/eigenda/encoding/kzg/verifier" - "github.com/Layr-Labs/eigenda/encoding/rs" -) - -// GenerateBlobCommitment computes a kzg-bn254 commitment of blob data using SRS -func GenerateBlobCommitment( - kzgVerifier *verifier.Verifier, - blob []byte) (*encoding.G1Commitment, error) { - - inputFr, err := rs.ToFrArray(blob) - if err != nil { - return nil, fmt.Errorf("convert bytes to field elements, %w", err) - } - - if len(kzgVerifier.Srs.G1) < len(inputFr) { - return nil, fmt.Errorf( - "insufficient SRS in memory: have %v, need %v", - len(kzgVerifier.Srs.G1), - len(inputFr)) - } - - var commitment bn254.G1Affine - _, err = commitment.MultiExp(kzgVerifier.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 GenerateAndCompareBlobCommitment( - kzgVerifier *verifier.Verifier, - claimedCommitment *encoding.G1Commitment, - blobBytes []byte) error { - - computedCommitment, err := GenerateBlobCommitment(kzgVerifier, 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) -} diff --git a/api/clients/v2/verification/verification_utils_test.go b/api/clients/v2/verification/verification_utils_test.go deleted file mode 100644 index 3ebb01ba63..0000000000 --- a/api/clients/v2/verification/verification_utils_test.go +++ /dev/null @@ -1,125 +0,0 @@ -package verification - -import ( - "github.com/Layr-Labs/eigenda/common/testutils/random" - "github.com/Layr-Labs/eigenda/encoding/kzg" - "github.com/Layr-Labs/eigenda/encoding/kzg/verifier" - "github.com/Layr-Labs/eigenda/encoding/utils/codec" - "github.com/stretchr/testify/require" - "runtime" - "testing" -) - -func getKzgConfig() *kzg.KzgConfig { - return &kzg.KzgConfig{ - G1Path: "../../../../inabox/resources/kzg/g1.point", - G2Path: "../../../../inabox/resources/kzg/g2.point", - G2PowerOf2Path: "../../../../inabox/resources/kzg/g2.point.powerOf2", - CacheDir: "../../../../inabox/resources/kzg/SRSTables", - SRSOrder: 3000, - SRSNumberToLoad: 2900, - NumWorker: uint64(runtime.GOMAXPROCS(0)), - LoadG2Points: false, - } -} - -// 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)) -} - -func TestComputeAndCompareKzgCommitmentSuccess(t *testing.T) { - testRandom := random.NewTestRandom(t) - randomBytes := getRandomPaddedBytes(testRandom, 1000) - - kzgVerifier, err := verifier.NewVerifier(getKzgConfig(), nil) - require.NotNil(t, kzgVerifier) - require.NoError(t, err) - - commitment, err := GenerateBlobCommitment(kzgVerifier, randomBytes) - require.NotNil(t, commitment) - require.NoError(t, err) - - // make sure the commitment verifies correctly - err = GenerateAndCompareBlobCommitment( - kzgVerifier, - commitment, - randomBytes) - require.NoError(t, err) -} - -func TestComputeAndCompareKzgCommitmentFailure(t *testing.T) { - testRandom := random.NewTestRandom(t) - randomBytes := getRandomPaddedBytes(testRandom, 1000) - - kzgVerifier, err := verifier.NewVerifier(getKzgConfig(), nil) - require.NotNil(t, kzgVerifier) - require.NoError(t, err) - - commitment, err := GenerateBlobCommitment(kzgVerifier, randomBytes) - require.NotNil(t, commitment) - require.NoError(t, err) - - // randomly modify the bytes, and make sure the commitment verification fails - randomlyModifyBytes(testRandom, randomBytes) - err = GenerateAndCompareBlobCommitment( - kzgVerifier, - commitment, - randomBytes) - require.NotNil(t, err) -} - -func TestGenerateBlobCommitmentEquality(t *testing.T) { - testRandom := random.NewTestRandom(t) - randomBytes := getRandomPaddedBytes(testRandom, 1000) - - kzgVerifier, err := verifier.NewVerifier(getKzgConfig(), nil) - require.NotNil(t, kzgVerifier) - require.NoError(t, err) - - // generate two identical commitments - commitment1, err := GenerateBlobCommitment(kzgVerifier, randomBytes) - require.NotNil(t, commitment1) - require.NoError(t, err) - commitment2, err := GenerateBlobCommitment(kzgVerifier, 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 := GenerateBlobCommitment(kzgVerifier, 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(getKzgConfig(), 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 := GenerateBlobCommitment(kzgVerifier, 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 := GenerateBlobCommitment(kzgVerifier, tooLongBytes) - require.Nil(t, commitment2) - require.NotNil(t, err) -} diff --git a/encoding/kzg/verifier/verifier.go b/encoding/kzg/verifier/verifier.go index 97de7906b5..81a49eef3f 100644 --- a/encoding/kzg/verifier/verifier.go +++ b/encoding/kzg/verifier/verifier.go @@ -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) { + 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 { + + 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) +} diff --git a/encoding/kzg/verifier/verifier_test.go b/encoding/kzg/verifier/verifier_test.go index 817e2de2a3..3ec17b6007 100644 --- a/encoding/kzg/verifier/verifier_test.go +++ b/encoding/kzg/verifier/verifier_test.go @@ -3,6 +3,7 @@ package verifier_test import ( "crypto/rand" "fmt" + "github.com/Layr-Labs/eigenda/common/testutils/random" "log" "os" "runtime" @@ -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) { @@ -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) +}