c-kzg-4844/bindings/go/main_test.go

239 lines
6.1 KiB
Go

package cgokzg4844
import (
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"math/rand"
"os"
"testing"
"github.com/stretchr/testify/require"
)
func TestMain(m *testing.M) {
ret := LoadTrustedSetupFile("../../src/trusted_setup.txt")
if ret != 0 {
panic("failed to load trusted setup")
}
defer FreeTrustedSetup()
code := m.Run()
os.Exit(code)
}
///////////////////////////////////////////////////////////////////////////////
// Helper Functions
///////////////////////////////////////////////////////////////////////////////
func (f *Bytes32) UnmarshalText(input []byte) error {
bytes, err := hex.DecodeString(string(input))
if err != nil {
return err
}
if len(bytes) != len(f) {
return errors.New("invalid Bytes32")
}
copy(f[:], bytes)
return nil
}
func (f *Bytes48) UnmarshalText(input []byte) error {
bytes, err := hex.DecodeString(string(input))
if err != nil {
return err
}
if len(bytes) != len(f) {
return errors.New("invalid Bytes48")
}
copy(f[:], bytes)
return nil
}
func (b *Blob) UnmarshalText(input []byte) error {
blobBytes, err := hex.DecodeString(string(input))
if err != nil {
return err
}
if len(blobBytes) != len(b) {
return errors.New("invalid Blob")
}
copy(b[:], blobBytes)
return nil
}
func GetRandFieldElement(seed int64) Bytes32 {
rand.Seed(seed)
bytes := make([]byte, 31)
_, err := rand.Read(bytes)
if err != nil {
panic("failed to get random field element")
}
// This leaves the last byte in fieldElementBytes as
// zero, which guarantees it's a canonical field element.
var fieldElementBytes Bytes32
copy(fieldElementBytes[:], bytes)
return fieldElementBytes
}
func GetRandBlob(seed int64) Blob {
var blob Blob
for i := 0; i < BytesPerBlob; i += BytesPerFieldElement {
fieldElementBytes := GetRandFieldElement(seed + int64(i))
copy(blob[i:i+BytesPerFieldElement], fieldElementBytes[:])
}
return blob
}
/*
HumanBytes will convert an integer to a human-readable value. Adapted from:
https://programming.guide/go/formatting-byte-size-to-human-readable-format.html
*/
func HumanBytes(b int64) string {
const unit = 1024
if b < unit {
return fmt.Sprintf("%dB", b)
}
div, exp := int64(unit), 0
for n := b / unit; n >= unit; n /= unit {
div *= unit
exp++
}
return fmt.Sprintf("%v%cB", float64(b)/float64(div), "KMGTPE"[exp])
}
///////////////////////////////////////////////////////////////////////////////
// Tests
///////////////////////////////////////////////////////////////////////////////
func TestComputeAggregateKZGProof(t *testing.T) {
type Test struct {
TestCases []struct {
Polynomials []Blob `json:"Polynomials"`
Proof Bytes48 `json:"Proof"`
Commitments []Bytes48 `json:"Commitments"`
}
}
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)
require.NoError(t, err)
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[:])
}
}
}
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"`
}
}
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)
require.NoError(t, err)
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)
}
}
///////////////////////////////////////////////////////////////////////////////
// Benchmarks
///////////////////////////////////////////////////////////////////////////////
func Benchmark(b *testing.B) {
const length = 64
blobs := [length]Blob{}
commitments := [length]Bytes48{}
for i := 0; i < length; i++ {
blobs[i] = GetRandBlob(int64(i))
commitment, _ := BlobToKZGCommitment(blobs[i])
commitments[i] = Bytes48(commitment)
}
z := Bytes32{1, 2, 3}
y := Bytes32{4, 5, 6}
trustedProof, _ := ComputeAggregateKZGProof(blobs[:1])
proof := Bytes48(trustedProof)
///////////////////////////////////////////////////////////////////////////
// Public functions
///////////////////////////////////////////////////////////////////////////
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)
}
})
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)
}
})
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)
}
})
for i := 1; i <= len(blobs); i *= 2 {
b.Run(fmt.Sprintf("ComputeAggregateKZGProof(blobs=%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)
}
})
}
///////////////////////////////////////////////////////////////////////////
// Private functions
///////////////////////////////////////////////////////////////////////////
for i := 2; i <= 20; i += 2 {
var numBytes = int64(1 << i)
var 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++ {
sha256(bytes)
}
})
}
}