1
use {
2
    anyhow::{anyhow, Context, Result},
3
    iop::*,
4
    num_bigint::BigUint,
5
    num_traits::Num,
6
    risc0_core::field::baby_bear::BabyBearElem,
7
    risc0_zkp::core::{
8
        digest::{Digest, DIGEST_WORDS},
9
        hash::poseidon_254::digest_to_fr,
10
    },
11
    std::{io::Write, path::Path},
12
    tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt},
13
};
14

            
15
static TOOLS_ENTRIES: [&str; 4] = [
16
    "stark_verify",
17
    "stark_verify.dat",
18
    "stark_verify_final.zkey",
19
    "rapidsnark",
20
];
21

            
22
pub fn check_x86_64arch() -> bool {
23
    if cfg!(target_arch = "x86_64") {
24
        true
25
    } else {
26
        false
27
    }
28
}
29

            
30
pub fn check_stark_compression_tools_path(path: &str) -> Result<()> {
31
    let tools_path = Path::new(path);
32
    for entry in TOOLS_ENTRIES.iter() {
33
        let entry_path = tools_path.join(entry);
34
        if !entry_path.exists() {
35
            return Err(anyhow!(
36
                "Error: Stark compression tools not found at {}",
37
                entry_path.to_string_lossy()
38
            ));
39
        }
40
    }
41
    Ok(())
42
}
43

            
44
pub async fn async_to_json<
45
    R: AsyncRead + std::marker::Unpin,
46
    W: AsyncWrite + std::marker::Unpin,
47
>(
48
    mut reader: R,
49
    mut writer: W,
50
) -> Result<()> {
51
    let mut iop = vec![0u32; K_SEAL_WORDS];
52
    reader
53
        .read_exact(bytemuck::cast_slice_mut(&mut iop))
54
        .await?;
55
    let mut mem = Vec::new();
56
    writeln!(mem, "{{\n  \"iop\": [")?;
57

            
58
    let mut pos = 0;
59
    for seal_type in K_SEAL_TYPES.iter().take(K_SEAL_ELEMS) {
60
        if pos != 0 {
61
            writeln!(mem, ",")?;
62
        }
63
        match seal_type {
64
            IopType::Fp => {
65
                let value = BabyBearElem::new_raw(iop[pos]).as_u32();
66
                pos += 1;
67
                writeln!(mem, "    \"{value}\"")?;
68
            }
69
            _ => {
70
                let digest = Digest::try_from(&iop[pos..pos + DIGEST_WORDS])?;
71
                let value = digest_to_decimal(&digest)?;
72
                pos += 8;
73
                writeln!(mem, "    \"{value}\"")?;
74
            }
75
        }
76
    }
77
    write!(mem, "  ]\n}}")?;
78
    writer.write_all(mem.as_slice()).await?;
79
    writer.flush().await?;
80
    Ok(())
81
}
82

            
83
fn digest_to_decimal(digest: &Digest) -> Result<String> {
84
    to_decimal(&format!("{:?}", digest_to_fr(digest))).context("digest_to_decimal failed")
85
}
86

            
87
fn to_decimal(s: &str) -> Option<String> {
88
    s.strip_prefix("Fr(0x")
89
        .and_then(|s| s.strip_suffix(')'))
90
        .and_then(|stripped| BigUint::from_str_radix(stripped, 16).ok())
91
        .map(|n| n.to_str_radix(10))
92
}