use super::{Case, Error};
use crate::field::Fe;
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Engine {
case: Option<Case>,
generator: Vec<Fe>,
residue: Vec<Fe>,
target: Vec<Fe>,
}
impl Engine {
pub fn new_codex32_short() -> Engine {
Engine {
case: None,
#[rustfmt::skip]
generator: vec![
Fe::E, Fe::M, Fe::_3, Fe::G, Fe::Q, Fe::E,
Fe::E, Fe::E, Fe::L, Fe::M, Fe::C, Fe::S,
Fe::S,
],
#[rustfmt::skip]
residue: vec![
Fe::Q, Fe::Q, Fe::Q, Fe::Q, Fe::Q, Fe::Q,
Fe::Q, Fe::Q, Fe::Q, Fe::Q, Fe::Q, Fe::Q,
Fe::P,
],
#[rustfmt::skip]
target: vec![
Fe::S, Fe::E, Fe::C, Fe::R, Fe::E, Fe::T,
Fe::S, Fe::H, Fe::A, Fe::R, Fe::E, Fe::_3,
Fe::_2,
],
}
}
pub fn new_codex32_long() -> Engine {
Engine {
case: None,
#[rustfmt::skip]
generator: vec![
Fe::_0, Fe::_2, Fe::E, Fe::_6, Fe::F, Fe::E,
Fe::_4, Fe::X, Fe::H, Fe::_4, Fe::X, Fe::_9,
Fe::K, Fe::Y, Fe::H,
],
#[rustfmt::skip]
residue: vec![
Fe::Q, Fe::Q, Fe::Q, Fe::Q, Fe::Q, Fe::Q,
Fe::Q, Fe::Q, Fe::Q, Fe::Q, Fe::Q, Fe::Q,
Fe::Q, Fe::Q, Fe::P,
],
#[rustfmt::skip]
target: vec![
Fe::S, Fe::E, Fe::C, Fe::R, Fe::E, Fe::T,
Fe::S, Fe::H, Fe::A, Fe::R, Fe::E, Fe::_3,
Fe::_2, Fe::E, Fe::X,
],
}
}
pub fn force_residue_to_zero(&mut self) {
self.residue = vec![Fe::Q; self.residue.len()];
}
pub fn into_residue(self) -> Vec<Fe> {
self.residue
}
pub fn is_valid(&self) -> bool {
self.residue == self.target
}
pub fn input_hrp(&mut self, hrp: &str) -> Result<(), Error> {
for ch in hrp.chars() {
self.set_check_case(ch)?;
self.input_fe(Fe::from_int(u32::from(ch.to_ascii_lowercase()) >> 5)?);
}
self.input_fe(Fe::Q);
for ch in hrp.chars() {
self.input_fe(Fe::from_int(u32::from(ch.to_ascii_lowercase()) & 0x1f)?);
}
Ok(())
}
pub fn input_char(&mut self, c: char) -> Result<(), Error> {
self.set_check_case(c)?;
self.input_fe(Fe::from_char(c)?);
Ok(())
}
pub fn input_data_str(&mut self, s: &str) -> Result<(), Error> {
for ch in s.chars() {
self.input_char(ch)?;
}
Ok(())
}
pub fn input_own_target(&mut self) {
let fuck_the_borrow_checker = self.target.clone();
for u in fuck_the_borrow_checker {
self.input_fe(u);
}
}
fn set_check_case(&mut self, c: char) -> Result<(), Error> {
if !c.is_ascii() {
Err(Error::InvalidChar(c))
} else if c.is_numeric() {
Ok(())
} else {
let is_lower = c.is_ascii_lowercase();
match (self.case, is_lower) {
(Some(Case::Lower), true) | (Some(Case::Upper), false) => Ok(()),
(Some(case @ Case::Lower), false) | (Some(case @ Case::Upper), true) => {
Err(Error::InvalidCase(case, c))
}
(None, true) => {
self.case = Some(Case::Lower);
Ok(())
}
(None, false) => {
self.case = Some(Case::Upper);
Ok(())
}
}
}
}
#[rustfmt::skip]
pub fn input_fe(&mut self, e: Fe) {
let res_len = self.residue.len(); let xn = self.residue[0];
for i in 1..res_len {
self.residue[i - 1] = self.residue[i];
}
self.residue[res_len - 1] = e;
for i in 0..res_len {
self.residue[i] += self.generator[i] * xn;
}
}
}