1#[cfg(feature = "evm-prove")]
2use std::io::{BufReader, BufWriter, Write};
3use std::{
4 fs::{create_dir_all, read, write, File},
5 path::Path,
6};
7
8use eyre::{Report, Result};
9use openvm_stark_backend::codec::{Decode, Encode};
10use serde::{de::DeserializeOwned, Serialize};
11
12#[cfg(feature = "evm-prove")]
13use crate::{
14 keygen::Halo2ProvingKey,
15 types::{EvmHalo2Verifier, EvmVerifierByteCode},
16 OPENVM_VERSION,
17};
18
19pub const EVM_HALO2_VERIFIER_INTERFACE_NAME: &str = "IOpenVmHalo2Verifier.sol";
20pub const EVM_HALO2_VERIFIER_PARENT_NAME: &str = "Halo2Verifier.sol";
21pub const EVM_HALO2_VERIFIER_BASE_NAME: &str = "OpenVmHalo2Verifier.sol";
22pub const EVM_VERIFIER_ARTIFACT_FILENAME: &str = "verifier.bytecode.json";
23
24#[cfg(feature = "evm-prove")]
27pub fn read_evm_halo2_verifier_from_folder<P: AsRef<Path>>(
28 folder: P,
29 version_dir: Option<&str>,
30) -> Result<EvmHalo2Verifier> {
31 use std::fs::read_to_string;
32
33 let folder = folder
34 .as_ref()
35 .join("src")
36 .join(version_dir.map_or_else(|| format!("v{OPENVM_VERSION}"), str::to_string));
37 let halo2_verifier_code_path = folder.join(EVM_HALO2_VERIFIER_PARENT_NAME);
38 let openvm_verifier_code_path = folder.join(EVM_HALO2_VERIFIER_BASE_NAME);
39 let interface_path = folder
40 .join("interfaces")
41 .join(EVM_HALO2_VERIFIER_INTERFACE_NAME);
42 let halo2_verifier_code = read_to_string(&halo2_verifier_code_path)
43 .map_err(|e| read_error(&halo2_verifier_code_path, e.into()))?;
44 let openvm_verifier_code = read_to_string(&openvm_verifier_code_path)
45 .map_err(|e| read_error(&openvm_verifier_code_path, e.into()))?;
46 let interface =
47 read_to_string(&interface_path).map_err(|e| read_error(&interface_path, e.into()))?;
48
49 let artifact_path = folder.join(EVM_VERIFIER_ARTIFACT_FILENAME);
50 let artifact: EvmVerifierByteCode = File::open(&artifact_path)
51 .map_err(|e| read_error(&artifact_path, e.into()))
52 .and_then(|file| {
53 serde_json::from_reader(file).map_err(|e| read_error(&artifact_path, e.into()))
54 })?;
55
56 Ok(EvmHalo2Verifier {
57 halo2_verifier_code,
58 openvm_verifier_code,
59 openvm_verifier_interface: interface,
60 artifact,
61 })
62}
63
64#[cfg(feature = "evm-prove")]
79pub fn write_evm_halo2_verifier_to_folder<P: AsRef<Path>>(
80 verifier: EvmHalo2Verifier,
81 folder: P,
82 version_dir: Option<&str>,
83) -> Result<()> {
84 let folder = folder
85 .as_ref()
86 .join("src")
87 .join(version_dir.map_or_else(|| format!("v{OPENVM_VERSION}"), str::to_string));
88 if !folder.exists() {
89 create_dir_all(&folder)?; }
91
92 let halo2_verifier_code_path = folder.join(EVM_HALO2_VERIFIER_PARENT_NAME);
93 let openvm_verifier_code_path = folder.join(EVM_HALO2_VERIFIER_BASE_NAME);
94 let interface_path = folder
95 .join("interfaces")
96 .join(EVM_HALO2_VERIFIER_INTERFACE_NAME);
97
98 if let Some(parent) = interface_path.parent() {
99 create_dir_all(parent)?;
100 }
101
102 write(halo2_verifier_code_path, verifier.halo2_verifier_code)
103 .expect("Failed to write halo2 verifier code");
104 write(openvm_verifier_code_path, verifier.openvm_verifier_code)
105 .expect("Failed to write openvm halo2 verifier code");
106 write(interface_path, verifier.openvm_verifier_interface)
107 .expect("Failed to write openvm halo2 verifier interface");
108
109 let artifact_path = folder.join(EVM_VERIFIER_ARTIFACT_FILENAME);
110 serde_json::to_writer(File::create(artifact_path)?, &verifier.artifact)?;
111
112 Ok(())
113}
114
115pub fn read_object_from_file<T: DeserializeOwned, P: AsRef<Path>>(path: P) -> Result<T> {
116 read_from_file_bitcode(path)
117}
118
119pub fn write_object_to_file<T: Serialize, P: AsRef<Path>>(path: P, data: T) -> Result<()> {
120 write_to_file_bitcode(path, data)
121}
122
123#[cfg(feature = "evm-prove")]
125pub fn write_halo2_pk_to_file<P: AsRef<Path>>(path: P, halo2_pk: &Halo2ProvingKey) -> Result<()> {
126 if let Some(parent) = path.as_ref().parent() {
127 create_dir_all(parent).map_err(|e| write_error(&path, e.into()))?;
128 }
129 let file = File::create(&path).map_err(|e| write_error(&path, e.into()))?;
130 let mut writer = BufWriter::new(file);
131 halo2_pk
132 .encode(&mut writer)
133 .map_err(|e| write_error(&path, e.into()))?;
134 writer.flush().map_err(|e| write_error(&path, e.into()))?;
135 Ok(())
136}
137
138#[cfg(feature = "evm-prove")]
140pub fn read_halo2_pk_from_file<P: AsRef<Path>>(path: P) -> Result<Halo2ProvingKey> {
141 let file = File::open(&path).map_err(|e| read_error(&path, e.into()))?;
142 let mut reader = BufReader::new(file);
143 Halo2ProvingKey::decode(&mut reader).map_err(|e| read_error(&path, e.into()))
144}
145
146fn read_from_file_bitcode<T: DeserializeOwned, P: AsRef<Path>>(path: P) -> Result<T> {
147 let ret = read(&path)
148 .map_err(|e| read_error(&path, e.into()))
149 .and_then(|data| {
150 bitcode::deserialize(&data).map_err(|e: bitcode::Error| read_error(&path, e.into()))
151 })?;
152 Ok(ret)
153}
154
155fn write_to_file_bitcode<T: Serialize, P: AsRef<Path>>(path: P, data: T) -> Result<()> {
156 if let Some(parent) = path.as_ref().parent() {
157 create_dir_all(parent).map_err(|e| write_error(&path, e.into()))?;
158 }
159 bitcode::serialize(&data)
160 .map_err(|e| write_error(&path, e.into()))
161 .and_then(|bytes| write(&path, bytes).map_err(|e| write_error(&path, e.into())))?;
162 Ok(())
163}
164
165pub fn read_from_file_json<T: DeserializeOwned, P: AsRef<Path>>(path: P) -> Result<T> {
166 let ret: T = File::open(&path)
167 .and_then(|file| serde_json::from_reader(file).map_err(|e| e.into()))
168 .map_err(|e| read_error(&path, e.into()))?;
169 Ok(ret)
170}
171
172pub fn write_to_file_json<T: Serialize, P: AsRef<Path>>(path: P, data: T) -> Result<()> {
173 if let Some(parent) = path.as_ref().parent() {
174 create_dir_all(parent).map_err(|e| write_error(&path, e.into()))?;
175 }
176 File::create(&path)
177 .and_then(|file| serde_json::to_writer_pretty(file, &data).map_err(|e| e.into()))
178 .map_err(|e| write_error(&path, e.into()))?;
179 Ok(())
180}
181
182pub fn read_from_file_bytes<T: From<Vec<u8>>, P: AsRef<Path>>(path: P) -> Result<T> {
183 let bytes = read(&path).map_err(|e| read_error(&path, e.into()))?;
184 Ok(T::from(bytes))
185}
186
187pub fn write_to_file_bytes<T: Into<Vec<u8>>, P: AsRef<Path>>(path: P, data: T) -> Result<()> {
188 if let Some(parent) = path.as_ref().parent() {
189 create_dir_all(parent)?;
190 }
191 write(path, data.into())?;
192 Ok(())
193}
194
195pub fn decode_from_file<T: Decode, P: AsRef<Path>>(path: P) -> Result<T> {
196 let reader = &mut File::open(&path).map_err(|e| read_error(&path, e.into()))?;
197 let ret = T::decode(reader).map_err(|e| read_error(&path, e.into()))?;
198 Ok(ret)
199}
200
201pub fn encode_to_file<T: Encode, P: AsRef<Path>>(path: P, data: T) -> Result<()> {
202 if let Some(parent) = path.as_ref().parent() {
203 create_dir_all(parent)?;
204 }
205 let writer = &mut File::create(path)?;
206 data.encode(writer)?;
207 Ok(())
208}
209
210fn read_error<P: AsRef<Path>>(path: P, error: Report) -> Report {
211 eyre::eyre!(
212 "reading from {} failed with the following error:\n {}",
213 path.as_ref().display(),
214 error,
215 )
216}
217
218fn write_error<P: AsRef<Path>>(path: P, error: Report) -> Report {
219 eyre::eyre!(
220 "writing to {} failed with the following error:\n {}",
221 path.as_ref().display(),
222 error,
223 )
224}