Skip to content

Commit a88bb34

Browse files
authored
Merge pull request #3 from 0xWOLAND/dyn-residue
feature tags + pow
2 parents 3189108 + 5283c9e commit a88bb34

File tree

5 files changed

+108
-2
lines changed

5 files changed

+108
-2
lines changed

Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,6 @@ criterion = { version = "0.5.1", features = ["html_reports"] }
2323
[[bench]]
2424
name = "benchmark"
2525
harness = false
26+
27+
[features]
28+
parallel = []

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ Generate benchmarks using:
3131

3232
```bash
3333
# If you don't have it already
34-
cargo install cargo-criterion criterion-table
34+
cargo install cargo-criterion criterion-table --cfg
3535

36-
cargo criterion --message-format=json | criterion-table > BENCHMARKS.md
36+
cargo criterion --message-format=json --features parallel | criterion-table > BENCHMARKS.md
3737
```
3838

3939
Benchmarks are also available [here](./BENCHMARKS.md)

src/ntt.rs

+64
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ fn order_reverse(inp: &mut Vec<BigInt>) {
7373
});
7474
}
7575

76+
#[cfg(feature = "parallel")]
7677
fn fft(inp: Vec<BigInt>, c: &Constants, w: BigInt) -> Vec<BigInt> {
7778
assert!(inp.len().is_power_of_two());
7879
let mut inp = inp.clone();
@@ -123,10 +124,62 @@ fn fft(inp: Vec<BigInt>, c: &Constants, w: BigInt) -> Vec<BigInt> {
123124
inp
124125
}
125126

127+
#[cfg(not(feature = "parallel"))]
128+
fn fft(inp: Vec<BigInt>, c: &Constants, w: BigInt) -> Vec<BigInt> {
129+
assert!(inp.len().is_power_of_two());
130+
let mut inp = inp.clone();
131+
let N = inp.len();
132+
let MOD = BigInt::from(c.N);
133+
let ONE = BigInt::from(1);
134+
let mut pre: Vec<BigInt> = vec![ONE; N / 2];
135+
let CHUNK_COUNT = 128;
136+
let chunk_count = BigInt::from(CHUNK_COUNT);
137+
138+
pre.chunks_mut(CHUNK_COUNT)
139+
.enumerate()
140+
.for_each(|(i, arr)| arr[0] = w.mod_exp(BigInt::from(i) * chunk_count, MOD));
141+
pre.chunks_mut(CHUNK_COUNT).for_each(|x| {
142+
(1..x.len()).for_each(|y| {
143+
let _x = x.to_vec();
144+
x[y] = (w * x[y - 1]).rem(MOD);
145+
})
146+
});
147+
order_reverse(&mut inp);
148+
149+
let mut gap = 1;
150+
151+
while gap < inp.len() {
152+
let nchunks = inp.len() / (2 * gap);
153+
inp.chunks_mut(2 * gap).for_each(|cxi| {
154+
let (lo, hi) = cxi.split_at_mut(gap);
155+
lo.iter_mut()
156+
.zip(hi)
157+
.enumerate()
158+
.for_each(|(idx, (lo, hi))| {
159+
*hi = (*hi * pre[nchunks * idx]).rem(MOD);
160+
let neg = if *lo < *hi {
161+
(MOD + *lo) - *hi
162+
} else {
163+
*lo - *hi
164+
};
165+
*lo = if *lo + *hi >= MOD {
166+
(*lo + *hi) - MOD
167+
} else {
168+
*lo + *hi
169+
};
170+
*hi = neg;
171+
});
172+
});
173+
gap *= 2;
174+
}
175+
inp
176+
}
177+
126178
pub fn forward(inp: Vec<BigInt>, c: &Constants) -> Vec<BigInt> {
127179
fft(inp, c, c.w)
128180
}
129181

182+
#[cfg(feature = "parallel")]
130183
pub fn inverse(inp: Vec<BigInt>, c: &Constants) -> Vec<BigInt> {
131184
let mut inv = BigInt::from(inp.len());
132185
let _ = inv.set_mod(c.N);
@@ -137,6 +190,17 @@ pub fn inverse(inp: Vec<BigInt>, c: &Constants) -> Vec<BigInt> {
137190
res
138191
}
139192

193+
#[cfg(not(feature = "parallel"))]
194+
pub fn inverse(inp: Vec<BigInt>, c: &Constants) -> Vec<BigInt> {
195+
let mut inv = BigInt::from(inp.len());
196+
let _ = inv.set_mod(c.N);
197+
let inv = inv.invert();
198+
let w = c.w.invert();
199+
let mut res = fft(inp, c, w);
200+
res.iter_mut().for_each(|x| *x = (inv * (*x)).rem(c.N));
201+
res
202+
}
203+
140204
#[cfg(test)]
141205
mod tests {
142206
use rand::Rng;

src/numbers.rs

+6
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,12 @@ impl BigInt {
7575
*self.v.params()
7676
}
7777

78+
pub fn pow(&self, n: u128) -> BigInt {
79+
BigInt {
80+
v: self.v.pow(&Uint::<4>::from_u128(n)),
81+
}
82+
}
83+
7884
pub fn mod_exp(&self, exp: BigInt, M: BigInt) -> BigInt {
7985
let mut res: BigInt = if !exp.is_even() {
8086
self.clone()

src/polynomial.rs

+33
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ impl Polynomial {
5050
Polynomial { coef: out }
5151
}
5252

53+
#[cfg(feature = "parallel")]
5354
pub fn mul(self, rhs: Polynomial, c: &Constants) -> Polynomial {
5455
let v1_deg = self.degree();
5556
let v2_deg = rhs.degree();
@@ -81,6 +82,38 @@ impl Polynomial {
8182
}
8283
}
8384

85+
#[cfg(not(feature = "parallel"))]
86+
pub fn mul(self, rhs: Polynomial, c: &Constants) -> Polynomial {
87+
let v1_deg = self.degree();
88+
let v2_deg = rhs.degree();
89+
let n = (self.len() + rhs.len()).next_power_of_two();
90+
let ZERO = BigInt::from(0);
91+
92+
let v1 = vec![ZERO; n - self.len()]
93+
.into_iter()
94+
.chain(self.coef.into_iter())
95+
.collect();
96+
let v2 = vec![ZERO; n - rhs.len()]
97+
.into_iter()
98+
.chain(rhs.coef.into_iter())
99+
.collect();
100+
101+
let a_forward = forward(v1, &c);
102+
let b_forward = forward(v2, &c);
103+
104+
let mut mul = vec![ZERO; n as usize];
105+
mul.iter_mut()
106+
.enumerate()
107+
.for_each(|(i, x)| *x = (a_forward[i] * b_forward[i]).rem(c.N));
108+
109+
let coef = inverse(mul, &c);
110+
// n - polynomial degree - 1
111+
let start = n - (v1_deg + v2_deg + 1) - 1;
112+
Polynomial {
113+
coef: coef[start..=(start + v1_deg + v2_deg)].to_vec(),
114+
}
115+
}
116+
84117
pub fn diff(mut self) -> Self {
85118
let N = self.len();
86119
for n in (1..N).rev() {

0 commit comments

Comments
 (0)