export_test_vectors/
main.rs1use clap::{Parser, ValueEnum};
2use core::str::FromStr;
3use std::{
4 fs::File,
5 io::{self, Write},
6};
7mod vectors;
8
9fn parse_seed(seed_str: &str) -> Result<[u8; 32], String> {
11 if seed_str.len() != 64 {
12 return Err(format!(
13 "Seed must be exactly 64 hex characters (32 bytes), got {}",
14 seed_str.len()
15 ));
16 }
17
18 let mut seed = [0u8; 32];
19 for (i, chunk) in seed_str.as_bytes().chunks(2).enumerate() {
20 let hex_str =
21 std::str::from_utf8(chunk).map_err(|_| "Invalid UTF-8 in seed".to_string())?;
22 seed[i] = u8::from_str_radix(hex_str, 16)
23 .map_err(|_| format!("Invalid hex character in seed: {}", hex_str))?;
24 }
25
26 Ok(seed)
27}
28
29#[derive(Debug, Clone, ValueEnum)]
30pub enum Mode {
31 B10,
32 Hex,
33}
34
35impl FromStr for Mode {
36 type Err = ();
37
38 fn from_str(input: &str) -> Result<Self, Self::Err> {
39 match input.to_lowercase().as_str() {
40 "b10" => Ok(Mode::B10),
41 "hex" => Ok(Mode::Hex),
42 _ => Err(()),
43 }
44 }
45}
46
47#[derive(Debug, Clone, ValueEnum)]
48pub enum OutputFormat {
49 Es5,
50 Json,
51}
52
53impl FromStr for OutputFormat {
54 type Err = ();
55
56 fn from_str(input: &str) -> Result<Self, Self::Err> {
57 match input.to_lowercase().as_str() {
58 "es5" => Ok(OutputFormat::Es5),
59 "json" => Ok(OutputFormat::Json),
60 _ => Err(()),
61 }
62 }
63}
64
65#[derive(Debug, Clone, ValueEnum)]
66pub enum ParamType {
67 Legacy,
68 Kimchi,
69}
70
71impl FromStr for ParamType {
72 type Err = ();
73
74 fn from_str(input: &str) -> Result<Self, Self::Err> {
75 match input.to_lowercase().as_str() {
76 "legacy" => Ok(ParamType::Legacy),
77 "kimchi" => Ok(ParamType::Kimchi),
78 _ => Err(()),
79 }
80 }
81}
82
83#[derive(Parser)]
84#[command(name = "export_test_vectors")]
85#[command(about = "Export test vectors for the mina-poseidon crate")]
86struct Args {
87 #[arg(value_enum)]
89 mode: Mode,
90
91 #[arg(value_enum)]
93 param_type: ParamType,
94
95 output_file: String,
97
98 #[arg(value_enum, default_value = "json", short, long)]
100 format: OutputFormat,
101
102 #[arg(long)]
109 deterministic: bool,
110
111 #[arg(long)]
115 seed: Option<String>,
116}
117
118pub fn main() {
119 let args = Args::parse();
120
121 let seed = args.seed.map(|seed_str| {
123 parse_seed(&seed_str).unwrap_or_else(|err| {
124 eprintln!("Error parsing seed: {}", err);
125 std::process::exit(1);
126 })
127 });
128
129 let vectors = vectors::generate(args.mode.clone(), args.param_type.clone(), seed);
131
132 let mut writer: Box<dyn Write> = match args.output_file.as_str() {
134 "-" => Box::new(io::stdout()),
135 _ => Box::new(File::create(&args.output_file).expect("could not create file")),
136 };
137
138 match args.format {
139 OutputFormat::Es5 => {
140 vectors::write_es5(
141 &mut writer,
142 &vectors,
143 args.param_type,
144 args.deterministic,
145 seed,
146 )
147 .expect("could not write to file");
148 }
149 OutputFormat::Json => {
150 serde_json::to_writer_pretty(writer, &vectors).expect("could not write to file");
151 }
152 }
153}