use ark_ff::Field;
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
#[cfg(all(not(feature = "std")))]
use ark_std::vec::Vec;
#[cfg(all(not(feature = "std"), target_arch = "aarch64"))]
use num_traits::Float;
#[cfg(feature = "parallel")]
use rayon::{
iter::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator},
prelude::IndexedParallelIterator,
};
#[macro_export]
macro_rules! to_bytes {
($x:expr) => {{
let mut buf = ark_std::vec![];
ark_serialize::CanonicalSerialize::serialize_compressed($x, &mut buf).map(|_| buf)
}};
}
pub(crate) fn ent(x: f64) -> f64 {
assert!(0f64 <= x && x <= 1f64);
if x == 0f64 || x == 1f64 {
0f64
} else {
-x * x.log2() - (1.0 - x) * (1.0 - x).log2()
}
}
#[inline]
pub(crate) fn ceil_mul(a: usize, b: (usize, usize)) -> usize {
(a * b.0 + b.1 - 1) / b.1
}
pub(crate) fn ceil_div(x: usize, y: usize) -> usize {
(x + y - 1) / y
}
#[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)]
#[derivative(Default(bound = ""), Clone(bound = ""), Debug(bound = ""))]
pub struct Matrix<F: Field> {
pub(crate) n: usize,
pub(crate) m: usize,
entries: Vec<Vec<F>>,
}
impl<F: Field> Matrix<F> {
pub(crate) fn new_from_flat(n: usize, m: usize, entry_list: &[F]) -> Self {
assert_eq!(
entry_list.len(),
n * m,
"Invalid matrix construction: dimensions are {} x {} but entry vector has {} entries",
n,
m,
entry_list.len()
);
let entries: Vec<Vec<F>> = (0..n)
.map(|row| (0..m).map(|col| entry_list[m * row + col]).collect())
.collect();
Self { n, m, entries }
}
pub(crate) fn new_from_rows(row_list: Vec<Vec<F>>) -> Self {
let m = row_list[0].len();
for row in row_list.iter().skip(1) {
assert_eq!(
row.len(),
m,
"Invalid matrix construction: not all rows have the same length"
);
}
Self {
n: row_list.len(),
m,
entries: row_list,
}
}
#[cfg(test)]
pub(crate) fn entry(&self, i: usize, j: usize) -> F {
self.entries[i][j]
}
pub(crate) fn rows(&self) -> Vec<Vec<F>> {
self.entries.clone()
}
pub(crate) fn cols(&self) -> Vec<Vec<F>> {
(0..self.m)
.map(|col| (0..self.n).map(|row| self.entries[row][col]).collect())
.collect()
}
pub(crate) fn row_mul(&self, v: &[F]) -> Vec<F> {
assert_eq!(
v.len(),
self.n,
"Invalid row multiplication: vector has {} elements whereas each matrix column has {}",
v.len(),
self.n
);
cfg_into_iter!(0..self.m)
.map(|col| {
inner_product(
v,
&cfg_into_iter!(0..self.n)
.map(|row| self.entries[row][col])
.collect::<Vec<F>>(),
)
})
.collect()
}
}
#[inline]
pub(crate) fn inner_product<F: Field>(v1: &[F], v2: &[F]) -> F {
ark_std::cfg_iter!(v1)
.zip(v2)
.map(|(li, ri)| *li * ri)
.sum()
}
#[inline]
pub(crate) fn scalar_by_vector<F: Field>(s: F, v: &[F]) -> Vec<F> {
ark_std::cfg_iter!(v).map(|x| *x * s).collect()
}
#[inline]
pub(crate) fn vector_sum<F: Field>(v1: &[F], v2: &[F]) -> Vec<F> {
ark_std::cfg_iter!(v1)
.zip(v2)
.map(|(li, ri)| *li + ri)
.collect()
}
#[inline]
#[cfg(test)]
pub(crate) fn to_field<F: Field>(v: Vec<u64>) -> Vec<F> {
v.iter().map(|x| F::from(*x)).collect::<Vec<F>>()
}
#[cfg(test)]
use ark_crypto_primitives::sponge::poseidon::PoseidonSponge;
#[cfg(test)]
use ark_ff::PrimeField;
#[cfg(test)]
pub(crate) fn test_sponge<F: PrimeField>() -> PoseidonSponge<F> {
use ark_crypto_primitives::sponge::{poseidon::PoseidonConfig, CryptographicSponge};
use ark_std::test_rng;
let full_rounds = 8;
let partial_rounds = 31;
let alpha = 17;
let mds = vec![
vec![F::one(), F::zero(), F::one()],
vec![F::one(), F::one(), F::zero()],
vec![F::zero(), F::one(), F::one()],
];
let mut v = Vec::new();
let mut ark_rng = test_rng();
for _ in 0..(full_rounds + partial_rounds) {
let mut res = Vec::new();
for _ in 0..3 {
res.push(F::rand(&mut ark_rng));
}
v.push(res);
}
let config = PoseidonConfig::new(full_rounds, partial_rounds, alpha, mds, v, 2, 1);
PoseidonSponge::new(&config)
}
#[cfg(test)]
pub(crate) mod tests {
use super::*;
use ark_bls12_377::Fr;
#[test]
fn test_matrix_constructor_flat() {
let entries: Vec<Fr> = to_field(vec![10, 100, 4, 67, 44, 50]);
let mat = Matrix::new_from_flat(2, 3, &entries);
assert_eq!(mat.entry(1, 2), Fr::from(50));
}
#[test]
fn test_matrix_constructor_flat_square() {
let entries: Vec<Fr> = to_field(vec![10, 100, 4, 67]);
let mat = Matrix::new_from_flat(2, 2, &entries);
assert_eq!(mat.entry(1, 1), Fr::from(67));
}
#[test]
#[should_panic(expected = "dimensions are 2 x 3 but entry vector has 5 entries")]
fn test_matrix_constructor_flat_panic() {
let entries: Vec<Fr> = to_field(vec![10, 100, 4, 67, 44]);
Matrix::new_from_flat(2, 3, &entries);
}
#[test]
fn test_matrix_constructor_rows() {
let rows: Vec<Vec<Fr>> = vec![
to_field(vec![10, 100, 4]),
to_field(vec![23, 1, 0]),
to_field(vec![55, 58, 9]),
];
let mat = Matrix::new_from_rows(rows);
assert_eq!(mat.entry(2, 0), Fr::from(55));
}
#[test]
#[should_panic(expected = "not all rows have the same length")]
fn test_matrix_constructor_rows_panic() {
let rows: Vec<Vec<Fr>> = vec![
to_field(vec![10, 100, 4]),
to_field(vec![23, 1, 0]),
to_field(vec![55, 58]),
];
Matrix::new_from_rows(rows);
}
#[test]
fn test_cols() {
let rows: Vec<Vec<Fr>> = vec![
to_field(vec![4, 76]),
to_field(vec![14, 92]),
to_field(vec![17, 89]),
];
let mat = Matrix::new_from_rows(rows);
assert_eq!(mat.cols()[1], to_field(vec![76, 92, 89]));
}
#[test]
fn test_row_mul() {
let rows: Vec<Vec<Fr>> = vec![
to_field(vec![10, 100, 4]),
to_field(vec![23, 1, 0]),
to_field(vec![55, 58, 9]),
];
let mat = Matrix::new_from_rows(rows);
let v: Vec<Fr> = to_field(vec![12, 41, 55]);
assert_eq!(mat.row_mul(&v), to_field::<Fr>(vec![4088, 4431, 543]));
}
}