risc0_groth16/
docker.rs

1// Copyright 2025 RISC Zero, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! This module contains functions for running a Groth16 prover using Docker.
16//!
17//! Docker is used here as a way to provide [gnark] and the required prover key in a single package.
18//! Proving with Groth16 is currently only supported using Docker.
19//!
20//! [gnark]: https://github.com/Consensys/gnark
21
22use 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
33/// Groth16 a given seal of an `identity_p254` receipt into a Groth16 `Seal`.
34/// Requires running Docker on an x86 architecture.
35pub 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}