arnaucube
arnaucube/hyperplonkPublic Self-hosted repository
hyperplonk/arithmetic/src/util.rs
arithmetic/src/util.rsRaw
  1// Copyright (c) 2023 Espresso Systems (espressosys.com)
  2// This file is part of the HyperPlonk library.
  3
  4// You should have received a copy of the MIT License
  5// along with the HyperPlonk library. If not, see <https://mit-license.org/>.
  6
  7use ark_ff::PrimeField;
  8use ark_std::log2;
  9
 10/// Decompose an integer into a binary vector in little endian.
 11pub fn bit_decompose(input: u64, num_var: usize) -> Vec<bool> {
 12    let mut res = Vec::with_capacity(num_var);
 13    let mut i = input;
 14    for _ in 0..num_var {
 15        res.push(i & 1 == 1);
 16        i >>= 1;
 17    }
 18    res
 19}
 20
 21/// given the evaluation input `point` of the `index`-th polynomial,
 22/// obtain the evaluation point in the merged polynomial
 23pub fn gen_eval_point<F: PrimeField>(index: usize, index_len: usize, point: &[F]) -> Vec<F> {
 24    let index_vec: Vec<F> = bit_decompose(index as u64, index_len)
 25        .into_iter()
 26        .map(|x| F::from(x))
 27        .collect();
 28    [point, &index_vec].concat()
 29}
 30
 31/// Return the number of variables that one need for an MLE to
 32/// batch the list of MLEs
 33#[inline]
 34pub fn get_batched_nv(num_var: usize, polynomials_len: usize) -> usize {
 35    num_var + log2(polynomials_len) as usize
 36}
 37
 38// Input index
 39// - `i := (i_0, ...i_{n-1})`,
 40// - `num_vars := n`
 41// return three elements:
 42// - `x0 := (i_1, ..., i_{n-1}, 0)`
 43// - `x1 := (i_1, ..., i_{n-1}, 1)`
 44// - `sign := i_0`
 45#[inline]
 46pub fn get_index(i: usize, num_vars: usize) -> (usize, usize, bool) {
 47    let bit_sequence = bit_decompose(i as u64, num_vars);
 48
 49    // the last bit comes first here because of LE encoding
 50    let x0 = project(&[[false].as_ref(), bit_sequence[..num_vars - 1].as_ref()].concat()) as usize;
 51    let x1 = project(&[[true].as_ref(), bit_sequence[..num_vars - 1].as_ref()].concat()) as usize;
 52
 53    (x0, x1, bit_sequence[num_vars - 1])
 54}
 55
 56/// Project a little endian binary vector into an integer.
 57#[inline]
 58pub(crate) fn project(input: &[bool]) -> u64 {
 59    let mut res = 0;
 60    for &e in input.iter().rev() {
 61        res <<= 1;
 62        res += e as u64;
 63    }
 64    res
 65}
 66
 67#[cfg(test)]
 68mod test {
 69    use super::{bit_decompose, get_index, project};
 70    use ark_std::{rand::RngCore, test_rng};
 71
 72    #[test]
 73    fn test_decomposition() {
 74        let mut rng = test_rng();
 75        for _ in 0..100 {
 76            let t = rng.next_u64();
 77            let b = bit_decompose(t, 64);
 78            let r = project(&b);
 79            assert_eq!(t, r)
 80        }
 81    }
 82
 83    #[test]
 84    fn test_get_index() {
 85        let a = 0b1010;
 86        let (x0, x1, sign) = get_index(a, 4);
 87        assert_eq!(x0, 0b0100);
 88        assert_eq!(x1, 0b0101);
 89        assert!(sign);
 90
 91        let (x0, x1, sign) = get_index(a, 5);
 92        assert_eq!(x0, 0b10100);
 93        assert_eq!(x1, 0b10101);
 94        assert!(!sign);
 95
 96        let a = 0b1111;
 97        let (x0, x1, sign) = get_index(a, 4);
 98        assert_eq!(x0, 0b1110);
 99        assert_eq!(x1, 0b1111);
100        assert!(sign);
101    }
102}