clock-hash 1.0.0

ClockHash-256: Consensus hash function for ClockinChain
Documentation
//! Build script for ClockHash-256
//!
//! Generates the S-box table at compile time to ensure correctness
//! and avoid hardcoding large arrays.

use std::fs::File;
use std::io::Write;
use std::path::Path;

fn main() {
    // Generate S-box table
    let sbox = generate_sbox();

    // Write to a file that can be included in the crate
    let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR environment variable not set by Cargo");
    let dest_path = Path::new(&out_dir).join("sbox.rs");
    let mut f = File::create(&dest_path).expect("Failed to create S-box output file");

    writeln!(f, "/// S-box substitution table (256 bytes)")
        .expect("Failed to write S-box header comment");
    writeln!(f, "///").expect("Failed to write S-box comment line");
    writeln!(f, "/// Auto-generated at compile time using: ROTL8(floor(256 * frac(sin(i+1))), i mod 8) ^ 0x9E")
        .expect("Failed to write S-box generation formula comment");
    writeln!(
        f,
        "/// This provides nonlinear substitution for the ClockMix operation."
    )
    .expect("Failed to write S-box purpose comment");
    writeln!(f, "pub const SBOX: [u8; 256] = [").expect("Failed to write S-box array start");

    for (i, &val) in sbox.iter().enumerate() {
        if i % 16 == 0 {
            write!(f, "    ").expect("Failed to write S-box indentation");
        }
        write!(f, "0x{:02X},", val).expect("Failed to write S-box value");
        if (i + 1) % 16 == 0 {
            writeln!(f).expect("Failed to write S-box line break");
        } else {
            write!(f, " ").expect("Failed to write S-box space separator");
        }
    }

    writeln!(f, "];").expect("Failed to write S-box array end");

    println!("cargo:rerun-if-changed=build.rs");
}

/// Generate S-box using the formula:
/// ROTL8(floor(256 * frac(sin(i+1))), i mod 8) ^ 0x9E
fn generate_sbox() -> [u8; 256] {
    let mut sbox = [0u8; 256];
    let mask = 0x9Eu8;

    for (i, item) in sbox.iter_mut().enumerate() {
        // Compute sin(i+1) and get fractional part
        let sin_val = ((i + 1) as f64).sin();
        let frac = sin_val - sin_val.floor();

        // Multiply by 256 and floor
        let base = (frac * 256.0).floor() as u8;

        // Rotate left by (i mod 8)
        let rot = (i % 8) as u8;
        let rotated = rotl8(base, rot);

        // XOR with mask
        *item = rotated ^ mask;
    }

    sbox
}

/// Rotate 8-bit value left by n bits
fn rotl8(x: u8, n: u8) -> u8 {
    let n = n & 7;
    if n == 0 {
        x
    } else {
        (x << n) | (x >> (8u8.wrapping_sub(n)))
    }
}