hacky but fixed modular exponentiation

This commit is contained in:
Christoph J. Scherr 2023-05-06 18:17:40 +02:00
parent 937622134b
commit 26fe9ed776
Signed by: PlexSheep
GPG Key ID: 25B4ACF7D88186CC
2 changed files with 75 additions and 28 deletions

View File

@ -19,6 +19,10 @@ struct Cli {
/// Machine output /// Machine output
#[arg(short, long, default_value_t = false, global = true)] #[arg(short, long, default_value_t = false, global = true)]
machine: bool, machine: bool,
/// Verbose output
#[arg(short, long, default_value_t = false, global = true)]
verbose: bool,
} }
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]
@ -79,7 +83,7 @@ pub fn main() {
let b = num_bigint::BigInt::from_str(&mod_exp_args.base.as_str()).expect("could not make bigint"); let b = num_bigint::BigInt::from_str(&mod_exp_args.base.as_str()).expect("could not make bigint");
let e = num_bigint::BigInt::from_str(&mod_exp_args.exp.as_str()).expect("could not make bigint"); let e = num_bigint::BigInt::from_str(&mod_exp_args.exp.as_str()).expect("could not make bigint");
let f = num_bigint::BigInt::from_str(&mod_exp_args.field.as_str()).expect("could not make bigint"); let f = num_bigint::BigInt::from_str(&mod_exp_args.field.as_str()).expect("could not make bigint");
let result = modular_exponentiation(b.clone(), e, f); let result = modular_exponentiation(b.clone(), e, f, args.verbose);
if args.machine { if args.machine {
println!("{}", result) println!("{}", result)
} }

View File

@ -1,9 +1,7 @@
#![allow(dead_code)] #![allow(dead_code)]
use num_bigint::BigInt; use num_bigint::{BigInt, BigUint};
use num_traits::ToPrimitive; use num_traits::ToPrimitive;
use num_traits::FromPrimitive;
use pyo3::exceptions::PyException;
use pyo3::exceptions::PyValueError; use pyo3::exceptions::PyValueError;
use pyo3::prelude::*; use pyo3::prelude::*;
@ -16,48 +14,64 @@ pub fn calc_exp_in_field_lib(
} }
/** /**
* modular exponentiation algorithm with big numbers. * square and multiply
*
* Umwandlung des Exponenten k in die zugehörige Binärdarstellung.
* Ersetzen jeder 0 durch Q und jeder 1 durch QM.
* Nun wird Q als Anweisung zum Quadrieren und M als Anweisung zum Multiplizieren aufgefasst.
* Somit bildet die resultierende Zeichenkette von links nach rechts gelesen eine Vorschrift zur Berechnung von x k .
* Man beginne mit 1, quadriere für jedes gelesene Q das bisherige Zwischenergebnis und
* multipliziere es für jedes gelesene M mit x .
*/ */
pub fn modular_exponentiation( pub fn modular_exponentiation(
base: BigInt, base: BigInt,
orig_exp: BigInt, exp: BigInt,
field: BigInt) -> BigInt { field: BigInt,
let binary_repr = orig_exp.to_bytes_be(); verbose: bool) -> BigInt {
if verbose {
println!("args:\nbase {base}\nexp {exp}\nfield {field}\nverbose {verbose}");
}
let mut instructions: Vec<bool> = bigint_to_bools(exp);
// remove the signing bit
if verbose {
println!("pre instructions {:?}",instructions);
}
let instructions: Vec<bool> = bytes_to_bools(&binary_repr.1); instructions.reverse();
if verbose {
println!("instructions {:?}",instructions);
}
let mut exp = BigInt::from(1); let mut res = base.clone();
for instr in instructions { for instr in instructions {
if instr { if verbose {
println!("current res: {res}");
}
if !instr {
// square // square
exp = (exp.pow(2) * &base) % &field; if verbose {
println!("square");
}
res = res.pow(2) % &field;
} }
else { else {
// square and multiply // square and multiply
exp = exp.pow(2) % &field; if verbose {
println!("square and multiply");
}
res = (res.pow(2) * &base) % &field;
} }
} }
return exp; return res;
} }
#[pyfunction] #[pyfunction]
#[pyo3(name="modular_exponentiation")] #[pyo3(name="modular_exponentiation")]
#[pyo3(signature=(base, orig_exp, field, verbose = false))]
pub fn py_modular_exponentiation( pub fn py_modular_exponentiation(
base: i128, base: i128,
orig_exp: i128, orig_exp: i128,
field: i128) -> PyResult<u128> { field: i128,
verbose: bool) -> PyResult<u128> {
let big_res = modular_exponentiation( let big_res = modular_exponentiation(
BigInt::from(base), BigInt::from(base),
BigInt::from(orig_exp), BigInt::from(orig_exp),
BigInt::from(field) BigInt::from(field),
verbose
); );
let res = big_res.to_u128(); let res = big_res.to_u128();
match res { match res {
@ -71,17 +85,46 @@ pub fn py_modular_exponentiation(
} }
// Vec<u8> to Vec<bool> ( binary representation interpreted otherwise ) /// Dont use this buggy mess
fn bytes_to_bools(bytes: &Vec<u8>) -> Vec<bool> { pub fn binary_exponentiation(base: BigInt, exp: BigInt, verbose: bool) -> BigInt {
if exp.clone() < BigInt::from(0) {
return binary_exponentiation(1/&base, -exp, verbose);
}
else if exp.clone() == BigInt::from(0) {
return BigInt::from(1);
}
else if exp.clone() % 2 == BigInt::from(0) {
return binary_exponentiation(&base*&base, &exp/2, verbose);
}
else if exp.clone() % 2 == BigInt::from(1) {
return binary_exponentiation(&base*&base, (&exp-1)/2, verbose);
}
else {
panic!("I don't know how we got here")
}
}
fn bigint_to_bools(item: BigInt) -> Vec<bool> {
let mut result: Vec<bool> = Vec::new(); let mut result: Vec<bool> = Vec::new();
for byte in bytes { let mut modul : BigInt;
for c in format!("{:b}", byte).chars() { let mut smaller = item;
result.push(c == '1'); loop {
if smaller < BigInt::from(2) {
break;
}
modul = &smaller % BigInt::from(2);
smaller = &smaller / BigInt::from(2);
if modul == BigInt::from(1) {
result.push(true);
}
else {
result.push(false);
} }
} }
result result
} }
fn dump_bin(bytes: &Vec<u8>) { fn dump_bin(bytes: &Vec<u8>) {
for byte in bytes.iter() { for byte in bytes.iter() {
println!("{:#08b}\t| {:#02x}", byte, byte); println!("{:#08b}\t| {:#02x}", byte, byte);