arnaucube
arnaucube/phantom-zonePublic Self-hosted repository
phantom-zone/src/utils.rs
src/utils.rsRaw
  1use std::{fmt::Debug, usize};
  2
  3use itertools::Itertools;
  4use num_traits::{FromPrimitive, PrimInt, Signed, Unsigned};
  5
  6use crate::{
  7    backend::Modulus,
  8    random::{RandomElement, RandomElementInModulus, RandomFill},
  9};
 10pub trait WithLocal {
 11    fn with_local<F, R>(func: F) -> R
 12    where
 13        F: Fn(&Self) -> R;
 14
 15    fn with_local_mut<F, R>(func: F) -> R
 16    where
 17        F: Fn(&mut Self) -> R;
 18}
 19
 20pub fn fill_random_ternary_secret_with_hamming_weight<
 21    T: Signed,
 22    R: RandomFill<[u8]> + RandomElementInModulus<usize, usize>,
 23>(
 24    out: &mut [T],
 25    hamming_weight: usize,
 26    rng: &mut R,
 27) {
 28    let mut bytes = vec![0u8; hamming_weight.div_ceil(8)];
 29    RandomFill::<[u8]>::random_fill(rng, &mut bytes);
 30
 31    let size = out.len();
 32    let mut secret_indices = (0..size).into_iter().map(|i| i).collect_vec();
 33    let mut bit_index = 0;
 34    let mut byte_index = 0;
 35    for _ in 0..hamming_weight {
 36        let s_index = RandomElementInModulus::<usize, usize>::random(rng, &secret_indices.len());
 37
 38        let curr_bit = (bytes[byte_index] >> bit_index) & 1;
 39        if curr_bit == 1 {
 40            out[secret_indices[s_index]] = T::one();
 41        } else {
 42            out[secret_indices[s_index]] = -T::one();
 43        }
 44
 45        secret_indices[s_index] = *secret_indices.last().unwrap();
 46        secret_indices.truncate(secret_indices.len());
 47
 48        if bit_index == 7 {
 49            bit_index = 0;
 50            byte_index += 1;
 51        } else {
 52            bit_index += 1;
 53        }
 54    }
 55}
 56
 57// TODO (Jay): this is only a workaround. Add a propoer way to perform primality
 58// tests.
 59fn is_probably_prime(candidate: u64) -> bool {
 60    num_bigint_dig::prime::probably_prime(&num_bigint_dig::BigUint::from(candidate), 0)
 61}
 62
 63/// Finds prime that satisfy
 64/// - $prime \lt upper_bound$
 65/// - $\log{prime} = num_bits$
 66/// - `prime % modulo == 1`
 67pub fn generate_prime(num_bits: usize, modulo: u64, upper_bound: u64) -> Option<u64> {
 68    let leading_zeros = (64 - num_bits) as u32;
 69
 70    let mut tentative_prime = upper_bound - 1;
 71    while tentative_prime % modulo != 1 && tentative_prime.leading_zeros() == leading_zeros {
 72        tentative_prime -= 1;
 73    }
 74
 75    while !is_probably_prime(tentative_prime)
 76        && tentative_prime.leading_zeros() == leading_zeros
 77        && tentative_prime >= modulo
 78    {
 79        tentative_prime -= modulo;
 80    }
 81
 82    if is_probably_prime(tentative_prime) && tentative_prime.leading_zeros() == leading_zeros {
 83        Some(tentative_prime)
 84    } else {
 85        None
 86    }
 87}
 88
 89/// Returns a^b mod q
 90pub fn mod_exponent(a: u64, mut b: u64, q: u64) -> u64 {
 91    let mod_mul = |v1: &u64, v2: &u64| {
 92        let tmp = *v1 as u128 * *v2 as u128;
 93        (tmp % q as u128) as u64
 94    };
 95
 96    let mut acc = a;
 97    let mut out = 1;
 98    while b != 0 {
 99        let flag = b & 1;
100
101        if flag == 1 {
102            out = mod_mul(&acc, &out);
103        }
104        acc = mod_mul(&acc, &acc);
105
106        b >>= 1;
107    }
108
109    out
110}
111
112pub fn mod_inverse(a: u64, q: u64) -> u64 {
113    mod_exponent(a, q - 2, q)
114}
115
116pub fn shoup_representation_fq(v: u64, q: u64) -> u64 {
117    ((v as u128 * (1u128 << 64)) / q as u128) as u64
118}
119
120pub fn negacyclic_mul<T: PrimInt, F: Fn(&T, &T) -> T>(
121    a: &[T],
122    b: &[T],
123    mul: F,
124    modulus: T,
125) -> Vec<T> {
126    let mut r = vec![T::zero(); a.len()];
127    for i in 0..a.len() {
128        for j in 0..i + 1 {
129            // println!("i: {j} {}", i - j);
130            r[i] = (r[i] + mul(&a[j], &b[i - j])) % modulus;
131        }
132
133        for j in i + 1..a.len() {
134            // println!("i: {j} {}", a.len() - j + i);
135            r[i] = (r[i] + modulus - mul(&a[j], &b[a.len() - j + i])) % modulus;
136        }
137        // println!("")
138    }
139
140    return r;
141}
142
143pub trait TryConvertFrom1<T: ?Sized, P> {
144    fn try_convert_from(value: &T, parameters: &P) -> Self;
145}
146
147impl<P: Modulus<Element = u64>> TryConvertFrom1<[i64], P> for Vec<u64> {
148    fn try_convert_from(value: &[i64], parameters: &P) -> Self {
149        value.iter().map(|v| parameters.from_i64(*v)).collect_vec()
150    }
151}
152
153impl<P: Modulus<Element = u64>> TryConvertFrom1<[i32], P> for Vec<u64> {
154    fn try_convert_from(value: &[i32], parameters: &P) -> Self {
155        value
156            .iter()
157            .map(|v| parameters.from_i64(*v as i64))
158            .collect_vec()
159    }
160}
161
162impl<P: Modulus> TryConvertFrom1<[P::Element], P> for Vec<i64> {
163    fn try_convert_from(value: &[P::Element], parameters: &P) -> Self {
164        value.iter().map(|v| parameters.to_i64(v)).collect_vec()
165    }
166}
167
168// pub trait TryConvertFrom<T: ?Sized> {
169//     type Parameters: ?Sized;
170
171//     fn try_convert_from(value: &T, parameters: &Self::Parameters) -> Self;
172// }
173
174// impl TryConvertFrom1<[i32]> for Vec<Vec<u32>> {
175//     type Parameters = u32;
176//     fn try_convert_from(value: &[i32], parameters: &Self::Parameters) -> Self
177// {         let row0 = value
178//             .iter()
179//             .map(|v| {
180//                 let is_neg = v.is_negative();
181//                 let v_u32 = v.abs() as u32;
182
183//                 assert!(v_u32 < *parameters);
184
185//                 if is_neg {
186//                     parameters - v_u32
187//                 } else {
188//                     v_u32
189//                 }
190//             })
191//             .collect_vec();
192
193//         vec![row0]
194//     }
195// }
196
197// impl TryConvertFrom1<[i32]> for Vec<Vec<u64>> {
198//     type Parameters = u64;
199//     fn try_convert_from(value: &[i32], parameters: &Self::Parameters) -> Self
200// {         let row0 = value
201//             .iter()
202//             .map(|v| {
203//                 let is_neg = v.is_negative();
204//                 let v_u64 = v.abs() as u64;
205
206//                 assert!(v_u64 < *parameters);
207
208//                 if is_neg {
209//                     parameters - v_u64
210//                 } else {
211//                     v_u64
212//                 }
213//             })
214//             .collect_vec();
215
216//         vec![row0]
217//     }
218// }
219
220// impl TryConvertFrom1<[i32]> for Vec<u64> {
221//     type Parameters = u64;
222//     fn try_convert_from(value: &[i32], parameters: &Self::Parameters) -> Self
223// {         value
224//             .iter()
225//             .map(|v| {
226//                 let is_neg = v.is_negative();
227//                 let v_u64 = v.abs() as u64;
228
229//                 assert!(v_u64 < *parameters);
230
231//                 if is_neg {
232//                     parameters - v_u64
233//                 } else {
234//                     v_u64
235//                 }
236//             })
237//             .collect_vec()
238//     }
239// }
240
241// impl TryConvertFrom1<[u64]> for Vec<i64> {
242//     type Parameters = u64;
243//     fn try_convert_from(value: &[u64], parameters: &Self::Parameters) -> Self
244// {         let q = *parameters;
245//         let qby2 = q / 2;
246//         value
247//             .iter()
248//             .map(|v| {
249//                 if *v > qby2 {
250//                     -((q - v) as i64)
251//                 } else {
252//                     *v as i64
253//                 }
254//             })
255//             .collect_vec()
256//     }
257// }
258
259pub(crate) struct Stats<T> {
260    pub(crate) samples: Vec<T>,
261}
262
263impl<T: PrimInt + FromPrimitive + Debug> Stats<T>
264where
265    // T: for<'a> Sum<&'a T>,
266    T: for<'a> std::iter::Sum<&'a T> + std::iter::Sum<T>,
267{
268    pub(crate) fn mean(&self) -> f64 {
269        self.samples.iter().sum::<T>().to_f64().unwrap() / (self.samples.len() as f64)
270    }
271
272    pub(crate) fn std_dev(&self) -> f64 {
273        let mean = self.mean();
274
275        // diff
276        let diff_sq = self
277            .samples
278            .iter()
279            .map(|v| {
280                let t = v.to_f64().unwrap() - mean;
281                t * t
282            })
283            .into_iter()
284            .sum::<f64>();
285
286        (diff_sq / (self.samples.len() as f64)).sqrt()
287    }
288
289    pub(crate) fn add_more(&mut self, values: &[T]) {
290        self.samples.extend(values.iter());
291    }
292}