// Copyright 2018 Chia Network Inc and POA Networks Ltd. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #![deny(unsafe_code)] use num_traits::{One, Zero}; use std::ops::{Mul, MulAssign, Rem, ShlAssign}; pub mod gmp; pub mod gmp_classgroup; pub use self::gmp_classgroup::{ do_compute, ffi::{export_obj, import_obj}, }; pub trait BigNum: Zero + One + Clone + PartialOrd + std::fmt::Debug + Rem + ShlAssign + for<'a> MulAssign<&'a Self> + std::ops::Sub + std::ops::Add + std::convert::From + for<'a> std::convert::From<&'a [u8]> + std::ops::Shl + std::ops::Shr + std::ops::Neg + std::str::FromStr + for<'a> std::ops::Div<&'a Self, Output = Self> + Eq + std::hash::Hash { fn probab_prime(&self, iterations: u32) -> bool; fn setbit(&mut self, offset: usize); fn mod_powm(&mut self, base: &Self, exponent: &Self, modulus: &Self); } pub trait BigNumExt: BigNum { fn frem_u32(&self, modulus: u32) -> u32; fn crem_u16(&mut self, modulus: u16) -> u16; } pub trait ClassGroup: Sized + Clone + for<'a> MulAssign<&'a Self> + for<'a> Mul<&'a Self> + PartialEq + std::fmt::Debug { type BigNum: BigNum; /// Produces a `Self` from `a`, `b`, and a discriminant. fn from_ab_discriminant(a: Self::BigNum, b: Self::BigNum, discriminant: Self::BigNum) -> Self; /// Unmarshals a `Self` from a byte array and discriminant. /// /// The byte array will be in the format of two big-endian byte sequences /// concatenated together. fn from_bytes(bytearray: &[u8], discriminant: Self::BigNum) -> Self; /// Computes the identity element of `Self` for a given discriminant. /// /// If the discriminant is not valid, the result is unspecified. /// /// # Panics /// /// This may panic (but is not required to) if the discriminant is not /// valid. If this function does not panic, the results of future /// operations are unspecified: they will not invoke undefined behavior, /// but may panic, loop forever, or just compute garbage. /// /// In debug builds, this will always panic if the discriminant is invalid. fn identity_for_discriminant(discriminant: Self::BigNum) -> Self { Self::from_ab_discriminant(Self::BigNum::one(), Self::BigNum::one(), discriminant) } /// Serializes `self` to a byte array. Returns `Err(s)` if there /// is not enough space in the buffer. /// /// The data must be serialized in twos-complement, big-endian format. fn serialize(&self, buf: &mut [u8]) -> std::result::Result<(), usize>; /// Deserializes a bignum from raw bytes. The bytes **must** be interpreted /// as a big-endian unsigned integer. fn unsigned_deserialize_bignum(_: &[u8]) -> Self::BigNum; /// Reduce `self` in-place. fn reduce(&mut self); /// Squares `self`, modifying it in-place. /// /// A default implementation is provided, but implementations are suggested /// to override it for performance reasons. fn square(&mut self) { let s = self.clone(); self.mul_assign(&s) } /// Normalize `self`. fn normalize(&mut self); /// The length of `num` in **bits** fn size_in_bits(num: &Self::BigNum) -> usize; /// Gets the discriminant of `self`. fn discriminant(&self) -> &Self::BigNum; /// Computes the identity element of a `ClassGroup`. fn identity(&self) -> Self { Self::identity_for_discriminant(self.discriminant().clone()) } /// Generates a *generator* for the class group of `Self`, given a /// discriminant. /// /// If the discriminant is not valid, the result is unspecified. /// /// # Relation to `Self::identity_for_discriminant` /// /// This is *not* the same as `Self::identity_for_discriminant`: the /// identity element is *never* a generator for *any* group. This follows /// from their definitions: the identity element, when multiplied by another /// element, always gives that other element, whereas *every* element in the /// group is some power of a generator. /// /// # Panics /// /// This may panic (but is not required to) if the discriminant is not /// valid. If this function does not panic, the results of future /// operations are unspecified: they will not invoke undefined behavior, /// but may panic, loop forever, or just compute garbage. /// /// If the global allocator panics on running out of memory, then this /// function may panic in the same situation, but it may also just abort the /// program instead. /// /// In debug builds, this will always panic if the discriminant is invalid. fn generator_for_discriminant(discriminant: Self::BigNum) -> Self { Self::from_ab_discriminant(2.into(), One::one(), discriminant) } /// Replaces `*self` with its inverse. fn inverse(&mut self); /// Squares `self` repeatedly in-place. /// /// Implementors of this trait are encouraged to override this /// with a more efficient implementation, if one exists. fn repeated_square(&mut self, iterations: u64) { for _ in 0..iterations { self.square() } } /// Exponentiation fn pow(&mut self, exponent: Self::BigNum); /// Deserialization fn deserialize(buf: &[u8], discriminant: Self::BigNum) -> Self; } #[cfg(test)] mod test { use std::{ fs::File, io::{BufRead, BufReader}, path::PathBuf, }; use super::{gmp_classgroup::GmpClassGroup, ClassGroup}; use super::gmp::mpz::Mpz; fn split_into_three_pieces(line: &str, c: char) -> [&str; 3] { let mut iter = line.split(c); let fst = iter.next().expect("bad test file"); let snd = iter.next().expect("bad test file"); let thd = iter.next().expect("bad test file"); assert!(iter.next().is_none(), "bad test file"); [fst, snd, thd] } #[test] fn multiplication_is_correct() { let manifest_path = std::env::var("CARGO_MANIFEST_DIR").expect("cargo should have set this"); let mut path = PathBuf::from(&manifest_path); path.push("tests/multiply.txt"); let mut f = BufReader::new(File::open(path).expect("test file missing or unreadable")); let mut buffer = String::new(); loop { let bytes_read = f .read_line(&mut buffer) .expect("could not read from test file"); assert!(bytes_read == buffer.len()); if bytes_read == 0 { break; } if buffer.ends_with('\n') { buffer.pop(); } if buffer.ends_with('\r') { buffer.pop(); } let mut current_discriminant: Option = None; let q: Vec<_> = split_into_three_pieces(&buffer, '|') .iter() .map(|i| { let k = split_into_three_pieces(i, ','); let a = Mpz::from_str_radix(k[0], 10).expect("bad test file"); let b = Mpz::from_str_radix(k[1], 10).expect("bad test file"); let c = Mpz::from_str_radix(k[2], 10).expect("bad test file"); let mut discriminant: Mpz = &b * &b; let mut minuand: Mpz = (4u64).into(); minuand *= &a * &c; discriminant -= &minuand; assert!(discriminant < Mpz::zero()); // takes waaaay too long // assert!(discriminant.probab_prime(20) != // gmp::mpz::ProbabPrimeResult::NotPrime); if let Some(ref q) = current_discriminant { assert_eq!(q, &discriminant, "mismatching discriminant in test files"); } else { current_discriminant = Some(discriminant.clone()); } GmpClassGroup::from_ab_discriminant(a, b, discriminant) }) .collect(); assert_eq!(q.len(), 3); if q[0] == q[1] { let mut i = q[0].clone(); i.square(); assert_eq!(i, q[2]); } assert_eq!(&q[1] * &q[0], q[2], "multiplication not valid"); assert_eq!(&q[0] * &q[1], q[2], "multiplication not valid"); buffer.clear(); } } }