Skip to content

Commit

Permalink
codegen: poseidon-codegen: Define codegen utils (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
joeykraut authored Jan 26, 2025
1 parent b290d59 commit fd6bef4
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# Compiler files
cache/
out/
**/target

# Ignores development broadcast logs
!/broadcast
Expand Down
13 changes: 13 additions & 0 deletions codegen/poseidon-codegen/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "poseidon-codegen"
version = "0.1.0"
edition = "2021"

[dependencies]
renegade-crypto = { git = "https://github.com/renegade-fi/renegade.git" }
renegade-constants = { package = "constants", git = "https://github.com/renegade-fi/renegade.git", default-features = false }

anyhow = "1.0"
clap = { version = "4.5.1", features = ["derive"] }
itertools = "0.14"
num-bigint = "0.4"
98 changes: 98 additions & 0 deletions codegen/poseidon-codegen/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
use anyhow::Result;
use clap::Parser;
use itertools::Itertools;
use num_bigint::BigUint;
use renegade_constants::Scalar;
use renegade_crypto::fields::scalar_to_biguint;
use renegade_crypto::hash::{FULL_ROUND_CONSTANTS, PARTIAL_ROUND_CONSTANTS, R_F, R_P};
use std::fs;
use std::path::PathBuf;

#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
/// Output file path for the generated Huff code
#[arg(short, long)]
output: PathBuf,
}

// --- Code Generation --- //

/// Generates the Huff source code as a string
///
/// Maintains the invariant that the state is always the first three words of the stack
fn generate_huff_code() -> String {
let mut code = String::new();
const HALF_FULL: usize = R_F / 2;
let partial_rounds = R_P;

for i in 0..HALF_FULL {
code.push_str(&generate_full_round(i));
}

for i in 0..partial_rounds {
code.push_str(&generate_partial_round(i));
}

for i in HALF_FULL..R_F {
code.push_str(&generate_full_round(i));
}

code
}

/// Generate a full round of the hash function
fn generate_full_round(i: usize) -> String {
let mut code = String::new();
let round_constants = FULL_ROUND_CONSTANTS[i];
let round_constants_str = round_constants
.iter()
.map(|fp| Scalar::new(*fp))
.map(scalar_to_hex)
.collect_vec();

code.push_str(&format!("// --- Full Round {i} --- //\n"));
code.push_str(&format!(
"EXTERNAL_ROUND({}, {}, {})\n\n",
round_constants_str[0], round_constants_str[1], round_constants_str[2]
));
code
}

/// Generate a partial round of the hash function
fn generate_partial_round(i: usize) -> String {
let mut code = String::new();

let round_constant = PARTIAL_ROUND_CONSTANTS[i];
let round_constant_str = scalar_to_hex(Scalar::new(round_constant));

code.push_str(&format!("// --- Partial Round {i} --- //\n"));
code.push_str(&format!("INTERNAL_ROUND({round_constant_str})\n\n"));
code
}

// --- Helpers --- //

/// Convert a `Scalar` element to a big-endian hex string
fn scalar_to_hex(scalar: Scalar) -> String {
let biguint = scalar_to_biguint(&scalar);
format!("{biguint:#x}")
}

// --- Main --- //

fn main() -> Result<()> {
let args = Args::parse();

// Generate the Huff code
let huff_code = generate_huff_code();

// Write to the output file
fs::write(&args.output, huff_code)?;
println!(
"Successfully generated Huff code at: {}",
args.output.display()
);

Ok(())
}

0 comments on commit fd6bef4

Please sign in to comment.