cfx_executor/builtin/
kzg_point_evaluations.rs1use c_kzg::{ethereum_kzg_settings, Bytes32, Bytes48, KzgSettings};
4
5use cfx_crypto::crypto::digest;
6use hex_literal::hex;
7use std::convert::TryInto;
8
9use super::Error;
10
11pub const VERSIONED_HASH_VERSION_KZG: u8 = 0x01;
12
13pub const RETURN_VALUE: &[u8; 64] = &hex!(
15 "0000000000000000000000000000000000000000000000000000000000001000"
16 "73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001"
17);
18
19pub fn run(input: &[u8]) -> Result<(), Error> {
28 if input.len() != 192 {
30 return Err("Blob invalid input length".into());
31 }
32
33 let versioned_hash = &input[..32];
35 let commitment = &input[96..144];
36 if kzg_to_versioned_hash(commitment) != versioned_hash {
37 return Err("Blob mismatched version".into());
38 }
39
40 let commitment = as_bytes48(commitment);
42 let z = as_bytes32(&input[32..64]);
43 let y = as_bytes32(&input[64..96]);
44 let proof = as_bytes48(&input[144..192]);
45 if !verify_kzg_proof(commitment, z, y, proof, ethereum_kzg_settings(8)) {
46 return Err("Blob verify kzg proof failed".into());
47 }
48 Ok(())
49}
50
51#[inline]
53pub fn kzg_to_versioned_hash(commitment: &[u8]) -> [u8; 32] {
54 let mut hash = [0u8; 32];
55 hash.copy_from_slice(&*digest::sha256(commitment));
56 hash[0] = VERSIONED_HASH_VERSION_KZG;
57 hash
58}
59
60#[inline]
61pub fn verify_kzg_proof(
62 commitment: &Bytes48, z: &Bytes32, y: &Bytes32, proof: &Bytes48,
63 kzg_settings: &KzgSettings,
64) -> bool {
65 kzg_settings
66 .verify_kzg_proof(commitment, z, y, proof)
67 .unwrap_or(false)
68}
69
70#[inline]
71#[track_caller]
72pub fn as_array<const N: usize>(bytes: &[u8]) -> &[u8; N] {
73 bytes.try_into().expect("slice with incorrect length")
74}
75
76#[inline]
77#[track_caller]
78pub fn as_bytes32(bytes: &[u8]) -> &Bytes32 {
79 unsafe { &*as_array::<32>(bytes).as_ptr().cast() }
81}
82
83#[inline]
84#[track_caller]
85pub fn as_bytes48(bytes: &[u8]) -> &Bytes48 {
86 unsafe { &*as_array::<48>(bytes).as_ptr().cast() }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[test]
95 fn basic_test() {
96 let commitment = hex!("8f59a8d2a1a625a17f3fea0fe5eb8c896db3764f3185481bc22f91b4aaffcca25f26936857bc3a7c2539ea8ec3a952b7").to_vec();
99 let mut versioned_hash = digest::sha256(&commitment).to_vec();
100 versioned_hash[0] = VERSIONED_HASH_VERSION_KZG;
101 let z = hex!(
102 "73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000"
103 )
104 .to_vec();
105 let y = hex!(
106 "1522a4a7f34e1ea350ae07c29c96c7e79655aa926122e95fe69fcbd932ca49e9"
107 )
108 .to_vec();
109 let proof = hex!("a62ad71d14c5719385c0686f1871430475bf3a00f0aa3f7b8dd99a9abc2160744faf0070725e00b60ad9a026a15b1a8c").to_vec();
110
111 let input = [versioned_hash, z, y, commitment, proof].concat();
112 run(&input).unwrap();
113
114 let expected_output = hex!("000000000000000000000000000000000000000000000000000000000000100073eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001");
115
116 assert_eq!(RETURN_VALUE[..], expected_output);
117 }
118}