cargo_openvm/
input.rs
1use std::{fs::read, path::PathBuf, str::FromStr};
2
3use eyre::Result;
4use openvm_sdk::{StdIn, F};
5use openvm_stark_backend::p3_field::FieldAlgebra;
6
7#[derive(Debug, Clone)]
14pub enum Input {
15 FilePath(PathBuf),
16 HexBytes(String),
17}
18
19impl FromStr for Input {
20 type Err = String;
21
22 fn from_str(s: &str) -> Result<Self, Self::Err> {
23 if is_valid_hex_string(s) {
24 Ok(Input::HexBytes(s.to_string()))
25 } else if PathBuf::from(s).exists() {
26 Ok(Input::FilePath(PathBuf::from(s)))
27 } else {
28 Err("Input must be a valid file path or hex string.".to_string())
29 }
30 }
31}
32
33pub fn is_valid_hex_string(s: &str) -> bool {
34 if s.len() % 2 != 0 {
35 return false;
36 }
37 s.starts_with("0x") && s[2..].chars().all(|c| c.is_ascii_hexdigit())
39 || s.chars().all(|c| c.is_ascii_hexdigit())
40}
41
42pub fn decode_hex_string(s: &str) -> Result<Vec<u8>> {
43 let s = s.trim_start_matches("0x");
45 if s.is_empty() {
46 return Ok(Vec::new());
47 }
48 hex::decode(s).map_err(|e| eyre::eyre!("Invalid hex: {}", e))
49}
50
51pub fn read_bytes_into_stdin(stdin: &mut StdIn, bytes: &[u8]) -> Result<()> {
52 match bytes[0] {
54 0x01 => {
55 stdin.write_bytes(&bytes[1..]);
56 Ok(())
57 }
58 0x02 => {
59 let data = &bytes[1..];
60 if data.len() % 4 != 0 {
61 return Err(eyre::eyre!(
62 "Invalid input format: incorrect number of bytes"
63 ));
64 }
65 let mut fields = Vec::with_capacity(data.len() / 4);
66 for chunk in data.chunks_exact(4) {
67 let value = u32::from_le_bytes(chunk.try_into().unwrap());
68 fields.push(F::from_canonical_u32(value));
69 }
70 stdin.write_field(&fields);
71 Ok(())
72 }
73 _ => Err(eyre::eyre!(
74 "Invalid input format: the first byte must be 0x01 or 0x02"
75 )),
76 }
77}
78
79pub fn read_to_stdin(input: &Option<Input>) -> Result<StdIn> {
80 match input {
81 Some(Input::FilePath(path)) => {
82 let mut stdin = StdIn::default();
83 let bytes = read(path)?;
85 let json: serde_json::Value = serde_json::from_slice(&bytes)?;
86 json["input"]
87 .as_array()
88 .ok_or_else(|| eyre::eyre!("Input must be an array under 'input' key"))?
89 .iter()
90 .try_for_each(|inner| {
91 inner
92 .as_str()
93 .ok_or_else(|| eyre::eyre!("Each value must be a hex string"))
94 .and_then(|s| {
95 if !is_valid_hex_string(s) {
96 return Err(eyre::eyre!("Invalid hex string"));
97 }
98 let bytes = decode_hex_string(s)?;
99 read_bytes_into_stdin(&mut stdin, &bytes)
100 })
101 })?;
102
103 Ok(stdin)
104 }
105 Some(Input::HexBytes(hex_str)) => {
106 let mut stdin = StdIn::default();
107 let bytes = decode_hex_string(hex_str)?;
108 read_bytes_into_stdin(&mut stdin, &bytes)?;
109 Ok(stdin)
110 }
111 None => Ok(StdIn::default()),
112 }
113}