added digit decomposition

This commit is contained in:
Jean-Philippe Bossuat
2025-01-21 00:21:57 +01:00
parent 70765026c5
commit 2888b9128d
4 changed files with 254 additions and 11 deletions

View File

@@ -146,7 +146,6 @@ pub mod macros {
macro_rules! apply_sv { macro_rules! apply_sv {
($self:expr, $f:expr, $a:expr, $b:expr, $CHUNK:expr) => { ($self:expr, $f:expr, $a:expr, $b:expr, $CHUNK:expr) => {
let n: usize = $b.len(); let n: usize = $b.len();
debug_assert!( debug_assert!(
CHUNK & (CHUNK - 1) == 0, CHUNK & (CHUNK - 1) == 0,
"invalid CHUNK const: not a power of two" "invalid CHUNK const: not a power of two"
@@ -426,13 +425,13 @@ pub mod macros {
) )
.for_each(|(a, b, e)| { .for_each(|(a, b, e)| {
$f(&$self, &a[0], &b[0], $c, $d, &mut e[0]); $f(&$self, &a[0], &b[0], $c, $d, &mut e[0]);
$f(&$self, &a[1], &b[1], $c, $d, &mut e[1]); $f(&$self, &a[1], &b[1], $c, $d, &mut e[1]);
$f(&$self, &a[2], &b[2], $c, $d, &mut e[2]); $f(&$self, &a[2], &b[2], $c, $d, &mut e[2]);
$f(&$self, &a[3], &b[3], $c, $d, &mut e[3]); $f(&$self, &a[3], &b[3], $c, $d, &mut e[3]);
$f(&$self, &a[4], &b[4], $c, $d, &mut e[4]); $f(&$self, &a[4], &b[4], $c, $d, &mut e[4]);
$f(&$self, &a[5], &b[5], $c, $d, &mut e[5]); $f(&$self, &a[5], &b[5], $c, $d, &mut e[5]);
$f(&$self, &a[6], &b[6], $c, $d, &mut e[6]); $f(&$self, &a[6], &b[6], $c, $d, &mut e[6]);
$f(&$self, &a[7], &b[7], $c, $d, &mut e[7]); $f(&$self, &a[7], &b[7], $c, $d, &mut e[7]);
}); });
let m = n - (n & 7); let m = n - (n & 7);
@@ -450,4 +449,59 @@ pub mod macros {
} }
}; };
} }
#[macro_export]
macro_rules! apply_vsssvv {
($self:expr, $f:expr, $a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $g:expr, $CHUNK:expr) => {
let n: usize = $a.len();
debug_assert!(
$e.len() == n,
"invalid argument b: e.len() = {} != a.len() = {}",
$e.len(),
n
);
debug_assert!(
$g.len() == n,
"invalid argument g: g.len() = {} != a.len() = {}",
$g.len(),
n
);
debug_assert!(
CHUNK & (CHUNK - 1) == 0,
"invalid CHUNK const: not a power of two"
);
match CHUNK {
8 => {
izip!(
$a.chunks_exact(8),
$e.chunks_exact_mut(8),
$g.chunks_exact_mut(8)
)
.for_each(|(a, e, g)| {
$f(&$self, &a[0], $b, $c, $d, &mut e[0], &mut g[0]);
$f(&$self, &a[1], $b, $c, $d, &mut e[1], &mut g[1]);
$f(&$self, &a[2], $b, $c, $d, &mut e[2], &mut g[2]);
$f(&$self, &a[3], $b, $c, $d, &mut e[3], &mut g[3]);
$f(&$self, &a[4], $b, $c, $d, &mut e[4], &mut g[4]);
$f(&$self, &a[5], $b, $c, $d, &mut e[5], &mut g[5]);
$f(&$self, &a[6], $b, $c, $d, &mut e[6], &mut g[6]);
$f(&$self, &a[7], $b, $c, $d, &mut e[7], &mut g[7]);
});
let m = n - (n & 7);
izip!($a[m..].iter(), $e[m..].iter_mut(), $g[m..].iter_mut()).for_each(
|(a, e, g)| {
$f(&$self, a, $b, $c, $d, e, g);
},
);
}
_ => {
izip!($a.iter(), $e.iter_mut(), $g.iter_mut()).for_each(|(a, e, g)| {
$f(&$self, a, $b, $c, $d, e, g);
});
}
}
};
}
} }

View File

