1use rand::RngExt as _;
6
7use fancy_circuits::util::as_mixed_radix;
8use vectoreyes::U8x16;
9
10pub(crate) fn tweak2(i: u64, j: u64) -> u128 {
12 (j as u128) << 64 | (i as u128)
13}
14
15pub fn output_tweak(i: usize, k: u16) -> u128 {
18 let (left, _) = (i as u128).overflowing_shl(64);
19 left + k as u128
20}
21
22pub(crate) fn digits_per_u128(modulus: u16) -> usize {
25 debug_assert_ne!(modulus, 0);
26 debug_assert_ne!(modulus, 1);
27 if modulus == 2 {
28 128
29 } else if modulus <= 4 {
30 64
31 } else if modulus <= 8 {
32 42
33 } else if modulus <= 16 {
34 32
35 } else if modulus <= 32 {
36 25
37 } else if modulus <= 64 {
38 21
39 } else if modulus <= 128 {
40 18
41 } else if modulus <= 256 {
42 16
43 } else if modulus <= 512 {
44 14
45 } else {
46 (128.0 / (modulus as f64).log2().ceil()).floor() as usize
47 }
48}
49
50pub(crate) fn from_base_q(ds: &[u16], q: u16) -> u128 {
52 let mut x = 0u128;
53 for &d in ds.iter().rev() {
54 let (xp, overflow) = x.overflowing_mul(q.into());
55 debug_assert!(!overflow, "overflow!!!! x={}", x);
56 x = xp + d as u128;
57 }
58 x
59}
60
61fn as_base_q(x: u128, q: u16, n: usize) -> Vec<u16> {
63 let ms = core::iter::repeat_n(q, n).collect::<Vec<_>>();
64 as_mixed_radix(x, &ms)
65}
66
67pub fn as_base_q_u128(x: u128, q: u16) -> Vec<u16> {
69 as_base_q(x, q, digits_per_u128(q))
70}
71
72pub trait RngExt: rand::Rng + Sized {
74 fn gen_usable_block(&mut self, modulus: u16) -> U8x16 {
76 if modulus.is_power_of_two() {
77 let nbits = (modulus - 1).count_ones();
78 if 128 % nbits == 0 {
79 return U8x16::from(self.random::<u128>());
80 }
81 }
82 let n = digits_per_u128(modulus);
83 let max = (modulus as u128).pow(n as u32);
84 U8x16::from(self.random::<u128>() % max)
85 }
86}
87
88impl<R: rand::Rng + Sized> RngExt for R {}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93 use fancy_circuits::util::RngExt as _;
94 use rand::rng;
95
96 #[test]
97 fn base_q_conversion() {
98 let mut rng = rng();
99 for _ in 0..1000 {
100 let q = rng.gen_modulus();
101 let x = u128::from(rng.gen_usable_block(q));
102 let y = as_base_q(x, q, digits_per_u128(q));
103 let z = from_base_q(&y, q);
104 assert_eq!(x, z);
105 }
106 }
107}