fn factorize_smooth(
x: u64,
row: &mut [u64],
br_primes: &[BarrettReduction<u64>],
) -> boolExamples found in repository?
crates/competitive/src/math/discrete_logarithm.rs (line 208)
182fn index_calculus_for_primitive_root(
183 p: u64,
184 ord: u64,
185 br_primes: &[BarrettReduction<u64>],
186 prec: &QdrtPowPrec,
187) -> Vec<u64> {
188 let br_ord = BarrettReduction::<u128>::new(ord as u128);
189 let mul = |x: u64, y: u64| br_ord.rem(x as u128 * y as u128) as u64;
190 let sub = |x: u64, y: u64| if x < y { x + ord - y } else { x - y };
191
192 let pc = br_primes.len();
193 let mut mat: Vec<Vec<u64>> = vec![];
194 let mut rows: Vec<Vec<u64>> = vec![];
195
196 let mut rng = Xorshift::default();
197 let br = BarrettReduction::<u128>::new(p as u128);
198
199 for i in 0..pc {
200 for ri in 0usize.. {
201 let mut row = vec![0u64; pc + 1];
202 let mut kk = rng.rand(ord - 1) + 1;
203 let mut gkk = prec.pow(kk, &br);
204 let mut k = kk;
205 let mut gk = gkk;
206 while ri >= rows.len() {
207 row[pc] = k;
208 if factorize_smooth(gk, &mut row, br_primes) {
209 rows.push(row);
210 break;
211 }
212 if k + kk < ord {
213 k += kk;
214 gk = br.rem(gk as u128 * gkk as u128) as u64;
215 } else {
216 kk = rng.rand(ord - 1) + 1;
217 gkk = prec.pow(kk, &br);
218 k = kk;
219 gk = gkk;
220 }
221 }
222 let row = &mut rows[ri];
223 for j in 0..i {
224 if row[j] != 0 {
225 let b = mul(modinv(mat[j][j], ord), row[j]);
226 for (r, a) in row[j..].iter_mut().zip(&mat[j][j..]) {
227 *r = sub(*r, mul(*a, b));
228 }
229 }
230 assert_eq!(row[j], 0);
231 }
232 if gcd(row[i], ord) == 1 {
233 let last = rows.len() - 1;
234 rows.swap(ri, last);
235 mat.push(rows.pop().unwrap());
236 break;
237 }
238 }
239 }
240 for i in (0..pc).rev() {
241 for j in i + 1..pc {
242 mat[i][pc] = sub(mat[i][pc], mul(mat[i][j], mat[j][pc]));
243 }
244 mat[i][pc] = mul(mat[i][pc], modinv(mat[i][i], ord));
245 }
246 (0..pc).map(|i| mat[i][pc]).collect()
247}
248
249#[derive(Debug)]
250struct IndexCalculusWithPrimitiveRoot {
251 p: u64,
252 ord: u64,
253 prec: QdrtPowPrec,
254 coeff: Vec<u64>,
255}
256
257impl IndexCalculusWithPrimitiveRoot {
258 fn new(p: u64, br_primes: &[BarrettReduction<u64>]) -> Self {
259 let ord = p - 1;
260 let g = primitive_root(p);
261 let br = BarrettReduction::<u128>::new(p as u128);
262 let prec = QdrtPowPrec::new(g, ord, &br);
263 let coeff = index_calculus_for_primitive_root(p, ord, br_primes, &prec);
264 Self {
265 p,
266 ord,
267 prec,
268 coeff,
269 }
270 }
271 fn index_calculus(&self, a: u64, br_primes: &[BarrettReduction<u64>]) -> Option<u64> {
272 let p = self.p;
273 let ord = self.ord;
274 let br = BarrettReduction::<u128>::new(p as u128);
275 let a = br.rem(a as _) as u64;
276 if a == 1 {
277 return Some(0);
278 }
279 if p == 2 {
280 return None;
281 }
282
283 let mut rng = Xorshift::new();
284 let mut row = vec![0u64; br_primes.len()];
285 let mut kk = rng.rand(ord - 1) + 1;
286 let mut gkk = self.prec.pow(kk, &br);
287 let mut k = kk;
288 let mut gk = br.rem(gkk as u128 * a as u128) as u64;
289 loop {
290 if factorize_smooth(gk, &mut row, br_primes) {
291 let mut res = ord - k;
292 for (&c, &r) in self.coeff.iter().zip(&row) {
293 for _ in 0..r {
294 res += c;
295 if res >= ord {
296 res -= ord;
297 }
298 }
299 }
300 return Some(res);
301 }
302 if k + kk < ord {
303 k += kk;
304 gk = br.rem(gk as u128 * gkk as u128) as u64;
305 } else {
306 kk = rng.rand(ord - 1) + 1;
307 gkk = self.prec.pow(kk, &br);
308 k = kk;
309 gk = br.rem(gkk as u128 * a as u128) as u64;
310 }
311 }
312 }