temporarily stage for osx

This commit is contained in:
Cassandra Heart 2025-01-18 17:39:55 -06:00
parent 3722901956
commit e9e86af207
No known key found for this signature in database
GPG Key ID: 6352152859385958
15 changed files with 769 additions and 232 deletions

16
Cargo.lock generated
View File

@ -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"

View File

@ -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"

View File

@ -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) {

View File

@ -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}");
}
}

View File

@ -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);

View File

@ -9,4 +9,4 @@ pub mod mpz;
pub mod sign;
#[cfg(test)]
mod test;
mod test;

View File

@ -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::<c_ulong>() == 8 || $what <= u32::MAX as u64 {
(u64, $what: ident, $e1: expr, $e2: expr) => {
if size_of::<c_ulong>() == 8 || $what <= u32::MAX as u64 {
$e1
} else {
$e2
}
else {
$e2
}
);
(i64, $what: ident, $e1: expr, $e2: expr) => (
if size_of::<c_long>() == 8 || $what <= i32::MAX as i64 {
};
(i64, $what: ident, $e1: expr, $e2: expr) => {
if size_of::<c_long>() == 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<Mpz> 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<Mpz> 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<Mpz> 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<Mpz> 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<u8> {
unsafe {
let bit_size = size_of::<u8>() * 8;
let size = (__gmpz_sizeinbase(&other.mpz, 2) + bit_size - 1) / bit_size;
let mut result: Vec<u8> = vec!(0; size);
__gmpz_export(result.as_mut_ptr() as *mut c_void, 0 as *mut size_t, 1, size_of::<u8>() as size_t, 0, 0, &other.mpz);
let mut result: Vec<u8> = vec![0; size];
__gmpz_export(
result.as_mut_ptr() as *mut c_void,
0 as *mut size_t,
1,
size_of::<u8>() as size_t,
0,
0,
&other.mpz,
);
result
}
}
@ -814,8 +839,16 @@ impl<'b> From<&'b Mpz> for Option<i64> {
}
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::<i64>() 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::<i64>() 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<u64> {
fn from(other: &Mpz) -> Option<u64> {
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::<u64>() 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::<u64>() as size_t,
0,
0,
&other.mpz,
);
Some(result)
} else {
None
@ -844,9 +885,7 @@ impl<'b> From<&'b Mpz> for Option<u64> {
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::<u8>() as size_t,
0, 0, other.as_ptr() as *const c_void);
__gmpz_import(
&mut res.mpz,
other.len(),
1,
size_of::<u8>() as size_t,
0,
0,
other.as_ptr() as *const c_void,
);
res
}
}
@ -865,8 +911,15 @@ impl From<u64> for Mpz {
fn from(other: u64) -> Mpz {
unsafe {
let mut res = Mpz::new();
__gmpz_import(&mut res.mpz, 1, -1, size_of::<u64>() as size_t, 0, 0,
&other as *const u64 as *const c_void);
__gmpz_import(
&mut res.mpz,
1,
-1,
size_of::<u64>() as size_t,
0,
0,
&other as *const u64 as *const c_void,
);
res
}
}
@ -876,8 +929,15 @@ impl From<u32> for Mpz {
fn from(other: u32) -> Mpz {
unsafe {
let mut res = Mpz::new();
__gmpz_import(&mut res.mpz, 1, -1, size_of::<u32>() as size_t, 0, 0,
&other as *const u32 as *const c_void);
__gmpz_import(
&mut res.mpz,
1,
-1,
size_of::<u32>() as size_t,
0,
0,
&other as *const u32 as *const c_void,
);
res
}
}
@ -889,12 +949,26 @@ impl From<i64> for Mpz {
let mut res = Mpz::new();
if other.is_negative() {
__gmpz_import(&mut res.mpz, 1, -1, size_of::<i64>() as size_t, 0, 0,
&(other ^ -1i64) as *const i64 as *const c_void);
__gmpz_import(
&mut res.mpz,
1,
-1,
size_of::<i64>() 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::<i64>() as size_t, 0, 0,
&other as *const i64 as *const c_void);
__gmpz_import(
&mut res.mpz,
1,
-1,
size_of::<i64>() as size_t,
0,
0,
&other as *const i64 as *const c_void,
);
}
res
}
@ -907,12 +981,26 @@ impl From<i32> for Mpz {
let mut res = Mpz::new();
if other.is_negative() {
__gmpz_import(&mut res.mpz, 1, -1, size_of::<i32>() as size_t, 0, 0,
&(other ^ -1i32) as *const i32 as *const c_void);
__gmpz_import(
&mut res.mpz,
1,
-1,
size_of::<i32>() 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::<i32>() as size_t, 0, 0,
&other as *const i32 as *const c_void);
__gmpz_import(
&mut res.mpz,
1,
-1,
size_of::<i32>() 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<S: hash::Hasher>(&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()
}
}
}

View File

@ -3,5 +3,4 @@ pub enum Sign {
Negative,
Zero,
Positive,
}
}

View File

@ -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::<mp_limb_t>() * 8,
unsafe { __gmp_bits_per_limb as usize });
assert_eq!(std::mem::size_of::<mp_limb_t>() * 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::<i64>::from(2);
let y: Mpz = From::<i64>::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::<i64>::from(2);
let y: Mpz = From::<i64>::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::<i64>::from(2);
let y: Mpz = From::<i64>::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::<i64>::from(2);
let y: Mpz = From::<i64>::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::<i64>::from(2);
let y: Mpz = From::<i64>::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::<i64>::from(2);
let y: Mpz = From::<i64>::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<u8> = vec!(255, 255);
let v: Vec<u8> = 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::<i64>::from(2);
assert!(prime.probab_prime(15) == ProbabPrimeResult::Prime);
let not_prime: Mpz = From::<i64>::from(4);
assert!(not_prime.probab_prime(15) == ProbabPrimeResult::NotPrime);
}
@ -367,7 +368,7 @@ mod mpz {
let twentyfour: Mpz = From::<i64>::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::<i64>::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::<i64>::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::<i64>::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::<Vec<u8>>::into(&one), vec!(1u8));
assert_eq!(Into::<Vec<u8>>::into(&five), vec!(5u8));
assert_eq!(Into::<Vec<u8>>::into(&xffff), vec!(255u8, 255u8));
assert_eq!(Into::<Vec<u8>>::into(&max_u64), vec!(255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8));
assert_eq!(
Into::<Vec<u8>>::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");
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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();
}
}
}
}

View File

@ -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 <cstdint>
#include <iostream>
#include <gmpxx.h>
#include <flint/fmpz.h>
#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);
}
}

View File

@ -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 "$@"

View File

@ -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[:])
// }
// }