use std::sync::OnceLock;
use twenty_first::math::ntt::intt;
use twenty_first::prelude::*;
use twenty_first::util_types::merkle_tree::MerkleTree;
pub trait GpuAccelerator: Send + Sync {
fn name(&self) -> &str;
fn hash_varlen_batch(&self, inputs: &[&[BFieldElement]]) -> Vec<Digest>;
fn intt_bfe(&self, column: &mut [BFieldElement]) {
intt(column);
}
fn intt_xfe(&self, column: &mut [XFieldElement]) {
intt(column);
}
fn ntt_bfe(&self, column: &mut [BFieldElement]) {
twenty_first::math::ntt::ntt(column);
}
fn ntt_xfe(&self, column: &mut [XFieldElement]) {
twenty_first::math::ntt::ntt(column);
}
fn merkle_tree(&self, leaves: &[Digest]) -> MerkleTree {
MerkleTree::par_new(leaves).unwrap()
}
fn gemv_bfe(
&self,
matrix: &[BFieldElement],
nrows: usize,
ncols: usize,
weights: &[XFieldElement],
) -> Vec<XFieldElement> {
use rayon::prelude::*;
(0..nrows)
.into_par_iter()
.map(|i| {
let row = &matrix[i * ncols..(i + 1) * ncols];
row.iter().zip(weights.iter()).map(|(&m, &w)| w * m).sum()
})
.collect()
}
fn gemv_xfe(
&self,
matrix: &[XFieldElement],
nrows: usize,
ncols: usize,
weights: &[XFieldElement],
) -> Vec<XFieldElement> {
use rayon::prelude::*;
(0..nrows)
.into_par_iter()
.map(|i| {
let row = &matrix[i * ncols..(i + 1) * ncols];
row.iter().zip(weights.iter()).map(|(&m, &w)| m * w).sum()
})
.collect()
}
fn fri_fold(
&self,
codeword: &[XFieldElement],
domain_point_inverses: &[BFieldElement],
folding_challenge: XFieldElement,
) -> Vec<XFieldElement> {
let one = XFieldElement::new([
BFieldElement::new(1),
BFieldElement::new(0),
BFieldElement::new(0),
]);
let two_inverse = XFieldElement::new([
BFieldElement::new(2),
BFieldElement::new(0),
BFieldElement::new(0),
])
.inverse();
let n = codeword.len();
(0..n / 2)
.map(|i| {
let scaled_offset_inv = folding_challenge * domain_point_inverses[i];
let left_summand = (one + scaled_offset_inv) * codeword[i];
let right_summand = (one - scaled_offset_inv) * codeword[n / 2 + i];
(left_summand + right_summand) * two_inverse
})
.collect()
}
}
static GPU_ACCELERATOR: OnceLock<Box<dyn GpuAccelerator>> = OnceLock::new();
pub fn set_gpu_accelerator(
accelerator: Box<dyn GpuAccelerator>,
) -> Result<(), Box<dyn GpuAccelerator>> {
GPU_ACCELERATOR.set(accelerator)
}
pub fn gpu_accelerator() -> Option<&'static dyn GpuAccelerator> {
GPU_ACCELERATOR.get().map(|b| b.as_ref())
}