From a231d5354bc9351e3cff78aa299d37ea53705581 Mon Sep 17 00:00:00 2001 From: Justin Traglia <95511699+jtraglia@users.noreply.github.com> Date: Mon, 20 Feb 2023 10:01:31 -0600 Subject: [PATCH] Update go bindings (#142) * Update go bindings * Fix some nits --- bindings/go/main.go | 64 ++++++---- bindings/go/main_test.go | 258 +++++++++++++++++++++++++++++---------- 2 files changed, 239 insertions(+), 83 deletions(-) diff --git a/bindings/go/main.go b/bindings/go/main.go index dcc6a37..3484772 100644 --- a/bindings/go/main.go +++ b/bindings/go/main.go @@ -159,6 +159,26 @@ func ComputeKZGProof(blob Blob, zBytes Bytes32) (KZGProof, CKzgRet) { return proof, CKzgRet(ret) } +/* +ComputeBlobKZGProof is the binding for: + + C_KZG_RET compute_blob_kzg_proof( + KZGProof *out, + const Blob *blob, + const KZGSettings *s); +*/ +func ComputeBlobKZGProof(blob Blob) (KZGProof, CKzgRet) { + if !loaded { + panic("trusted setup isn't loaded") + } + proof := KZGProof{} + ret := C.compute_blob_kzg_proof( + (*C.KZGProof)(unsafe.Pointer(&proof)), + (*C.Blob)(unsafe.Pointer(&blob)), + &settings) + return proof, CKzgRet(ret) +} + /* VerifyKZGProof is the binding for: @@ -186,52 +206,54 @@ func VerifyKZGProof(commitmentBytes Bytes48, zBytes, yBytes Bytes32, proofBytes } /* -ComputeAggregateKZGProof is the binding for: +VerifyBlobKZGProof is the binding for: - C_KZG_RET compute_aggregate_kzg_proof( - KZGProof *out, - const Blob *blobs, - size_t n, + C_KZG_RET verify_blob_kzg_proof( + bool *out, + const Blob *blob, + const Bytes48 *commitment_bytes, + const Bytes48 *proof_bytes, const KZGSettings *s); */ -func ComputeAggregateKZGProof(blobs []Blob) (KZGProof, CKzgRet) { +func VerifyBlobKZGProof(blob Blob, commitmentBytes, proofBytes Bytes48) (bool, CKzgRet) { if !loaded { panic("trusted setup isn't loaded") } - proof := KZGProof{} - ret := C.compute_aggregate_kzg_proof( - (*C.KZGProof)(unsafe.Pointer(&proof)), - *(**C.Blob)(unsafe.Pointer(&blobs)), - (C.size_t)(len(blobs)), + var result C.bool + ret := C.verify_blob_kzg_proof( + &result, + (*C.Blob)(unsafe.Pointer(&blob)), + (*C.Bytes48)(unsafe.Pointer(&commitmentBytes)), + (*C.Bytes48)(unsafe.Pointer(&proofBytes)), &settings) - return proof, CKzgRet(ret) + return bool(result), CKzgRet(ret) } /* -VerifyAggregateKZGProof is the binding for: +VerifyBlobKZGProofBatch is the binding for: - C_KZG_RET verify_aggregate_kzg_proof( + C_KZG_RET verify_blob_kzg_proof_batch( bool *out, const Blob *blobs, const Bytes48 *commitments_bytes, - size_t n, - const Bytes48 *aggregated_proof_bytes, + const Bytes48 *proofs_bytes, const KZGSettings *s); */ -func VerifyAggregateKZGProof(blobs []Blob, commitmentsBytes []Bytes48, aggregatedProofBytes Bytes48) (bool, CKzgRet) { +func VerifyBlobKZGProofBatch(blobs []Blob, commitmentsBytes, proofsBytes []Bytes48) (bool, CKzgRet) { if !loaded { panic("trusted setup isn't loaded") } - if len(blobs) != len(commitmentsBytes) { - panic("len(blobs) != len(commitments)") + if len(blobs) != len(commitmentsBytes) || len(blobs) != len(proofsBytes) { + panic("the number of blobs/commitments/proofs should be equal") } + var result C.bool - ret := C.verify_aggregate_kzg_proof( + ret := C.verify_blob_kzg_proof_batch( &result, *(**C.Blob)(unsafe.Pointer(&blobs)), *(**C.Bytes48)(unsafe.Pointer(&commitmentsBytes)), + *(**C.Bytes48)(unsafe.Pointer(&proofsBytes)), (C.size_t)(len(blobs)), - (*C.Bytes48)(unsafe.Pointer(&aggregatedProofBytes)), &settings) return bool(result), CKzgRet(ret) } diff --git a/bindings/go/main_test.go b/bindings/go/main_test.go index f2a1d55..5e25d5c 100644 --- a/bindings/go/main_test.go +++ b/bindings/go/main_test.go @@ -2,11 +2,12 @@ package cgokzg4844 import ( "encoding/hex" - "encoding/json" "errors" "fmt" "math/rand" "os" + "path/filepath" + "strings" "testing" "github.com/stretchr/testify/require" @@ -103,60 +104,189 @@ func HumanBytes(b int64) string { return fmt.Sprintf("%v%cB", float64(b)/float64(div), "KMGTPE"[exp]) } +/////////////////////////////////////////////////////////////////////////////// +// Test Helper Functions +/////////////////////////////////////////////////////////////////////////////// + +func getBlob(path string) Blob { + inputBytes, err := os.ReadFile(path) + if err != nil { + panic(err) + } + var blob Blob + err = blob.UnmarshalText(inputBytes) + if err != nil { + panic(err) + } + return blob +} + +func getBytes32(path string) Bytes32 { + inputBytes, err := os.ReadFile(path) + if err != nil { + panic(err) + } + var bytes32 Bytes32 + err = bytes32.UnmarshalText(inputBytes) + if err != nil { + panic(err) + } + return bytes32 +} + +func getBytes48(path string) Bytes48 { + inputBytes, err := os.ReadFile(path) + if err != nil { + panic(err) + } + var bytes48 Bytes48 + err = bytes48.UnmarshalText(inputBytes) + if err != nil { + panic(err) + } + return bytes48 +} + +func getBoolean(path string) bool { + inputBytes, err := os.ReadFile(path) + if err != nil { + panic(err) + } + return strings.Contains(string(inputBytes), "true") +} + /////////////////////////////////////////////////////////////////////////////// // Tests /////////////////////////////////////////////////////////////////////////////// -func TestComputeAggregateKZGProof(t *testing.T) { - type Test struct { - TestCases []struct { - Polynomials []Blob `json:"Polynomials"` - Proof Bytes48 `json:"Proof"` - Commitments []Bytes48 `json:"Commitments"` +var ( + testDir = "../../tests" + blobToKZGCommitmentTests = filepath.Join(testDir, "blob_to_kzg_commitment/*") + computeKZGProofTests = filepath.Join(testDir, "compute_kzg_proof/*") + computeBlobKZGProofTests = filepath.Join(testDir, "compute_blob_kzg_proof/*") + verifyKZGProofTests = filepath.Join(testDir, "verify_kzg_proof/*") + verifyBlobKZGProofTests = filepath.Join(testDir, "verify_blob_kzg_proof/*") + verifyBlobKZGProofBatchTests = filepath.Join(testDir, "verify_blob_kzg_proof_batch/*") +) + +func TestBlobToKZGCommitment(t *testing.T) { + tests, err := filepath.Glob(blobToKZGCommitmentTests) + require.NoError(t, err) + for _, test := range tests { + blob := getBlob(filepath.Join(test, "blob.txt")) + + commitment, ret := BlobToKZGCommitment(blob) + if ret == C_KZG_OK { + expectedCommitment := KZGCommitment(getBytes48(filepath.Join(test, "commitment.txt"))) + require.Equal(t, commitment, expectedCommitment, test) + } else { + require.NoFileExists(t, filepath.Join(test, "commitment.txt")) } } +} - testFile, err := os.Open("../rust/test_vectors/public_agg_proof.json") - require.NoError(t, err) - defer testFile.Close() - test := Test{} - err = json.NewDecoder(testFile).Decode(&test) +func TestComputeKZGProof(t *testing.T) { + tests, err := filepath.Glob(computeKZGProofTests) require.NoError(t, err) + for _, test := range tests { + blob := getBlob(filepath.Join(test, "blob.txt")) + inputPoint := getBytes32(filepath.Join(test, "input_point.txt")) - for _, tc := range test.TestCases { - proof, ret := ComputeAggregateKZGProof(tc.Polynomials) - require.Zero(t, ret) - require.Equal(t, tc.Proof[:], proof[:]) - for i := range tc.Polynomials { - commitment, ret := BlobToKZGCommitment(tc.Polynomials[i]) - require.Equal(t, C_KZG_OK, ret) - require.Equal(t, tc.Commitments[i][:], commitment[:]) + proof, ret := ComputeKZGProof(blob, inputPoint) + if ret == C_KZG_OK { + expectedProof := KZGProof(getBytes48(filepath.Join(test, "proof.txt"))) + require.Equal(t, proof, expectedProof, test) + } else { + require.NoFileExists(t, filepath.Join(test, "proof.txt")) + } + } +} + +func TestComputeBlobKZGProof(t *testing.T) { + tests, err := filepath.Glob(computeBlobKZGProofTests) + require.NoError(t, err) + for _, test := range tests { + blob := getBlob(filepath.Join(test, "blob.txt")) + + proof, ret := ComputeBlobKZGProof(blob) + if ret == C_KZG_OK { + expectedProof := KZGProof(getBytes48(filepath.Join(test, "proof.txt"))) + require.Equal(t, proof, expectedProof, test) + } else { + require.NoFileExists(t, filepath.Join(test, "proof.txt")) } } } func TestVerifyKZGProof(t *testing.T) { - type Test struct { - TestCases []struct { - Polynomial Blob `json:"Polynomial"` - Proof Bytes48 `json:"Proof"` - Commitment Bytes48 `json:"Commitment"` - InputPoint Bytes32 `json:"InputPoint"` - ClaimedValue Bytes32 `json:"ClaimedValue"` + tests, err := filepath.Glob(verifyKZGProofTests) + require.NoError(t, err) + for _, test := range tests { + commitment := getBytes48(filepath.Join(test, "commitment.txt")) + inputPoint := getBytes32(filepath.Join(test, "input_point.txt")) + claimedValue := getBytes32(filepath.Join(test, "claimed_value.txt")) + proof := getBytes48(filepath.Join(test, "proof.txt")) + + ok, ret := VerifyKZGProof(commitment, inputPoint, claimedValue, proof) + if ret == C_KZG_OK { + expectedOk := getBoolean(filepath.Join(test, "ok.txt")) + require.Equal(t, ok, expectedOk, test) + } else { + require.NoFileExists(t, filepath.Join(test, "ok.txt")) } } +} - testFile, err := os.Open("../rust/test_vectors/public_verify_kzg_proof.json") - require.NoError(t, err) - defer testFile.Close() - test := Test{} - err = json.NewDecoder(testFile).Decode(&test) +func TestVerifyBlobKZGProof(t *testing.T) { + tests, err := filepath.Glob(verifyBlobKZGProofTests) require.NoError(t, err) + for _, test := range tests { + blob := getBlob(filepath.Join(test, "blob.txt")) + commitment := getBytes48(filepath.Join(test, "commitment.txt")) + proof := getBytes48(filepath.Join(test, "proof.txt")) - for _, tc := range test.TestCases { - result, ret := VerifyKZGProof(tc.Commitment, tc.InputPoint, tc.ClaimedValue, tc.Proof) - require.Equal(t, C_KZG_OK, ret) - require.True(t, result) + ok, ret := VerifyBlobKZGProof(blob, commitment, proof) + if ret == C_KZG_OK { + expectedOk := getBoolean(filepath.Join(test, "ok.txt")) + require.Equal(t, ok, expectedOk, test) + } else { + require.NoFileExists(t, filepath.Join(test, "ok.txt")) + } + } +} + +func TestVerifyBlobKZGProofBatch(t *testing.T) { + tests, err := filepath.Glob(verifyBlobKZGProofBatchTests) + require.NoError(t, err) + for _, test := range tests { + blobFiles, err := filepath.Glob(filepath.Join(test, "blobs/*")) + require.NoError(t, err) + blobs := make([]Blob, len(blobFiles)) + for i, blobFile := range blobFiles { + blobs[i] = getBlob(blobFile) + } + commitmentFiles, err := filepath.Glob(filepath.Join(test, "commitments/*")) + require.NoError(t, err) + commitments := make([]Bytes48, len(commitmentFiles)) + for i, commitmentFile := range commitmentFiles { + commitments[i] = getBytes48(commitmentFile) + } + proofFiles, err := filepath.Glob(filepath.Join(test, "proofs/*")) + require.NoError(t, err) + proofs := make([]Bytes48, len(proofFiles)) + for i, proofFile := range proofFiles { + proofs[i] = getBytes48(proofFile) + } + require.Len(t, commitments, len(blobs)) + require.Len(t, proofs, len(blobs)) + + ok, ret := VerifyBlobKZGProofBatch(blobs, commitments, proofs) + if ret == C_KZG_OK { + expectedOk := getBoolean(filepath.Join(test, "ok.txt")) + require.Equal(t, ok, expectedOk, test) + } else { + require.NoFileExists(t, filepath.Join(test, "ok.txt")) + } } } @@ -168,15 +298,20 @@ func Benchmark(b *testing.B) { const length = 64 blobs := [length]Blob{} commitments := [length]Bytes48{} + proofs := [length]Bytes48{} + fields := [length]Bytes32{} for i := 0; i < length; i++ { - blobs[i] = GetRandBlob(int64(i)) - commitment, _ := BlobToKZGCommitment(blobs[i]) + blob := GetRandBlob(int64(i)) + commitment, ret := BlobToKZGCommitment(blob) + require.Equal(b, ret, C_KZG_OK) + proof, ret := ComputeBlobKZGProof(blob) + require.Equal(b, ret, C_KZG_OK) + + blobs[i] = blob commitments[i] = Bytes48(commitment) + proofs[i] = Bytes48(proof) + fields[i] = GetRandFieldElement(int64(i)) } - z := Bytes32{1, 2, 3} - y := Bytes32{4, 5, 6} - trustedProof, _ := ComputeAggregateKZGProof(blobs[:1]) - proof := Bytes48(trustedProof) /////////////////////////////////////////////////////////////////////////// // Public functions @@ -184,39 +319,38 @@ func Benchmark(b *testing.B) { b.Run("BlobToKZGCommitment", func(b *testing.B) { for n := 0; n < b.N; n++ { - _, ret := BlobToKZGCommitment(blobs[0]) - require.Equal(b, C_KZG_OK, ret) + BlobToKZGCommitment(blobs[0]) } }) b.Run("ComputeKZGProof", func(b *testing.B) { for n := 0; n < b.N; n++ { - _, ret := ComputeKZGProof(blobs[0], z) - require.Equal(b, C_KZG_OK, ret) + ComputeKZGProof(blobs[0], fields[0]) + } + }) + + b.Run("ComputeBlobKZGProof", func(b *testing.B) { + for n := 0; n < b.N; n++ { + ComputeBlobKZGProof(blobs[0]) } }) b.Run("VerifyKZGProof", func(b *testing.B) { for n := 0; n < b.N; n++ { - _, ret := VerifyKZGProof(commitments[0], z, y, proof) - require.Equal(b, C_KZG_OK, ret) + VerifyKZGProof(commitments[0], fields[0], fields[1], proofs[0]) + } + }) + + b.Run("VerifyBlobKZGProof", func(b *testing.B) { + for n := 0; n < b.N; n++ { + VerifyBlobKZGProof(blobs[0], commitments[0], proofs[0]) } }) for i := 1; i <= len(blobs); i *= 2 { - b.Run(fmt.Sprintf("ComputeAggregateKZGProof(blobs=%v)", i), func(b *testing.B) { + b.Run(fmt.Sprintf("VerifyBlobKZGProofBatch(count=%v)", i), func(b *testing.B) { for n := 0; n < b.N; n++ { - _, ret := ComputeAggregateKZGProof(blobs[:i]) - require.Equal(b, C_KZG_OK, ret) - } - }) - } - - for i := 1; i <= len(blobs); i *= 2 { - b.Run(fmt.Sprintf("VerifyAggregateKZGProof(blobs=%v)", i), func(b *testing.B) { - for n := 0; n < b.N; n++ { - _, ret := VerifyAggregateKZGProof(blobs[:i], commitments[:i], proof) - require.Equal(b, C_KZG_OK, ret) + VerifyBlobKZGProofBatch(blobs[:i], commitments[:i], proofs[:i]) } }) } @@ -226,8 +360,8 @@ func Benchmark(b *testing.B) { /////////////////////////////////////////////////////////////////////////// for i := 2; i <= 20; i += 2 { - var numBytes = int64(1 << i) - var bytes = make([]byte, numBytes) + numBytes := int64(1 << i) + bytes := make([]byte, numBytes) b.Run(fmt.Sprintf("sha256(size=%v)", HumanBytes(numBytes)), func(b *testing.B) { b.SetBytes(numBytes) for n := 0; n < b.N; n++ {