Skip to content
This repository was archived by the owner on Apr 4, 2025. It is now read-only.
Merged
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
103 changes: 90 additions & 13 deletions crypto/kzg/kzg.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,80 @@ package kzg

import (
"crypto/sha256"
"encoding/json"
"errors"
"fmt"
"math/big"
"os"
"sync"

gokzg4844 "github.com/crate-crypto/go-kzg-4844"
)

const (
BlobCommitmentVersionKZG uint8 = 0x01
PrecompileInputLength int = 192
)

type VersionedHash [32]byte

var gCryptoCtx *gokzg4844.Context
var initCryptoCtx sync.Once
var (
errInvalidInputLength = errors.New("invalid input length")

// InitializeCryptoCtx initializes the global context object returned via CryptoCtx
func InitializeCryptoCtx() {
// The value that gets returned when the `verify_kzg_proof“ precompile is called
precompileReturnValue [64]byte

trustedSetupFile string

gokzgCtx *gokzg4844.Context
initCryptoCtx sync.Once
)

func init() {
new(big.Int).SetUint64(gokzg4844.ScalarsPerBlob).FillBytes(precompileReturnValue[:32])
copy(precompileReturnValue[32:], gokzg4844.BlsModulus[:])
}

func SetTrustedSetupFilePath(path string) {
trustedSetupFile = path
}

// InitKZGCtx initializes the global context object returned via CryptoCtx
func InitKZGCtx() {
initCryptoCtx.Do(func() {
var err error
// Initialize context to match the configurations that the
// specs are using.
gCryptoCtx, err = gokzg4844.NewContext4096Insecure1337()
if err != nil {
panic(fmt.Sprintf("could not create context, err : %v", err))
if trustedSetupFile != "" {
file, err := os.ReadFile(trustedSetupFile)
if err != nil {
panic(fmt.Sprintf("could not read file, err: %v", err))
}

setup := new(gokzg4844.JSONTrustedSetup)
if err = json.Unmarshal(file, setup); err != nil {
panic(fmt.Sprintf("could not unmarshal, err: %v", err))
}

gokzgCtx, err = gokzg4844.NewContext4096(setup)
if err != nil {
panic(fmt.Sprintf("could not create KZG context, err: %v", err))
}
} else {
var err error
// Initialize context to match the configurations that the
// specs are using.
gokzgCtx, err = gokzg4844.NewContext4096Insecure1337()
if err != nil {
panic(fmt.Sprintf("could not create context, err : %v", err))
}
}
})
}

// Ctx returns a context object that stores all of the necessary configurations to allow one to
// create and verify blob proofs. This function is expensive to run if the crypto context isn't
// initialized, so production services should pre-initialize by calling InitializeCryptoCtx.
// initialized, so production services should pre-initialize by calling InitKZGCtx.
func Ctx() *gokzg4844.Context {
InitializeCryptoCtx()
return gCryptoCtx
InitKZGCtx()
return gokzgCtx
}

// KZGToVersionedHash implements kzg_to_versioned_hash from EIP-4844
Expand All @@ -45,3 +85,40 @@ func KZGToVersionedHash(kzg gokzg4844.KZGCommitment) VersionedHash {

return VersionedHash(h)
}

// PointEvaluationPrecompile implements point_evaluation_precompile from EIP-4844
func PointEvaluationPrecompile(input []byte) ([]byte, error) {
if len(input) != PrecompileInputLength {
return nil, errInvalidInputLength
}
// versioned hash: first 32 bytes
var versionedHash [32]byte
copy(versionedHash[:], input[:32])

var x, y [32]byte
// Evaluation point: next 32 bytes
copy(x[:], input[32:64])
// Expected output: next 32 bytes
copy(y[:], input[64:96])

// input kzg point: next 48 bytes
var dataKZG [48]byte
copy(dataKZG[:], input[96:144])
if KZGToVersionedHash(dataKZG) != versionedHash {
return nil, errors.New("mismatched versioned hash")
}

// Quotient kzg: next 48 bytes
var quotientKZG [48]byte
copy(quotientKZG[:], input[144:PrecompileInputLength])

cryptoCtx := Ctx()
err := cryptoCtx.VerifyKZGProof(dataKZG, x, y, quotientKZG)
if err != nil {
return nil, fmt.Errorf("verify_kzg_proof error: %w", err)
}

result := precompileReturnValue // copy the value

return result[:], nil
}