UNPKG

@tokamak-zk-evm/synthesizer

Version:

Tokamak zk-EVM Synthesizer - Processes Ethereum transactions into wire maps for Tokamak zk-SNARK proof generation

95 lines (80 loc) 3.13 kB
import { bigIntToBytes, bytesToHex, computeVersionedHash, concatBytes, setLengthLeft, } from "@synthesizer-libs/util" import { EvmErrorResult, OOGResult } from '../evm.js' import { ERROR, EvmError } from '../exceptions.js' import { gasLimitCheck } from './util.js' import { getPrecompileName } from './index.js' import type { ExecResult } from '../types.js' import type { PrecompileInput } from './types.js' export const BLS_MODULUS = BigInt( '52435875175126190479447740508185965837690552500527637822603658699938581184513', ) const modulusBuffer = setLengthLeft(bigIntToBytes(BLS_MODULUS), 32) export async function precompile0a(opts: PrecompileInput): Promise<ExecResult> { const pName = getPrecompileName('0a') if (opts.common.customCrypto?.kzg === undefined) { throw new Error('kzg not initialized') } const gasUsed = opts.common.param('kzgPointEvaluationPrecompileGas') if (!gasLimitCheck(opts, gasUsed, pName)) { return OOGResult(opts.gasLimit) } if (opts.data.length !== 192) { return EvmErrorResult(new EvmError(ERROR.INVALID_INPUT_LENGTH), opts.gasLimit) } const version = Number(opts.common.param('blobCommitmentVersionKzg')) const fieldElementsPerBlob = opts.common.param('fieldElementsPerBlob') const versionedHash = bytesToHex(opts.data.subarray(0, 32)) const z = bytesToHex(opts.data.subarray(32, 64)) const y = bytesToHex(opts.data.subarray(64, 96)) const commitment = bytesToHex(opts.data.subarray(96, 144)) const kzgProof = bytesToHex(opts.data.subarray(144, 192)) if (computeVersionedHash(commitment, version) !== versionedHash) { if (opts._debug !== undefined) { opts._debug(`${pName} failed: INVALID_COMMITMENT`) } return EvmErrorResult(new EvmError(ERROR.INVALID_COMMITMENT), opts.gasLimit) } if (opts._debug !== undefined) { opts._debug( `${pName}: proof verification with commitment=${ commitment } z=${z} y=${y} kzgProof=${kzgProof}`, ) } try { const res = opts.common.customCrypto?.kzg?.verifyProof(commitment, z, y, kzgProof) if (res === false) { return EvmErrorResult(new EvmError(ERROR.INVALID_PROOF), opts.gasLimit) } } catch (err: any) { if (err.message.includes('C_KZG_BADARGS') === true) { if (opts._debug !== undefined) { opts._debug(`${pName} failed: INVALID_INPUTS`) } return EvmErrorResult(new EvmError(ERROR.INVALID_INPUTS), opts.gasLimit) } if (opts._debug !== undefined) { opts._debug(`${pName} failed: Unknown error - ${err.message}`) } return EvmErrorResult(new EvmError(ERROR.REVERT), opts.gasLimit) } // Return value - FIELD_ELEMENTS_PER_BLOB and BLS_MODULUS as padded 32 byte big endian values const fieldElementsBuffer = setLengthLeft(bigIntToBytes(fieldElementsPerBlob), 32) if (opts._debug !== undefined) { opts._debug( `${pName} return fieldElements=${bytesToHex( fieldElementsBuffer, )} modulus=${bytesToHex(modulusBuffer)}`, ) } return { executionGasUsed: gasUsed, returnValue: concatBytes(fieldElementsBuffer, modulusBuffer), } }