From 9d2a972cc9661282e85da686ef837fbed0871aab Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Sun, 28 May 2023 11:51:07 +0200 Subject: [PATCH] ecc point checker, generic reducing in gallois --- src/main.rs | 2 +- src/math/ecc.rs | 55 +++++++++++++++++++++++++++++++++++--- src/math/gallois.rs | 65 ++++++++++++++++++++++++++++++++------------- 3 files changed, 99 insertions(+), 23 deletions(-) diff --git a/src/main.rs b/src/main.rs index c01582f..e010dc7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -68,7 +68,7 @@ pub fn main() { cplex::printing::proc_result_tup_num(result, args); } GalloisActions::Reduce(gal_red_args) => { - let result = field.reduce_neg(gal_red_args.n); + let result = field.reduce(gal_red_args.n); cplex::printing::proc_num(result, args); } GalloisActions::Invert(gal_inv_args) => { diff --git a/src/math/ecc.rs b/src/math/ecc.rs index d690b0f..02d0062 100644 --- a/src/math/ecc.rs +++ b/src/math/ecc.rs @@ -46,10 +46,53 @@ impl ElipticCurve { }; return e; } + + /// calculate a point for coordinates + pub fn poly(&self, x: i128, y: i128) -> i128 { + return y.pow(2) - x.pow(3) - (self.a * x) - self.b; + } + + pub fn check_point(self, p: ElipticCurvePoint) -> bool { + let mut valid = true; + let r = self.f.reduce(self.poly(p.x, p.y)); + if self.verbose { + println!("F({}, {}) = {}² - {}³ - {} * {} - {} = {r}", + p.x, p.y, p.y, p.x, self.a, p.x, self.b + ) + } + valid &= r == 0; + return valid; + } +} + +#[test] +fn test_check_point() { + let f = GalloisField::new(1151, true); + let ec = ElipticCurve::new(f, 1, 679, true); + // real points + let p = vec![ + ElipticCurvePoint::new(298, 531), + ElipticCurvePoint::new(600, 127), + ElipticCurvePoint::new(846, 176), + ]; + // random values, not part of the ec. + let np = vec![ + ElipticCurvePoint::new(198, 331), + ElipticCurvePoint::new(100, 927), + ElipticCurvePoint::new(446, 876), + ]; + for i in p { + dbg!(&i); + assert!(ec.clone().check_point(i)); + } + for i in np { + dbg!(&i); + assert!(!ec.clone().check_point(i)); + } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] #[pyclass] /// represent a specific eliptic curves point pub struct ElipticCurvePoint { @@ -60,12 +103,12 @@ pub struct ElipticCurvePoint { } impl ElipticCurvePoint { - pub fn new(x: i128, y: i128, verbose: bool) -> Self { + pub fn new(x: i128, y: i128) -> Self { ElipticCurvePoint { x, y, is_infinity_point: false, - verbose + verbose: false } } @@ -79,6 +122,12 @@ impl ElipticCurvePoint { panic!("TODO"); } + /// get negative of a point + pub fn neg(p: Self) -> Self { + // TODO + panic!("TODO"); + } + /// multiply a point by an integer pub fn mul(n: u128, a: Self) -> Self { // TODO diff --git a/src/math/gallois.rs b/src/math/gallois.rs index 12a74c7..1226de1 100644 --- a/src/math/gallois.rs +++ b/src/math/gallois.rs @@ -7,7 +7,9 @@ /// It does also not even come close to statisfying the characteristic of prime powers q = p^k.as /// base => p = 0 /// -/// Something is wrong here. +/// GalloisFields with a base that is a prime power have p^k elements, but only p real elements, +/// the rest are denoted as polynomials with alpha, this makes computation much more complicated. +/// Therefore, currently, I can only support gallois fields with primes as base. /// /// Author: Christoph J. Scherr /// License: MIT @@ -16,12 +18,13 @@ use crate::{math::modexp, cplex::printing::seperator}; use core::fmt; +use std::{fmt::Debug, ops::{AddAssign, Add}}; use num::Integer; use pyo3::{prelude::*, exceptions::PyValueError}; -use primes::{Sieve, PrimeSet, is_prime}; +use primes::is_prime; /////////////////////////////////////////////////////////////////////////////////////////////////// #[derive(Debug)] @@ -61,17 +64,30 @@ pub struct GalloisField { base: u128, cha: u128, verbose: bool, + prime_base: bool } /// implementations for the gallois field impl GalloisField { /// make a new gallois field pub fn new(base: u128, verbose: bool) -> Self { + let prime_base: bool = is_prime(base as u64); + if !prime_base { + println!("Non prime bases for a field are currently not supported. {} is not a prime.", base); + panic!("Non prime bases for a field are currently not supported."); + } let mut field = GalloisField{ base, - cha: 0, - verbose + cha: base, + verbose, + prime_base }; + if field.prime_base { + field.cha = base; + } + else { + field.calc_char(); + } if verbose { println!("In Gallois Field F_{}", field.base); } @@ -79,13 +95,21 @@ impl GalloisField { } /// reduce a number to fit into the gallois field - pub fn reduce(self, n: u128) -> u128 { + /// only works with u128 as input + /// depreciated + pub fn reduce_pos(self, n: u128) -> u128 { return n % self.base; } /// reduce a negative number to fit into the gallois field - pub fn reduce_neg(self, n: i128) -> u128 { - let mut n = n; + /// + /// utilizes generic types to reduce any integer + pub fn reduce(self, n: T) -> u128 + where + T: Integer, + T: num::cast::AsPrimitive + { + let mut n: i128 = num::cast::AsPrimitive::as_(n); if n < 0 { while n < 0 { n += self.base as i128; @@ -181,7 +205,7 @@ impl GalloisField { let mut b_pm1_2: u128; for b_candidate in 0..self.base { b_pm1_2 = modexp::modular_exponentiation_wrapper(b_candidate, pm1_2, self.base, false); - if self.reduce(b_pm1_2) == self.reduce_neg(-1) { + if self.reduce(b_pm1_2) == self.reduce(-1) { b = Some(b_candidate); if self.verbose { println!("b^([p-1]/[2]) = {}^({pm1_2}) = -1 (mod {})", b.unwrap(), self.base); @@ -309,15 +333,16 @@ impl GalloisField { if self.verbose { seperator(); println!("calculating characteristic of F_{}", self.base); - seperator(); } let mut i = 1u128; while self.reduce(i) > 0 { - if self.verbose { - println!("{i}.\t {i} = {} (mod {})", self.reduce(i), self.base) - } i += 1; } + if self.verbose { + println!("{i} = {} (mod {})", self.reduce(i), self.base); + println!("Therefore, char(F_{}) = {i}", self.base); + seperator(); + } self.cha = i; return i; @@ -341,9 +366,9 @@ impl GalloisField { #[pyo3(name="reduce")] /// reduce any int pub fn py_reduce(&self, n: i128) -> u128 { - if n.is_negative() { - return self.reduce_neg(n); - } + //if n.is_negative() { + // return self.reduce_neg(n); + //} return self.reduce(n as u128); } @@ -407,10 +432,12 @@ fn test_gallois_inverse() { #[test] fn test_calc_char() { - assert_eq!(GalloisField::new(16, true).calc_char(), 2); - assert_eq!(GalloisField::new(81, true).calc_char(), 81); + assert_eq!(GalloisField::new(83, true).calc_char(), 83); assert_eq!(GalloisField::new(1151, true).calc_char(), 1151); - assert_eq!(GalloisField::new(8, true).calc_char(), 2); assert_eq!(GalloisField::new(2, true).calc_char(), 2); - assert_eq!(GalloisField::new(60, true).calc_char(), 3); + + // only primes are supported right now. TODO + //assert_eq!(GalloisField::new(8, true).calc_char(), 2); + //assert_eq!(GalloisField::new(64, true).calc_char(), 2); + //assert_eq!(GalloisField::new(2u128.pow(64u32), true).calc_char(), 2); }