@@ -187,6 +187,22 @@ pub trait ScalarOperations<O> {
d: &barrett::Barrett<u64>, d: &barrett::Barrett<u64>,
a: &mut u64, a: &mut u64,
); );
fn sa_rsh_sb_mask_sc_into_sa(&self, c: &u64, b: &u64, a: &mut u64);
fn sa_rsh_sb_mask_sc_into_sd(&self, a: &u64, b: &u64, c: &u64, d: &mut u64);
fn sa_rsh_sb_mask_sc_add_sd_into_sd(&self, a: &u64, b: &u64, c: &u64, d: &mut u64);
fn sa_signed_digit_into_sb<const CARRYOVERWRITE: bool, const BALANCED: bool>(
&self,
a: &u64,
base: &u64,
shift: &u64,
mask: &u64,
carry: &mut u64,
b: &mut u64,
);
} }
pub trait VectorOperations<O> { pub trait VectorOperations<O> {
@@ -354,4 +370,48 @@ pub trait VectorOperations<O> {
sd: &barrett::Barrett<u64>, sd: &barrett::Barrett<u64>,
va: &mut [u64], va: &mut [u64],
); );
// vec(a) <- (vec(a)>>scalar(b)) & scalar(c).
fn va_rsh_sb_mask_sd_into_va<const CHUNK: usize>(&self, sb: &u64, sc: &u64, va: &mut [u64]);
// vec(d) <- (vec(a)>>scalar(b)) & scalar(c).
fn va_rsh_sb_mask_sc_into_vd<const CHUNK: usize>(
&self,
va: &[u64],
sb: &u64,
sc: &u64,
vd: &mut [u64],
);
// vec(d) <- vec(d) + (vec(a)>>scalar(b)) & scalar(c).
fn va_rsh_sb_mask_sc_add_vd_into_vd<const CHUNK: usize>(
&self,
va: &[u64],
sb: &u64,
sc: &u64,
vd: &mut [u64],
);
// vec(c) <- i-th unsigned digit base 2^{sb} of vec(a).
// vec(c) is ensured to be in the range [0, 2^{sb}-1[ with E[vec(c)] = 2^{sb}-1.
fn va_ith_digit_unsigned_base_sb_into_vc<const CHUNK: usize>(
&self,
i: usize,
va: &[u64],
sb: &u64,
vc: &mut [u64],
);
// vec(c) <- i-th signed digit base 2^{w} of vec(a).
// Reads the carry of the i-1-th iteration and write the carry on the i-th iteration on carry.
// if i > 0, carry of the i-1th iteration must be provided.
// if BALANCED: vec(c) is ensured to be [-2^{sb-1}, 2^{sb-1}[ with E[vec(c)] = 0, else E[vec(c)] = -0.5
fn va_ith_digit_signed_base_sb_into_vc<const CHUNK: usize, const BALANCED: bool>(
&self,
i: usize,
va: &[u64],
sb: &u64,
carry: &mut [u64],
vc: &mut [u64],
);
} }

View File

