From 79c923a08c316569ad0f60faed565ec782245177 Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Thu, 18 May 2023 01:51:30 +0200 Subject: [PATCH] gallois module --- src/math/gallois.rs | 152 ++++++++++++++++++++++++++++++++++++++++++++ src/math/mod.rs | 1 + src/math/modexp.rs | 13 ++++ 3 files changed, 166 insertions(+) create mode 100644 src/math/gallois.rs diff --git a/src/math/gallois.rs b/src/math/gallois.rs new file mode 100644 index 0000000..ff608af --- /dev/null +++ b/src/math/gallois.rs @@ -0,0 +1,152 @@ +#![allow(dead_code)] +use num::Integer; + +/// calculation in a gallois field +/// +/// This module contains functions that can be used to calculate things in a gallois field +/// +/// Author: Christoph J. Scherr +/// License: MIT +/// Source: + +use crate::math::modexp; + +use core::fmt; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +#[derive(Debug)] +/// used when trying to find a root for a number which does not have a root. +pub struct NoInverseError; + +impl fmt::Display for NoInverseError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "inverse for 0 does not exist") + } +} +/////////////////////////////////////////////////////////////////////////////////////////////////// +#[derive(Debug)] +/// used when trying to find a root for a number which does not have a root. +pub struct DivisionByZeroError; + +impl fmt::Display for DivisionByZeroError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "division by zero") + } +} +/////////////////////////////////////////////////////////////////////////////////////////////////// +#[derive(Debug)] +/// used when trying to find a root for a number which does not have a root. +pub struct NoRootError; + +impl fmt::Display for NoRootError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "no root in the specified gallois field") + } +} +/////////////////////////////////////////////////////////////////////////////////////////////////// +#[derive(Debug, Copy, Clone)] +/// represent a gallois field +pub struct GalloisFiled { + base: u128, + cha: u128, + verbose: bool, +} + +/// implementations for the gallois field +impl GalloisFiled { + /// make a new gallois field + pub fn new(base: u128, verbose: bool) -> Self { + let mut field = GalloisFiled{ + base, + // TODO: calculate the characteristic + cha: 0, + verbose + }; + if verbose { + dbg!(&field); + } + return field; + } + + /// reduce a number to fit into the gallois field + pub fn reduce(self, n: u128) -> u128 { + let mut n = n; + if n < 0 { + while n < 0 { + n += self.base; + } + } + n %= self.base; + return n; + } + + /// reduce a negative number to fit into the gallois field + pub fn reduce_neg(self, n: i128) -> u128 { + let mut n = n; + if n < 0 { + while n < 0 { + n += self.base as i128; + } + } + n %= self.base as i128; + return n as u128; + } + + /// calculate the exponent of a base in the field + pub fn pow(self, base: u128, exp: u128) -> u128 { + return modexp::modular_exponentiation_wrapper(base, exp, self.base, false); + } + + /// find the additive inverse of a number + pub fn a_inverse(self, n: u128) -> u128 { + return self.base - self.reduce(n); + } + + /// find the multiplicative inverse of a number + pub fn inverse(self, n: u128) -> Result { + if n == 0 { + return Err(NoInverseError); + } + let egcd = (n as i128).extended_gcd(&(self.base as i128)); + dbg!(n); + return Ok(egcd.x as u128); + } + + pub fn divide(self, a: u128, b: u128) -> Result { + let b = self.inverse(b); + match b { + Ok(r) => { + return Ok(self.reduce(a * r)); + } + Err(e) => { + dbg!(e); + return Err(DivisionByZeroError); + } + } + } + + /// calculate the square root of a number in a field + pub fn sqrt(self, n: u128) -> Result { + // TODO implement this + panic!("TODO") + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +#[test] +fn test_gallois_sqrt() { + panic!("TODO") +} + +#[test] +fn test_gallois_inverse() { + let field = GalloisFiled::new(31, true); + assert_eq!(field.inverse(12).unwrap(), 13); + assert_eq!(field.inverse(28).unwrap(), 10); + assert!(field.inverse(0).is_err()); + + let field = GalloisFiled::new(83, true); + assert_eq!(field.inverse(6).unwrap(), 14); + assert_eq!(field.inverse(54).unwrap(), 20); + assert!(field.inverse(0).is_err()); +} diff --git a/src/math/mod.rs b/src/math/mod.rs index 6beca9c..3c829fa 100644 --- a/src/math/mod.rs +++ b/src/math/mod.rs @@ -9,3 +9,4 @@ pub mod modexp; pub mod pm1; pub mod modred; +pub mod gallois; diff --git a/src/math/modexp.rs b/src/math/modexp.rs index 4fe4dc5..da39441 100644 --- a/src/math/modexp.rs +++ b/src/math/modexp.rs @@ -68,6 +68,19 @@ pub fn modular_exponentiation( return res; } +/// quick wrapper for modular_exponentiation without BigInts +pub fn modular_exponentiation_wrapper( + base: u128, + exp: u128, + field: u128, + verbose: bool) -> u128 { + + let base = BigInt::from(base); + let exp = BigInt::from(exp); + let field = BigInt::from(field); + return modular_exponentiation(base, exp, field, verbose).to_u128().expect("number too big"); +} + #[pyfunction] #[pyo3(name="modular_exponentiation")] #[pyo3(signature=(base, orig_exp, field, verbose = false))]