use rug::{Complete, Integer}; use eframe::egui; // use std::time::Instant; fn main() { let options = eframe::NativeOptions::default(); eframe::run_native( "Криптографические методы защиты информации", options, Box::new(|_cc| Box::new(Application::default())), ); } enum State { Idle, Running(u32), Done, Error, } struct Application { order: u32, element: u32, element_check: Option, primitive_roots: Vec, state: State, str_num: String, } impl Default for Application { fn default() -> Self { Self { order: 29, element: 2, element_check: None, primitive_roots: Vec::new(), state: State::Idle, str_num: String::from("20"), } } } fn min_order(x: u32, order: u32) -> u32 { let mut min = 0; let mut pow = x; for power in 1..order { if pow == 1 { min = power; break; } pow = (pow * x) % order; } return min; } fn is_prime(x: u32) -> bool { if x <= 1 { return false; } for i in 2..x / 2 + 1 { if x % i == 0 { return false; } } return true; } impl eframe::App for Application { fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { let clear_state = |app: &mut Application| { app.element_check = None; app.state = State::Idle; }; egui::Window::new("Задача №1").show(ctx, |ui| { ui.horizontal(|ui| { ui.label("Порядок поля: "); if ui .add(egui::DragValue::new(&mut self.order).clamp_range(2..=u32::MAX)) .changed() { clear_state(self); } }); ui.horizontal(|ui| { ui.label("Проверяемый элемент: "); if ui .add(egui::DragValue::new(&mut self.element).clamp_range(1..=self.order - 1)) .changed() { clear_state(self); } }); if ui.button("Проверить элемент").clicked() { let min = min_order(self.element, self.order); self.element_check = Some(min == self.order - 1); } match self.element_check { Some(true) => { ui.label("Элемент является порождающим элементом"); } Some(false) => { ui.label("Элемент не является порождающим элементом"); } None => {} } if ui.button("Рассчитать порождающие элементы").clicked() { self.primitive_roots.clear(); self.state = if is_prime(self.order) { State::Running(1) } else { State::Error } } match self.state { State::Running(current) => { ui.label("Вычисление..."); let min = min_order(current, self.order); if min == self.order - 1 { self.primitive_roots.push(current); } self.state = if current == self.order - 1 { State::Done } else { State::Running(current + 1) } } State::Done => { ui.label(format!( "Порождающие элементы поля F_{}: {:?}", self.order, self.primitive_roots )); } State::Idle => {} State::Error => { ui.label("Можно указать только простое число!"); } } }); egui::Window::new("Задача №2").show(ctx, |ui| { ui.horizontal(|ui| { ui.label("Число: "); ui.add(egui::TextEdit::singleline(&mut self.str_num)); }); if ui.button("Разложить на множители").clicked() { let number = Integer::parse(&self.str_num).unwrap().complete(); let factors = factorize(&number); println!("Множители: {:?}", factors); } }); } } fn factorize(n: &Integer) -> Vec { let mut factors = Vec::new(); let mut front = vec![n.clone()]; while !front.is_empty() { let num = front.pop().unwrap(); match lehman(&num) { Some(factor) => { let other = num.div_exact_ref(&factor).complete(); front.push(factor); front.push(other); }, None => factors.push(num) }; } return factors; } fn lehman(n: &Integer) -> Option { let one = &Integer::from(1u32); let mut a = Integer::from(2u32); let root3 = n.root_ref(3).complete(); while a <= root3 { let (_, r) = n.div_rem_ref(&a).complete(); if r == 0 { return Some(a); } a += one; } let root6 = n.root_ref(6).complete(); let mut k = Integer::from(1u32); while k <= root3 { let mut d = Integer::ZERO; let sqrtk4 = k.sqrt_ref().complete() * 4; let (r6sk4, _) = root6.div_rem_ref(&sqrtk4).complete(); while d <= (&r6sk4 + one).complete() { let kn4: Integer = k.clone() * n.clone() * 4; let sqrt_kn4 = kn4.sqrt_ref().complete(); let number = (sqrt_kn4.clone() + d.clone()).square() - kn4.clone(); if number.is_perfect_square() { let big_a = sqrt_kn4 + d.clone(); let big_b = (big_a.square_ref() - kn4).sqrt(); let gcd1 = (big_a.clone() + big_b.clone()).gcd_ref(n).complete(); let gcd2 = (big_a.clone() - big_b.clone()).gcd_ref(n).complete(); if &gcd1 > one && &gcd1 < n { return Some(gcd1); } else if &gcd2 > one && &gcd2 < n { return Some(gcd2); } } d += one; } k += one; } return None; }