1use std::{
23 env::consts::ARCH,
24 path::Path,
25 process::{Command, Stdio},
26};
27
28use anyhow::{bail, Result};
29use tempfile::tempdir;
30
31use crate::{to_json, ProofJson, Seal};
32
33pub fn stark_to_snark(identity_p254_seal_bytes: &[u8]) -> Result<Seal> {
36 if !is_x86_architecture() {
37 bail!("stark_to_snark is only supported on x86 architecture.")
38 }
39 if !is_docker_installed() {
40 bail!("Please install docker first.")
41 }
42
43 let tmp_dir = tempdir()?;
44 let work_dir = std::env::var("RISC0_WORK_DIR");
45 let work_dir = work_dir.as_ref().map(Path::new).unwrap_or(tmp_dir.path());
46
47 tracing::debug!("seal-to-json");
48 std::fs::write(work_dir.join("seal.r0"), identity_p254_seal_bytes)?;
49 let seal_path = work_dir.join("input.json");
50 let proof_path = work_dir.join("proof.json");
51 let mut seal_json = Vec::new();
52 to_json(identity_p254_seal_bytes, &mut seal_json)?;
53 std::fs::write(seal_path, seal_json)?;
54
55 tracing::debug!("risc0-groth16-prover");
56 let output = Command::new("docker")
57 .arg("run")
58 .arg("--rm")
59 .arg("-v")
60 .arg(format!("{}:/mnt", work_dir.to_string_lossy()))
61 .arg("risczero/risc0-groth16-prover:v2025-01-31.1")
62 .stdout(Stdio::piped())
63 .stderr(Stdio::piped())
64 .output()?;
65 if !output.status.success() {
66 bail!(
67 "docker returned failure exit code: {:?}",
68 output.status.code()
69 );
70 }
71
72 tracing::debug!("Parsing proof");
73 let contents = std::fs::read_to_string(proof_path)?;
74 let proof_json: ProofJson = serde_json::from_str(&contents)?;
75 proof_json.try_into()
76}
77
78fn is_docker_installed() -> bool {
79 Command::new("docker")
80 .arg("--version")
81 .output()
82 .map(|output| output.status.success())
83 .unwrap_or(false)
84}
85
86fn is_x86_architecture() -> bool {
87 ARCH == "x86_64" || ARCH == "x86"
88}