use crate::constants::NUM_CONSTANTS;
use crate::field::Goldilocks;
use crate::params::{RATE, RATE_BYTES, WIDTH};
use crate::permutation::permute_with_constants;
pub const GENESIS_SEED: &[u8] = &[0x63, 0x79, 0x62, 0x65, 0x72];
const ZERO_CONSTANTS: [Goldilocks; NUM_CONSTANTS] = [Goldilocks::ZERO; NUM_CONSTANTS];
pub fn bootstrap_sponge_state() -> [Goldilocks; WIDTH] {
let mut state = [Goldilocks::ZERO; WIDTH];
let mut padded = [0u8; RATE_BYTES];
padded[..GENESIS_SEED.len()].copy_from_slice(GENESIS_SEED);
padded[GENESIS_SEED.len()] = 0x01;
let mut rate_block = [Goldilocks::ZERO; RATE];
crate::encoding::bytes_to_rate_block(&padded, &mut rate_block);
for i in 0..RATE {
state[i] = state[i] + rate_block[i];
}
state[RATE + 2] = Goldilocks::new(GENESIS_SEED.len() as u64);
permute_with_constants(&mut state, &ZERO_CONSTANTS);
state
}
pub fn bootstrap_constants_u64() -> [u64; NUM_CONSTANTS] {
let mut state = bootstrap_sponge_state();
let mut constants = [0u64; NUM_CONSTANTS];
let mut pos = RATE; let mut filled = 0usize;
for i in 0..NUM_CONSTANTS {
if pos >= RATE {
if filled > 0 {
permute_with_constants(&mut state, &ZERO_CONSTANTS);
}
pos = 0;
}
constants[i] = state[pos].as_canonical_u64();
pos += 1;
filled += 1;
}
constants
}
#[cfg(test)]
mod tests {
use super::*;
use crate::constants::ROUND_CONSTANTS_U64;
#[test]
fn static_constants_match_bootstrap() {
let derived = bootstrap_constants_u64();
assert_eq!(
derived.len(),
ROUND_CONSTANTS_U64.len(),
"constant count mismatch"
);
for (i, (&derived, &static_val)) in
derived.iter().zip(ROUND_CONSTANTS_U64.iter()).enumerate()
{
assert_eq!(
derived, static_val,
"constant[{i}] mismatch: bootstrap=0x{derived:016X}, static=0x{static_val:016X}"
);
}
}
#[test]
fn bootstrap_constants_count() {
let constants = bootstrap_constants_u64();
let expected = NUM_CONSTANTS;
assert_eq!(constants.len(), expected);
}
#[test]
fn bootstrap_constants_deterministic() {
let c1 = bootstrap_constants_u64();
let c2 = bootstrap_constants_u64();
assert_eq!(c1, c2);
}
#[test]
fn bootstrap_constants_nonzero() {
let constants = bootstrap_constants_u64();
assert!(constants.iter().any(|&c| c != 0));
}
#[test]
fn bootstrap_constants_are_canonical() {
let constants = bootstrap_constants_u64();
let p: u64 = 0xFFFF_FFFF_0000_0001;
for (i, &c) in constants.iter().enumerate() {
assert!(c < p, "constant[{i}] = {c} >= p");
}
}
#[test]
fn bootstrap_pinned_first_constants() {
let constants = bootstrap_constants_u64();
assert_eq!(constants[0], 0x7E6EF67C13BC8100);
assert_eq!(constants[1], 0x3A658EE0B11555F9);
assert_eq!(constants[2], 0x42F4F5D6BE505B01);
assert_eq!(constants[3], 0x8D6E969951FEA22C);
}
#[test]
fn genesis_seed_is_cyber() {
assert_eq!(GENESIS_SEED, b"cyber");
assert_eq!(GENESIS_SEED, &[0x63, 0x79, 0x62, 0x65, 0x72]);
}
}