@@ -4,8 +4,8 @@ use crate::modulus::prime::Prime;
use crate::modulus::{ScalarOperations, VectorOperations}; use crate::modulus::{ScalarOperations, VectorOperations};
use crate::modulus::{NONE, REDUCEMOD}; use crate::modulus::{NONE, REDUCEMOD};
use crate::{ use crate::{
apply_ssv, apply_sv, apply_svv, apply_v, apply_vssv, apply_vsv, apply_vv, apply_vvssv, apply_ssv, apply_sv, apply_svv, apply_v, apply_vsssvv, apply_vssv, apply_vsv, apply_vv,
apply_vvsv, apply_vvv, apply_vvssv, apply_vvsv, apply_vvv,
}; };
use itertools::izip; use itertools::izip;
@@ -211,6 +211,47 @@ impl ScalarOperations<u64> for Prime<u64> {
self.sa_sub_sb_into_sb::<SBRANGE, NONE>(&(b + c), a); self.sa_sub_sb_into_sb::<SBRANGE, NONE>(&(b + c), a);
self.barrett.mul_external_assign::<REDUCE>(*d, a); self.barrett.mul_external_assign::<REDUCE>(*d, a);
} }
#[inline(always)]
fn sa_rsh_sb_mask_sc_into_sa(&self, b: &u64, c: &u64, a: &mut u64) {
*a = (*a >> b) & c
}
#[inline(always)]
fn sa_rsh_sb_mask_sc_into_sd(&self, a: &u64, b: &u64, c: &u64, d: &mut u64) {
*d = (*a >> b) & c
}
#[inline(always)]
fn sa_rsh_sb_mask_sc_add_sd_into_sd(&self, a: &u64, b: &u64, c: &u64, d: &mut u64) {
*d += (*a >> b) & c
}
#[inline(always)]
fn sa_signed_digit_into_sb<const CARRYOVERWRITE: bool, const BALANCED: bool>(
&self,
a: &u64,
base: &u64,
shift: &u64,
mask: &u64,
carry: &mut u64,
b: &mut u64,
) {
if CARRYOVERWRITE {
self.sa_rsh_sb_mask_sc_into_sd(a, shift, mask, carry);
} else {
self.sa_rsh_sb_mask_sc_add_sd_into_sd(a, shift, mask, carry);
}
let c: u64 = if BALANCED && *carry == base >> 1 {
a & 1
} else {
((*carry | (*carry << 1)) >> base) & 1
};
*b = *carry + (self.q - base) * c;
*carry = c;
}
} }
impl VectorOperations<u64> for Prime<u64> { impl VectorOperations<u64> for Prime<u64> {
@@ -518,4 +559,92 @@ impl VectorOperations<u64> for Prime<u64> {
CHUNK CHUNK
); );
} }
// vec(a) <- (vec(a)>>scalar(b)) & scalar(c).
fn va_rsh_sb_mask_sd_into_va<const CHUNK: usize>(&self, sb: &u64, sc: &u64, va: &mut [u64]) {
apply_ssv!(self, Self::sa_rsh_sb_mask_sc_into_sa, sb, sc, va, CHUNK);
}
// vec(d) <- (vec(a)>>scalar(b)) & scalar(c).
fn va_rsh_sb_mask_sc_into_vd<const CHUNK: usize>(
&self,
va: &[u64],
sb: &u64,
sc: &u64,
vd: &mut [u64],
) {
apply_vssv!(self, Self::sa_rsh_sb_mask_sc_into_sd, va, sb, sc, vd, CHUNK);
}
// vec(d) <- vec(d) + (vec(a)>>scalar(b)) & scalar(c).
fn va_rsh_sb_mask_sc_add_vd_into_vd<const CHUNK: usize>(
&self,
va: &[u64],
sb: &u64,
sc: &u64,
vd: &mut [u64],
) {
apply_vssv!(
self,
Self::sa_rsh_sb_mask_sc_add_sd_into_sd,
va,
sb,
sc,
vd,
CHUNK
);
}
// vec(c) <- i-th unsigned digit base 2^{sb} of vec(a).
// vec(c) is ensured to be in the range [0, 2^{sb}-1[ with E[vec(c)] = 2^{sb}-1.
fn va_ith_digit_unsigned_base_sb_into_vc<const CHUNK: usize>(
&self,
i: usize,
va: &[u64],
sb: &u64,
vc: &mut [u64],
) {
self.va_rsh_sb_mask_sc_into_vd::<CHUNK>(va, &((i as u64) * sb), &((1 << sb) - 1), vc);
}
// vec(c) <- i-th signed digit base 2^{w} of vec(a).
// Reads the carry of the i-1-th iteration and write the carry on the i-th iteration on carry.
// if i > 0, carry of the i-1th iteration must be provided.
// if BALANCED: vec(c) is ensured to be [-2^{sb-1}, 2^{sb-1}[ with E[vec(c)] = 0, else E[vec(c)] = -0.5
fn va_ith_digit_signed_base_sb_into_vc<const CHUNK: usize, const BALANCED: bool>(
&self,
i: usize,
va: &[u64],
sb: &u64,
carry: &mut [u64],
vc: &mut [u64],
) {
let base: u64 = 1 << sb;
let mask: u64 = base - 1;
if i == 0 {
apply_vsssvv!(
self,
Self::sa_signed_digit_into_sb::<true, BALANCED>,
va,
&base,
&(i as u64 * sb),
&mask,
carry,
vc,
CHUNK
);
} else {
apply_vsssvv!(
self,
Self::sa_signed_digit_into_sb::<false, BALANCED>,
va,
&base,
&(i as u64 * sb),
&mask,
carry,
vc,
CHUNK
);
}
}
} }

View File

@@ -35,7 +35,7 @@ impl Ring<u64> {
}); });
} }
pub fn fill_normal(&self, source: &mut Source, sigma: f64, bound: f64, a: &mut Poly<u64>){ pub fn fill_normal(&self, source: &mut Source, sigma: f64, bound: f64, a: &mut Poly<u64>) {
self.fill_dist_f64(source, Normal::new(0.0, sigma).unwrap(), bound, a); self.fill_dist_f64(source, Normal::new(0.0, sigma).unwrap(), bound, a);
} }
} }