use crate::field::Goldilocks4;
use crate::hash::{JV_FSCH, JV_OPEN, shake_field_elements};
use crate::params::Params;
pub(crate) fn prefix_bytes(
params: Params,
root: &[u8; 32],
w: &Goldilocks4,
msg: &[u8],
ys: &[Goldilocks4],
) -> Vec<u8> {
let mut buf = Vec::with_capacity(8 + 4 + 32 + 32 + 8 + msg.len() + ys.len() * 32);
buf.extend_from_slice(&JV_OPEN);
buf.extend_from_slice(¶ms.canonical_bytes());
buf.extend_from_slice(root);
buf.extend_from_slice(&w.to_bytes());
buf.extend_from_slice(&(msg.len() as u64).to_le_bytes());
buf.extend_from_slice(msg);
for y in ys {
buf.extend_from_slice(&y.to_bytes());
}
buf
}
pub(crate) fn derive_betas(root: &[u8; 32], msg: &[u8], ys: &[Goldilocks4]) -> Vec<Goldilocks4> {
let want = ys.len() + 1;
let y_bytes: Vec<[u8; 32]> = ys.iter().map(|y| y.to_bytes()).collect();
let mut inputs: Vec<&[u8]> = Vec::with_capacity(2 + ys.len());
inputs.push(root);
inputs.push(msg);
for yb in &y_bytes {
inputs.push(yb);
}
shake_field_elements(JV_FSCH, &inputs, want)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::field::Goldilocks;
fn g(n: u64) -> Goldilocks4 {
Goldilocks4::new([
Goldilocks::new(n),
Goldilocks::new(0),
Goldilocks::new(0),
Goldilocks::new(0),
])
}
#[test]
fn betas_count_and_determinism() {
let ys = vec![g(1), g(2), g(3)];
let a = derive_betas(&[0u8; 32], b"hello", &ys);
let b = derive_betas(&[0u8; 32], b"hello", &ys);
assert_eq!(a.len(), 4);
assert_eq!(a, b);
}
#[test]
fn betas_vary_with_root() {
let ys = vec![g(1), g(2)];
let a = derive_betas(&[0u8; 32], b"x", &ys);
let b = derive_betas(&[1u8; 32], b"x", &ys);
assert_ne!(a, b);
}
#[test]
fn betas_vary_with_msg() {
let ys = vec![g(1), g(2)];
let a = derive_betas(&[0u8; 32], b"a", &ys);
let b = derive_betas(&[0u8; 32], b"b", &ys);
assert_ne!(a, b);
}
#[test]
fn betas_vary_with_ys() {
let a = derive_betas(&[0u8; 32], b"x", &[g(1), g(2)]);
let b = derive_betas(&[0u8; 32], b"x", &[g(1), g(3)]);
assert_ne!(a, b);
}
#[test]
fn prefix_bytes_layout() {
let params = Params::new(3);
let root = [7u8; 32];
let w = g(0xabcd);
let msg = b"hi";
let ys = vec![g(0xff), g(0xee)];
let p = prefix_bytes(params, &root, &w, msg, &ys);
assert_eq!(p.len(), 150);
assert_eq!(&p[..8], b"JV-OPEN ");
assert_eq!(&p[8..12], ¶ms.canonical_bytes());
assert_eq!(&p[12..44], &root);
assert_eq!(&p[44..76], &w.to_bytes());
assert_eq!(&p[76..84], &(2u64).to_le_bytes());
assert_eq!(&p[84..86], msg);
}
}