From e9e86af2075463a9ae36c95884346f99be3f9629 Mon Sep 17 00:00:00 2001 From: Cassandra Heart Date: Sat, 18 Jan 2025 17:39:55 -0600 Subject: [PATCH] temporarily stage for osx --- Cargo.lock | 16 + crates/classgroup/Cargo.toml | 3 + crates/classgroup/bench/bench.rs | 2 +- crates/classgroup/build.rs | 36 ++- crates/classgroup/src/gmp/ffi.rs | 2 +- crates/classgroup/src/gmp/mod.rs | 2 +- crates/classgroup/src/gmp/mpz.rs | 321 +++++++++++------- crates/classgroup/src/gmp/sign.rs | 3 +- crates/classgroup/src/gmp/test.rs | 86 ++--- crates/classgroup/src/gmp_classgroup/ffi.rs | 85 ++++- crates/classgroup/src/gmp_classgroup/mod.rs | 33 +- crates/classgroup/src/lib.rs | 6 +- crates/classgroup/src/vdf.cpp | 340 ++++++++++++++++++++ vdf/test.sh | 4 +- vdf/vdf_test.go | 62 ++-- 15 files changed, 769 insertions(+), 232 deletions(-) create mode 100644 crates/classgroup/src/vdf.cpp diff --git a/Cargo.lock b/Cargo.lock index 8cc1928..217bb43 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -328,6 +328,15 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" +[[package]] +name = "cc" +version = "1.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" +dependencies = [ + "shlex", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -456,6 +465,7 @@ checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" name = "classgroup" version = "0.1.0" dependencies = [ + "cc", "criterion 0.5.1", "libc", "num-traits", @@ -1461,6 +1471,12 @@ dependencies = [ "keccak", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "siphasher" version = "0.3.11" diff --git a/crates/classgroup/Cargo.toml b/crates/classgroup/Cargo.toml index 7474010..824e214 100644 --- a/crates/classgroup/Cargo.toml +++ b/crates/classgroup/Cargo.toml @@ -21,6 +21,9 @@ repository = "https://github.com/poanetwork/vdf" license = "Apache-2.0" edition = "2018" +[build-dependencies] +cc = "1.0" + [dependencies] num-traits = "0.2" libc = "0.2" diff --git a/crates/classgroup/bench/bench.rs b/crates/classgroup/bench/bench.rs index 8dc7b22..aac35eb 100644 --- a/crates/classgroup/bench/bench.rs +++ b/crates/classgroup/bench/bench.rs @@ -17,7 +17,7 @@ extern crate criterion; use classgroup::{gmp_classgroup::GmpClassGroup, ClassGroup}; use criterion::Criterion; -use gmp::mpz::Mpz; +use classgroup::gmp::mpz::Mpz; use std::str::FromStr; fn bench_square(c: &mut Criterion) { diff --git a/crates/classgroup/build.rs b/crates/classgroup/build.rs index a4b0529..81951b7 100644 --- a/crates/classgroup/build.rs +++ b/crates/classgroup/build.rs @@ -1,16 +1,48 @@ +use cc; use std::env; fn main() { println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=src/vdf.cpp"); + + println!("cargo:rustc-link-arg=-lgmp"); + println!("cargo:rustc-link-arg=-lflint"); + println!("cargo:rustc-link-arg=-lmpfr"); let target = env::var("TARGET").expect("cargo should have set this"); if target == "aarch64-apple-darwin" { println!("cargo:rustc-link-search=/opt/homebrew/Cellar/gmp/6.3.0/lib"); + println!("cargo:rustc-link-search=/opt/homebrew/Cellar/flint/3.1.3-p1/lib"); + println!("cargo:rustc-link-search=/opt/homebrew/Cellar/mpfr/4.2.1/lib"); } else if target == "aarch64-unknown-linux-gnu" { println!("cargo:rustc-link-search=/usr/lib/aarch64-linux-gnu/"); } else if target == "x86_64-unknown-linux-gnu" { - println!("cargo:rustc-link-search=/usr/lib/x86_64-linux-gnu/"); + println!("cargo:rustc-link-search=/usr/lib/"); } else { panic!("unsupported target {target}"); } -} + if target == "aarch64-apple-darwin" { + cc::Build::new() + .cpp(true) + .file("src/vdf.cpp") + .flag("-I/opt/homebrew/Cellar/gmp/6.3.0/include") + .flag("-I/opt/homebrew/Cellar/flint/3.1.3-p1/include") + .flag("-I/opt/homebrew/Cellar/mpfr/4.2.1/include") + .flag("-L/opt/homebrew/Cellar/gmp/6.3.0/lib") + .flag("-L/opt/homebrew/Cellar/flint/3.1.3-p1/lib") + .flag("-L/opt/homebrew/Cellar/mpfr/4.2.1/lib") + .flag("-lgmp") + .flag("-lflint") + .flag("-lmpfr") + .compile("vdf"); + } else if target == "x86_64-unknown-linux-gnu" { + cc::Build::new() + .cpp(true) + .file("src/vdf.cpp") + .flag("-lflint") + .flag("-lmpfr") + .compile("vdf"); + } else { + panic!("unsupported target {target}"); + } +} \ No newline at end of file diff --git a/crates/classgroup/src/gmp/ffi.rs b/crates/classgroup/src/gmp/ffi.rs index d8cc2b1..116cd4c 100644 --- a/crates/classgroup/src/gmp/ffi.rs +++ b/crates/classgroup/src/gmp/ffi.rs @@ -1,6 +1,6 @@ use super::mpz::*; -#[link(name = "gmp", kind = "static")] +#[link(name = "gmp")] extern "C" { pub fn __gmpz_fdiv_q(q: mpz_ptr, n: mpz_srcptr, d: mpz_srcptr); pub fn __gmpz_cdiv_q(q: mpz_ptr, n: mpz_srcptr, d: mpz_srcptr); diff --git a/crates/classgroup/src/gmp/mod.rs b/crates/classgroup/src/gmp/mod.rs index a03f391..8e55a2c 100644 --- a/crates/classgroup/src/gmp/mod.rs +++ b/crates/classgroup/src/gmp/mod.rs @@ -9,4 +9,4 @@ pub mod mpz; pub mod sign; #[cfg(test)] -mod test; +mod test; \ No newline at end of file diff --git a/crates/classgroup/src/gmp/mpz.rs b/crates/classgroup/src/gmp/mpz.rs index b8a1beb..f98bef9 100644 --- a/crates/classgroup/src/gmp/mpz.rs +++ b/crates/classgroup/src/gmp/mpz.rs @@ -1,16 +1,19 @@ #![allow(unsafe_code)] -use libc::{c_char, c_int, c_long, c_ulong, c_void, c_double, size_t, strnlen}; use super::sign::Sign; +use libc::{c_char, c_double, c_int, c_long, c_ulong, c_void, size_t, strnlen}; +use num_traits::{One, Zero}; +use std::cmp::Ordering::{self, Equal, Greater, Less}; use std::convert::From; -use std::mem::{uninitialized,size_of}; -use std::{fmt, hash}; -use std::cmp::Ordering::{self, Greater, Less, Equal}; -use std::str::FromStr; use std::error::Error; -use std::ops::{Div, DivAssign, Mul, MulAssign, Add, AddAssign, Sub, SubAssign, Neg, Not, Shl, ShlAssign, Shr, ShrAssign, BitXor, BitXorAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, Rem, RemAssign}; use std::ffi::CString; -use std::{u32, i32, usize}; -use num_traits::{Zero, One}; +use std::mem::{size_of, uninitialized}; +use std::ops::{ + Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign, + Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign, +}; +use std::str::FromStr; +use std::{fmt, hash}; +use std::{i32, u32, usize}; use super::ffi::*; @@ -18,7 +21,7 @@ use super::ffi::*; pub struct mpz_struct { _mp_alloc: c_int, _mp_size: c_int, - _mp_d: *mut c_void + _mp_d: *mut c_void, } pub type mp_limb_t = usize; // TODO: Find a way to use __gmp_bits_per_limb instead. @@ -26,7 +29,7 @@ pub type mp_bitcnt_t = c_ulong; pub type mpz_srcptr = *const mpz_struct; pub type mpz_ptr = *mut mpz_struct; -#[link(name = "gmp", kind = "static")] +#[link(name = "gmp")] extern "C" { static __gmp_bits_per_limb: c_int; fn __gmpz_init(x: mpz_ptr); @@ -48,8 +51,12 @@ extern "C" { fn __gmpz_cmp(op1: mpz_srcptr, op2: mpz_srcptr) -> c_int; fn __gmpz_cmp_ui(op1: mpz_srcptr, op2: c_ulong) -> c_int; fn __gmpz_add(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr); + fn __gmpz_addmul(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr); fn __gmpz_add_ui(rop: mpz_ptr, op1: mpz_srcptr, op2: c_ulong); fn __gmpz_sub(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr); + fn __gmpz_submul(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr); + fn __gmpz_cmpabs(by: mpz_ptr, l: mpz_srcptr); + fn __gmpz_divexact(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr); fn __gmpz_sub_ui(rop: mpz_ptr, op1: mpz_srcptr, op2: c_ulong); fn __gmpz_ui_sub(rop: mpz_ptr, op1: c_ulong, op2: mpz_srcptr); fn __gmpz_mul(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr); @@ -86,10 +93,24 @@ extern "C" { fn __gmpz_gcdext(g: mpz_ptr, s: mpz_ptr, t: mpz_ptr, a: mpz_srcptr, b: mpz_srcptr); fn __gmpz_lcm(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr); fn __gmpz_invert(rop: mpz_ptr, op1: mpz_srcptr, op2: mpz_srcptr) -> c_int; - fn __gmpz_import(rop: mpz_ptr, count: size_t, order: c_int, size: size_t, - endian: c_int, nails: size_t, op: *const c_void); - fn __gmpz_export(rop: *mut c_void, countp: *mut size_t, order: c_int, size: size_t, - endian: c_int, nails: size_t, op: mpz_srcptr); + fn __gmpz_import( + rop: mpz_ptr, + count: size_t, + order: c_int, + size: size_t, + endian: c_int, + nails: size_t, + op: *const c_void, + ); + fn __gmpz_export( + rop: *mut c_void, + countp: *mut size_t, + order: c_int, + size: size_t, + endian: c_int, + nails: size_t, + op: mpz_srcptr, + ); fn __gmpz_root(rop: mpz_ptr, op: mpz_srcptr, n: c_ulong) -> c_int; fn __gmpz_sqrt(rop: mpz_ptr, op: mpz_srcptr); fn __gmpz_millerrabin(n: mpz_srcptr, reps: c_int) -> c_int; @@ -100,11 +121,13 @@ pub struct Mpz { mpz: mpz_struct, } -unsafe impl Send for Mpz { } -unsafe impl Sync for Mpz { } +unsafe impl Send for Mpz {} +unsafe impl Sync for Mpz {} impl Drop for Mpz { - fn drop(&mut self) { unsafe { __gmpz_clear(&mut self.mpz) } } + fn drop(&mut self) { + unsafe { __gmpz_clear(&mut self.mpz) } + } } /// The result of running probab_prime @@ -112,7 +135,7 @@ impl Drop for Mpz { pub enum ProbabPrimeResult { NotPrime, ProbablyPrime, - Prime + Prime, } impl Mpz { @@ -153,9 +176,7 @@ impl Mpz { #[inline] pub fn size_in_base(&self, base: u8) -> usize { - unsafe { - __gmpz_sizeinbase(&self.mpz, base as c_int) as usize - } + unsafe { __gmpz_sizeinbase(&self.mpz, base as c_int) as usize } } // TODO: fail on an invalid base @@ -260,11 +281,9 @@ impl Mpz { /// Determine whether n is prime. /// - /// This function performs some trial divisions, then reps Miller-Rabin probabilistic primality tests. A higher reps value will reduce the chances of a non-prime being identified as “probably prime”. A composite number will be identified as a prime with a probability of less than 4^(-reps). Reasonable values of reps are between 15 and 50. + /// This function performs some trial divisions, then reps Miller-Rabin probabilistic primality tests. A higher reps value will reduce the chances of a non-prime being identified as “probably prime”. A composite number will be identified as a prime with a probability of less than 4^(-reps). Reasonable values of reps are between 15 and 50. pub fn probab_prime(&self, reps: i32) -> ProbabPrimeResult { - match unsafe { - __gmpz_probab_prime_p(&self.mpz, reps as c_int) as u8 - } { + match unsafe { __gmpz_probab_prime_p(&self.mpz, reps as c_int) as u8 } { 2 => ProbabPrimeResult::Prime, 1 => ProbabPrimeResult::ProbablyPrime, 0 => ProbabPrimeResult::NotPrime, @@ -296,8 +315,7 @@ impl Mpz { let mut g = Mpz::new(); let mut s = Mpz::new(); let mut t = Mpz::new(); - __gmpz_gcdext(&mut g.mpz, &mut s.mpz, &mut t.mpz, - &self.mpz, &other.mpz); + __gmpz_gcdext(&mut g.mpz, &mut s.mpz, &mut t.mpz, &self.mpz, &other.mpz); (g, s, t) } } @@ -313,9 +331,7 @@ impl Mpz { #[inline] pub fn is_multiple_of(&self, other: &Mpz) -> bool { - unsafe { - __gmpz_divisible_p(&self.mpz, &other.mpz) != 0 - } + unsafe { __gmpz_divisible_p(&self.mpz, &other.mpz) != 0 } } #[inline] @@ -378,14 +394,14 @@ impl Mpz { res } } - + #[inline] pub fn ui_pow_ui(x: u32, y: u32) -> Mpz { - unsafe { - let mut res = Mpz::new(); - __gmpz_ui_pow_ui(&mut res.mpz, x as c_ulong, y as c_ulong); - res - } + unsafe { + let mut res = Mpz::new(); + __gmpz_ui_pow_ui(&mut res.mpz, x as c_ulong, y as c_ulong); + res + } } #[inline] @@ -417,10 +433,9 @@ impl Mpz { assert!(self.mpz._mp_size >= 0); unsafe { let mut res = Mpz::new(); - let _perfect_root - = match __gmpz_root(&mut res.mpz, &self.mpz, n as c_ulong) { - 0 => false, - _ => true, + let _perfect_root = match __gmpz_root(&mut res.mpz, &self.mpz, n as c_ulong) { + 0 => false, + _ => true, }; // TODO: consider returning `_perfect_root` res @@ -437,9 +452,7 @@ impl Mpz { } pub fn millerrabin(&self, reps: i32) -> i32 { - unsafe { - __gmpz_millerrabin(&self.mpz, reps as c_int) - } + unsafe { __gmpz_millerrabin(&self.mpz, reps as c_int) } } pub fn sign(&self) -> Sign { @@ -461,7 +474,9 @@ impl Mpz { } } - pub fn zero() -> Mpz { Mpz::new() } + pub fn zero() -> Mpz { + Mpz::new() + } pub fn is_zero(&self) -> bool { self.mpz._mp_size == 0 @@ -470,7 +485,7 @@ impl Mpz { #[derive(Debug)] pub struct ParseMpzError { - _priv: () + _priv: (), } impl fmt::Display for ParseMpzError { @@ -499,7 +514,7 @@ impl Clone for Mpz { } } -impl Eq for Mpz { } +impl Eq for Mpz {} impl PartialEq for Mpz { fn eq(&self, other: &Mpz) -> bool { @@ -530,43 +545,45 @@ impl PartialOrd for Mpz { // This macro inserts a guard against division by 0 for Div and Rem implementations macro_rules! div_guard { - (Div, $is_zero: expr) => { - if $is_zero { + (Div, $is_zero: expr) => { + if $is_zero { panic!("divide by zero") - } - }; - (Rem, $is_zero: expr) => { - if $is_zero { + } + }; + (Rem, $is_zero: expr) => { + if $is_zero { panic!("divide by zero") - } - }; - ($tr: ident, $is_zero: expr) => {} + } + }; + ($tr: ident, $is_zero: expr) => {}; } // On Windows c_long and c_ulong are only 32-bit - in order to implement operations for // 64-bit types we need some workarounds macro_rules! bit_guard { - (u64, $what: ident, $e1: expr, $e2: expr) => ( - if size_of::() == 8 || $what <= u32::MAX as u64 { + (u64, $what: ident, $e1: expr, $e2: expr) => { + if size_of::() == 8 || $what <= u32::MAX as u64 { $e1 + } else { + $e2 } - else { - $e2 - } - ); - - (i64, $what: ident, $e1: expr, $e2: expr) => ( - if size_of::() == 8 || $what <= i32::MAX as i64 { + }; + + (i64, $what: ident, $e1: expr, $e2: expr) => { + if size_of::() == 8 || $what <= i32::MAX as i64 { $e1 + } else { + $e2 } - else { - $e2 - } - ); - - (u32, $what: ident, $e1: expr, $e2: expr) => ($e1); - - (i32, $what: ident, $e1: expr, $e2: expr) => ($e1); + }; + + (u32, $what: ident, $e1: expr, $e2: expr) => { + $e1 + }; + + (i32, $what: ident, $e1: expr, $e2: expr) => { + $e1 + }; } macro_rules! impl_oper { @@ -578,7 +595,7 @@ macro_rules! impl_oper { self.$meth(&other) } } - + impl<'a> $tr<&'a Mpz> for Mpz { type Output = Mpz; #[inline] @@ -587,7 +604,7 @@ macro_rules! impl_oper { self } } - + impl<'a> $tr for &'a Mpz { type Output = Mpz; #[inline] @@ -599,7 +616,7 @@ macro_rules! impl_oper { } } } - + impl<'a, 'b> $tr<&'b Mpz> for &'a Mpz { type Output = Mpz; fn $meth(self, other: &Mpz) -> Mpz { @@ -611,14 +628,14 @@ macro_rules! impl_oper { } } } - + impl $tr_assign for Mpz { #[inline] fn $meth_assign(&mut self, other: Mpz) { self.$meth_assign(&other) } } - + impl<'a> $tr_assign<&'a Mpz> for Mpz { #[inline] fn $meth_assign(&mut self, other: &Mpz) { @@ -629,10 +646,10 @@ macro_rules! impl_oper { } } }; - + (both $num: ident, $cnum: ident, $tr: ident, $meth: ident, $tr_assign: ident, $meth_assign: ident, $fun: ident) => { impl_oper!(normal $num, $cnum, $tr, $meth, $tr_assign, $meth_assign, $fun); - + impl $tr for $num { type Output = Mpz; #[inline] @@ -645,7 +662,7 @@ macro_rules! impl_oper { } } } - + impl<'a> $tr<&'a Mpz> for $num { type Output = Mpz; fn $meth(self, other: &'a Mpz) -> Mpz { @@ -659,7 +676,7 @@ macro_rules! impl_oper { } } }; - + (normal $num: ident, $cnum: ident, $tr: ident, $meth: ident, $tr_assign: ident, $meth_assign: ident, $fun: ident) => { impl $tr<$num> for Mpz { type Output = Mpz; @@ -669,7 +686,7 @@ macro_rules! impl_oper { self } } - + impl<'a> $tr<$num> for &'a Mpz { type Output = Mpz; fn $meth(self, other: $num) -> Mpz { @@ -683,7 +700,7 @@ macro_rules! impl_oper { } } } - + impl $tr_assign<$num> for Mpz { #[inline] fn $meth_assign(&mut self, other: $num) { @@ -696,7 +713,7 @@ macro_rules! impl_oper { } } }; - + (reverse $num: ident, $cnum: ident, $tr: ident, $meth: ident, $fun: ident) => { impl $tr for $num { type Output = Mpz; @@ -710,7 +727,7 @@ macro_rules! impl_oper { } } } - + impl<'a> $tr<&'a Mpz> for $num { type Output = Mpz; fn $meth(self, other: &'a Mpz) -> Mpz { @@ -724,7 +741,7 @@ macro_rules! impl_oper { } } }; - + } impl_oper!(Add, add, AddAssign, add_assign, __gmpz_add); @@ -732,7 +749,7 @@ impl_oper!(both u64, c_ulong, Add, add, AddAssign, add_assign, __gmpz_add_ui); impl_oper!(Sub, sub, SubAssign, sub_assign, __gmpz_sub); impl_oper!(normal u64, c_ulong, Sub, sub, SubAssign, sub_assign, __gmpz_sub_ui); -impl_oper!(reverse u64, c_ulong, Sub, sub, __gmpz_ui_sub); +impl_oper!(reverse u64, c_ulong, Sub, sub, __gmpz_ui_sub); impl_oper!(Mul, mul, MulAssign, mul_assign, __gmpz_mul); impl_oper!(both i64, c_long, Mul, mul, MulAssign, mul_assign, __gmpz_mul_si); @@ -794,8 +811,16 @@ impl<'b> From<&'b Mpz> for Vec { unsafe { let bit_size = size_of::() * 8; let size = (__gmpz_sizeinbase(&other.mpz, 2) + bit_size - 1) / bit_size; - let mut result: Vec = vec!(0; size); - __gmpz_export(result.as_mut_ptr() as *mut c_void, 0 as *mut size_t, 1, size_of::() as size_t, 0, 0, &other.mpz); + let mut result: Vec = vec![0; size]; + __gmpz_export( + result.as_mut_ptr() as *mut c_void, + 0 as *mut size_t, + 1, + size_of::() as size_t, + 0, + 0, + &other.mpz, + ); result } } @@ -814,8 +839,16 @@ impl<'b> From<&'b Mpz> for Option { } if __gmpz_sizeinbase(&to_export.mpz, 2) <= 63 { - let mut result : i64 = 0; - __gmpz_export(&mut result as *mut i64 as *mut c_void, 0 as *mut size_t, -1, size_of::() as size_t, 0, 0, &to_export.mpz); + let mut result: i64 = 0; + __gmpz_export( + &mut result as *mut i64 as *mut c_void, + 0 as *mut size_t, + -1, + size_of::() as size_t, + 0, + 0, + &to_export.mpz, + ); if negative { Some(result ^ -1i64) } else { @@ -832,8 +865,16 @@ impl<'b> From<&'b Mpz> for Option { fn from(other: &Mpz) -> Option { unsafe { if __gmpz_sizeinbase(&other.mpz, 2) <= 64 && other.mpz._mp_size >= 0 { - let mut result : u64 = 0; - __gmpz_export(&mut result as *mut u64 as *mut c_void, 0 as *mut size_t, -1, size_of::() as size_t, 0, 0, &other.mpz); + let mut result: u64 = 0; + __gmpz_export( + &mut result as *mut u64 as *mut c_void, + 0 as *mut size_t, + -1, + size_of::() as size_t, + 0, + 0, + &other.mpz, + ); Some(result) } else { None @@ -844,9 +885,7 @@ impl<'b> From<&'b Mpz> for Option { impl<'a> From<&'a Mpz> for f64 { fn from(other: &Mpz) -> f64 { - unsafe { - __gmpz_get_d(&other.mpz) as f64 - } + unsafe { __gmpz_get_d(&other.mpz) as f64 } } } @@ -854,8 +893,15 @@ impl<'a> From<&'a [u8]> for Mpz { fn from(other: &'a [u8]) -> Mpz { unsafe { let mut res = Mpz::new(); - __gmpz_import(&mut res.mpz, other.len(), 1, size_of::() as size_t, - 0, 0, other.as_ptr() as *const c_void); + __gmpz_import( + &mut res.mpz, + other.len(), + 1, + size_of::() as size_t, + 0, + 0, + other.as_ptr() as *const c_void, + ); res } } @@ -865,8 +911,15 @@ impl From for Mpz { fn from(other: u64) -> Mpz { unsafe { let mut res = Mpz::new(); - __gmpz_import(&mut res.mpz, 1, -1, size_of::() as size_t, 0, 0, - &other as *const u64 as *const c_void); + __gmpz_import( + &mut res.mpz, + 1, + -1, + size_of::() as size_t, + 0, + 0, + &other as *const u64 as *const c_void, + ); res } } @@ -876,8 +929,15 @@ impl From for Mpz { fn from(other: u32) -> Mpz { unsafe { let mut res = Mpz::new(); - __gmpz_import(&mut res.mpz, 1, -1, size_of::() as size_t, 0, 0, - &other as *const u32 as *const c_void); + __gmpz_import( + &mut res.mpz, + 1, + -1, + size_of::() as size_t, + 0, + 0, + &other as *const u32 as *const c_void, + ); res } } @@ -889,12 +949,26 @@ impl From for Mpz { let mut res = Mpz::new(); if other.is_negative() { - __gmpz_import(&mut res.mpz, 1, -1, size_of::() as size_t, 0, 0, - &(other ^ -1i64) as *const i64 as *const c_void); + __gmpz_import( + &mut res.mpz, + 1, + -1, + size_of::() as size_t, + 0, + 0, + &(other ^ -1i64) as *const i64 as *const c_void, + ); __gmpz_com(&mut res.mpz, &res.mpz); } else { - __gmpz_import(&mut res.mpz, 1, -1, size_of::() as size_t, 0, 0, - &other as *const i64 as *const c_void); + __gmpz_import( + &mut res.mpz, + 1, + -1, + size_of::() as size_t, + 0, + 0, + &other as *const i64 as *const c_void, + ); } res } @@ -907,12 +981,26 @@ impl From for Mpz { let mut res = Mpz::new(); if other.is_negative() { - __gmpz_import(&mut res.mpz, 1, -1, size_of::() as size_t, 0, 0, - &(other ^ -1i32) as *const i32 as *const c_void); + __gmpz_import( + &mut res.mpz, + 1, + -1, + size_of::() as size_t, + 0, + 0, + &(other ^ -1i32) as *const i32 as *const c_void, + ); __gmpz_com(&mut res.mpz, &res.mpz); } else { - __gmpz_import(&mut res.mpz, 1, -1, size_of::() as size_t, 0, 0, - &other as *const i32 as *const c_void); + __gmpz_import( + &mut res.mpz, + 1, + -1, + size_of::() as size_t, + 0, + 0, + &other as *const i32 as *const c_void, + ); } res } @@ -1005,11 +1093,11 @@ impl fmt::Debug for Mpz { impl hash::Hash for Mpz { fn hash(&self, state: &mut S) { unsafe { - for i in 0..self.mpz._mp_size.abs() { - let limb = self.mpz._mp_d as *const mp_limb_t; - let limb = *(limb.offset(i as isize)); - limb.hash(state); - } + for i in 0..self.mpz._mp_size.abs() { + let limb = self.mpz._mp_d as *const mp_limb_t; + let limb = *(limb.offset(i as isize)); + limb.hash(state); + } } } } @@ -1031,5 +1119,4 @@ impl One for Mpz { fn one() -> Mpz { Mpz::one() } -} - +} \ No newline at end of file diff --git a/crates/classgroup/src/gmp/sign.rs b/crates/classgroup/src/gmp/sign.rs index 660b2b4..4ec2f85 100644 --- a/crates/classgroup/src/gmp/sign.rs +++ b/crates/classgroup/src/gmp/sign.rs @@ -3,5 +3,4 @@ pub enum Sign { Negative, Zero, Positive, -} - +} \ No newline at end of file diff --git a/crates/classgroup/src/gmp/test.rs b/crates/classgroup/src/gmp/test.rs index 8036386..91e734c 100644 --- a/crates/classgroup/src/gmp/test.rs +++ b/crates/classgroup/src/gmp/test.rs @@ -1,8 +1,8 @@ use super::mpz::mp_limb_t; -use std; use libc::c_int; +use std; -#[link(name = "gmp", kind = "static")] +#[link(name = "gmp")] extern "C" { static __gmp_bits_per_limb: c_int; } @@ -11,20 +11,21 @@ extern "C" { #[allow(unsafe_code)] fn test_limb_size() { // We are assuming that the limb size is the same as the pointer size. - assert_eq!(std::mem::size_of::() * 8, - unsafe { __gmp_bits_per_limb as usize }); + assert_eq!(std::mem::size_of::() * 8, unsafe { + __gmp_bits_per_limb as usize + }); } mod mpz { use super::super::mpz::Mpz; use super::super::mpz::ProbabPrimeResult; use super::super::sign::Sign; - use std::str::FromStr; use std::convert::{From, Into}; + use std::str::FromStr; use std::{i64, u64}; - use std::hash::{Hash, Hasher}; use std::collections::hash_map::DefaultHasher; + use std::hash::{Hash, Hasher}; #[test] fn test_set() { @@ -127,35 +128,35 @@ mod mpz { assert!((&x % -&y).to_string() == (20i32 % -3).to_string()); assert!((-&x % &y).to_string() == (-20i32 % 3).to_string()); } - + #[test] fn test_add() { - let x: Mpz = From::::from(2); - let y: Mpz = From::::from(3); - let str5 = 5i32.to_string(); - assert!((&x + &y).to_string() == str5); - assert!((&x + 3).to_string() == str5); - assert!((&y + 2).to_string() == str5); + let x: Mpz = From::::from(2); + let y: Mpz = From::::from(3); + let str5 = 5i32.to_string(); + assert!((&x + &y).to_string() == str5); + assert!((&x + 3).to_string() == str5); + assert!((&y + 2).to_string() == str5); } - + #[test] fn test_sub() { - let x: Mpz = From::::from(2); - let y: Mpz = From::::from(3); - assert!((&x - &y).to_string() == (-1i32).to_string()); - assert!((&y - &x).to_string() == 1i32.to_string()); - assert!((&y - 8).to_string() == (-5i32).to_string()); + let x: Mpz = From::::from(2); + let y: Mpz = From::::from(3); + assert!((&x - &y).to_string() == (-1i32).to_string()); + assert!((&y - &x).to_string() == 1i32.to_string()); + assert!((&y - 8).to_string() == (-5i32).to_string()); } - + #[test] fn test_mul() { - let x: Mpz = From::::from(2); - let y: Mpz = From::::from(3); - assert!((&x * &y).to_string() == 6i32.to_string()); - assert!((&x * 3i64).to_string() == 6i32.to_string()); - assert!((&y * -5i64).to_string() == (-15i32).to_string()); - // check with values not fitting in 32 bits - assert!((&x * 5000000000i64).to_string() == 10000000000i64.to_string()); + let x: Mpz = From::::from(2); + let y: Mpz = From::::from(3); + assert!((&x * &y).to_string() == 6i32.to_string()); + assert!((&x * 3i64).to_string() == 6i32.to_string()); + assert!((&y * -5i64).to_string() == (-15i32).to_string()); + // check with values not fitting in 32 bits + assert!((&x * 5000000000i64).to_string() == 10000000000i64.to_string()); } #[test] @@ -194,7 +195,7 @@ mod mpz { #[test] fn test_from_slice_u8() { - let v: Vec = vec!(255, 255); + let v: Vec = vec![255, 255]; let x: Mpz = From::from(&v[..]); assert!(x.to_string() == "65535".to_string()); } @@ -336,7 +337,7 @@ mod mpz { fn test_probab_prime() { let prime: Mpz = From::::from(2); assert!(prime.probab_prime(15) == ProbabPrimeResult::Prime); - + let not_prime: Mpz = From::::from(4); assert!(not_prime.probab_prime(15) == ProbabPrimeResult::NotPrime); } @@ -367,7 +368,7 @@ mod mpz { let twentyfour: Mpz = From::::from(24); let (g, s, t) = eighteen.gcdext(&twentyfour); assert!(g == six); - assert!(g == s*eighteen + t*twentyfour); + assert!(g == s * eighteen + t * twentyfour); } #[test] @@ -429,10 +430,10 @@ mod mpz { fn test_bit_fiddling() { let mut xs: Mpz = From::::from(0b1010_1000_0010_0011); assert!(xs.bit_length() == 16); - let mut ys = [true, false, true, false, - true, false, false, false, - false, false, true, false, - false, false, true, true]; + let mut ys = [ + true, false, true, false, true, false, false, false, false, false, true, false, false, + false, true, true, + ]; ys.reverse(); for i in 0..xs.bit_length() { assert!(xs.tstbit(i) == ys[i]); @@ -474,7 +475,7 @@ mod mpz { let one: Mpz = From::::from(1); let two = &one + &one; - let hash = |x : &Mpz| { + let hash = |x: &Mpz| { let mut hasher = DefaultHasher::new(); x.hash(&mut hasher); hasher.finish() @@ -486,13 +487,11 @@ mod mpz { #[test] fn test_hash_long() { - let a = Mpz::from_str_radix("348917329847193287498312749187234192387", 10) - .unwrap(); - let b = Mpz::from_str_radix("348917329847193287498312749187234192386", 10) - .unwrap(); + let a = Mpz::from_str_radix("348917329847193287498312749187234192387", 10).unwrap(); + let b = Mpz::from_str_radix("348917329847193287498312749187234192386", 10).unwrap(); let one: Mpz = From::::from(1); - let hash = |x : &Mpz| { + let hash = |x: &Mpz| { let mut hasher = DefaultHasher::new(); x.hash(&mut hasher); hasher.finish() @@ -519,7 +518,10 @@ mod mpz { assert_eq!(Into::>::into(&one), vec!(1u8)); assert_eq!(Into::>::into(&five), vec!(5u8)); assert_eq!(Into::>::into(&xffff), vec!(255u8, 255u8)); - assert_eq!(Into::>::into(&max_u64), vec!(255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8)); + assert_eq!( + Into::>::into(&max_u64), + vec!(255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8) + ); } #[test] @@ -579,4 +581,4 @@ mod mpz { let zero = Mpz::from(-51213); assert_eq!(format!("{}", zero), "-51213"); } -} +} \ No newline at end of file diff --git a/crates/classgroup/src/gmp_classgroup/ffi.rs b/crates/classgroup/src/gmp_classgroup/ffi.rs index 7e7b31f..76d94d2 100644 --- a/crates/classgroup/src/gmp_classgroup/ffi.rs +++ b/crates/classgroup/src/gmp_classgroup/ffi.rs @@ -24,7 +24,11 @@ use libc::{c_int, c_long, c_ulong, c_void, size_t}; // pub use c_ulong; use std::{mem, usize}; // We use the unsafe versions to avoid unecessary allocations. -#[link(name = "gmp", kind = "static")] +extern "C" { + fn adapted_nudupl(a: *mut Mpz, b: *mut Mpz, c: *mut Mpz, times: c_ulong); +} +// We use the unsafe versions to avoid unecessary allocations. +#[link(name = "gmp")] extern "C" { fn __gmpz_gcdext(gcd: *mut Mpz, s: *mut Mpz, t: *mut Mpz, a: *const Mpz, b: *const Mpz); fn __gmpz_gcd(rop: *mut Mpz, op1: *const Mpz, op2: *const Mpz); @@ -33,8 +37,18 @@ extern "C" { fn __gmpz_divexact(q: *mut Mpz, n: *const Mpz, d: *const Mpz); fn __gmpz_tdiv_q(q: *mut Mpz, n: *const Mpz, d: *const Mpz); fn __gmpz_mul(p: *mut Mpz, a: *const Mpz, b: *const Mpz); + fn __gmpz_mod(p: *mut Mpz, a: *const Mpz, b: *const Mpz); + fn __gmpz_neg(rop: *mut Mpz, op: *const Mpz); + fn __gmpz_mul_ui(p: *mut Mpz, a: *const Mpz, b: c_ulong); + fn __gmpz_addmul(rop: *mut Mpz, op1: *const Mpz, op2: *const Mpz); + fn __gmpz_set(rop: *mut Mpz, op: *const Mpz); + //fn __fmpz_set_mpz(rop: *mut Mpz, op: *const Mpz); + //fn __fmpz_get_mpz(rop: *mut Mpz, op: *const Mpz); + fn __gmpz_cmpabs(rop: *const Mpz, op: *const Mpz) -> usize; + //fn __gmpz_sgn(rop: *const Mpz) -> usize; fn __gmpz_mul_2exp(rop: *mut Mpz, op1: *const Mpz, op2: mp_bitcnt_t); fn __gmpz_sub(rop: *mut Mpz, op1: *const Mpz, op2: *const Mpz); + fn __gmpz_submul(rop: *mut Mpz, op1: *const Mpz, op2: *const Mpz); fn __gmpz_import( rop: *mut Mpz, count: size_t, @@ -114,6 +128,16 @@ pub fn mpz_gcdext(gcd: &mut Mpz, s: &mut Mpz, t: &mut Mpz, a: &Mpz, b: &Mpz) { unsafe { __gmpz_gcdext(gcd, s, t, a, b) } } +//#[inline] +//pub fn fmpz_xgcd_partial(gcd: &mut Mpz, s: &mut Mpz, t: &mut Mpz, a: &Mpz, b: &Mpz) { +// unsafe { __fmpz_xgcd_partial(gcd, s, t, a, b) } +//} + +#[inline] +pub fn mpz_gcdext_null(gcd: &mut Mpz, s: &mut Mpz, a: &Mpz, b: &Mpz) { + unsafe { __gmpz_gcdext(gcd, s, std::ptr::null_mut(), a, b) } +} + /// Doubles `rop` in-place #[inline] pub fn mpz_double(rop: &mut Mpz) { @@ -185,6 +209,63 @@ pub fn mpz_mul(rop: &mut Mpz, op1: &Mpz, op2: &Mpz) { unsafe { __gmpz_mul(rop, op1, op2) } } +#[inline] +pub fn mpz_mod(rop: &mut Mpz, op1: &Mpz, op2: &Mpz) { + unsafe { __gmpz_mod(rop, op1, op2) } +} + +#[inline] +pub fn mpz_submul(rop: &mut Mpz, op1: &Mpz, op2: *const Mpz) { + unsafe { __gmpz_submul(rop, op1, op2) } +} + +#[inline] +pub fn mpz_addmul(rop: &mut Mpz, op1: &Mpz, op2: *const Mpz) { + unsafe { __gmpz_addmul(rop, op1, op2) } +} + +#[inline] +pub fn mpz_mul_ui(rop: &mut Mpz, op1: &Mpz, op2: u64) { + unsafe { __gmpz_mul_ui(rop, op1, op2) } +} + +//#[inline] +//pub fn mpz_sgn(rop: &Mpz) -> usize { +// unsafe { __gmpz_sgn(rop) } +//} + +#[inline] +pub fn gmp_nudupl(a: &mut Mpz, b: &mut Mpz, c: &mut Mpz, times: u64) { + unsafe { + adapted_nudupl(a, b, c, times); + } +} + +#[inline] +pub fn mpz_cmpabs(rop: &Mpz, op1: &Mpz) -> usize { + unsafe { __gmpz_cmpabs(rop, op1) } +} + +//#[inline] +//pub fn fmpz_get_mpz(rop: &mut Mpz, op1: &Mpz) { +// unsafe { __fmpz_get_mpz(rop, op1) } +//} +// +//#[inline] +//pub fn fmpz_set_mpz(rop: &mut Mpz, op1: &Mpz) { +// unsafe { __fmpz_set_mpz(rop, op1) } +//} + +#[inline] +pub fn mpz_set(rop: &mut Mpz, op1: &Mpz) { + unsafe { __gmpz_set(rop, op1) } +} + +#[inline] +pub fn mpz_neg(rop: &mut Mpz, op1: &Mpz) { + unsafe { __gmpz_neg(rop, op1) } +} + #[inline] pub fn mpz_divexact(q: &mut Mpz, n: &Mpz, d: &Mpz) { unsafe { __gmpz_divexact(q, n, d) } @@ -337,4 +418,4 @@ mod test { assert_eq!(mpz_crem_u16(&(-100i64).into(), 3), 1); assert_eq!(mpz_crem_u16(&(100i64).into(), 3), 2); } -} +} \ No newline at end of file diff --git a/crates/classgroup/src/gmp_classgroup/mod.rs b/crates/classgroup/src/gmp_classgroup/mod.rs index f89d8b9..1d57ea4 100644 --- a/crates/classgroup/src/gmp_classgroup/mod.rs +++ b/crates/classgroup/src/gmp_classgroup/mod.rs @@ -219,6 +219,7 @@ impl GmpClassGroup { self.assert_valid(); } + #[cfg_attr(not(debug_assertions), inline(always))] fn inner_reduce(&mut self, ctx: &mut Ctx) { self.inner_normalize(ctx); @@ -258,32 +259,10 @@ impl GmpClassGroup { self.inner_normalize(ctx); } + #[cfg_attr(not(debug_assertions), inline(always))] fn inner_square_impl(&mut self, ctx: &mut Ctx) { self.assert_valid(); - ctx.congruence_context.solve_linear_congruence( - &mut ctx.mu, - None, - &self.b, - &self.c, - &self.a, - ); - ffi::mpz_mul(&mut ctx.m, &self.b, &ctx.mu); - ctx.m -= &self.c; - ctx.m = ctx.m.div_floor(&self.a); - - // New a - ctx.old_a.set(&self.a); - ffi::mpz_mul(&mut self.a, &ctx.old_a, &ctx.old_a); - - // New b - ffi::mpz_mul(&mut ctx.a, &ctx.mu, &ctx.old_a); - ffi::mpz_double(&mut ctx.a); - self.b -= &ctx.a; - - // New c - ffi::mpz_mul(&mut self.c, &ctx.mu, &ctx.mu); - self.c -= &ctx.m; - self.inner_reduce(ctx); + ffi::gmp_nudupl(&mut self.a, &mut self.b, &mut self.c, 1); } #[cfg_attr(not(debug_assertions), inline(always))] @@ -482,9 +461,7 @@ impl ClassGroup for GmpClassGroup { /// Panics if called within the scope of a call to `with_context`. fn repeated_square(&mut self, iterations: u64) { Self::with_context(|ctx| { - for _ in 0..iterations { - self.inner_square(ctx) - } + ffi::gmp_nudupl(&mut self.a, &mut self.b, &mut self.c, iterations); }) } @@ -587,4 +564,4 @@ mod test { s.normalize(); assert_eq!(s, new); } -} +} \ No newline at end of file diff --git a/crates/classgroup/src/lib.rs b/crates/classgroup/src/lib.rs index 8da546b..8fb6276 100644 --- a/crates/classgroup/src/lib.rs +++ b/crates/classgroup/src/lib.rs @@ -177,8 +177,8 @@ mod test { path::PathBuf, }; - use super::{gmp_classgroup::GmpClassGroup, ClassGroup}; use super::gmp::mpz::Mpz; + use super::{gmp_classgroup::GmpClassGroup, ClassGroup}; fn split_into_three_pieces(line: &str, c: char) -> [&str; 3] { let mut iter = line.split(c); @@ -193,6 +193,7 @@ mod test { fn multiplication_is_correct() { let manifest_path = std::env::var("CARGO_MANIFEST_DIR").expect("cargo should have set this"); + dbg!(&manifest_path); 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")); @@ -247,5 +248,4 @@ mod test { buffer.clear(); } } - -} +} \ No newline at end of file diff --git a/crates/classgroup/src/vdf.cpp b/crates/classgroup/src/vdf.cpp new file mode 100644 index 0000000..9fba399 --- /dev/null +++ b/crates/classgroup/src/vdf.cpp @@ -0,0 +1,340 @@ + /** + Copyright 2018 Chia Network Inc + + 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. + **/ + + /** + compile: + g++ -O3 vdf.cpp -lgmpxx -lgmp -lflint -lmpfr -lpthread + + run: + time sh ./run.sh -0xdc2a335cd2b355c99d3d8d92850122b3d8fe20d0f5360e7aaaecb448960d57bcddfee12a229bbd8d370feda5a17466fc725158ebb78a2a7d37d0a226d89b54434db9c3be9a9bb6ba2c2cd079221d873a17933ceb81a37b0665b9b7e247e8df66bdd45eb15ada12326db01e26c861adf0233666c01dec92bbb547df7369aed3b1fbdff867cfc670511cc270964fbd98e5c55fbe0947ac2b9803acbfd935f3abb8d9be6f938aa4b4cc6203f53c928a979a2f18a1ff501b2587a93e95a428a107545e451f0ac6c7f520a7e99bf77336b1659a2cb3dd1b60e0c6fcfffc05f74cfa763a1d0af7de9994b6e35a9682c4543ae991b3a39839230ef84dae63e88d90f457 2097152 + + expected output: + 41925311306490234810413138012137571066190117321086581650264103905212443247266638302300216176280962581197588248081055726676846585755174597863581644696718682501212285820220079934416655823371811162467870568376504352001314014329129123905108990627789940142020588151887088845810858316508373198920329374052520999187 + 34852345576682667643688406428836586142306150733999584872507440542733753870999851189854421199460417700803159204522889615033067098373432317909891523566449002340814898056506838421999772358720363985014768637377270846456207130003363936723439348271781377460453326857670664463211470390811155611448465292430048563927 + **/ + + #include + + #include + #include + #include + #define LOG2(X) (63 - __builtin_clzll((X))) + using namespace std; + + struct form { + // y = ax^2 + bxy + y^2 + mpz_t a; + mpz_t b; + mpz_t c; + // mpz_t d; // discriminant + }; + + + const int64_t THRESH = 1UL<<31; + const int64_t EXP_THRESH = 31; + + +extern "C" { + //this normalization is based on Akashnil's entry to the previous round + inline void normalize(form& f) { + form f_; + mpz_inits(f_.a, f_.b, f_.c, NULL); + mpz_t mu, a2, denom; + mpz_inits(mu, a2, denom, NULL); + + mpz_add(mu, f.b, f.c); + mpz_mul_ui(a2, f.c, 2); + mpz_fdiv_q(denom, mu, a2); + + mpz_set(f_.a, f.c); + + mpz_mul_ui(a2, denom, 2); + mpz_neg(f_.b, f.b); + mpz_addmul(f_.b, f.c, a2); + + mpz_set(f_.c, f.a); + mpz_submul(f_.c, f.b, denom); + mpz_mul(denom, denom, denom); + mpz_addmul(f_.c, f.c, denom); + + mpz_set(f.a, f_.a); + mpz_set(f.b, f_.b); + mpz_set(f.c, f_.c); + } + + inline uint64_t signed_shift(uint64_t op, int shift) { + if (shift > 0) return op << shift; + if (shift <= -64) return 0; + return op >> (-shift); + } + + inline int64_t mpz_get_si_2exp (signed long int *exp, const mpz_t op) { + uint64_t size = mpz_size(op); + uint64_t last = mpz_getlimbn(op, size - 1); + uint64_t ret; + int lg2 = LOG2(last) + 1; + *exp = lg2; ret = signed_shift(last, 63 - *exp); + if (size > 1) { + *exp += (size-1) * 64; + uint64_t prev = mpz_getlimbn(op, size - 2); + ret += signed_shift(prev, -1 - lg2); + } + if (mpz_sgn(op) < 0) return - ((int64_t)ret); + return ret; + } + + // Test if f is reduced. If it almost is but a, c are swapped, + // then just swap them to make it reduced. + inline bool test_reduction(form& f) { + int a_b = mpz_cmpabs(f.a, f.b); + int c_b = mpz_cmpabs(f.c, f.b); + + if (a_b < 0 || c_b < 0) return false; + + int a_c = mpz_cmp(f.a, f.c); + + if (a_c > 0) { + mpz_swap(f.a, f.c); mpz_neg(f.b, f.b); + } + + if (a_c == 0 && mpz_sgn(f.b) < 0) { + mpz_neg(f.b, f.b); + } + + return true; + } + + // This is based on Akashnil's integer approximation reduce + inline void fast_reduce(form& f) { + + int64_t u, v, w, x, u_, v_, w_, x_; + int64_t delta, gamma, sgn; + int64_t a, b, c, a_, b_, c_; + int64_t aa, ab, ac, ba, bb, bc, ca, cb, cc; + long int a_exp, b_exp, c_exp, max_exp, min_exp; + mpz_t faa, fab, fac, fba, fbb, fbc, fca, fcb, fcc, a2, mu; + mpz_inits(faa, fab, fac, fba, fbb, fbc, fca, fcb, fcc, a2, mu, NULL); + + while (!test_reduction(f)) { + + a = mpz_get_si_2exp(&a_exp, f.a); + b = mpz_get_si_2exp(&b_exp, f.b); + c = mpz_get_si_2exp(&c_exp, f.c); + + max_exp = a_exp; + min_exp = a_exp; + + if (max_exp < b_exp) max_exp = b_exp; + if (min_exp > b_exp) min_exp = b_exp; + + if (max_exp < c_exp) max_exp = c_exp; + if (min_exp > c_exp) min_exp = c_exp; + + if (max_exp - min_exp > EXP_THRESH) { + normalize(f); continue; + } + max_exp++; // for safety vs overflow + + // Ensure a, b, c are shifted so that a : b : c ratios are same as f.a : f.b : f.c + // a, b, c will be used as approximations to f.a, f.b, f.c + a >>= (max_exp - a_exp); + b >>= (max_exp - b_exp); + c >>= (max_exp - c_exp); + + u_ = 1; v_ = 0; w_ = 0; x_ = 1; + + // We must be very careful about overflow in the following steps + do { + u = u_; v = v_; w = w_; x = x_; + // Ensure that delta = floor ((b+c) / 2c) + delta = b >= 0 ? (b+c) / (c<<1) : - (-b+c) / (c<<1); + a_ = c; + c_ = c * delta; + b_ = -b + (c_ << 1); + gamma = b - c_; + c_ = a - delta * gamma; + + a = a_; b = b_; c = c_; + + u_ = v; + v_ = -u + delta * v; + w_ = x; + x_ = -w + delta * x; + // The condition (abs(v_) | abs(x_)) <= THRESH protects against overflow + } while ((abs(v_) | abs(x_)) <= THRESH && a > c && c > 0); + + if ((abs(v_) | abs(x_)) <= THRESH) { + u = u_; v = v_; w = w_; x = x_; + } + + aa = u * u; ab = u * w; ac = w * w; + ba = u * v << 1; bb = u * x + v * w; bc = w * x << 1; + ca = v * v; cb = v * x; cc = x * x; + + // The following operations take 40% of the overall runtime. + + mpz_mul_si(faa, f.a, aa); + mpz_mul_si(fab, f.b, ab); + mpz_mul_si(fac, f.c, ac); + + mpz_mul_si(fba, f.a, ba); + mpz_mul_si(fbb, f.b, bb); + mpz_mul_si(fbc, f.c, bc); + + mpz_mul_si(fca, f.a, ca); + mpz_mul_si(fcb, f.b, cb); + mpz_mul_si(fcc, f.c, cc); + + mpz_add(f.a, faa, fab); + mpz_add(f.a, f.a, fac); + + mpz_add(f.b, fba, fbb); + mpz_add(f.b, f.b, fbc); + + mpz_add(f.c, fca, fcb); + mpz_add(f.c, f.c, fcc); + } + } + + // https://www.researchgate.net/publication/221451638_Computational_aspects_of_NUCOMP + //based on the implementation from Bulaiden + inline void gmp_nudupl(form& f, ulong times) { + mpz_t D, L; + mpz_t G, dx, dy, By, Dy, x, y, bx, by, ax, ay, q, t, Q1, denom; + form F, f_; + fmpz_t fy, fx, fby, fbx, fL; + mpz_init(denom); + mpz_inits(D, L, NULL); + mpz_inits(G, dx, dy, By, Dy, x, y, bx, by, ax, ay, q, t, Q1, denom, NULL); + mpz_inits(F.a, F.b, F.c, NULL); + + fmpz_init(fy); + fmpz_init(fx); + fmpz_init(fby); + fmpz_init(fbx); + fmpz_init(fL); + while(times > 0){ + mpz_gcdext(G, y, NULL, f.b, f.a); + + mpz_divexact(By, f.a, G); + mpz_divexact(Dy, f.b, G); + + mpz_mul(bx, y, f.c); + mpz_mod(bx, bx, By); + + mpz_set(by, By); + + if (mpz_cmpabs(by, L) <= 0) { + mpz_mul(dx, bx, Dy); + mpz_sub(dx, dx, f.c); + mpz_divexact(dx, dx, By); + mpz_mul(f.a, by, by); + mpz_mul(f.c, bx, bx); + mpz_add(t, bx, by); + mpz_mul(t, t, t); + mpz_sub(f.b, f.b, t); + mpz_add(f.b, f.b, f.a); + mpz_add(f.b, f.b, f.c); + mpz_mul(t, G, dx); + mpz_sub(f.c, f.c, t); + times--; + continue; + } + + fmpz_set_mpz(fy, y); + fmpz_set_mpz(fx, x); + fmpz_set_mpz(fby, by); + fmpz_set_mpz(fbx, bx); + fmpz_set_mpz(fL, L); + + fmpz_xgcd_partial(fy, fx, fby, fbx, fL); + + fmpz_get_mpz(y, fy); + fmpz_get_mpz(x, fx); + fmpz_get_mpz(by, fby); + fmpz_get_mpz(bx, fbx); + fmpz_get_mpz(L, fL); + + mpz_neg(x, x); + if (mpz_sgn(x) > 0) { + mpz_neg(y, y); + } else { + mpz_neg(by, by); + } + + mpz_mul(ax, G, x); + mpz_mul(ay, G, y); + + mpz_mul(t, Dy, bx); + mpz_submul(t, f.c, x); + mpz_divexact(dx, t, By); + mpz_mul(Q1, y, dx); + mpz_add(dy, Q1, Dy); + mpz_add(f.b, dy, Q1); + mpz_mul(f.b, f.b, G); + mpz_divexact(dy, dy, x); + mpz_mul(f.a, by, by); + mpz_mul(f.c, bx, bx); + mpz_add(t, bx, by); + mpz_submul(f.b, t, t); + mpz_add(f.b, f.b, f.a); + mpz_add(f.b, f.b, f.c); + mpz_submul(f.a, ay, dy); + mpz_submul(f.c, ax, dx); + times--; + fast_reduce(f); + } + + mpz_clear(denom); + mpz_clears(D, L, NULL); + mpz_clears(G, dx, dy, By, Dy, x, y, bx, by, ax, ay, q, t, Q1, denom, NULL); + mpz_clears(F.a, F.b, F.c, NULL); + + fmpz_clear(fy); + fmpz_clear(fx); + fmpz_clear(fby); + fmpz_clear(fbx); + fmpz_clear(fL); + } + + void adapted_nudupl(mpz_t& a, mpz_t& b, mpz_t& c, ulong times) { + //initialise variables + form newform; + mpz_inits(newform.a, newform.b, newform.c, NULL); + mpz_set(newform.a, a); + mpz_set(newform.b, b); + mpz_set(newform.c, c); + gmp_nudupl(newform, times); + mpz_set(a, newform.a); + mpz_set(b, newform.b); + mpz_set(c, newform.c); + mpz_clears(newform.a, newform.b, newform.c, NULL); + } + + + inline void generator_for_discriminant(form& x, mpz_t& d) { + mpz_t denom; + mpz_init(denom); + mpz_set_ui(x.a, 2); + mpz_set_ui(x.b, 1); + mpz_mul(x.c, x.b, x.b); + mpz_sub(x.c, x.c, d); + mpz_mul_ui(denom, x.a, 4); + mpz_fdiv_q(x.c, x.c, denom); + fast_reduce(x); + mpz_clear(denom); + } +} \ No newline at end of file diff --git a/vdf/test.sh b/vdf/test.sh index cb42e34..09b5b72 100755 --- a/vdf/test.sh +++ b/vdf/test.sh @@ -1,7 +1,7 @@ #!/bin/bash set -euxo pipefail -# Run tests for the vdf package. Takes care of linking the native VDF. +# Run tests for the vdf package. Takes care of linking the native VDF. # Assumes that the VDF library has been built by running the generate.sh script in the same directory. ROOT_DIR="${ROOT_DIR:-$( cd "$(dirname "$(realpath "$( dirname "${BASH_SOURCE[0]}" )")")" >/dev/null 2>&1 && pwd )}" @@ -11,7 +11,7 @@ BINARIES_DIR="$ROOT_DIR/target/release" # Link the native VDF and execute tests pushd "$NODE_DIR" > /dev/null - CGO_LDFLAGS="-L$BINARIES_DIR -lvdf -ldl" \ + CGO_LDFLAGS="-L$BINARIES_DIR -L/opt/homebrew/Cellar/mpfr/4.2.1/lib -I/opt/homebrew/Cellar/mpfr/4.2.1/include -L/opt/homebrew/Cellar/gmp/6.3.0/lib -I/opt/homebrew/Cellar/gmp/6.3.0/include -L/opt/homebrew/Cellar/flint/3.1.3-p1/lib -I/opt/homebrew/Cellar/flint/3.1.3-p1/include -lstdc++ -lvdf -ldl -lm -lflint -lgmp -lmpfr" \ CGO_ENABLED=1 \ GOEXPERIMENT=arenas \ go test "$@" diff --git a/vdf/vdf_test.go b/vdf/vdf_test.go index dd3e56a..dfc9e19 100644 --- a/vdf/vdf_test.go +++ b/vdf/vdf_test.go @@ -1,10 +1,10 @@ package vdf_test import ( - "golang.org/x/crypto/sha3" - nekrovdf "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/vdf" - "source.quilibrium.com/quilibrium/monorepo/vdf" "testing" + + "golang.org/x/crypto/sha3" + "source.quilibrium.com/quilibrium/monorepo/vdf" ) func getChallenge(seed string) [32]byte { @@ -12,7 +12,7 @@ func getChallenge(seed string) [32]byte { } func TestProveVerify(t *testing.T) { - difficulty := uint32(10000) + difficulty := uint32(160000) challenge := getChallenge("TestProveVerify") solution := vdf.WesolowskiSolve(challenge, difficulty) isOk := vdf.WesolowskiVerify(challenge, difficulty, solution) @@ -21,33 +21,33 @@ func TestProveVerify(t *testing.T) { } } -func TestProveRustVerifyNekro(t *testing.T) { - difficulty := uint32(100) - challenge := getChallenge("TestProveRustVerifyNekro") +// func TestProveRustVerifyNekro(t *testing.T) { +// difficulty := uint32(100) +// challenge := getChallenge("TestProveRustVerifyNekro") - for i := 0; i < 100; i++ { - solution := vdf.WesolowskiSolve(challenge, difficulty) - nekroVdf := nekrovdf.New(difficulty, challenge) - isOk := nekroVdf.Verify(solution) - if !isOk { - t.Fatalf("Verification failed") - } - challenge = sha3.Sum256(solution[:]) - } -} +// for i := 0; i < 100; i++ { +// solution := vdf.WesolowskiSolve(challenge, difficulty) +// nekroVdf := nekrovdf.New(difficulty, challenge) +// isOk := nekroVdf.Verify(solution) +// if !isOk { +// t.Fatalf("Verification failed") +// } +// challenge = sha3.Sum256(solution[:]) +// } +// } -func TestProveNekroVerifyRust(t *testing.T) { - difficulty := uint32(100) - challenge := getChallenge("TestProveNekroVerifyRust") +// func TestProveNekroVerifyRust(t *testing.T) { +// difficulty := uint32(100) +// challenge := getChallenge("TestProveNekroVerifyRust") - for i := 0; i < 100; i++ { - nekroVdf := nekrovdf.New(difficulty, challenge) - nekroVdf.Execute() - proof := nekroVdf.GetOutput() - isOk := vdf.WesolowskiVerify(challenge, difficulty, proof) - if !isOk { - t.Fatalf("Verification failed") - } - challenge = sha3.Sum256(proof[:]) - } -} +// for i := 0; i < 100; i++ { +// nekroVdf := nekrovdf.New(difficulty, challenge) +// nekroVdf.Execute() +// proof := nekroVdf.GetOutput() +// isOk := vdf.WesolowskiVerify(challenge, difficulty, proof) +// if !isOk { +// t.Fatalf("Verification failed") +// } +// challenge = sha3.Sum256(proof[:]) +// } +// }