prover_elf_utils/
elf_info.rs1use std::{env, fs, io::Write, path::Path};
2
3use bincode::Options;
4use sp1_prover::{HashableKey, SP1Prover, SP1VerifyingKey};
5
6pub fn bincode_options() -> impl bincode::Options {
7 bincode::DefaultOptions::new()
8 .with_big_endian()
9 .with_fixint_encoding()
10}
11
12pub struct ElfInfo {
14 prover: Option<SP1Prover>,
16
17 output: fs::File,
19}
20
21impl ElfInfo {
22 pub fn writing_to(file_name: impl AsRef<Path>) -> Self {
23 println!("cargo::rerun-if-changed=build.rs");
24
25 let prover = None;
26
27 let dir = env::var_os("OUT_DIR").expect("output directory");
28 let path = Path::new(&dir).join(file_name);
29 let output = fs::File::create(path).expect("elf info output file");
30
31 Self { prover, output }
32 }
33
34 pub fn module<EB>(self, module_name: &str, elf_bytes: EB) -> Emitter<EB> {
36 Emitter::new(self, module_name, elf_bytes)
37 }
38
39 pub fn module_from_file(
41 self,
42 module_name: &str,
43 elf_path: impl AsRef<Path>,
44 ) -> Emitter<Box<[u8]>> {
45 let path_string = elf_path.as_ref().to_string_lossy();
46 println!("cargo::rerun-if-changed={path_string}");
47
48 let elf_bytes = fs::read(elf_path).unwrap().into_boxed_slice();
49 self.module(module_name, elf_bytes)
50 }
51
52 fn prover(&mut self) -> &SP1Prover {
53 self.prover.get_or_insert_with(SP1Prover::new)
54 }
55}
56
57#[must_use = "Please finalize the sequence with a .finish() call"]
59pub struct Emitter<ElfBytes> {
60 context: ElfInfo,
61 elf: ElfBytes,
62 vkey: Option<SP1VerifyingKey>,
63}
64
65impl<ElfBytes> Emitter<ElfBytes> {
66 fn new(context: ElfInfo, name: &str, elf: ElfBytes) -> Self {
67 writeln!(&context.output, "pub mod {name} {{").unwrap();
68 let vkey = None;
69 Emitter { context, elf, vkey }
70 }
71
72 pub fn finish(self) -> ElfInfo {
73 self.output().write_all(b"}\n").unwrap();
74 self.context
75 }
76
77 fn output(&self) -> &fs::File {
78 &self.context.output
79 }
80}
81
82impl<ElfBytes: AsRef<[u8]>> Emitter<ElfBytes> {
83 pub fn emit_vkey_bytes(mut self) -> Self {
85 let bytes = bincode_options().serialize(self.vkey()).unwrap();
86 writeln!(
87 self.output(),
88 " pub const VKEY_BYTES: &[u8] = &{bytes:?};"
89 )
90 .unwrap();
91 self
92 }
93
94 pub fn emit_vkey_hash(mut self) -> Self {
96 let hash = self.vkey().hash_u32();
97 writeln!(
98 self.output(),
99 " pub const VKEY_HASH: [u32; 8] = {hash:?};"
100 )
101 .unwrap();
102 self
103 }
104
105 pub fn emit_vkey_commitment(mut self) -> Self {
107 let commitment = self.vkey().hash_bytes();
108 writeln!(
109 self.output(),
110 " pub const VKEY_COMMITMENT: [u8; 32] = {commitment:?};"
111 )
112 .unwrap();
113 self
114 }
115
116 fn vkey(&mut self) -> &SP1VerifyingKey {
117 self.vkey.get_or_insert_with(|| {
118 let (_sp1_pkey, _stark_pkey, _program, vkey) =
119 self.context.prover().setup(self.elf.as_ref());
120 vkey
121 })
122 }
123}