diff options
| author | Andrew Guschin <guschin.drew@gmail.com> | 2022-11-13 11:40:34 +0400 |
|---|---|---|
| committer | Andrew Guschin <guschin.drew@gmail.com> | 2022-11-13 11:40:34 +0400 |
| commit | 9bbc7b8c31458fbf8c639794531e3d324004d8d5 (patch) | |
| tree | 7d6128c58518c78da03652e9f4e974e6de5a927f /labs/src | |
| parent | 14fefa99fae1433de08812558c07a0f81c40ab04 (diff) | |
Реализации лабораторных перенесены во отдельную папку
Diffstat (limited to 'labs/src')
| -rw-r--r-- | labs/src/lab1.rs | 134 | ||||
| -rw-r--r-- | labs/src/lab3.rs | 128 | ||||
| -rw-r--r-- | labs/src/lab6.rs | 114 | ||||
| -rw-r--r-- | labs/src/lab7.rs | 305 | ||||
| -rw-r--r-- | labs/src/lab_trait.rs | 6 | ||||
| -rw-r--r-- | labs/src/main.rs | 42 |
6 files changed, 729 insertions, 0 deletions
diff --git a/labs/src/lab1.rs b/labs/src/lab1.rs new file mode 100644 index 0000000..b442199 --- /dev/null +++ b/labs/src/lab1.rs @@ -0,0 +1,134 @@ +use crate::lab_trait::Lab; +use eframe::egui; + +pub struct Window { + order: u32, + element: u32, + element_check: Option<bool>, + primitive_roots: Vec<u32>, + state: State, +} + +impl Window { + fn clear_state(&mut self) { + self.element_check = None; + self.state = State::Idle; + } +} + +impl Default for Window { + fn default() -> Self { + Self { + order: 29, + element: 2, + element_check: None, + primitive_roots: Vec::new(), + state: State::Idle, + } + } +} + +impl Lab for Window { + fn get_name(&self) -> &str { "Задача №1" } + + fn update(&mut self, ui: &mut egui::Ui) { + ui.horizontal(|ui| { + ui.label("Порядок поля: "); + if ui + .add(egui::DragValue::new(&mut self.order).clamp_range(2..=u32::MAX)) + .changed() + { + self.clear_state(); + } + }); + ui.horizontal(|ui| { + ui.label("Проверяемый элемент: "); + if ui + .add(egui::DragValue::new(&mut self.element).clamp_range(1..=self.order - 1)) + .changed() + { + self.clear_state(); + } + }); + + 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("Можно указать только простое число!"); + } + } + } +} + +enum State { + Idle, + Running(u32), + Done, + Error, +} + +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; +} + diff --git a/labs/src/lab3.rs b/labs/src/lab3.rs new file mode 100644 index 0000000..7f8edf5 --- /dev/null +++ b/labs/src/lab3.rs @@ -0,0 +1,128 @@ +use crate::lab_trait::Lab; +use eframe::egui; +use rug::{Complete, Integer}; + +enum State { + Clean, + Done, + Error, +} + +pub struct Window { + str_num: String, + factors: Vec<Integer>, + state: State, +} + +impl Default for Window { + fn default() -> Self { + Self { + str_num: String::from("21894583143407671"), + factors: Vec::new(), + state: State::Clean, + } + } +} + +impl Lab for Window { + fn get_name(&self) -> &str { "Задача №3" } + + fn update(&mut self, ui: &mut egui::Ui) { + ui.horizontal(|ui| { + ui.label("Число: "); + let field = ui.add(egui::TextEdit::singleline(&mut self.str_num)); + if field.changed() { + self.state = State::Clean; + self.factors.clear(); + } + }); + if ui.button("Разложить на множители").clicked() { + self.factors.clear(); + match Integer::parse(&self.str_num) { + Ok(number) => { + self.factors.append(&mut factorize(&number.complete())); + self.state = State::Done; + }, + Err(_) => self.state = State::Error, + }; + } + if let State::Done = self.state { + if self.factors.len() == 1 { + ui.label(format!("Число является простым")); + } + else { + ui.label(format!("Множители: {:?}", self.factors)); + } + } + if let State::Error = self.state { + ui.label("В числе имеются недопустимые символы"); + } + } +} + +fn factorize(n: &Integer) -> Vec<Integer> { + 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<Integer> { + 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; +} + diff --git a/labs/src/lab6.rs b/labs/src/lab6.rs new file mode 100644 index 0000000..9061da7 --- /dev/null +++ b/labs/src/lab6.rs @@ -0,0 +1,114 @@ +use crate::lab_trait::Lab; +use eframe::egui; +use std::collections::HashSet; +use std::collections::HashMap; + +enum State<'a> { + Clean, + Done1, + Done2, + Error(&'a str), +} + +pub struct Window<'a> { + n: u32, + q: u32, + subgroup: Vec<u32>, + subgroups: HashMap<u32, Vec<u32>>, + state: State<'a>, +} + +impl<'a> Default for Window<'a> { + fn default() -> Self { + Self { + n: 6, + q: 3, + subgroup: Vec::new(), + subgroups: HashMap::new(), + state: State::Clean, + } + } +} + +impl<'a> Lab for Window<'a> { + fn get_name(&self) -> &str { "Задача №6" } + + fn update(&mut self, ui: &mut egui::Ui) { + ui.horizontal(|ui| { + ui.label("Порядок группы Z_n: "); + if ui.add(egui::DragValue::new(&mut self.n).clamp_range(2..=u32::MAX)).changed() { + self.state = State::Clean; + self.subgroup.clear(); + } + }); + ui.horizontal(|ui| { + ui.label("Порядок q подгруппы: "); + if ui.add(egui::DragValue::new(&mut self.q).clamp_range(1..=self.n)).changed() { + self.state = State::Clean; + self.subgroup.clear(); + } + }); + if ui.button("Вычислить подгруппу").clicked() { + self.subgroups.clear(); + if self.n % self.q != 0 { + self.state = State::Error("q не является делителем n"); + } + else { + self.subgroups = calculate_subgroups(self.n); + for (_, sg) in &self.subgroups { + if sg.len() == self.q as usize { + self.subgroup = sg.clone(); + break; + } + } + self.state = State::Done1; + } + } + if ui.button("Вычислить все подгруппы").clicked() { + self.subgroups.clear(); + if self.n % self.q != 0 { + self.state = State::Error("q не является делителем n"); + } + else { + self.subgroups = calculate_subgroups(self.n); + self.state = State::Done2; + } + } + match self.state { + State::Clean => {}, + State::Done1 => { + ui.label(format!("Вычисленная подгруппа: {:?}", self.subgroup)); + }, + State::Done2 => { + for (gen, set) in self.subgroups.iter() { + ui.label(format!("Подгруппа {:?} с генератором {}", set, gen)); + } + }, + State::Error(msg) => { ui.label(msg); }, + } + } +} + +fn powmod(x: u32, n: u32, m: u32) -> u32 { + let mut res = 0; + for _ in 0..n { + res = (res + x) % m; + } + return res; +} + +fn calculate_subgroups(n: u32) -> HashMap<u32, Vec<u32>> { + let mut subgroups = HashMap::new(); + for i in 0..n { + let mut group = HashSet::new(); + group.insert(i); + for p in 2..=n { + let power = powmod(i, p, n); + group.insert(power); + } + let mut vec = group.drain().collect::<Vec<u32>>(); + vec.sort(); + subgroups.insert(i as u32, vec); + } + return subgroups; +} diff --git a/labs/src/lab7.rs b/labs/src/lab7.rs new file mode 100644 index 0000000..030c0d4 --- /dev/null +++ b/labs/src/lab7.rs @@ -0,0 +1,305 @@ +use crate::lab_trait::Lab; +use eframe::egui; +use std::collections::HashSet; + +enum State { + Nothing, + Cipher, + Decipher, + Line(u32), + + RDecipher, + RLine(u32), +} + +pub struct Window { + state: State, + line: u32, + q1: Vec<String>, + q2: Vec<String>, + q3: Vec<String>, + q4: Vec<String>, + + rq1: String, + rq2: String, + rq3: String, + rq4: String, + rline: u32, +} + +impl Default for Window { + fn default() -> Self { + Self { + state: State::Nothing, + line: 1, + q1: vec![ + "Нечаянно пригрѣтый славой".to_string(), + "Орла двуглаваго щипали".to_string(), + "Остервененіе народа".to_string(), + "Мы очутилися въ П".to_string(), + "Скажи за чѣмъ ты въ сам дѣлѣ".to_string(), + "Но стихоплетъ Великородный".to_string(), + "Авось по манью — --".to_string(), + "Сей всадникъ Папою вѣнчанный".to_string(), + "Безрукій К. друзьямъ Мореи".to_string(), + "А про тебя и въ усъ не дуетъ".to_string(), + "Предавшихъ нѣкогда — --".to_string(), + "Но искры пламени инова".to_string(), + "Они за рюмкой руской водки".to_string(), + "У безпокойнаго Никиты".to_string(), + "Свои рѣшительныя мѣры".to_string(), + "Блеститъ надъ К. тѣнистой".to_string(), + "Надъ нами З — валъ тогда".to_string(), + "У Б — шатра".to_string(), + "Б., зима иль Р. Б.".to_string(), + "А Р. З. главой З.".to_string(), + "Меня уже предупредилъ".to_string(), + "Семействамъ возвратитъ с".to_string(), + "Изчезнувшій какъ тѣнь зари".to_string(), + "Изъ К. ужъ мигалъ".to_string(), + "Ты А. холопъ".to_string(), + "Свирѣпой шайкѣ палачей".to_string(), + "Уже издавно можетъ быть ".to_string(), + ], + q2: vec![ + "Моря достались Албіону".to_string(), + "Авось дороги намъ испр.".to_string(), + "Измученъ казнію покоя".to_string(), + "Кинжалъ… тѣмъ… ".to_string(), + ], + q3: vec![ + "Вл. слабый и лукавый".to_string(), + "Его мы очень смирн знали".to_string(), + "Гроза 12 года".to_string(), + "Но Богъ помогъ — сталъ ропотъ ниже".to_string(), + "И чѣмъ жирнѣе тѣмъ тяжелѣ".to_string(), + "Авось, о Шиболетъ народный".to_string(), + "Авось аренды забывая".to_string(), + "Сей мужъ судьбы, сей странникъ бранный".to_string(), + "Тряслися грозно Пиринеи —".to_string(), + "Я всѣхъ уйму съ моимъ народомъ".to_string(), + "Потѣшный полкъ Петра титана ".to_string(), + "Р. Р. снова присм…".to_string(), + "У нихъ [свои бывали] сходки".to_string(), + "Витійствомъ рѣзкимъ знамениты".to_string(), + "Другъ Марса, Вакха и Венеры".to_string(), + "[Но т] Такъ было надъ Невою льдистой".to_string(), + "Плѣшивый щеголь врагъ труда".to_string(), + "Когда ненаши повара".to_string(), + "Насти… — кто тутъ намъ помогъ?".to_string(), + "И скоро сило вещей".to_string(), + "ОР… нашъ н".to_string(), + "Тебѣ бъ я оду посвятилъ".to_string(), + "Ханжа запрется въ монастырь".to_string(), + "Предъ кѣмъ унизились З".to_string(), + "Волканъ Неаполя пылалъ".to_string(), + ], + q4: vec![ + "Нашъ З. въ покоѣ говорилъ".to_string(), + "Дружина старыхъ усачей".to_string(), + "И пуще З. пошелъ кутить".to_string(), + "Они за чашею вина".to_string(), + "Сбирались члены сей семьи".to_string(), + "Тутъ [бы] Л. дерзко предлагалъ".to_string(), + "Но тамъ гдѣ ранѣе весна ".to_string(), + ], + + rq1: String::new(), + rq2: String::new(), + rq3: String::new(), + rq4: String::new(), + rline: 1, + } + } +} + +impl Lab for Window { + fn get_name(&self) -> &str { + "Задача №7" + } + + fn update(&mut self, ui: &mut egui::Ui) { + if ui.button("Вывести оригинал").clicked() { + self.state = State::Cipher; + } + if ui.button("Вывести дешифровку").clicked() { + self.state = State::Decipher; + } + ui.horizontal(|ui| { + if ui + .add(egui::DragValue::new(&mut self.line).clamp_range(1..=56)) + .changed() + { + self.state = State::Nothing; + } + if ui.button("Вывести строку").clicked() { + self.state = State::Line(self.line); + } + }); + let response = ui.add(egui::TextEdit::multiline(&mut self.rq1)); + if response.changed() { + self.state = State::Nothing; + } + let response = ui.add(egui::TextEdit::multiline(&mut self.rq2)); + if response.changed() { + self.state = State::Nothing; + } + let response = ui.add(egui::TextEdit::multiline(&mut self.rq3)); + if response.changed() { + self.state = State::Nothing; + } + let response = ui.add(egui::TextEdit::multiline(&mut self.rq4)); + if response.changed() { + self.state = State::Nothing; + } + if ui.button("Вывести дешифровку введённого текста").clicked() + { + self.state = State::RDecipher; + } + ui.horizontal(|ui| { + let q1 = self.rq1.lines().collect::<Vec<_>>().len(); + let q2 = self.rq2.lines().collect::<Vec<_>>().len(); + let q3 = self.rq3.lines().collect::<Vec<_>>().len(); + let q4 = self.rq4.lines().collect::<Vec<_>>().len(); + if ui + .add(egui::DragValue::new(&mut self.rline).clamp_range(1..=q1 + q2 + q3 + q4)) + .changed() + { + self.state = State::Nothing; + } + if ui.button("Вывести строку введённого текста").clicked() + { + self.state = State::RLine(self.rline); + } + }); + + match self.state { + State::Nothing => {} + State::Cipher => { + let mut cipher = Vec::new(); + cipher.extend(&self.q1); + cipher.extend(&self.q2); + cipher.extend(&self.q3); + cipher.extend(&self.q4); + egui::ScrollArea::vertical().show(ui, |ui| { + for line in cipher { + ui.label(line); + } + }); + } + State::Decipher => { + egui::ScrollArea::vertical().show(ui, |ui| { + get_poem(&self.q1, &self.q2, &self.q3, &self.q4) + .into_iter() + .for_each(|x| { + ui.label(x); + }); + }); + } + State::Line(n) => { + let poem = get_poem(&self.q1, &self.q2, &self.q3, &self.q4); + ui.label(format!("Строка {}: \"{}\"", n, poem[n as usize - 1])); + } + State::RDecipher => { + let q1 = splitlines(&self.rq1); + let q2 = splitlines(&self.rq2); + let q3 = splitlines(&self.rq3); + let q4 = splitlines(&self.rq4); + let mut lens = HashSet::new(); + lens.insert(q1.len()); + lens.insert(q2.len()); + lens.insert(q3.len()); + lens.insert(q4.len()); + if lens.len() != 1 { + ui.label("Введённые тексты должны быть одинаковой длины"); + } else { + get_random_poem(&q1, &q2, &q3, &q4) + .into_iter() + .for_each(|x| { + ui.label(x); + }); + } + } + State::RLine(n) => { + let q1 = splitlines(&self.rq1); + let q2 = splitlines(&self.rq2); + let q3 = splitlines(&self.rq3); + let q4 = splitlines(&self.rq4); + let mut lens = HashSet::new(); + lens.insert(q1.len()); + lens.insert(q2.len()); + lens.insert(q3.len()); + lens.insert(q4.len()); + if lens.len() != 1 { + ui.label("Введённые тексты должны быть одинаковой длины"); + } else { + let poem = get_random_poem(&q1, &q2, &q3, &q4); + ui.label(format!("Строка {}: \"{}\"", n, poem[n as usize - 1])); + } + } + } + } +} + +fn splitlines(text: &String) -> Vec<String> { + text.lines().map(|x| x.to_string()).collect::<Vec<String>>() +} + +fn get_poem( + q1: &Vec<String>, + _q2: &Vec<String>, + q3: &Vec<String>, + q4: &Vec<String>, +) -> Vec<String> { + let mut cipher = Vec::new(); + cipher.extend(q1); + cipher.extend(q3); + cipher.extend(q4); + let mut key = vec![27, 43, 0, 16]; + let mut poem = Vec::new(); + let mut count = 1; + while key[1] < cipher.len() { + if count == 5 { + for i in 0..=2 { + poem.push(cipher[key[i]].clone()); + key[i] += 1; + } + } else if count == 10 { + for i in 0..=1 { + poem.push(cipher[key[i]].clone()); + key[i] += 1; + } + key[2] += 1; + key[3] += 1; + } else if count == 11 || count >= 13 && count <= 16 { + for i in 0..=2 { + poem.push(cipher[key[i]].clone()); + key[i] += 1; + } + key[3] += 1; + } else { + for i in 0..=3 { + poem.push(cipher[key[i]].clone()); + key[i] += 1; + } + } + count += 1; + } + return poem; +} + +fn get_random_poem( + q1: &Vec<String>, + q2: &Vec<String>, + q3: &Vec<String>, + q4: &Vec<String>, +) -> Vec<String> { + let mut poem = Vec::new(); + for i in 0..q1.len() { + poem.push(q3[i].clone()); + poem.push(q4[i].clone()); + poem.push(q1[i].clone()); + poem.push(q2[i].clone()); + } + return poem; +} diff --git a/labs/src/lab_trait.rs b/labs/src/lab_trait.rs new file mode 100644 index 0000000..23f110b --- /dev/null +++ b/labs/src/lab_trait.rs @@ -0,0 +1,6 @@ +use eframe::egui; + +pub trait Lab { + fn get_name(&self) -> &str; + fn update(&mut self, ui: &mut egui::Ui); +} diff --git a/labs/src/main.rs b/labs/src/main.rs new file mode 100644 index 0000000..f672971 --- /dev/null +++ b/labs/src/main.rs @@ -0,0 +1,42 @@ +mod lab1; +mod lab3; +mod lab6; +mod lab7; +mod lab_trait; + +use eframe::egui; +use lab_trait::Lab; + +fn main() { + let options = eframe::NativeOptions::default(); + eframe::run_native( + "Криптографические методы защиты информации", + options, + Box::new(|_cc| Box::new(Application::default())), + ); +} + +struct Application { + labs: Vec<Box<dyn Lab>>, +} + +impl Default for Application { + fn default() -> Self { + Self { + labs: vec![ + Box::new(lab1::Window::default()), + Box::new(lab3::Window::default()), + Box::new(lab6::Window::default()), + Box::new(lab7::Window::default()), + ], + } + } +} + +impl eframe::App for Application { + fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { + for window in &mut self.labs { + egui::Window::new(window.get_name()).show(ctx, |ui| window.update(ui)); + } + } +} |