revm_precompile/
kzg_point_evaluation.rs1use crate::{
4 crypto, eth_precompile_fn, Address, EthPrecompileOutput, EthPrecompileResult, Precompile,
5 PrecompileHalt, PrecompileId,
6};
7pub mod arkworks;
8
9#[cfg(feature = "blst")]
10pub mod blst;
11
12use primitives::hex_literal::hex;
13
14eth_precompile_fn!(kzg_precompile, run);
15
16pub const POINT_EVALUATION: Precompile =
18 Precompile::new(PrecompileId::KzgPointEvaluation, ADDRESS, kzg_precompile);
19
20pub const ADDRESS: Address = crate::u64_to_address(0x0A);
22
23pub const GAS_COST: u64 = 50_000;
25
26pub const VERSIONED_HASH_VERSION_KZG: u8 = 0x01;
28
29pub const RETURN_VALUE: &[u8; 64] = &hex!(
31 "0000000000000000000000000000000000000000000000000000000000001000"
32 "73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001"
33);
34
35pub fn run(input: &[u8], gas_limit: u64) -> EthPrecompileResult {
44 if gas_limit < GAS_COST {
45 return Err(PrecompileHalt::OutOfGas);
46 }
47
48 if input.len() != 192 {
50 return Err(PrecompileHalt::BlobInvalidInputLength);
51 }
52
53 let versioned_hash = &input[..32];
55 let commitment = &input[96..144];
56 if kzg_to_versioned_hash(commitment) != versioned_hash {
57 return Err(PrecompileHalt::BlobMismatchedVersion);
58 }
59
60 let commitment: &[u8; 48] = commitment.try_into().unwrap();
62 let z = input[32..64].try_into().unwrap();
63 let y = input[64..96].try_into().unwrap();
64 let proof = input[144..192].try_into().unwrap();
65 crypto().verify_kzg_proof(z, y, commitment, proof)?;
66
67 Ok(EthPrecompileOutput::new(GAS_COST, RETURN_VALUE.into()))
69}
70
71#[inline]
73pub fn kzg_to_versioned_hash(commitment: &[u8]) -> [u8; 32] {
74 let mut hash = crypto().sha256(commitment);
75 hash[0] = VERSIONED_HASH_VERSION_KZG;
76 hash
77}
78
79#[inline]
81pub fn verify_kzg_proof(
82 commitment: &[u8; 48],
83 z: &[u8; 32],
84 y: &[u8; 32],
85 proof: &[u8; 48],
86) -> bool {
87 cfg_if::cfg_if! {
88 if #[cfg(feature = "c-kzg")] {
89 use c_kzg::{Bytes48, Bytes32};
90
91 let as_bytes48 = |bytes: &[u8; 48]| -> &Bytes48 { unsafe { &*bytes.as_ptr().cast() } };
92 let as_bytes32 = |bytes: &[u8; 32]| -> &Bytes32 { unsafe { &*bytes.as_ptr().cast() } };
93
94 let kzg_settings = c_kzg::ethereum_kzg_settings(8);
95 kzg_settings.verify_kzg_proof(as_bytes48(commitment), as_bytes32(z), as_bytes32(y), as_bytes48(proof)).unwrap_or(false)
96 } else if #[cfg(feature = "blst")] {
97 blst::verify_kzg_proof(commitment, z, y, proof)
98 } else {
99 arkworks::verify_kzg_proof(commitment, z, y, proof)
100 }
101 }
102}
103#[cfg(test)]
104mod tests {
105 use super::*;
106
107 #[test]
108 fn basic_test() {
109 let commitment = hex!("8f59a8d2a1a625a17f3fea0fe5eb8c896db3764f3185481bc22f91b4aaffcca25f26936857bc3a7c2539ea8ec3a952b7").to_vec();
112 let crypto = &crate::DefaultCrypto;
113 let mut versioned_hash = crate::Crypto::sha256(crypto, &commitment).to_vec();
114 versioned_hash[0] = VERSIONED_HASH_VERSION_KZG;
115 let z = hex!("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000").to_vec();
116 let y = hex!("1522a4a7f34e1ea350ae07c29c96c7e79655aa926122e95fe69fcbd932ca49e9").to_vec();
117 let proof = hex!("a62ad71d14c5719385c0686f1871430475bf3a00f0aa3f7b8dd99a9abc2160744faf0070725e00b60ad9a026a15b1a8c").to_vec();
118
119 let input = [versioned_hash, z, y, commitment, proof].concat();
120
121 let expected_output = hex!("000000000000000000000000000000000000000000000000000000000000100073eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001");
122 let gas = 50000;
123 let output = run(&input, gas).unwrap();
124 assert_eq!(output.gas_used, gas);
125 assert_eq!(output.bytes[..], expected_output);
126 }
127
128 #[test]
129 fn test_invalid_input() {
130 let commitment = hex!("c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
131 let z = hex!("0000000000000000000000000000000000000000000000000000000000000000");
132 let y = hex!("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001");
133 let proof = hex!("c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
134
135 let t = verify_kzg_proof(&commitment, &z, &y, &proof);
136 assert!(!t);
137 }
138
139 #[test]
140 fn test_valid_input() {
141 let commitment = hex!("c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
142 let z = hex!("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000");
143 let y = hex!("0000000000000000000000000000000000000000000000000000000000000000");
144 let proof = hex!("c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
145
146 let t = verify_kzg_proof(&commitment, &z, &y, &proof);
147 assert!(t);
148 }
149}