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 }