python integration of ecc, code cleanup

This commit is contained in:
Christoph J. Scherr 2023-06-09 00:15:17 +02:00
parent 8a0d41b134
commit ea28bbf30b
Signed by: PlexSheep
GPG Key ID: 25B4ACF7D88186CC
4 changed files with 148 additions and 62 deletions

View File

@ -1,7 +1,7 @@
[package]
name = "plexcryptool"
authors = ["Christoph J. Scherr <software@cscherr.de>"]
version = "0.2.9"
version = "0.2.10"
edition = "2021"
readme = "README.md"
description = "Various tools for use with math and cryptology, includes executable and a library."

View File

@ -57,6 +57,8 @@ fn register_math_module(py: Python, parent_module: &PyModule) -> PyResult<()> {
math_module.add_function(wrap_pyfunction!(math::gcd::alt_egcd, math_module)?)?;
math_module.add_function(wrap_pyfunction!(math::factorise::prime_factors , math_module)?)?;
math_module.add_class::<math::gallois::GalloisField>()?;
math_module.add_class::<math::ecc::ElipticCurve>()?;
math_module.add_class::<math::ecc::ElipticCurvePoint>()?;
parent_module.add_submodule(math_module)?;
Ok(())
}

View File

@ -12,14 +12,15 @@ use crate::cplex::printing::seperator;
use super::gallois::GalloisField;
use std::{ops::{Mul, Neg}, fmt::{Debug, Display}, f32::consts::PI};
use std::fmt::Debug;
use num::{Integer, Unsigned, NumCast};
use bitvec::prelude::*;
use pyo3::prelude::*;
use pyo3::{prelude::*, exceptions::PyValueError};
#[pyclass]
#[derive(Debug, Clone, Eq, PartialEq)]
#[allow(non_snake_case)]
/// represent a specific eliptic curve
@ -69,7 +70,7 @@ impl ElipticCurve {
Check for Diskriminante passed", field.reduce::<_, u128>(d));
}
let mut infty = ElipticCurvePoint::new(0, 0, field, false);
let mut infty = ElipticCurvePoint::new(0, 0);
infty.is_infinity_point = true;
let infty = infty;
let e = ElipticCurve {
@ -85,7 +86,7 @@ impl ElipticCurve {
/// build a new point in the EC
pub fn new_point(&self, r: u128, s: u128) -> Result<ElipticCurvePoint, String> {
let p = ElipticCurvePoint::new(r, s, self.field, self.verbose);
let p = ElipticCurvePoint::new(r, s);
if self.verbose {
println!("{p}")
}
@ -103,13 +104,9 @@ impl ElipticCurve {
pub fn poly<T>(&self, r: T, s: T) -> i128
where
T: Integer,
T: Mul,
T: Debug,
T: num::cast::AsPrimitive<u128>,
T: Neg
{
dbg!(&r);
dbg!(&s);
let r: u128 = num::cast::AsPrimitive::as_(r);
let s: u128 = num::cast::AsPrimitive::as_(s);
let res = (s.pow(2) as u128) - (r.pow(3) as u128) - (self.a * r) - self.b;
@ -123,6 +120,10 @@ impl ElipticCurve {
}
pub fn check_point(&self, p: ElipticCurvePoint, verbose: bool) -> bool {
if p.is_infinity_point {
println!("p is infinity: {p}");
return true;
}
let mut valid = true;
// insert into poly
@ -158,23 +159,20 @@ impl ElipticCurve {
println!("adding {p1} + {p2}");
seperator();
}
if p1.field != p2.field {
return Err(String::from("Points are not on the same field"));
}
if !self.check_point(p1, self.verbose) {
if !self.check_point(p1, false) {
return Err(String::from("{p1} is not a valid point"));
}
if !self.check_point(p2, self.verbose) {
if !self.check_point(p2, false) {
return Err(String::from("{p2} is not a valid point"));
}
if p1.field.prime_base {
if self.field.prime_base {
// verbisity stuff
if self.verbose {
println!("{} = {}; {} = -{} = {} <=> {}",
p1.r, p2.r, p1.s, p2.s, self.neg(p2).s,
p1.r == p2.r && p1.s == self.neg(p2).s,
);
}
//if self.verbose {
// println!("{} = {}; {} = -{} = {} <=> {}",
// p1.r, p2.r, p1.s, p2.s, self.neg(p2).s,
// p1.r == p2.r && p1.s == self.neg(p2).s,
// );
//}
// case 1: both infty
if p1.is_infinity_point && p2.is_infinity_point {
if self.verbose {
@ -204,14 +202,14 @@ impl ElipticCurve {
let m: i128 = m as i128;
if self.verbose {
println!("m = [s_2 - s_1]/[r_2 - r_1] = [{} - {}]/[{} - {}] = {} = {}",
p2.s, p1.s, p2.r, p1.r, m, p1.field.reduce::<_, u128>(m))
p2.s, p1.s, p2.r, p1.r, m, self.field.reduce::<_, u128>(m))
}
let m: i128 = self.field.reduce(m);
let r3 = m.pow(2) - p1.r as i128 - p2.r as i128;
if self.verbose {
println!("r_3 = m² - r_1 - r_2 = {} - {} - {} = {} = {}",
m.pow(2), p1.r, p2.r, r3, p1.field.reduce::<_, u128>(r3));
m.pow(2), p1.r, p2.r, r3, self.field.reduce::<_, u128>(r3));
}
let r3 = self.field.reduce::<_, u128>(r3);
@ -225,9 +223,9 @@ impl ElipticCurve {
let s3 = self.field.reduce::<_, u128>(s3) as i128;
if self.verbose {
println!("-s_3 = - {s3} = {}", self.field.reduce::<_, u128>(-s3));
println!("Q = ({}, {})", r3, s3);
}
let p3 = ElipticCurvePoint::new(r3, self.field.reduce::<_, u128>(-s3),
self.field, self.verbose);
let p3 = self.new_point(r3, self.field.reduce::<_, u128>(-s3)).expect("calculated point does not exist");
if self.verbose {
seperator();
@ -286,19 +284,18 @@ impl ElipticCurve {
let r3: i128 = self.field.reduce::<_, i128>(m.pow(2)) - p1.r as i128 - p2.r as i128;
if self.verbose {
println!("r_3 = m² - r_1 - r_2 = {} - {} - {} = {} = {}",
m.pow(2), p1.r, p2.r, r3, p1.field.reduce::<_, u128>(r3));
m.pow(2), p1.r, p2.r, r3, self.field.reduce::<_, u128>(r3));
}
let r3: i128 = self.field.reduce(r3);
let s3: i128 = m.pow(3) - 2*m*p1.r as i128 - m*p2.r as i128 + p1.s as i128;
if self.verbose || p2.verbose {
if self.verbose {
println!("s_3 = m³ 2*m*r_1 m*r_2 + s1 = {} - 2*{m}*{} - {m}*{} + {} = \
{} = {}",
m.pow(3), p1.r, p2.r, p1.s, s3, self.field.reduce::<_, u128>(s3));
}
let s3: i128 = self.field.reduce(s3);
let p3 = ElipticCurvePoint::new(r3 as u128, self.field.reduce::<_, u128>(-s3),
self.field, self.verbose);
let p3 = self.new_point(r3 as u128, self.field.reduce::<_, u128>(-s3)).expect("calculated point does not exist in curve");
if self.verbose {
seperator();
@ -337,7 +334,7 @@ impl ElipticCurve {
T: Debug,
T: Unsigned,
{
if !self.check_point(g, self.verbose) {
if !self.check_point(g, false) {
return Err(String::from("invalid point"));
}
let t: usize = num::cast(t).unwrap();
@ -362,7 +359,6 @@ impl ElipticCurve {
return Ok(h);
}
for bit in t_bits {
dbg!(&index);
if index == l {
if self.verbose {
println!("h_{index} = {h}")
@ -390,12 +386,85 @@ impl ElipticCurve {
}
}
#[pymethods]
impl ElipticCurve {
#[new]
pub fn py_new(field: GalloisField, a: i128, b: i128, verbose: bool) -> PyResult<Self> {
match Self::new(field, a, b, verbose) {
Ok(v) => {return Ok(v)},
Err(e) => {
let py_e = PyValueError::new_err(e.to_string());
return Err(py_e)
}
}
}
#[pyo3(name="new_point")]
pub fn py_new_point(&self, r: u128, s: u128) -> PyResult<ElipticCurvePoint> {
match self.new_point(r, s) {
Ok(v) => {return Ok(v)},
Err(e) => {
let py_e = PyValueError::new_err(e.to_string());
return Err(py_e)
}
}
}
#[pyo3(name="poly")]
pub fn py_poly(&self, x: i128, y: i128) -> i128 {
self.poly(x, y)
}
#[pyo3(name="check_point", signature=(p, verbose = true))]
pub fn py_check_point(&self, p: ElipticCurvePoint, verbose: bool) -> bool {
self.check_point(p, verbose)
}
#[pyo3(name="add")]
pub fn py_add(&self, p1: ElipticCurvePoint, p2: ElipticCurvePoint)
-> PyResult<ElipticCurvePoint> {
match self.add(p1, p2) {
Ok(v) => {return Ok(v)},
Err(e) => {
let py_e = PyValueError::new_err(e.to_string());
return Err(py_e)
}
}
}
#[pyo3(name="neg")]
pub fn py_neg(&self, p: ElipticCurvePoint) -> ElipticCurvePoint {
self.neg(p)
}
#[pyo3(name="mul")]
pub fn py_mul(&self, p1: ElipticCurvePoint, t: u128)
-> PyResult<ElipticCurvePoint> {
match self.mul(p1, t) {
Ok(v) => {return Ok(v)},
Err(e) => {
let py_e = PyValueError::new_err(e.to_string());
return Err(py_e)
}
}
}
fn __str__(&self) -> PyResult<String> {
Ok(format!("{}", self))
}
fn __repr__(&self) -> PyResult<String> {
Ok(format!("{}", self))
}
}
impl std::fmt::Display for ElipticCurve{
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "F(X, Y) = Y² - X³ -{}X - {}", self.a, self.b)
}
}
#[pyclass]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
/// represent a specific eliptic curves point
///
@ -404,21 +473,27 @@ pub struct ElipticCurvePoint {
r: u128,
s: u128,
is_infinity_point: bool,
field: GalloisField,
verbose: bool
}
#[pymethods]
impl ElipticCurvePoint {
#[new]
/// create a new point
pub fn new(r: u128, s: u128, field: GalloisField, verbose: bool) -> ElipticCurvePoint {
pub fn new(r: u128, s: u128) -> ElipticCurvePoint {
ElipticCurvePoint {
r,
s,
is_infinity_point: false,
field,
verbose
}
}
fn __str__(&self) -> PyResult<String> {
Ok(format!("{}", self))
}
fn __repr__(&self) -> PyResult<String> {
Ok(format!("{}", self))
}
}
impl std::fmt::Display for ElipticCurvePoint {
@ -450,33 +525,27 @@ pub mod test {
let ec = ElipticCurve::new(f, -3, 3, true).expect("ec cant be created");
// real points
let p = vec![
ElipticCurvePoint::new(0, 4, f, false),
ElipticCurvePoint::new(0, 9, f, false),
ElipticCurvePoint::new(1, 1, f, false),
ElipticCurvePoint::new(1, 12, f, false),
ElipticCurvePoint::new(4, 4, f, false),
ElipticCurvePoint::new(4, 9, f, false),
ElipticCurvePoint::new(5, 3, f, false),
ElipticCurvePoint::new(5, 10, f, false),
ElipticCurvePoint::new(7, 0, f, false),
ElipticCurvePoint::new(8, 6, f, false),
ElipticCurvePoint::new(9, 4, f, false),
ElipticCurvePoint::new(9, 9, f, false),
ElipticCurvePoint::new(11, 1, f, false),
ElipticCurvePoint::new(11, 12, f, false),
ec.new_point(0, 4 ).unwrap(),
ec.new_point(0, 9 ).unwrap(),
ec.new_point(1, 1 ).unwrap(),
ec.new_point(1, 1 ).unwrap(),
ec.new_point(4, 4 ).unwrap(),
ec.new_point(4, 9 ).unwrap(),
ec.new_point(5, 3 ).unwrap(),
ec.new_point(5, 10 ).unwrap(),
ec.new_point(7, 0 ).unwrap(),
ec.new_point(8, 6 ).unwrap(),
ec.new_point(9, 4 ).unwrap(),
ec.new_point(9, 9 ).unwrap(),
ec.new_point(11, 1 ).unwrap(),
ec.new_point(11, 12 ).unwrap(),
];
// random values, not part of the e, fc.
let np = vec![
ElipticCurvePoint::new(0, 5, f, false),
ElipticCurvePoint::new(1, 9, f, false),
ElipticCurvePoint::new(1, 4, f, false),
ec.new_point(0, 5).unwrap_err(),
ec.new_point(1, 9).unwrap_err(),
ec.new_point(1, 4).unwrap_err(),
];
for i in p {
assert!(ec.clone().check_point(i, true));
}
for i in np {
assert!(!ec.clone().check_point(i, true));
}
}
#[test]

View File

@ -15,12 +15,12 @@
/// License: MIT
/// Source: <https://git.cscherr.de/PlexSheep/plexcryptool/>
use crate::{math::modexp::{self, modular_exponentiation_wrapper}, cplex::printing::seperator, math::modred::modred};
use crate::{math::modexp, cplex::printing::seperator, math::modred::modred};
use core::fmt;
use std::fmt::Debug;
use num::{Integer, NumCast, Signed, Unsigned};
use num::{Integer, NumCast};
use pyo3::{prelude::*, exceptions::PyValueError};
@ -391,6 +391,7 @@ impl GalloisField {
self.cha = i;
return i;
}
}
#[pymethods]
@ -458,6 +459,20 @@ impl GalloisField {
}
panic!("No order was found, but n is not 0 and all possibilities have been tried");
}
fn __str__(&self) -> PyResult<String> {
Ok(format!("{}", self))
}
fn __repr__(&self) -> PyResult<String> {
Ok(format!("{}", self))
}
}
impl std::fmt::Display for GalloisField {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "F_{}", self.base)
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
@ -482,7 +497,7 @@ pub mod test {
assert_eq!(field.reduce::<_, u128>(i as u128), i);
}
let field = GalloisField::new(16, true, None);
let _ = GalloisField::new(16, true, None);
}
#[test]