snark_verifier/loader/evm/
util.rs
1use crate::{
2 cost::Cost,
3 util::{arithmetic::PrimeField, Itertools},
4};
5use std::{
6 io::Write,
7 iter,
8 process::{Command, Stdio},
9};
10
11#[cfg(feature = "revm")]
12pub use executor::deploy_and_call;
13pub use ruint::aliases::{B160 as Address, B256, U256, U512};
14
15#[cfg(feature = "revm")]
16pub(crate) mod executor;
17
18#[derive(Debug)]
20pub struct MemoryChunk {
21 ptr: usize,
22 len: usize,
23}
24
25impl MemoryChunk {
26 pub(crate) fn new(ptr: usize) -> Self {
27 Self { ptr, len: 0 }
28 }
29
30 pub(crate) fn ptr(&self) -> usize {
31 self.ptr
32 }
33
34 pub(crate) fn len(&self) -> usize {
35 self.len
36 }
37
38 pub(crate) fn end(&self) -> usize {
39 self.ptr + self.len
40 }
41
42 pub(crate) fn reset(&mut self, ptr: usize) {
43 self.ptr = ptr;
44 self.len = 0;
45 }
46
47 pub(crate) fn extend(&mut self, size: usize) {
48 self.len += size;
49 }
50}
51
52pub fn fe_to_u256<F>(f: F) -> U256
56where
57 F: PrimeField<Repr = [u8; 32]>,
58{
59 U256::from_le_bytes(f.to_repr())
60}
61
62pub fn u256_to_fe<F>(value: U256) -> F
64where
65 F: PrimeField<Repr = [u8; 32]>,
66{
67 let value = value % modulus::<F>();
68 F::from_repr(value.to_le_bytes::<32>()).unwrap()
69}
70
71pub fn modulus<F>() -> U256
73where
74 F: PrimeField<Repr = [u8; 32]>,
75{
76 U256::from_le_bytes((-F::ONE).to_repr()) + U256::from(1)
77}
78
79pub fn encode_calldata<F>(instances: &[Vec<F>], proof: &[u8]) -> Vec<u8>
81where
82 F: PrimeField<Repr = [u8; 32]>,
83{
84 iter::empty()
85 .chain(
86 instances
87 .iter()
88 .flatten()
89 .flat_map(|value| value.to_repr().as_ref().iter().rev().cloned().collect_vec()),
90 )
91 .chain(proof.iter().cloned())
92 .collect()
93}
94
95pub fn estimate_gas(cost: Cost) -> usize {
97 let proof_size = cost.num_commitment * 64 + (cost.num_evaluation + cost.num_instance) * 32;
98
99 let intrinsic_cost = 21000;
100 let calldata_cost = (proof_size as f64 * 15.25).ceil() as usize;
101 let ec_operation_cost = (45100 + cost.num_pairing * 34000) + (cost.num_msm - 2) * 6350;
102
103 intrinsic_cost + calldata_cost + ec_operation_cost
104}
105
106pub fn compile_solidity(code: &str) -> Vec<u8> {
108 let mut cmd = Command::new("solc")
109 .stdin(Stdio::piped())
110 .stdout(Stdio::piped())
111 .arg("--bin")
112 .arg("-")
113 .spawn()
114 .unwrap();
115 cmd.stdin.take().unwrap().write_all(code.as_bytes()).unwrap();
116 let output = cmd.wait_with_output().unwrap().stdout;
117 let binary = *split_by_ascii_whitespace(&output).last().unwrap();
118 assert!(!binary.is_empty());
119 hex::decode(binary).unwrap()
120}
121
122fn split_by_ascii_whitespace(bytes: &[u8]) -> Vec<&[u8]> {
123 let mut split = Vec::new();
124 let mut start = None;
125 for (idx, byte) in bytes.iter().enumerate() {
126 if byte.is_ascii_whitespace() {
127 if let Some(start) = start.take() {
128 split.push(&bytes[start..idx]);
129 }
130 } else if start.is_none() {
131 start = Some(idx);
132 }
133 }
134 if let Some(last) = start {
135 split.push(&bytes[last..]);
136 }
137 split
138}
139
140#[test]
141fn test_split_by_ascii_whitespace_1() {
142 let bytes = b" \x01 \x02 \x03";
143 let split = split_by_ascii_whitespace(bytes);
144 assert_eq!(split, [b"\x01", b"\x02", b"\x03"]);
145}
146
147#[test]
148fn test_split_by_ascii_whitespace_2() {
149 let bytes = b"123456789abc";
150 let split = split_by_ascii_whitespace(bytes);
151 assert_eq!(split, [b"123456789abc"]);
152}