pub mod matrix_functions;
use num_bigint::BigUint;
use std::fmt::Display;
use crate::error::CharacterParseError;
use crate::prelude::{ALPHABET, ALPHABET_LEN};
use num_integer::gcd;
use rayon::prelude::*;
#[cfg(feature = "python-integration")]
use pyo3::prelude::*;
#[cfg(feature = "python-integration")]
use pyo3_helper_macros::py3_bind;
use rug::Integer;
const THRESHOLD: usize = 1000;
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "python-integration", pyclass)]
pub enum StringType {
Standard,
Assymetric,
Unknown,
}
#[cfg_attr(feature = "python-integration", py3_bind)]
impl Default for StringType {
fn default() -> Self {
Self::Unknown
}
}
#[derive(Default, Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "python-integration", pyclass)]
pub struct BaseString {
pub data: String,
}
#[derive(Default, Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "python-integration", pyclass)]
pub struct EncodedString {
pub data: Vec<usize>,
str_type: StringType,
}
impl From<String> for BaseString {
fn from(data: String) -> Self {
Self { data }
}
}
impl From<&str> for BaseString {
fn from(data: &str) -> Self {
Self {
data: data.to_string(),
}
}
}
impl From<Vec<usize>> for EncodedString {
fn from(data: Vec<usize>) -> Self {
Self {
data,
str_type: StringType::Unknown,
}
}
}
impl From<BaseString> for String {
fn from(data: BaseString) -> Self {
data.data
}
}
impl From<String> for EncodedString {
fn from(data: String) -> Self {
let mut numbers = Vec::new();
let mut chars = data.chars().peekable();
let mut string_type = StringType::Unknown;
if let Some(first_char) = chars.next() {
string_type = match first_char {
'S' => StringType::Standard,
'A' => StringType::Assymetric,
_ => StringType::Unknown,
};
}
if let Some(first_char) = chars.next() {
let mut first_number_str = first_char.to_string();
if first_char != '0' && chars.peek().map_or(false, |&c| c != '0') {
if let Some(second_char) = chars.next() {
first_number_str.push(second_char);
}
}
if let Ok(first_number) = first_number_str.parse::<usize>() {
numbers.push(first_number);
} else {
numbers.push(*ALPHABET_LEN + 1); }
}
while chars.peek().is_some() {
let mut number_str = String::new();
number_str.push(chars.next().unwrap()); number_str.push(chars.next().unwrap_or('0'));
if let Ok(number) = number_str.parse::<usize>() {
numbers.push(number);
} else {
numbers.push(0);
}
}
EncodedString::new(numbers, string_type) }
}
impl Display for BaseString {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.data)
}
}
impl Display for EncodedString {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?} {:?}", self.data, self.str_type)
}
}
#[cfg_attr(feature = "python-integration", pyfunction)]
pub fn encode_string(t: &str) -> Result<Vec<usize>, CharacterParseError> {
if t.len() > THRESHOLD {
t.to_lowercase()
.par_chars()
.map(|x| {
ALPHABET
.chars()
.position(|y| y == x)
.ok_or(CharacterParseError::InvalidCharacter(x))
})
.collect()
} else {
t.to_lowercase()
.chars()
.map(|x| {
ALPHABET
.chars()
.position(|y| y == x)
.ok_or(CharacterParseError::InvalidCharacter(x))
})
.collect()
}
}
#[cfg_attr(feature = "python-integration", pyfunction)]
pub fn decode_list(t: Vec<usize>) -> Result<String, CharacterParseError> {
if t.len() > THRESHOLD {
t.par_iter()
.map(|&x| {
ALPHABET
.chars()
.nth(x)
.ok_or(CharacterParseError::InvalidIndex(x))
})
.collect::<Result<String, _>>()
} else {
t.iter()
.map(|&x| {
ALPHABET
.chars()
.nth(x)
.ok_or(CharacterParseError::InvalidIndex(x))
})
.collect::<Result<String, _>>()
}
}
#[cfg_attr(feature = "python-integration", pyfunction)]
pub fn encode_char(t: char) -> Result<usize, CharacterParseError> {
ALPHABET
.find(t.to_lowercase().next().unwrap())
.ok_or(CharacterParseError::InvalidCharacter(t))
}
#[cfg_attr(feature = "python-integration", pyfunction)]
pub fn decode_digit(i: usize) -> Result<char, CharacterParseError> {
ALPHABET
.chars()
.nth(i)
.ok_or(CharacterParseError::InvalidIndex(i))
}
#[cfg_attr(feature = "python-integration", pyfunction)]
pub fn num_gcd(a: usize, b: usize) -> usize {
gcd(a, b)
}
pub fn factorize(n: BigUint) -> Vec<String> {
let factors = num_prime::nt_funcs::factorize(n);
factors.iter().map(|x| format!("{:?}", x.0)).collect()
}
pub fn mod_add(a: usize, b: usize) -> usize {
((a + b) % *ALPHABET_LEN + *ALPHABET_LEN) % *ALPHABET_LEN }
pub fn cyclic_left_shift(vec: &Vec<usize>, shift: usize) -> Vec<usize> {
let effective_shift = shift % vec.len(); let mut shifted = vec.clone();
shifted.rotate_left(effective_shift);
shifted
}
#[cfg(feature = "python-integration")]
#[pyfunction]
pub fn print_info(py: Python) -> PyResult<()> {
let code = r#"
import ferric_crypto_lib
# Get a list of all attributes in the ferric_crypto_lib module
attributes = dir(ferric_crypto_lib)
# Filter the list to include only functions and classes
functions_and_classes = [attr for attr in attributes if callable(getattr(ferric_crypto_lib, attr))]
# Print each function and class
for item in functions_and_classes:
print(item)
actual_class = getattr(ferric_crypto_lib, item)
if isinstance(actual_class, type):
item_attributes = dir(actual_class)
item_functions_and_classes = [attr for attr in item_attributes if callable(getattr(actual_class, attr)) and not attr.startswith('_')]
if len(item_functions_and_classes) > 0:
print(f'\t{item} member functions:')
for class_item in item_functions_and_classes:
print(f'\t\t{class_item}')
else:
print(f'\t\tNo member functions')
"#;
py.run(code, None, None)?;
Ok(())
}
mod encoding;
#[cfg(test)]
mod test;
#[cfg(feature = "python-integration")]
pub mod python_integration;