github.com/ledgerwatch/erigon-lib@v1.0.0/crypto/kzg/kzg.go (about)

     1  package kzg
     2  
     3  import (
     4  	"crypto/sha256"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"math/big"
     9  	"os"
    10  	"sync"
    11  
    12  	gokzg4844 "github.com/crate-crypto/go-kzg-4844"
    13  )
    14  
    15  const (
    16  	BlobCommitmentVersionKZG uint8 = 0x01
    17  	PrecompileInputLength    int   = 192
    18  )
    19  
    20  type VersionedHash [32]byte
    21  
    22  var (
    23  	errInvalidInputLength = errors.New("invalid input length")
    24  
    25  	// The value that gets returned when the `verify_kzg_proof“ precompile is called
    26  	precompileReturnValue [64]byte
    27  
    28  	trustedSetupFile string
    29  
    30  	gokzgCtx      *gokzg4844.Context
    31  	initCryptoCtx sync.Once
    32  )
    33  
    34  func init() {
    35  	new(big.Int).SetUint64(gokzg4844.ScalarsPerBlob).FillBytes(precompileReturnValue[:32])
    36  	copy(precompileReturnValue[32:], gokzg4844.BlsModulus[:])
    37  }
    38  
    39  func SetTrustedSetupFilePath(path string) {
    40  	trustedSetupFile = path
    41  }
    42  
    43  // InitKZGCtx initializes the global context object returned via CryptoCtx
    44  func InitKZGCtx() {
    45  	initCryptoCtx.Do(func() {
    46  		if trustedSetupFile != "" {
    47  			file, err := os.ReadFile(trustedSetupFile)
    48  			if err != nil {
    49  				panic(fmt.Sprintf("could not read file, err: %v", err))
    50  			}
    51  
    52  			setup := new(gokzg4844.JSONTrustedSetup)
    53  			if err = json.Unmarshal(file, setup); err != nil {
    54  				panic(fmt.Sprintf("could not unmarshal, err: %v", err))
    55  			}
    56  
    57  			gokzgCtx, err = gokzg4844.NewContext4096(setup)
    58  			if err != nil {
    59  				panic(fmt.Sprintf("could not create KZG context, err: %v", err))
    60  			}
    61  		} else {
    62  			var err error
    63  			// Initialize context to match the configurations that the
    64  			// specs are using.
    65  			gokzgCtx, err = gokzg4844.NewContext4096Insecure1337()
    66  			if err != nil {
    67  				panic(fmt.Sprintf("could not create context, err : %v", err))
    68  			}
    69  		}
    70  	})
    71  }
    72  
    73  // Ctx returns a context object that stores all of the necessary configurations to allow one to
    74  // create and verify blob proofs.  This function is expensive to run if the crypto context isn't
    75  // initialized, so production services should pre-initialize by calling InitKZGCtx.
    76  func Ctx() *gokzg4844.Context {
    77  	InitKZGCtx()
    78  	return gokzgCtx
    79  }
    80  
    81  // KZGToVersionedHash implements kzg_to_versioned_hash from EIP-4844
    82  func KZGToVersionedHash(kzg gokzg4844.KZGCommitment) VersionedHash {
    83  	h := sha256.Sum256(kzg[:])
    84  	h[0] = BlobCommitmentVersionKZG
    85  
    86  	return VersionedHash(h)
    87  }
    88  
    89  // PointEvaluationPrecompile implements point_evaluation_precompile from EIP-4844
    90  func PointEvaluationPrecompile(input []byte) ([]byte, error) {
    91  	if len(input) != PrecompileInputLength {
    92  		return nil, errInvalidInputLength
    93  	}
    94  	// versioned hash: first 32 bytes
    95  	var versionedHash [32]byte
    96  	copy(versionedHash[:], input[:32])
    97  
    98  	var x, y [32]byte
    99  	// Evaluation point: next 32 bytes
   100  	copy(x[:], input[32:64])
   101  	// Expected output: next 32 bytes
   102  	copy(y[:], input[64:96])
   103  
   104  	// input kzg point: next 48 bytes
   105  	var dataKZG [48]byte
   106  	copy(dataKZG[:], input[96:144])
   107  	if KZGToVersionedHash(dataKZG) != versionedHash {
   108  		return nil, errors.New("mismatched versioned hash")
   109  	}
   110  
   111  	// Quotient kzg: next 48 bytes
   112  	var quotientKZG [48]byte
   113  	copy(quotientKZG[:], input[144:PrecompileInputLength])
   114  
   115  	cryptoCtx := Ctx()
   116  	err := cryptoCtx.VerifyKZGProof(dataKZG, x, y, quotientKZG)
   117  	if err != nil {
   118  		return nil, fmt.Errorf("verify_kzg_proof error: %w", err)
   119  	}
   120  
   121  	result := precompileReturnValue // copy the value
   122  
   123  	return result[:], nil
   124  }