#![allow(dead_code)]
use std::sync::atomic::{AtomicU64, Ordering::Relaxed};
use lens::rspcs::backend::{
self, Backend, CosetLeaves, Cpu, CpuSession, Inject, LineSession, State,
};
use lens::rspcs::program::{Limbs, Program};
const P: u64 = 0xFFFF_FFFF_0000_0001;
const METHODS: [&str; 9] = [
"permute",
"grind",
"sponge",
"line_sums",
"line_session",
"merkle_levels",
"coset_leaves",
"coset_ntt",
"name",
];
pub struct Rec {
name: &'static str,
evil: bool,
pub calls: [AtomicU64; 9],
}
impl Rec {
pub fn new(name: &'static str, evil: bool) -> Self {
Self {
name,
evil,
calls: Default::default(),
}
}
fn hit(&self, i: usize) {
self.calls[i].fetch_add(1, Relaxed);
}
pub fn counts(&self) -> Vec<(&'static str, u64)> {
METHODS[..8]
.iter()
.zip(&self.calls)
.map(|(m, c)| (*m, c.load(Relaxed)))
.filter(|c| c.1 > 0)
.collect()
}
}
impl Backend for Rec {
fn name(&self) -> &'static str {
self.name
}
fn permute(&self, states: &mut [State]) {
self.hit(0);
Cpu.permute(states);
if self.evil {
states.iter_mut().for_each(|s| s[0] ^= 1);
}
}
fn grind(&self, template: &State, inject: Inject, bits: u32) -> u64 {
self.hit(1);
Cpu.grind(template, inject, bits) + u64::from(self.evil)
}
fn sponge(&self, init: &State, rate: usize, blocks: usize, lanes: &[u64]) -> Vec<[u64; 4]> {
self.hit(2);
let mut v = Cpu.sponge(init, rate, blocks, lanes);
if self.evil {
v.iter_mut().for_each(|d| d[0] ^= 1);
}
v
}
fn line_sums(
&self,
prog: &Program,
cols: &[Limbs],
weights: &[Limbs],
xs: &[u64],
) -> Vec<Limbs> {
self.hit(3);
let mut v = Cpu.line_sums(prog, cols, weights, xs);
if self.evil {
v.iter_mut().for_each(|l| l[0] = (l[0] + 1) % P);
}
v
}
fn line_session<'a>(
&'a self,
prog: &'a Program,
cols: &[Limbs],
len: usize,
) -> Option<Box<dyn LineSession + 'a>> {
self.hit(4);
Some(Box::new(CpuSession::new(prog, cols, len)))
}
fn merkle_levels(
&self,
leaves: &span>; 4,
arities: &[usize],
tag: u64,
) -> Option<Vec<Vec<[u64; 4]>>> {
self.hit(5);
let mut v = backend::merkle_levels_reference(leaves, arities, tag);
if self.evil {
v.iter_mut()
.for_each(|l| l.iter_mut().for_each(|d| d[0] ^= 1));
}
Some(v)
}
fn coset_leaves(
&self,
job: &CosetLeaves<'_>,
cosets: core::ops::Range<usize>,
) -> Option<Vec<[u64; 4]>> {
self.hit(6);
let mut v = backend::coset_leaves_reference(job, cosets);
if self.evil {
v.iter_mut().for_each(|d| d[0] ^= 1);
}
Some(v)
}
fn coset_ntt(&self, coeffs: &[u64], shifts: &[u64]) -> Vec<Vec<u64>> {
self.hit(7);
let mut v = Cpu.coset_ntt(coeffs, shifts);
if self.evil {
v.iter_mut().for_each(|c| c[0] = (c[0] + 1) % P);
}
v
}
}
pub struct Cpu2;
impl Backend for Cpu2 {
fn name(&self) -> &'static str {
"cpu"
}
}