risc0_groth16/
seal_to_json.rs

1// Copyright 2024 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
15use std::io::{Read, Write};
16
17use anyhow::{Context, Result};
18use num_bigint::BigUint;
19use num_traits::Num;
20use risc0_core::field::baby_bear::BabyBearElem;
21use risc0_zkp::core::{
22    digest::{Digest, DIGEST_WORDS},
23    hash::poseidon_254::digest_to_fr,
24};
25
26use crate::seal_format::{IopType, K_SEAL_ELEMS, K_SEAL_TYPES, K_SEAL_WORDS};
27
28/// Convert a recursion VM seal (i.e. succinct receipt) into a JSON format compatible with the
29/// `stark_verify` witness generator.
30pub fn to_json<R: Read, W: Write>(mut reader: R, mut writer: W) -> Result<()> {
31    let mut iop = vec![0u32; K_SEAL_WORDS];
32    reader.read_exact(bytemuck::cast_slice_mut(&mut iop))?;
33
34    writeln!(writer, "{{\n  \"iop\" : [")?;
35
36    let mut pos = 0;
37    for seal_type in K_SEAL_TYPES.iter().take(K_SEAL_ELEMS) {
38        if pos != 0 {
39            writeln!(writer, ",")?;
40        }
41        match seal_type {
42            IopType::Fp => {
43                let value = BabyBearElem::new_raw(iop[pos]).as_u32();
44                pos += 1;
45                writeln!(writer, "    \"{value}\"")?;
46            }
47            _ => {
48                let digest = Digest::try_from(&iop[pos..pos + DIGEST_WORDS])?;
49                let value = digest_to_decimal(&digest)?;
50                pos += 8;
51                writeln!(writer, "    \"{value}\"")?;
52            }
53        }
54    }
55    write!(writer, "  ]\n}}")?;
56
57    Ok(())
58}
59
60fn digest_to_decimal(digest: &Digest) -> Result<String> {
61    to_decimal(&format!("{:?}", digest_to_fr(digest))).context("digest_to_decimal failed")
62}
63
64fn to_decimal(s: &str) -> Option<String> {
65    s.strip_prefix("Fr(0x")
66        .and_then(|s| s.strip_suffix(')'))
67        .and_then(|stripped| BigUint::from_str_radix(stripped, 16).ok())
68        .map(|n| n.to_str_radix(10))
69}