Merge remote-tracking branch 'agost/rust-vdf' into perf-grinder

This commit is contained in:
Cassandra Heart 2024-06-06 22:19:10 -05:00
commit cb43c42cf2
No known key found for this signature in database
GPG Key ID: 6352152859385958
46 changed files with 7262 additions and 52 deletions

View File

@ -4,3 +4,6 @@
github.env
Taskfile.yaml
# Rust
target
vdf/generated

4
.gitignore vendored
View File

@ -8,3 +8,7 @@ ceremony-client
.env.signers
.task
node-tmp-*
build
# Rust
target

34
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,34 @@
# Local development
The following software is required for local development (assuming MacOS ARM):
- Go 1.20
- Rust toolchain
- GMP 6.3: `brew install gmp`
- Install the Go plugin for uniffi-rs: `cargo install uniffi-bindgen-go --git https://github.com/NordSecurity/uniffi-bindgen-go --tag v0.2.1+v0.25.0`
# Building release binaries
The following is software is required to build release binaries (assuming MacOS
ARM) :
- [Local development](#local-development) dependencies
- Docker
- [Taskfile](https://taskfile.dev/)
Then from the repo root use the following commands to build the release binaries
that statically link the [native VDF](./crates/vdf) for the supported platforms:
```shell
task build_node_arm64_macos
task build_node_arm64_linux
task build_node_arm64_macos
```
The output binaries will be in `node/build`.
# Testing
Testing the [`vdf`](./vdf) and [`node`](./node) packages requires linking the
[native VDF](./crates/vdf). The `test.sh` scripts in the respective directories
help with this.

1201
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

25
Cargo.toml Normal file
View File

@ -0,0 +1,25 @@
# 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
# and limitations under the License.
[workspace]
members = [
"crates/vdf",
"crates/classgroup",
]
[profile.release]
# rpath = false is important to make Go bindings work
rpath = false
lto = true
debug = false
# panic = 'abort'

View File

@ -1,4 +1,20 @@
FROM golang:1.20.14-alpine3.19 as build
FROM golang:1.20.14-bullseye as build-base
ENV PATH="${PATH}:/root/.cargo/bin/"
# Install GMP 6.2 (6.3 which MacOS is using only available on Debian unstable)
RUN apt-get update && apt-get install -y \
libgmp-dev \
&& rm -rf /var/lib/apt/lists/*
COPY docker/rustup-init.sh /opt/rustup-init.sh
RUN /opt/rustup-init.sh -y --profile minimal
# Install uniffi-bindgen-go
RUN cargo install uniffi-bindgen-go --git https://github.com/NordSecurity/uniffi-bindgen-go --tag v0.2.1+v0.25.0
FROM build-base as build
ENV GOEXPERIMENT=arenas
@ -6,16 +22,27 @@ WORKDIR /opt/ceremonyclient
COPY . .
## Generate Rust bindings for VDF
WORKDIR /opt/ceremonyclient/vdf
RUN ./generate.sh
# Build and install the node
WORKDIR /opt/ceremonyclient/node
RUN go install ./...
RUN ./build.sh && cp node /go/bin
RUN go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest
# Build and install qclient
WORKDIR /opt/ceremonyclient/client
RUN go build -o qclient ./main.go
FROM alpine:3.19
# Allows exporting single binary
FROM scratch AS node
COPY --from=build /go/bin/node /node
ENTRYPOINT [ "/node" ]
FROM debian:bullseye
ARG NODE_VERSION
ARG GIT_REPO

View File

@ -26,6 +26,22 @@ tasks:
- echo -n "Commit :" && echo " {{.GIT_COMMIT}}"
silent: true
build_node_arm64_macos:
desc: Build the Quilibrium node binary for MacOS ARM. Assumes it's ran from the same platform. Outputs to node/build.
cmds:
- vdf/generate.sh
- node/build.sh -o build/arm64_macos/node
build_node_arm64_linux:
desc: Build the Quilibrium node binary for ARM64 Linux. Outputs to node/build.
cmds:
- docker build --platform linux/arm64 -f Dockerfile --output node/build/arm64_linux --target=node .
build_node_amd64_linux:
desc: Build the Quilibrium node binary for AMD64 Linux. Outputs to node/build.
cmds:
- docker build --platform linux/amd64 -f Dockerfile --output node/build/amd64_linux --target=node .
build:
desc: Build the Quilibrium docker image, unless it is already built.
cmds:

View File

@ -24,8 +24,8 @@ require (
github.com/minio/sha256-simd v1.0.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.18.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/crypto v0.24.0 // indirect
golang.org/x/sys v0.21.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
source.quilibrium.com/quilibrium/monorepo/nekryptology v0.0.0-00010101000000-000000000000 // indirect

View File

@ -89,8 +89,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ=
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -103,8 +103,8 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=

View File

@ -0,0 +1,34 @@
# Copyright 2018 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
# and limitations under the License.
[package]
name = "classgroup"
version = "0.1.0"
authors = ["Demi M. Obenour <demiobenour@gmail.com>"]
description = """An implementation of class groups in Rust. Uses GMP for arithmetic."""
keywords = ["classgroup", "vdf"]
repository = "https://github.com/poanetwork/vdf"
license = "Apache-2.0"
edition = "2018"
[dependencies]
num-traits = "0.2"
libc = "0.2"
[dev-dependencies]
criterion = ">=0.2"
[[bench]]
name = "classgroup-bench"
harness = false
path = "bench/bench.rs"

View File

@ -0,0 +1,66 @@
// Copyright 2018 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.
#[macro_use]
extern crate criterion;
use classgroup::{gmp_classgroup::GmpClassGroup, ClassGroup};
use criterion::Criterion;
use gmp::mpz::Mpz;
use std::str::FromStr;
fn bench_square(c: &mut Criterion) {
for _ in 0..2 {
let m_2048 = -Mpz::from_str(
"201493927071865251625903550712920535753645598483515670853547009\
878440933309489362800393797428711071833308081461824159206915864\
150805748296170245037221957772328044276705571745811271212292422\
075849739248257870371300001313586036515879618764093772248760562\
386804073478433157526816295216137723803793411828867470089409596\
238958950007370719325959579892866588928887249912429688364409867\
895510817680171869190054122881274299350947669820596157115994418\
034091728887584373727555384075665624624856766441009974642693066\
751400054217209981490667208950669417773785631693879782993019167\
69407006303085854796535778826115224633447713584423",
)
.unwrap();
let m_1024 = -Mpz::from_str(
"-11208471744389096429663063172516742066731683613191418514476174383781\
682509882427394963852743081347678693241523614532942268295868231081182\
819214054220080323345750407342623884342617809879459211722505867733607\
400509994975706778681543998242335468203860240586171413971485860382901\
6409314686266660248501773529803183",
)
.unwrap();
let group_1024 = GmpClassGroup::generator_for_discriminant(m_1024);
let group_2048 = GmpClassGroup::generator_for_discriminant(m_2048);
let (group_1024_clone, group_2048_clone) = (group_1024.clone(), group_2048.clone());
c.bench_function("square 1024", move |b| {
b.iter(|| group_1024_clone.clone().square())
});
c.bench_function("multiply 1024", move |b| {
b.iter(|| &group_1024 * &group_1024)
});
c.bench_function("square 2048", move |b| {
b.iter(|| group_2048_clone.clone().square())
});
c.bench_function("multiply 2048", move |b| {
b.iter(|| &group_2048 * &group_2048)
});
}
}
criterion_group!(benches, bench_square);
criterion_main!(benches);

View File

@ -0,0 +1,16 @@
use std::env;
fn main() {
println!("cargo:rerun-if-changed=build.rs");
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");
} 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/");
} else {
panic!("unsupported target {target}");
}
}

View File

@ -0,0 +1,7 @@
use super::mpz::*;
#[link(name = "gmp", kind = "static")]
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

@ -0,0 +1,12 @@
#![warn(deprecated)]
#![allow(non_camel_case_types)]
extern crate libc;
extern crate num_traits;
mod ffi;
pub mod mpz;
pub mod sign;
#[cfg(test)]
mod test;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash, Debug)]
pub enum Sign {
Negative,
Zero,
Positive,
}

View File

@ -0,0 +1,582 @@
use super::mpz::mp_limb_t;
use std;
use libc::c_int;
#[link(name = "gmp", kind = "static")]
extern "C" {
static __gmp_bits_per_limb: c_int;
}
#[test]
#[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 });
}
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::{i64, u64};
use std::hash::{Hash, Hasher};
use std::collections::hash_map::DefaultHasher;
#[test]
fn test_set() {
let mut x: Mpz = From::<i64>::from(1000);
let y: Mpz = From::<i64>::from(5000);
assert!(x != y);
x.set(&y);
assert!(x == y);
}
#[test]
fn test_set_from_str_radix() {
let mut x: Mpz = From::<i64>::from(1000);
let y: Mpz = From::<i64>::from(5000);
assert!(x != y);
assert!(x.set_from_str_radix("5000", 10));
assert!(x == y);
assert!(!x.set_from_str_radix("aaaa", 2));
}
#[test]
#[should_panic]
fn test_from_str_radix_lower_bound() {
let _ = Mpz::from_str_radix("", 1);
}
#[test]
#[should_panic]
fn test_from_str_radix_upper_bound() {
let _ = Mpz::from_str_radix("", 63);
}
#[test]
#[should_panic]
fn test_set_from_str_radix_lower_bound() {
let mut x = Mpz::new();
x.set_from_str_radix("", 1);
}
#[test]
#[should_panic]
fn test_set_from_str_radix_upper_bound() {
let mut x = Mpz::new();
x.set_from_str_radix("", 63);
}
#[test]
fn test_eq() {
let x: Mpz = From::<i64>::from(4242142195);
let y: Mpz = From::<i64>::from(4242142195);
let z: Mpz = From::<i64>::from(4242142196);
assert!(x == y);
assert!(x != z);
assert!(y != z);
}
#[test]
fn test_ord() {
let x: Mpz = FromStr::from_str("40000000000000000000000").unwrap();
let y: Mpz = FromStr::from_str("45000000000000000000000").unwrap();
let z: Mpz = FromStr::from_str("50000000000000000000000").unwrap();
assert!(x < y && x < z && y < z);
assert!(x <= x && x <= y && x <= z && y <= z);
assert!(z > y && z > x && y > x);
assert!(z >= z && z >= y && z >= x && y >= x);
}
#[test]
#[should_panic]
fn test_div_zero() {
let x: Mpz = From::<i64>::from(1);
let y = Mpz::new();
drop(x / y)
}
#[test]
#[should_panic]
fn test_rem_zero() {
let x: Mpz = From::<i64>::from(1);
let y = Mpz::new();
drop(x % y)
}
#[test]
fn test_div_round() {
let x: Mpz = From::<i64>::from(2);
let y: Mpz = From::<i64>::from(3);
assert!((&x / &y).to_string() == (2i32 / 3).to_string());
assert!((&x / -&y).to_string() == (2i32 / -3).to_string());
}
#[test]
fn test_rem() {
let x: Mpz = From::<i64>::from(20);
let y: Mpz = From::<i64>::from(3);
assert!((&x % &y).to_string() == (20i32 % 3).to_string());
assert!((&x % 3).to_string() == (20i32 % 3).to_string());
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);
}
#[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());
}
#[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());
}
#[test]
fn test_to_str_radix() {
let x: Mpz = From::<i64>::from(255);
assert!(x.to_str_radix(16) == "ff".to_string());
}
#[test]
fn test_to_string() {
let x: Mpz = FromStr::from_str("1234567890").unwrap();
assert!(x.to_string() == "1234567890".to_string());
}
#[test]
fn test_invalid_str() {
let x: Result<Mpz, _> = FromStr::from_str("foobar");
assert!(x.is_err());
}
#[test]
fn test_clone() {
let a: Mpz = From::<i64>::from(100);
let b = a.clone();
let aplusb: Mpz = From::<i64>::from(200);
assert!(b == a);
assert!(a + b == aplusb);
}
#[test]
fn test_from_int() {
let x: Mpz = From::<i64>::from(150);
assert!(x.to_string() == "150".to_string());
assert!(x == FromStr::from_str("150").unwrap());
}
#[test]
fn test_from_slice_u8() {
let v: Vec<u8> = vec!(255, 255);
let x: Mpz = From::from(&v[..]);
assert!(x.to_string() == "65535".to_string());
}
#[test]
fn test_abs() {
let x: Mpz = From::<i64>::from(1000);
let y: Mpz = From::<i64>::from(-1000);
assert!(-&x == y);
assert!(x == -&y);
assert!(x == y.abs());
assert!(x.abs() == y.abs());
}
#[test]
fn test_div_floor() {
let two: Mpz = From::<i64>::from(2);
let eight: Mpz = From::<i64>::from(8);
let minuseight: Mpz = From::<i64>::from(-8);
let three: Mpz = From::<i64>::from(3);
let minusthree: Mpz = From::<i64>::from(-3);
assert_eq!(eight.div_floor(&three), two);
assert_eq!(eight.div_floor(&minusthree), minusthree);
assert_eq!(minuseight.div_floor(&three), minusthree);
assert_eq!(minuseight.div_floor(&minusthree), two);
}
#[test]
fn test_mod_floor() {
let one: Mpz = From::<i64>::from(1);
let minusone: Mpz = From::<i64>::from(-1);
let two: Mpz = From::<i64>::from(2);
let minustwo: Mpz = From::<i64>::from(-2);
let three: Mpz = From::<i64>::from(3);
let minusthree: Mpz = From::<i64>::from(-3);
let eight: Mpz = From::<i64>::from(8);
let minuseight: Mpz = From::<i64>::from(-8);
assert_eq!(eight.mod_floor(&three), two);
assert_eq!(eight.mod_floor(&minusthree), minusone);
assert_eq!(minuseight.mod_floor(&three), one);
assert_eq!(minuseight.mod_floor(&minusthree), minustwo);
}
#[test]
fn test_bitand() {
let a = 0b1001_0111;
let b = 0b1100_0100;
let mpza: Mpz = From::<i64>::from(a);
let mpzb: Mpz = From::<i64>::from(b);
let mpzres: Mpz = From::<i64>::from(a & b);
assert!(mpza & mpzb == mpzres);
}
#[test]
fn test_bitor() {
let a = 0b1001_0111;
let b = 0b1100_0100;
let mpza: Mpz = From::<i64>::from(a);
let mpzb: Mpz = From::<i64>::from(b);
let mpzres: Mpz = From::<i64>::from(a | b);
assert!(mpza | mpzb == mpzres);
}
#[test]
fn test_bitxor() {
let a = 0b1001_0111;
let b = 0b1100_0100;
let mpza: Mpz = From::<i64>::from(a);
let mpzb: Mpz = From::<i64>::from(b);
let mpzres: Mpz = From::<i64>::from(a ^ b);
assert!(mpza ^ mpzb == mpzres);
}
#[test]
fn test_shifts() {
let i = 227;
let j: Mpz = From::<i64>::from(i);
assert!((i << 4).to_string() == (&j << 4).to_string());
assert!((-i << 4).to_string() == (-&j << 4).to_string());
assert!((i >> 4).to_string() == (&j >> 4).to_string());
assert!((-i >> 4).to_string() == (-&j >> 4).to_string());
}
#[test]
fn test_compl() {
let a: Mpz = From::<i64>::from(13);
let b: Mpz = From::<i64>::from(-442);
assert!(a.compl().to_string() == (!13i32).to_string());
assert!(b.compl().to_string() == (!-442i32).to_string());
}
#[test]
fn test_pow() {
let a: Mpz = From::<i64>::from(2);
let b: Mpz = From::<i64>::from(8);
assert!(a.pow(3) == b);
assert!(Mpz::ui_pow_ui(2, 3) == b);
}
#[test]
fn test_powm() {
let a: Mpz = From::<i64>::from(13);
let b: Mpz = From::<i64>::from(7);
let p: Mpz = From::<i64>::from(19);
let c: Mpz = From::<i64>::from(10);
assert!(a.powm(&b, &p) == c);
}
#[test]
fn test_powm_sec() {
let a: Mpz = From::<i64>::from(13);
let b: Mpz = From::<i64>::from(7);
let p: Mpz = From::<i64>::from(19);
let c: Mpz = From::<i64>::from(10);
assert!(a.powm_sec(&b, &p) == c);
}
#[test]
fn test_popcount() {
assert_eq!(Mpz::from_str_radix("1010010011", 2).unwrap().popcount(), 5);
}
#[test]
fn test_hamdist() {
let a: Mpz = From::<i64>::from(0b1011_0001);
let b: Mpz = From::<i64>::from(0b0010_1011);
assert!(a.hamdist(&b) == 4);
}
#[test]
fn test_bit_length() {
let a: Mpz = From::<i64>::from(0b1011_0000_0001_0000);
let b: Mpz = From::<i64>::from(0b101);
assert!(a.bit_length() == 16);
assert!(b.bit_length() == 3);
}
#[test]
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);
}
#[test]
fn test_nextprime() {
let a: Mpz = From::<i64>::from(123456);
let b: Mpz = From::<i64>::from(123457);
assert!(a.nextprime() == b);
}
#[test]
fn test_gcd() {
let zero: Mpz = From::<i64>::from(0);
let three: Mpz = From::<i64>::from(3);
let six: Mpz = From::<i64>::from(6);
let eighteen: Mpz = From::<i64>::from(18);
let twentyfour: Mpz = From::<i64>::from(24);
assert!(zero.gcd(&zero) == zero);
assert!(three.gcd(&six) == three);
assert!(eighteen.gcd(&twentyfour) == six);
}
#[test]
fn test_gcdext() {
let six: Mpz = From::<i64>::from(6);
let eighteen: Mpz = From::<i64>::from(18);
let twentyfour: Mpz = From::<i64>::from(24);
let (g, s, t) = eighteen.gcdext(&twentyfour);
assert!(g == six);
assert!(g == s*eighteen + t*twentyfour);
}
#[test]
fn test_lcm() {
let zero: Mpz = From::<i64>::from(0);
let three: Mpz = From::<i64>::from(3);
let five: Mpz = From::<i64>::from(5);
let six: Mpz = From::<i64>::from(6);
let eighteen: Mpz = From::<i64>::from(18);
let twentyfour: Mpz = From::<i64>::from(24);
let seventytwo: Mpz = From::<i64>::from(72);
assert!(zero.lcm(&five) == zero);
assert!(five.lcm(&zero) == zero);
assert!(three.lcm(&six) == six);
assert!(eighteen.lcm(&twentyfour) == seventytwo);
}
#[test]
fn test_is_multiple_of() {
let two: Mpz = From::<i64>::from(2);
let three: Mpz = From::<i64>::from(3);
let six: Mpz = From::<i64>::from(6);
assert!(six.is_multiple_of(&two));
assert!(six.is_multiple_of(&three));
assert!(!three.is_multiple_of(&two));
}
#[test]
fn test_modulus() {
let minusone: Mpz = From::<i64>::from(-1);
let two: Mpz = From::<i64>::from(2);
let three: Mpz = From::<i64>::from(3);
assert_eq!(two.modulus(&three), two);
assert_eq!(minusone.modulus(&three), two);
}
#[test]
fn test_invert() {
let two: Mpz = From::<i64>::from(2);
let three: Mpz = From::<i64>::from(3);
let four: Mpz = From::<i64>::from(4);
let five: Mpz = From::<i64>::from(5);
let eleven: Mpz = From::<i64>::from(11);
assert!(three.invert(&eleven) == Some(four.clone()));
assert!(four.invert(&eleven) == Some(three.clone()));
assert!(two.invert(&five) == Some(three.clone()));
assert!(three.invert(&five) == Some(two.clone()));
assert!(two.invert(&four).is_none());
}
#[test]
fn test_one() {
let onea: Mpz = From::<i64>::from(1);
let oneb: Mpz = From::<i64>::from(1);
assert!(onea == oneb);
}
#[test]
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];
ys.reverse();
for i in 0..xs.bit_length() {
assert!(xs.tstbit(i) == ys[i]);
}
xs.setbit(0);
ys[0] = true;
xs.setbit(3);
ys[3] = true;
xs.clrbit(1);
ys[1] = false;
xs.clrbit(5);
ys[5] = false;
xs.combit(14);
ys[14] = !ys[14];
xs.combit(15);
ys[15] = !ys[15];
for i in 0..xs.bit_length() {
assert!(xs.tstbit(i) == ys[i]);
}
}
#[test]
fn test_root() {
let x: Mpz = From::<i64>::from(123456);
let y: Mpz = From::<i64>::from(49);
assert!(x.root(3) == y);
}
#[test]
fn test_sqrt() {
let x: Mpz = From::<i64>::from(567);
let y: Mpz = From::<i64>::from(23);
assert!(x.sqrt() == y);
}
#[test]
fn test_hash_short() {
let zero: Mpz = From::<i64>::from(0);
let one: Mpz = From::<i64>::from(1);
let two = &one + &one;
let hash = |x : &Mpz| {
let mut hasher = DefaultHasher::new();
x.hash(&mut hasher);
hasher.finish()
};
assert!(hash(&zero) != hash(&one));
assert_eq!(hash(&one), hash(&(&two - &one)));
}
#[test]
fn test_hash_long() {
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 mut hasher = DefaultHasher::new();
x.hash(&mut hasher);
hasher.finish()
};
assert!(hash(&a) != hash(&b));
assert_eq!(hash(&a), hash(&(&b + &one)));
assert_eq!(hash(&(&a - &a)), hash(&(&one - &one)));
}
#[test]
fn test_to_vec_u8() {
let minus_five: Mpz = From::<i64>::from(-5);
let minus_one: Mpz = From::<i64>::from(-1);
let zero: Mpz = From::<i64>::from(0);
let one: Mpz = From::<i64>::from(1);
let five: Mpz = From::<i64>::from(5);
let xffff: Mpz = From::<i64>::from(65535);
let max_u64: Mpz = From::<u64>::from(u64::MAX);
assert_eq!(Into::<Vec<u8>>::into(&minus_five), vec!(5u8));
assert_eq!(Into::<Vec<u8>>::into(&minus_one), vec!(1u8));
assert_eq!(Into::<Vec<u8>>::into(&zero), vec!(0u8));
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));
}
#[test]
fn test_to_u64() {
let minus_five: Mpz = From::<i64>::from(-5);
let minus_one: Mpz = From::<i64>::from(-1);
let zero: Mpz = From::<i64>::from(0);
let one: Mpz = From::<i64>::from(1);
let five: Mpz = From::<i64>::from(5);
let max_u64: Mpz = From::<u64>::from(u64::MAX);
assert_eq!(Into::<Option<u64>>::into(&minus_five), None);
assert_eq!(Into::<Option<u64>>::into(&minus_one), None);
assert_eq!(Into::<Option<u64>>::into(&zero), Some(0u64));
assert_eq!(Into::<Option<u64>>::into(&one), Some(1u64));
assert_eq!(Into::<Option<u64>>::into(&five), Some(5u64));
assert_eq!(Into::<Option<u64>>::into(&max_u64), Some(u64::MAX));
assert_eq!(Into::<Option<u64>>::into(&(&max_u64 + &one)), None);
}
#[test]
fn test_to_i64() {
let min_i64: Mpz = From::<i64>::from(i64::MIN);
let minus_five: Mpz = From::<i64>::from(-5);
let minus_one: Mpz = From::<i64>::from(-1);
let zero: Mpz = From::<i64>::from(0);
let one: Mpz = From::<i64>::from(1);
let five: Mpz = From::<i64>::from(5);
let max_i64: Mpz = From::<i64>::from(i64::MAX);
assert_eq!(Into::<Option<i64>>::into(&(&min_i64 - &one)), None);
assert_eq!(Into::<Option<i64>>::into(&min_i64), Some(i64::MIN));
assert_eq!(Into::<Option<i64>>::into(&minus_five), Some(-5i64));
assert_eq!(Into::<Option<i64>>::into(&minus_one), Some(-1i64));
assert_eq!(Into::<Option<i64>>::into(&zero), Some(0i64));
assert_eq!(Into::<Option<i64>>::into(&one), Some(1i64));
assert_eq!(Into::<Option<i64>>::into(&five), Some(5i64));
assert_eq!(Into::<Option<i64>>::into(&max_i64), Some(i64::MAX));
assert_eq!(Into::<Option<i64>>::into(&(&max_i64 + &one)), None);
}
#[test]
fn test_sign() {
let zero: Mpz = From::<i64>::from(0);
let five: Mpz = From::<i64>::from(5);
let minus_five: Mpz = From::<i64>::from(-5);
assert_eq!(zero.sign(), Sign::Zero);
assert_eq!(five.sign(), Sign::Positive);
assert_eq!(minus_five.sign(), Sign::Negative);
}
#[test]
fn test_format() {
let zero = Mpz::zero();
assert_eq!(format!("{}", zero), "0");
let zero = Mpz::from(-51213);
assert_eq!(format!("{}", zero), "-51213");
}
}

View File

@ -0,0 +1,90 @@
// 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.
#![forbid(unsafe_code)]
use self::ffi::Mpz;
use super::ffi;
/// Stores temporary values for congruence computations, to avoid
/// repeated allocations.
///
/// It is allowed (but inefficient) to generate a fresh `CongruenceContest`
/// for each call to `solve_linear_congruence`.
///
/// `self.solve_linear_congruence` can be called no matter what values
/// this structs public members hold, so long as they are valid `Mpz` values.
/// However, the values of these members after such a call must not be relied
/// on.
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct CongruenceContext {
pub g: Mpz,
pub d: Mpz,
pub q: Mpz,
pub r: Mpz,
}
// #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
// struct NoCongruence;
impl Default for CongruenceContext {
fn default() -> Self {
Self {
g: Mpz::new(),
d: Mpz::new(),
q: Mpz::new(),
r: Mpz::new(),
}
}
}
impl CongruenceContext {
/// Solves `a*x = b (mod m)`, storing `x` in `mu`
///
/// This function may clobber any or all of `self`s member variables.
///
/// # Panics
///
/// Panics if the congruence could not be solved.
pub fn solve_linear_congruence(
&mut self,
mu: &mut Mpz,
v: Option<&mut Mpz>,
a: &Mpz,
b: &Mpz,
m: &Mpz,
) {
ffi::mpz_gcdext(&mut self.g, &mut self.d, mu, a, m);
if cfg!(test) {
println!(
"g = {}, d = {}, e = {}, a = {}, m = {}",
self.g, self.d, mu, a, m
);
}
if cfg!(debug_assertions) {
ffi::mpz_fdiv_qr(&mut self.q, &mut self.r, b, &self.g);
debug_assert!(self.r.is_zero(), "Could not solve the congruence ― did you pass a non-prime or a positive number to the command line tool?!");
} else {
ffi::mpz_divexact(&mut self.q, b, &self.g)
}
ffi::mpz_mul(&mut self.r, &self.q, &self.d);
ffi::mpz_tdiv_r(mu, &self.r, m);
if let Some(v) = v {
if cfg!(debug_assertions) {
ffi::mpz_fdiv_qr(v, &mut self.r, &m, &self.g);
debug_assert!(self.r.is_zero(), "Could not solve the congruence ― did you pass a non-prime or a positive number to the command line tool?!");
} else {
ffi::mpz_divexact(v, &m, &self.g)
}
}
}
}

View File

@ -0,0 +1,340 @@
// Copyright 2018 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.
//! FFI bindings to GMP. This module exists because the `rust-gmp` crate
//! is too high-level. High-performance bignum computation requires that
//! bignums be modified in-place, so that their storage can be reused.
//! Furthermore, the `rust-gmp` crate doesnt support many operations that
//! this library requires.
#![allow(unsafe_code)]
pub use super::super::gmp::mpz::Mpz;
use super::super::gmp::mpz::{mp_bitcnt_t, mp_limb_t};
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 __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);
fn __gmpz_fdiv_qr(q: *mut Mpz, r: *mut Mpz, b: *const Mpz, g: *const Mpz);
fn __gmpz_fdiv_q(q: *mut Mpz, n: *const Mpz, d: *const Mpz);
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_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_import(
rop: *mut Mpz,
count: size_t,
order: c_int,
size: size_t,
endian: c_int,
nails: size_t,
op: *const c_void,
);
fn __gmpz_tdiv_r(r: *mut Mpz, n: *const Mpz, d: *const Mpz);
fn __gmpz_sizeinbase(op: &Mpz, base: c_int) -> size_t;
fn __gmpz_fdiv_q_ui(rop: *mut Mpz, op1: *const Mpz, op2: c_ulong) -> c_ulong;
fn __gmpz_add(rop: *mut Mpz, op1: *const Mpz, op2: *const Mpz);
fn __gmpz_add_ui(rop: *mut Mpz, op1: *const Mpz, op2: c_ulong);
fn __gmpz_set_ui(rop: &mut Mpz, op: c_ulong);
fn __gmpz_set_si(rop: &mut Mpz, op: c_long);
fn __gmpz_cdiv_ui(n: &Mpz, d: c_ulong) -> c_ulong;
fn __gmpz_fdiv_ui(n: &Mpz, d: c_ulong) -> c_ulong;
fn __gmpz_tdiv_ui(n: &Mpz, d: c_ulong) -> c_ulong;
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,
) -> *mut c_void;
fn __gmpz_powm(rop: *mut Mpz, base: *const Mpz, exp: *const Mpz, modulus: *const Mpz);
}
// MEGA HACK: rust-gmp doesnt expose the fields of this struct, so we must define
// it ourselves and cast.
//
// Should be stable though, as only GMP can change it, and doing would break binary compatibility.
#[repr(C)]
struct MpzStruct {
mp_alloc: c_int,
mp_size: c_int,
mp_d: *mut mp_limb_t,
}
macro_rules! impl_div_ui {
($t:ident, $i:ident, $f:expr) => {
pub fn $i(n: &Mpz, d: $t) -> $t {
use std::$t;
let res = unsafe { $f(n, c_ulong::from(d)) };
assert!(res <= $t::MAX.into());
res as $t
}
};
}
impl_div_ui!(u16, mpz_crem_u16, __gmpz_cdiv_ui);
impl_div_ui!(u32, mpz_frem_u32, __gmpz_fdiv_ui);
/// Returns `true` if `z` is negative and not zero. Otherwise,
/// returns `false`.
#[inline]
pub fn mpz_is_negative(z: &Mpz) -> bool {
unsafe { (*(z as *const _ as *const MpzStruct)).mp_size < 0 }
}
#[inline]
pub fn mpz_powm(rop: &mut Mpz, base: &Mpz, exponent: &Mpz, modulus: &Mpz) {
unsafe { __gmpz_powm(rop, base, exponent, modulus) }
}
#[inline]
pub fn mpz_tdiv_r(r: &mut Mpz, n: &Mpz, d: &Mpz) {
unsafe { __gmpz_tdiv_r(r, n, d) }
}
/// Sets `g` to the GCD of `a` and `b`.
#[inline]
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) }
}
/// Doubles `rop` in-place
#[inline]
pub fn mpz_double(rop: &mut Mpz) {
if true {
// slightly faster
unsafe { __gmpz_mul_2exp(rop, rop, 1) }
} else {
unsafe { __gmpz_add(rop, rop, rop) }
}
}
#[inline]
pub fn mpz_fdiv_qr(q: &mut Mpz, r: &mut Mpz, b: &Mpz, g: &Mpz) {
unsafe { __gmpz_fdiv_qr(q, r, b, g) }
}
#[inline]
pub fn mpz_fdiv_q_ui_self(rop: &mut Mpz, op: c_ulong) -> c_ulong {
unsafe { __gmpz_fdiv_q_ui(rop, rop, op) }
}
/// Unmarshals a buffer to an `Mpz`. `buf` is interpreted as a 2s complement,
/// big-endian integer. If the buffer is empty, zero is returned.
pub fn import_obj(buf: &[u8]) -> Mpz {
fn raw_import(buf: &[u8]) -> Mpz {
let mut obj = Mpz::new();
unsafe { __gmpz_import(&mut obj, buf.len(), 1, 1, 1, 0, buf.as_ptr() as *const _) }
obj
}
let is_negative = match buf.first() {
None => return Mpz::zero(),
Some(x) => x & 0x80 != 0,
};
if !is_negative {
raw_import(buf)
} else {
let mut new_buf: Vec<_> = buf.iter().cloned().skip_while(|&x| x == 0xFF).collect();
if new_buf.is_empty() {
(-1).into()
} else {
for i in &mut new_buf {
*i ^= 0xFF
}
!raw_import(&new_buf)
}
}
}
pub fn three_gcd(rop: &mut Mpz, a: &Mpz, b: &Mpz, c: &Mpz) {
unsafe {
__gmpz_gcd(rop, a, b);
__gmpz_gcd(rop, rop, c)
}
}
#[inline]
pub fn size_in_bits(obj: &Mpz) -> usize {
unsafe { __gmpz_sizeinbase(obj, 2) }
}
#[inline]
pub fn mpz_add(rop: &mut Mpz, op1: &Mpz, op2: &Mpz) {
unsafe { __gmpz_add(rop, op1, op2) }
}
#[inline]
pub fn mpz_mul(rop: &mut Mpz, op1: &Mpz, op2: &Mpz) {
unsafe { __gmpz_mul(rop, op1, op2) }
}
#[inline]
pub fn mpz_divexact(q: &mut Mpz, n: &Mpz, d: &Mpz) {
unsafe { __gmpz_divexact(q, n, d) }
}
#[inline]
pub fn mpz_mul_2exp(rop: &mut Mpz, op1: &Mpz, op2: mp_bitcnt_t) {
unsafe { __gmpz_mul_2exp(rop as *mut _ as *mut Mpz, op1, op2) }
}
/// Divide `n` by `d`. Round towards -∞ and place the result in `q`.
#[inline]
pub fn mpz_fdiv_q(q: &mut Mpz, n: &Mpz, d: &Mpz) {
if mpz_is_negative(n) == mpz_is_negative(d) {
unsafe { __gmpz_tdiv_q(q, n, d) }
} else {
unsafe { __gmpz_fdiv_q(q, n, d) }
}
}
/// Sets `rop` to `(-1) * op`
#[inline]
#[cfg(none)]
pub fn mpz_neg(rop: &mut Mpz) {
assert!(mem::size_of::<Mpz>() == mem::size_of::<MpzStruct>());
unsafe {
let ptr = rop as *mut _ as *mut MpzStruct;
let v = (*ptr).mp_size;
(*ptr).mp_size = -v;
}
}
/// Subtracts `op2` from `op1` and stores the result in `rop`.
#[inline]
pub fn mpz_sub(rop: &mut Mpz, op1: &Mpz, op2: &Mpz) {
unsafe { __gmpz_sub(rop as *mut _ as *mut Mpz, op1, op2) }
}
/// Exports `obj` to `v` as an array of 2s complement, big-endian
/// bytes. If `v` is too small to hold the result, returns `Err(s)`,
/// where `s` is the size needed to hold the exported version of `obj`.
pub fn export_obj(obj: &Mpz, v: &mut [u8]) -> Result<(), usize> {
// Requires: offset < v.len() and v[offset..] be able to hold all of `obj`
unsafe fn raw_export(v: &mut [u8], offset: usize, obj: &Mpz) -> usize {
// SAFE as `offset` will always be in-bounds, since byte_len always <=
// byte_len_needed and we check that v.len() >= byte_len_needed.
let ptr = v.as_mut_ptr().add(offset) as *mut c_void;
// Necessary ― this byte may not be fully overwritten
*(ptr as *mut u8) = 0;
// SAFE as __gmpz_export will *always* initialize this.
let mut s: usize = mem::uninitialized();
let ptr2 = __gmpz_export(ptr, &mut s, 1, 1, 1, 0, obj);
assert_eq!(ptr, ptr2);
if 0 == s {
1
} else {
s
}
}
let size = size_in_bits(obj);
assert!(size > 0);
// Check to avoid integer overflow in later operations.
if size > usize::MAX - 8 || v.len() > usize::MAX >> 3 {
return Err(usize::MAX);
}
// One additional bit is needed for the sign bit.
let byte_len_needed = (size + 8) >> 3;
if v.len() < byte_len_needed {
return if v.is_empty() && obj.is_zero() {
Ok(())
} else {
Err(byte_len_needed)
};
}
let is_negative = mpz_is_negative(obj);
if is_negative {
// MEGA HACK: GMP does not have a function to perform 2's complement
let obj = !obj;
debug_assert!(
!mpz_is_negative(&obj),
"bitwise negation of a negative number produced a negative number"
);
let new_byte_size = (size_in_bits(&obj) + 7) >> 3;
let offset = v.len() - new_byte_size;
for i in &mut v[..offset] {
*i = 0xFF
}
unsafe {
assert_eq!(raw_export(v, offset, &obj), new_byte_size);
}
// We had to do a ones complement to get the data in a decent format,
// so now we need to flip all of the bits back. LLVM should be able to
// vectorize this loop easily.
for i in &mut v[offset..] {
*i ^= 0xFF
}
} else {
// ...but GMP will not include that in the number of bytes it writes
// (except for negative numbers)
let byte_len = (size + 7) >> 3;
assert!(byte_len > 0);
let offset = v.len() - byte_len;
// Zero out any leading bytes
for i in &mut v[..offset] {
*i = 0
}
unsafe {
assert_eq!(raw_export(v, offset, &obj), byte_len);
}
}
Ok(())
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn check_expected_bit_width() {
let mut s: Mpz = (-2).into();
assert_eq!(size_in_bits(&s), 2);
s = !s;
assert_eq!(s, 1.into());
s.setbit(2);
assert_eq!(s, 5.into());
}
#[test]
fn check_export() {
let mut s: Mpz = 0x100.into();
s = !s;
let mut buf = [0, 0, 0];
export_obj(&s, &mut buf).expect("buffer should be large enough");
assert_eq!(buf, [0xFF, 0xFE, 0xFF]);
export_obj(&Mpz::zero(), &mut []).unwrap();
}
#[test]
fn check_rem() {
assert_eq!(mpz_crem_u16(&(-100i64).into(), 3), 1);
assert_eq!(mpz_crem_u16(&(100i64).into(), 3), 2);
}
}

View File

@ -0,0 +1,590 @@
// 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 super::ClassGroup;
use super::gmp::mpz::Mpz;
use super::gmp::mpz::ProbabPrimeResult::NotPrime;
use num_traits::{One, Zero};
use std::{
borrow::Borrow,
cell::RefCell,
mem::swap,
ops::{Mul, MulAssign},
};
use std::convert::TryInto;
mod congruence;
pub(super) mod ffi;
#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Debug, Clone)]
pub struct GmpClassGroup {
a: Mpz,
b: Mpz,
c: Mpz,
discriminant: Mpz,
}
#[derive(PartialEq, PartialOrd, Eq, Ord, Clone, Hash, Debug)]
pub struct Ctx {
negative_a: Mpz,
r: Mpz,
denom: Mpz,
old_a: Mpz,
old_b: Mpz,
ra: Mpz,
s: Mpz,
x: Mpz,
congruence_context: congruence::CongruenceContext,
h: Mpz,
w: Mpz,
m: Mpz,
u: Mpz,
a: Mpz,
l: Mpz,
j: Mpz,
b: Mpz,
k: Mpz,
t: Mpz,
mu: Mpz,
v: Mpz,
sigma: Mpz,
lambda: Mpz,
}
thread_local! {
static CTX: RefCell<Ctx> = Default::default();
}
impl GmpClassGroup {
pub fn into_raw(self) -> (Mpz, Mpz) {
(self.a, self.b)
}
fn inner_multiply(&mut self, rhs: &Self, ctx: &mut Ctx) {
self.assert_valid();
rhs.assert_valid();
// g = (b1 + b2) / 2
ffi::mpz_add(&mut ctx.congruence_context.g, &self.b, &rhs.b);
ffi::mpz_fdiv_q_ui_self(&mut ctx.congruence_context.g, 2);
// h = (b2 - b1) / 2
ffi::mpz_sub(&mut ctx.h, &rhs.b, &self.b);
ffi::mpz_fdiv_q_ui_self(&mut ctx.h, 2);
debug_assert!(&ctx.h + &ctx.congruence_context.g == rhs.b);
debug_assert!(&ctx.congruence_context.g - &ctx.h == self.b);
// w = gcd(a1, a2, g)
ffi::three_gcd(&mut ctx.w, &self.a, &rhs.a, &ctx.congruence_context.g);
// j = w
ctx.j.set(&ctx.w);
// s = a1/w
ffi::mpz_fdiv_q(&mut ctx.s, &self.a, &ctx.w);
// t = a2/w
ffi::mpz_fdiv_q(&mut ctx.t, &rhs.a, &ctx.w);
// u = g/w
ffi::mpz_fdiv_q(&mut ctx.u, &ctx.congruence_context.g, &ctx.w);
// a = t*u
ffi::mpz_mul(&mut ctx.a, &ctx.t, &ctx.u);
// b = h*u - s*c1
ffi::mpz_mul(&mut ctx.b, &ctx.h, &ctx.u);
ffi::mpz_mul(&mut ctx.m, &ctx.s, &self.c);
ctx.b += &ctx.m;
// m = s*t
ffi::mpz_mul(&mut ctx.m, &ctx.s, &ctx.t);
ctx.congruence_context.solve_linear_congruence(
&mut ctx.mu,
Some(&mut ctx.v),
&ctx.a,
&ctx.b,
&ctx.m,
);
// a = t*v
ffi::mpz_mul(&mut ctx.a, &ctx.t, &ctx.v);
// b = h - t * mu
ffi::mpz_mul(&mut ctx.m, &ctx.t, &ctx.mu);
ffi::mpz_sub(&mut ctx.b, &ctx.h, &ctx.m);
// m = s
ctx.m.set(&ctx.s);
ctx.congruence_context.solve_linear_congruence(
&mut ctx.lambda,
Some(&mut ctx.sigma),
&ctx.a,
&ctx.b,
&ctx.m,
);
// k = mu + v*lambda
ffi::mpz_mul(&mut ctx.a, &ctx.v, &ctx.lambda);
ffi::mpz_add(&mut ctx.k, &ctx.mu, &ctx.a);
// l = (k*t - h)/s
ffi::mpz_mul(&mut ctx.l, &ctx.k, &ctx.t);
ffi::mpz_sub(&mut ctx.v, &ctx.l, &ctx.h);
ffi::mpz_fdiv_q(&mut ctx.l, &ctx.v, &ctx.s);
// m = (t*u*k - h*u - c*s) / s*t
ffi::mpz_mul(&mut ctx.m, &ctx.t, &ctx.u);
ctx.m *= &ctx.k;
ffi::mpz_mul(&mut ctx.a, &ctx.h, &ctx.u);
ctx.m -= &ctx.a;
ffi::mpz_mul(&mut ctx.a, &self.c, &ctx.s);
ctx.m -= &ctx.a;
ffi::mpz_mul(&mut ctx.a, &ctx.s, &ctx.t);
ffi::mpz_fdiv_q(&mut ctx.lambda, &ctx.m, &ctx.a);
// A = s*t - r*u
ffi::mpz_mul(&mut self.a, &ctx.s, &ctx.t);
// B = ju + mr - (kt + ls)
ffi::mpz_mul(&mut self.b, &ctx.j, &ctx.u);
ffi::mpz_mul(&mut ctx.a, &ctx.k, &ctx.t);
self.b -= &ctx.a;
ffi::mpz_mul(&mut ctx.a, &ctx.l, &ctx.s);
self.b -= &ctx.a;
// C = kl - jm
ffi::mpz_mul(&mut self.c, &ctx.k, &ctx.l);
ffi::mpz_mul(&mut ctx.a, &ctx.j, &ctx.lambda);
self.c -= &ctx.a;
self.inner_reduce(ctx);
}
#[cfg_attr(not(debug_assertions), inline(always))]
fn new(a: Mpz, b: Mpz, c: Mpz, discriminant: Mpz) -> Self {
let s = GmpClassGroup {
a,
b,
c,
discriminant,
};
s.assert_valid();
s
}
#[cfg_attr(not(debug_assertions), inline(always))]
fn assert_valid(&self) {
if cfg!(debug_assertions) {
let four: Mpz = 4u64.into();
let four_ac: Mpz = four * &self.a * &self.c;
assert!(&self.discriminant + four_ac == &self.b * &self.b);
}
}
fn inner_normalize(&mut self, ctx: &mut Ctx) {
self.assert_valid();
ctx.negative_a = -&self.a;
if self.b > ctx.negative_a && self.b <= self.a {
return;
}
ffi::mpz_sub(&mut ctx.r, &self.a, &self.b);
ffi::mpz_mul_2exp(&mut ctx.denom, &self.a, 1);
ffi::mpz_fdiv_q(&mut ctx.negative_a, &ctx.r, &ctx.denom);
swap(&mut ctx.negative_a, &mut ctx.r);
swap(&mut ctx.old_b, &mut self.b);
ffi::mpz_mul(&mut ctx.ra, &ctx.r, &self.a);
ffi::mpz_mul_2exp(&mut ctx.negative_a, &ctx.ra, 1);
ffi::mpz_add(&mut self.b, &ctx.old_b, &ctx.negative_a);
ffi::mpz_mul(&mut ctx.negative_a, &ctx.ra, &ctx.r);
ffi::mpz_add(&mut ctx.old_a, &self.c, &ctx.negative_a);
ffi::mpz_mul(&mut ctx.ra, &ctx.r, &ctx.old_b);
ffi::mpz_add(&mut self.c, &ctx.old_a, &ctx.ra);
self.assert_valid();
}
fn inner_reduce(&mut self, ctx: &mut Ctx) {
self.inner_normalize(ctx);
while if ffi::mpz_is_negative(&self.b) {
self.a >= self.c
} else {
self.a > self.c
} {
debug_assert!(!self.c.is_zero());
ffi::mpz_add(&mut ctx.s, &self.c, &self.b);
ffi::mpz_add(&mut ctx.x, &self.c, &self.c);
swap(&mut self.b, &mut ctx.old_b);
ffi::mpz_fdiv_q(&mut self.b, &ctx.s, &ctx.x);
swap(&mut self.b, &mut ctx.s);
swap(&mut self.a, &mut self.c);
// x = 2sc
ffi::mpz_mul(&mut self.b, &ctx.s, &self.a);
ffi::mpz_mul_2exp(&mut ctx.x, &self.b, 1);
// b = x - old_b
ffi::mpz_sub(&mut self.b, &ctx.x, &ctx.old_b);
// x = b*s
ffi::mpz_mul(&mut ctx.x, &ctx.old_b, &ctx.s);
// s = c*s^2
ffi::mpz_mul(&mut ctx.old_b, &ctx.s, &ctx.s);
ffi::mpz_mul(&mut ctx.s, &self.a, &ctx.old_b);
// c = s - x
ffi::mpz_sub(&mut ctx.old_a, &ctx.s, &ctx.x);
// c += a
self.c += &ctx.old_a;
}
self.inner_normalize(ctx);
}
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);
}
#[cfg_attr(not(debug_assertions), inline(always))]
fn inner_square(&mut self, ctx: &mut Ctx) {
if cfg!(debug_assertions) {
let mut q = self.clone();
q.inner_multiply(self, ctx);
self.inner_square_impl(ctx);
assert_eq!(*self, q);
} else {
self.inner_square_impl(ctx);
}
}
/// Call `cb` with a mutable reference to the context of type `Ctx`.
///
/// The reference cannot escape the closure and cannot be sent across
/// threads.
///
/// # Panics
///
/// Panics if called recursively. This library guarantees that it will
/// never call this function from any function that takes a parameter of
/// type `&mut Ctx`.
pub fn with_context<T, U>(cb: T) -> U
where
T: FnOnce(&mut Ctx) -> U,
{
let mut opt = None;
CTX.with(|x| opt = Some(cb(&mut x.borrow_mut())));
opt.unwrap()
}
}
impl Default for GmpClassGroup {
fn default() -> Self {
GmpClassGroup {
a: Mpz::new(),
b: Mpz::new(),
c: Mpz::new(),
discriminant: Mpz::new(),
}
}
}
impl<B: Borrow<GmpClassGroup>> MulAssign<B> for GmpClassGroup {
#[cfg_attr(not(debug_assertions), inline(always))]
fn mul_assign(&mut self, rhs: B) {
let rhs = rhs.borrow();
debug_assert!(self.discriminant == rhs.discriminant);
GmpClassGroup::with_context(|ctx| self.inner_multiply(rhs, ctx));
}
}
impl super::BigNum for Mpz {
fn probab_prime(&self, iterations: u32) -> bool {
let reps: i32 = iterations.try_into().expect("Iterations fits into i32");
self.probab_prime(reps) != NotPrime
}
fn setbit(&mut self, bit_index: usize) {
self.setbit(bit_index)
}
fn mod_powm(&mut self, base: &Self, exponent: &Self, modulus: &Self) {
ffi::mpz_powm(self, base, exponent, modulus)
}
}
impl super::BigNumExt for Mpz {
fn frem_u32(&self, modulus: u32) -> u32 {
ffi::mpz_frem_u32(self, modulus)
}
fn crem_u16(&mut self, modulus: u16) -> u16 {
ffi::mpz_crem_u16(self, modulus)
}
}
impl<B: Borrow<Self>> Mul<B> for GmpClassGroup {
type Output = Self;
#[inline]
fn mul(mut self, rhs: B) -> Self {
self *= rhs.borrow();
self
}
}
impl<'a, B: Borrow<GmpClassGroup>> Mul<B> for &'a GmpClassGroup {
type Output = GmpClassGroup;
#[inline(always)]
fn mul(self, rhs: B) -> Self::Output {
let mut s = Clone::clone(self.borrow());
s *= rhs;
s
}
}
impl ClassGroup for GmpClassGroup {
type BigNum = Mpz;
/// Normalize `self`.
///
/// # Panics
///
/// Panics if called within a call to `Self::with_context`.
fn normalize(&mut self) {
Self::with_context(|x| self.inner_normalize(x))
}
#[cfg_attr(not(debug_assertions), inline(always))]
fn inverse(&mut self) {
self.assert_valid();
self.b = -self.b.clone();
}
fn serialize(&self, buf: &mut [u8]) -> Result<(), usize> {
self.assert_valid();
if buf.len() & 1 == 1 {
// odd lengths do not make sense
Err(0)
} else {
let len = buf.len() >> 1;
ffi::export_obj(&self.a, &mut buf[..len])?;
ffi::export_obj(&self.b, &mut buf[len..])
}
}
fn from_bytes(bytearray: &[u8], discriminant: Self::BigNum) -> Self {
let len = (ffi::size_in_bits(&discriminant) + 16) >> 4;
let a = ffi::import_obj(&bytearray[..len]);
let b = ffi::import_obj(&bytearray[len..]);
Self::from_ab_discriminant(a, b, discriminant)
}
fn from_ab_discriminant(a: Self::BigNum, b: Self::BigNum, discriminant: Self::BigNum) -> Self {
let mut four_a: Self::BigNum = 4u64.into();
four_a *= &a;
let c = (&b * &b - &discriminant) / four_a;
Self {
a,
b,
c,
discriminant,
}
}
/// Returns the discriminant of `self`.
#[inline(always)]
fn discriminant(&self) -> &Self::BigNum {
&self.discriminant
}
fn size_in_bits(num: &Self::BigNum) -> usize {
ffi::size_in_bits(num)
}
/// Reduce `self`.
///
/// # Panics
///
/// Panics if called within a call to `Self::with_context`.
fn reduce(&mut self) {
Self::with_context(|x| self.inner_reduce(x))
}
fn deserialize(buf: &[u8], discriminant: Self::BigNum) -> Self {
let len = buf.len();
debug_assert!(len != 0, "Cannot deserialize an empty buffer!");
debug_assert!(len & 1 == 0, "Buffer must be of even length");
let half_len = len >> 1;
Self::from_ab_discriminant(
ffi::import_obj(&buf[..half_len]),
ffi::import_obj(&buf[half_len..]),
discriminant,
)
}
/// Square `self`.ClassGroupPartial
///
/// # Panics
///
/// Panics if called within the scope of a call to `with_context`.
fn square(&mut self) {
Self::with_context(|ctx| self.inner_square(ctx))
}
fn unsigned_deserialize_bignum(buf: &[u8]) -> Self::BigNum {
buf.into()
}
/// Square `self` `iterations` times.
///
/// # Panics
///
/// 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)
}
})
}
fn generator_for_discriminant(discriminant: Self::BigNum) -> Self {
let one: Mpz = One::one();
let x: Mpz = &one - &discriminant;
let mut form = Self::new(2.into(), one, x.div_floor(&8.into()), discriminant);
form.reduce();
form
}
fn pow(&mut self, mut exponent: Mpz) {
self.assert_valid();
debug_assert!(exponent >= Mpz::zero());
let mut state = self.identity();
loop {
let is_odd = exponent.tstbit(0);
exponent >>= 1;
if is_odd {
state *= &*self
}
if exponent.is_zero() {
*self = state;
break;
}
self.square();
}
}
}
impl Default for Ctx {
fn default() -> Self {
Self {
negative_a: Mpz::new(),
r: Mpz::new(),
denom: Mpz::new(),
old_a: Mpz::new(),
old_b: Mpz::new(),
ra: Mpz::new(),
s: Mpz::new(),
x: Mpz::new(),
congruence_context: Default::default(),
w: Mpz::new(),
m: Mpz::new(),
u: Mpz::new(),
l: Mpz::new(),
j: Mpz::new(),
t: Mpz::new(),
a: Mpz::new(),
b: Mpz::new(),
k: Mpz::new(),
h: Mpz::new(),
mu: Mpz::new(),
v: Mpz::new(),
sigma: Mpz::new(),
lambda: Mpz::new(),
}
}
}
pub fn do_compute(discriminant: Mpz, iterations: u64) -> GmpClassGroup {
debug_assert!(discriminant < Zero::zero());
debug_assert!(discriminant.probab_prime(50) != NotPrime);
let mut f = GmpClassGroup::generator_for_discriminant(discriminant);
f.repeated_square(iterations);
f
}
#[cfg(test)]
mod test {
#![allow(unused_imports)]
use super::*;
#[test]
fn normalize() {
let mut s = GmpClassGroup::new(
16.into(),
(-23).into(),
5837_3892.into(),
(-0xdead_beefi64).into(),
);
let mut new = GmpClassGroup {
b: 9.into(),
c: 5837_3885.into(),
..s.clone()
};
s.normalize();
assert_eq!(s, new);
s = GmpClassGroup {
a: (1 << 16).into(),
b: (-76951).into(),
c: 36840.into(),
..s
};
new = GmpClassGroup {
b: 54121.into(),
c: 25425.into(),
..s.clone()
};
s.normalize();
assert_eq!(s, new);
}
}

View File

@ -0,0 +1,251 @@
// 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<usize>
+ for<'a> MulAssign<&'a Self>
+ std::ops::Sub<u64, Output = Self>
+ std::ops::Add<u64, Output = Self>
+ std::convert::From<u64>
+ for<'a> std::convert::From<&'a [u8]>
+ std::ops::Shl<usize, Output = Self>
+ std::ops::Shr<usize, Output = Self>
+ std::ops::Neg<Output = Self>
+ 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<Mpz> = 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();
}
}
}

View File

@ -0,0 +1,100 @@
10000018491751458060893889018190756675058808109876974330719629294415871248770716417843542202672894233523533522085426391611508488462673577289978500560291881560964103822003262872704649110111368415677918460552197008588860300461769848797788221536509692873112178498610293735717449110462487732034905273446995235572,6192881975696225786035966982664995064937044822044587534644251299449043731778362309709151420033302511678628887337754750911692576543520793791684926797453257880919340267222510512181015985728296989735175472866965866872698457694161211487470544291337368825900113948256559852781942460432108372735686602775132351861,447562623961213317971342646547297454284223350038133828902656285846421695114449573517005802064814603287280139301229441755696758326577197667784458131993559071961595818908854193681416803619972011522725445624820104005456169532111411278882533391024720916070194718519556110684723979632586634811370262763099820931946|10000018491751458060893889018190756675058808109876974330719629294415871248770716417843542202672894233523533522085426391611508488462673577289978500560291881560964103822003262872704649110111368415677918460552197008588860300461769848797788221536509692873112178498610293735717449110462487732034905273446995235572,6192881975696225786035966982664995064937044822044587534644251299449043731778362309709151420033302511678628887337754750911692576543520793791684926797453257880919340267222510512181015985728296989735175472866965866872698457694161211487470544291337368825900113948256559852781942460432108372735686602775132351861,447562623961213317971342646547297454284223350038133828902656285846421695114449573517005802064814603287280139301229441755696758326577197667784458131993559071961595818908854193681416803619972011522725445624820104005456169532111411278882533391024720916070194718519556110684723979632586634811370262763099820931946|19255554116382770161579383715714909264782708765539029964624834623077914838241374452996111823462588737699221151887520236764901217774034554643488538519529924118839366411749516259835028878669578401436677730193218203890014064720579917095034628468204338354122803225577022412929359504950608508400413031048217497926,15092837287167018117143864462870004173493326087323162483214185994683512256473920528820058682931229518373567536566141901399624393736734616696317492646832399845295961581562413238135817545423153806714585874605091134049460217739322207059368564835209958877374166810803213938557201936549078491894191793263450700347,234893006768044042788914260913118901546740453084924505628085298368208613193607118822477736613870586900826160773678687890939302953916150044522278344184471658898873737893277827322372416620559784208443693756270533224257971092005354126278524692768704444715469609790946460097751182675767317515935452615150233004184
10000041052183522790242850644893154590720039288612095879016416132777489378534703527529316376767361213758229530778215090392226004364711343494340009516684351602465954563523094253968698993441741189497557646486818525059302740665570749018871945434231968929038967533223013692831944903924891259290137962329173675618,1902993169831098968408340994163042640289698812843652994188396853325597449053613940738900681358483309978075948057374939279288006967407927201371876070720282077185512088102089011109098339510946105167168603912904329219763993441428070797711607939058596983469167495985136256807429373538982995591135613664471290691,648679116947253221704188706776650677211463611636395838310356904951972039958552218839434071543988637793619482253205477878855250277635662749169650536657554110192985236141029049474956216985923614316507072329807839408341849104680142145376380471455107520480114830913820742685234228885993868983705228973767491332409|10000041052183522790242850644893154590720039288612095879016416132777489378534703527529316376767361213758229530778215090392226004364711343494340009516684351602465954563523094253968698993441741189497557646486818525059302740665570749018871945434231968929038967533223013692831944903924891259290137962329173675618,1902993169831098968408340994163042640289698812843652994188396853325597449053613940738900681358483309978075948057374939279288006967407927201371876070720282077185512088102089011109098339510946105167168603912904329219763993441428070797711607939058596983469167495985136256807429373538982995591135613664471290691,648679116947253221704188706776650677211463611636395838310356904951972039958552218839434071543988637793619482253205477878855250277635662749169650536657554110192985236141029049474956216985923614316507072329807839408341849104680142145376380471455107520480114830913820742685234228885993868983705228973767491332409|11014730391994022921548019318564443238610906141262076480168925966763126765751815894971319798676750825680596366806816953155468468927850506963854768575341863098700465049052526243803093026353195834059474734029876952052212354875982568724849333989940233032713622829273608000126280643959163722728068472850088622786,10741667368771260991465304819723549356187315169745538829427954074292104964386739024958802023185700235860418655331632400858711212007319896932342251013222776723172845936147563193613725240374195945000924112718166206035243862199173787901602224623957181722190890413718871860292878014198837725481829866947825981913,591458717193488352905603034790202837072660316706237076413003353962226001987681937225165602501036312777007571264636495875979803481147253392478958512772229202313701414596984055959140281478236518410326724468820458881999271606689529119264353275033892327553507658401114443924515886686374958949587811834733084613494
10000381915681932465973261183425742883776417480816046593820159088331265076946313439425523314444345253320002870252043057595684488140407211015115892705028395378796407813776706176594457902083795049968208905578343034404017956993894296039160788337679442024505335413399442760803039586109332233036553257459967307992,4817573728667361865336022581228097408185105735439009440346088109945423944514625700845976724084897576632126538284617885680024575350161902075565426943435359103696435860065323384485576321976518692508202982451179520762630115309722600967720404130152140308793673263051352095721900258702511325402177650727880246935,669873650881721761367318894015191721808238052876596531632606045247446982615721443478227885999211090819818334947786875090863090531638122013530669226521626152920347047659485744946461307259365312735407042929006458450763753134816736952808194188478460912675596404179851630644942038849386883091149385220764843706257|10000381915681932465973261183425742883776417480816046593820159088331265076946313439425523314444345253320002870252043057595684488140407211015115892705028395378796407813776706176594457902083795049968208905578343034404017956993894296039160788337679442024505335413399442760803039586109332233036553257459967307992,4817573728667361865336022581228097408185105735439009440346088109945423944514625700845976724084897576632126538284617885680024575350161902075565426943435359103696435860065323384485576321976518692508202982451179520762630115309722600967720404130152140308793673263051352095721900258702511325402177650727880246935,669873650881721761367318894015191721808238052876596531632606045247446982615721443478227885999211090819818334947786875090863090531638122013530669226521626152920347047659485744946461307259365312735407042929006458450763753134816736952808194188478460912675596404179851630644942038849386883091149385220764843706257|15406883651839353468888340788129827256524366500559993343402492794080742895081542466902089892082975781941021139173750937371748781682695257732868858255213590996446142784059996942302405311028161097993332331718537383888482114789770414489490580461393020737016788325059322912336073066124099655242000162998144490191,4360823987526422964670528620808397080272081276432190896883401768539814490180903410645821165307382339042226562722529652661460320310396511517028476587614669988004410806997734064375576646534713644939599630073534432499720811712867334091133681123961660738588960398432344316577526812821260889068523826290764750305,434737123855318232136803285518736106774596594589476825779021338309188039202684276728719741767739900154018854551253981210446831263812934806367418646532886786527458187655685060926749423401952358398253824964655841491692769761412354811289837062586506164527515355144754089246394187279961001728737349715244065290684
10000382084844819863091735393428537123796094124029988695624509543701671917373805547793586171907452267004536696714359178508237591675470611568215269390130161491021123479579310299191808477715227540644280867131359924216029489859205866802370878621090778893635118109144685744213704279596306855259529008805569484738,-444155911792016461297666514223280647275019670279235098115904524278820479908555182212414682305357120850467322036353999623022556562078881846242421627622835673248504490647482104203937046492778180626801172318868765508903156634858880238203680354870853572676123032093150013906751911065758499256507194503286999359,567054671672969689387757610046141412714538710354002952292665369546607156429867011238555624731427279061383543924144630291236714076290759079492403352598432624404020019598559946194717566760077730429172494635087510893397235439040191683342313758118884331110227782487142203190483880485876667351431228811762752414559|10000382084844819863091735393428537123796094124029988695624509543701671917373805547793586171907452267004536696714359178508237591675470611568215269390130161491021123479579310299191808477715227540644280867131359924216029489859205866802370878621090778893635118109144685744213704279596306855259529008805569484738,-444155911792016461297666514223280647275019670279235098115904524278820479908555182212414682305357120850467322036353999623022556562078881846242421627622835673248504490647482104203937046492778180626801172318868765508903156634858880238203680354870853572676123032093150013906751911065758499256507194503286999359,567054671672969689387757610046141412714538710354002952292665369546607156429867011238555624731427279061383543924144630291236714076290759079492403352598432624404020019598559946194717566760077730429172494635087510893397235439040191683342313758118884331110227782487142203190483880485876667351431228811762752414559|25233315598122077418065976820332071042466787077699487654424387918664961172156179342884760885536120785360009215201873305025819279551843543582105904004062292352688557410351568671077765651689593128194982886401323218888273326531345494420553999096902303332712335656165115841742118280506588108873800795844703864919,-21589572107561067243363628128888045942080137348693403707950771695641329996718935854060105037586070646944119604332897696206540905887323628203932721112852139156892903280775223036949323848394414919310082155940615053363132829628799672709557839434529964085755781777411447385312731490258576057970445296620960747711,229349228584333455202515805454481561086661761655883453088894599746824713549123206719584169689814830025633382253625181015273278307916408839487283320828823538420290774632766998050162873483736921565586622385485530453983863042070274251829142359266901387980967335820672065096008596106715431022577378179753339164658
10000535283948766913969186677763146947350893764133523013624566402396075467775122389351423347627366996308717336970472190566686266526440447170486872996146388310569838407203380788397656952824650289706008150444069157387402604479170310815759950456001810768733293842505752683896727400110806658910272623240889276302,3517715128667026666780257130236186883393464552180724243651182669587910084592324227192755249223315343739548139286489599592680626480533511441942660471947189354661549994487257423179947475122454624754426244988595239282883275819687054584105503928955994194464535141072191228405010641132986293339925974908519502951,570034118010650587062470713310391834950695503036920240298132931861980289236162947574989015145270228575455513419386383991154247888350856213235253786311087987346865298158646949041224197372582390632868027286119802250763817862749191433673344918830453654023465432067298969962772419746088402608223812814936545467246|10000535283948766913969186677763146947350893764133523013624566402396075467775122389351423347627366996308717336970472190566686266526440447170486872996146388310569838407203380788397656952824650289706008150444069157387402604479170310815759950456001810768733293842505752683896727400110806658910272623240889276302,3517715128667026666780257130236186883393464552180724243651182669587910084592324227192755249223315343739548139286489599592680626480533511441942660471947189354661549994487257423179947475122454624754426244988595239282883275819687054584105503928955994194464535141072191228405010641132986293339925974908519502951,570034118010650587062470713310391834950695503036920240298132931861980289236162947574989015145270228575455513419386383991154247888350856213235253786311087987346865298158646949041224197372582390632868027286119802250763817862749191433673344918830453654023465432067298969962772419746088402608223812814936545467246|59075354970692991755903146214605554332637224507205941847466515241658938543685224447213353186403252887052183944064961699964728259961938411627544944845776708313892390437907961447141588832103578886894741951168483053303302416173045780507296127716028825436246283574600092245162214148065236680479535423660537547914,6142586061770095737227904853540455719428485301510321654081360726874454746843797212863006221294314976215484969948774214251692404250673117267549442037815482195083213974160653516820675375995512277154295678704255795063545010227709473438581077714090470093020228882800682332012139884210689872621538573295925265993,96605184581646361029373732724432135349175091555904351927012123488431445097722589746711095342410196584277564279992867684018993498546178659279293376777551513451631505380655431533215245951077120355215801949799249196142928522335615942042353764886891560316955633828555662725473411497902686741832487630568702990486
10000992092359348487480681816729833858083850458212481718635084324812805161168823645716695515173763020806162121153711923870750015861003941980870964102569907660333270160386745314618020099129085566179786211585530303068327607946822258160299176181360948584855686949828385515610423848592364973361809055890165682387,1387707194943048769069000645578034755727575677682880147095892736572338185330919801102067876481652092034533316677281336622039276010947331496276488954193596489132454018768653574924396409513550904384989555254933742194365096022768325215822785577085941233088045260998209615597763890732713200353258054623633203363,717334904486111082107761816895355357018690502858423612748563938578649989943228419203563081094256539563484346776479991186971459579979441405718434993605445911043337999222596585935065011724285592737227690661183256354762587476450143021573235732571046140183664111033663616265739167081365443050278073128430130275044|10000992092359348487480681816729833858083850458212481718635084324812805161168823645716695515173763020806162121153711923870750015861003941980870964102569907660333270160386745314618020099129085566179786211585530303068327607946822258160299176181360948584855686949828385515610423848592364973361809055890165682387,1387707194943048769069000645578034755727575677682880147095892736572338185330919801102067876481652092034533316677281336622039276010947331496276488954193596489132454018768653574924396409513550904384989555254933742194365096022768325215822785577085941233088045260998209615597763890732713200353258054623633203363,717334904486111082107761816895355357018690502858423612748563938578649989943228419203563081094256539563484346776479991186971459579979441405718434993605445911043337999222596585935065011724285592737227690661183256354762587476450143021573235732571046140183664111033663616265739167081365443050278073128430130275044|46482666589787057164981427600152979028584675170625944424946407599960201881805307116957471661211638766618134840736062752900079748534826618093953946800313092285412874757225443617416186449293441503680335786478712016820930243711850679772176006938838607901709770799483635364697553013258865109416434882051210741449,3101717798468321538599785648396208464189816894621339325506629294456148802654755640066207376362353269286149982363784579708988481769754035006891067923386713257060529140906313751403507998251605485836475302614223762235407657418301209467207199741940328204824018102771458491705342260612142478146285653246057987987,154379792819937466421655387360779358004857339117994029103954006768201464432625988196022580370956875717212647779858597489967018623693936133011607398083022906238217469025231498041115162395196295497816525433748189786409656276394144968660209259259055129261299657708619246489632848864169630941858852164482792598772
100016993550415829135262361263254459069906572411523652885898601946150332160005753209165983241360621518247046578246408973951913750019427396230791395391900464740479884371689964652672891087059763533492805056734857093926525888370387953270730195624561287530833550654825448807998575583518751690880145682614320134626,97867808093652711513661030354940855898834960524171083907471520733521588237588575528935854367900557849089129501606401645574828485643984844895342166280487749477320616345326562522776423978127616648618120061233592736634312164206210712776242358394865817287600812334839844119000151584498625451416447766525556737091,101546865178620340984298080630771114165409461904937118589108835750643335026750315119287055941177105859697880165662377691746530085636458948369814197349790717060438350144172923110723731589639766266300381349821152919234474715235659078426677984814293485454727036020005038295982154861599467045526190910921111647828|100016993550415829135262361263254459069906572411523652885898601946150332160005753209165983241360621518247046578246408973951913750019427396230791395391900464740479884371689964652672891087059763533492805056734857093926525888370387953270730195624561287530833550654825448807998575583518751690880145682614320134626,97867808093652711513661030354940855898834960524171083907471520733521588237588575528935854367900557849089129501606401645574828485643984844895342166280487749477320616345326562522776423978127616648618120061233592736634312164206210712776242358394865817287600812334839844119000151584498625451416447766525556737091,101546865178620340984298080630771114165409461904937118589108835750643335026750315119287055941177105859697880165662377691746530085636458948369814197349790717060438350144172923110723731589639766266300381349821152919234474715235659078426677984814293485454727036020005038295982154861599467045526190910921111647828|38112895924354771000755967523257705692975308805226188158888846989042277994318034233632572801944291367363544635160689172507870767350780603573652174702847837195353422410303076999489362677424810242035375507542324255582549804459073498689456734177829753341266635299826832746075600445484602669454902196797110414268,29514825972671498452469428270002667581396743351651746797469797047436108385118786112979101930068512381300796319538713657519350359618509818562580593402643136639943548729030802553674984090829042397520519175389582956780710082733565916489480248905811215441925467758974481931055406921284703112579763389522667256173,209369197456369085510398489829077224010383063845121124974155708663637684112727148688124840116395472316273115362880530986565561714461662746456509765896943657967931982155109566457128704664240543108345283001161566864139257311910823070822151712032036583892036613154176268529246135956533435036580269691993608092680
10001857278272414635783742468687626112156223003835485801536389954295572560863634462501676022563000509436968020300398791815574826898175032553202096799719821296404518525211113962533485614199031043964942385615363652892938675160040173449995570062547675787656647030050979129677693759900885701969029983016110814344,4689276451232458601825639665209988136946233783317430787463374655024892705415877731372938558103104801918261384975590626995047805878141047994265820723310810966786623993284261416684874325742989563037963206467146622805115830511715873009621433988190289268680824928937364349844265466118648518849937971040073290847,417151168234058306514924962236880342366392470330250088900617117412557071558608977094869379187282436222898630224671275148160961737937513168266914431807498623302460140528881877180166348694674662748849360025138764269398178107070427436885941278328572218964052739099341639294288244256170434477924203033934350673327|10001857278272414635783742468687626112156223003835485801536389954295572560863634462501676022563000509436968020300398791815574826898175032553202096799719821296404518525211113962533485614199031043964942385615363652892938675160040173449995570062547675787656647030050979129677693759900885701969029983016110814344,4689276451232458601825639665209988136946233783317430787463374655024892705415877731372938558103104801918261384975590626995047805878141047994265820723310810966786623993284261416684874325742989563037963206467146622805115830511715873009621433988190289268680824928937364349844265466118648518849937971040073290847,417151168234058306514924962236880342366392470330250088900617117412557071558608977094869379187282436222898630224671275148160961737937513168266914431807498623302460140528881877180166348694674662748849360025138764269398178107070427436885941278328572218964052739099341639294288244256170434477924203033934350673327|39512406098482423779120312488933213318036506673065796538336022993655638182250527755522829589375917826833348984821059004871245970343092490834408525776732580142621174939994986501353324355190007207510458548320626445520306240377159533568686613898702507848891809938754441261902406274233712558160571614302439957131,33458680315871522230740954658476053975126560151398110919331173177225767029941330426356821906446363070251030468052516656211641983986229753635879608148342626307073260672093693099423083101538134818421873088154104042575469404107414196063491342206675483762419581621360672445423968155195195983917204254937268665705,112538323552595379512976869360963431325956968605739748467981199043411580278581204995308070112281536994589175551282469490999392089726267157369534414758432876571069898487221813246689682731800084089695271351717243345819033451481449481940560204129785884663224360555776373560572513249146398346919605386672664225732
10001885848475688153826124264809818246080666151576830718882253306412201821167674972767046901596625026072385280166547579462646990262300818624039744400633121727773879619930855094164710044647150456604915949836019563376717637829785627004484641494826695600821088683607312916171680087163211415876920408834836303184,-6401849646396930994521658626667447090190354097997530993450466589091600058118189817231880440719330366452128426380645424906405833189843064340607355709362044588398581812540592198712107929843518387144633043143678667045861106413931254718474764939962100744640406024944116893338624373426827575556627557030324975185,729010733894420808263762284440227341447693348621882426869722779163540379242011358298248405166128119693780872987746515732812024832371695093716504877119416045933332381529307504733200317114594647306152268108402837078447121693601055930678151182644443827620435481034522157377127949376404692708089215142290715182147|10001885848475688153826124264809818246080666151576830718882253306412201821167674972767046901596625026072385280166547579462646990262300818624039744400633121727773879619930855094164710044647150456604915949836019563376717637829785627004484641494826695600821088683607312916171680087163211415876920408834836303184,-6401849646396930994521658626667447090190354097997530993450466589091600058118189817231880440719330366452128426380645424906405833189843064340607355709362044588398581812540592198712107929843518387144633043143678667045861106413931254718474764939962100744640406024944116893338624373426827575556627557030324975185,729010733894420808263762284440227341447693348621882426869722779163540379242011358298248405166128119693780872987746515732812024832371695093716504877119416045933332381529307504733200317114594647306152268108402837078447121693601055930678151182644443827620435481034522157377127949376404692708089215142290715182147|29744618895999892950369062264736486891947372089326189805787662049365991492371249728993520356943689392647109012744687302300685788536119433016012855224253957313263294648625309856809103016565484862180956099939466843259337398301571034092060768935310042949815131108676382925915723778520018870120465703148469427226,-10209285996871914054868241646783255177966316197845761911887894869148957597460422378515655227929008210712234487944652632986850515682880041083632277387837772452379138668071836676947710588769042538916436601704393264463866941375385749221300434945563044575029802713999893603873804815268692854499670177122342861333,245667750146427110150677187685482906099978771660913415239953145936955067540313763536644215438217145059701666728130321490946010447912027178133916738527033418368981585094936292739042791746985193177096407440545894318127458296684680664341938696795502212145624334822453802110708189609055956050992529688916696742439
10002016107047298540914373810554280751018084476212026169532336244000095667290766720576480147453702781819098831501724861337484902920323127318735651635800283580581543246660775103367813382337363027395892342097619966629022106712471908155888170784651450900253429516651100879214540932985016853993115133868182018064,3932953570343042122021312972484149360925874859667466184891542534824273073163448674737029662190753442883970728845641115381889397609743429783435425637213409939798177187589001177019943245975437142488968879145205618985792078085357316999616817143927979980310665100836939307474346180730761675171280731347158671449,501820428787763072597412186811130523406055528535842317937667844140331895435375780110188856271616785538949009425271158566975765518229735762290911833082144356638560737127790858277137050097833066958564259261818227652665496782587799644931796940046040067871968056722480981736692953918030967693251282638067356406145|10002016107047298540914373810554280751018084476212026169532336244000095667290766720576480147453702781819098831501724861337484902920323127318735651635800283580581543246660775103367813382337363027395892342097619966629022106712471908155888170784651450900253429516651100879214540932985016853993115133868182018064,3932953570343042122021312972484149360925874859667466184891542534824273073163448674737029662190753442883970728845641115381889397609743429783435425637213409939798177187589001177019943245975437142488968879145205618985792078085357316999616817143927979980310665100836939307474346180730761675171280731347158671449,501820428787763072597412186811130523406055528535842317937667844140331895435375780110188856271616785538949009425271158566975765518229735762290911833082144356638560737127790858277137050097833066958564259261818227652665496782587799644931796940046040067871968056722480981736692953918030967693251282638067356406145|64735528603519488065780804878324224417188886620278284672701068126880574848630151784368770212266476848015707656767389613750457721321054695685260658278678665196373574627583845291930832489025699028328049591231345912341357077706665618380075933900907723135182099099317242925058024706513979297237254597076227095551,4676767511975502628189775967741301363073348373643615464321451471292999156583060169457486234222367809825517380380305131875518326506653500784620820595247817795436795668446618561421217197076229074005115884048096800861583629462266306937502121558685767398985500271610752282597009278306418521631471902811873963535,77558909729073708624985274700160896365175589183029958928607160881016530406365743721430360419631842295388705380922110512036514218268293799548453381932743351256518434510701744265175175287358735767897041689462764452869200380851139430193325516047764774954110200096814808839955087651569998366318539183831351467636
10002034549022819403076408239222347017099550415714472028923655065363879242538082883332046406086443448767298655226522786685511031384602322251464988942315474592768020948704552969250388174426697733005815698500285576084348657180234667772665672224649309035191988841439951539719672753703757656633080728573515972292,2010796810968504378931299158317582090146742925585241000850486049458701149088072887117382202081460750175074877155829037914121263394655667323321997117300425990805089503958548860857023509792455388955490579562907955528791083522774450681564161379845706643578690350999966442870934289738064461129972772676090524913,558321669961648887847428632824052548431625768519625138834794746205714201508858412984925892097351057558062620149468106508584560558388430324467000609767675063271492932614039773497135546738436362846803805003389182782828963768739992366197919348230812882254139576244708687275965273358081737826555824405654768290694|6826578859626734597480939133878569229694460186644971629457853526114421649076835335603573751879988329839397104649987465835398566386002039755592773568446984903389961798459390528478761929712163120494037385730792909171532085167309911050308445263496353865937264941597436020907055251736048076644006844409202248304,5916703632910582851125880793132408903816292476260991242513549737921610794279828040608017189829216974970365350284663821730060215581487763067707193344265376739551991053238254698337087591646614840450823227220261123886424801128338724411047128491092060105475853943890821103779036774500319107460531685286202841441,819164879939066316247739921674596158995075399415076526828586576697986820808489862654252316603348700696267835592140978359698748448462852314742485570195189002909951418034161212683212111469166114805395316595157859568773382000204444562394625047968122644730117571140576687713835978983039148632840884180063353321919|24525593055568742416097249604269483346856874441455178370798633512644823613408551383898889724136436641596007886888916843304556505396562460452498580122367837296026711996552032327466172455184570034171840642876125912558571322892683749487069829210684821264854566376842632617791479252532263566234814371052354893484,-1533308789349159850456496166928278185899248924637820082743446320631452265558278807739507468009525157831824183682096795742851767532204899527778707496003773066153051313109361171305769881696175185189326727846932831915940721252274125841396183853650527186995865126146441484052102425089961043364891055445991541807,227677657081722376213157149142023336288707753333770972277638057778548802624067098792373455123375286502620159760351354502534495438446400227420867854824820469572948638801811562066346273782346907474917163347261714943740349452378338981756888788776146521650040273657711500699241321825395413707817445618060462480902
10002074125017355975599743151046242846511112798798396053226619327592735057422378177948114365284430939135093491265336806767482478919758311098907293451660632908142687429542305038471993566061112091142254674235636984969318093242303552823770654042157452160266396125764144057012639465935378258561790879307671193782,-2677875592705731980082114894429792995071386706298929334230749772186164127600272370546755010431170895608048375369668020170159823760294147973474095537503850192302837032131733237064875342982073993793395058782971441692000690573793255526540716486233592692407763281116363187020386252791667246848349317822548915689,648635985571325401692595356147567233561468612108663071405974903212101924183730392746938934107001054497457734923399698902258386855829500228588241165821030031659482670628135844118612829510920403042586089191580683729603024542404607259365592152472123612035976391470864076397175842526847201114587386293478162448846|10002074125017355975599743151046242846511112798798396053226619327592735057422378177948114365284430939135093491265336806767482478919758311098907293451660632908142687429542305038471993566061112091142254674235636984969318093242303552823770654042157452160266396125764144057012639465935378258561790879307671193782,-2677875592705731980082114894429792995071386706298929334230749772186164127600272370546755010431170895608048375369668020170159823760294147973474095537503850192302837032131733237064875342982073993793395058782971441692000690573793255526540716486233592692407763281116363187020386252791667246848349317822548915689,648635985571325401692595356147567233561468612108663071405974903212101924183730392746938934107001054497457734923399698902258386855829500228588241165821030031659482670628135844118612829510920403042586089191580683729603024542404607259365592152472123612035976391470864076397175842526847201114587386293478162448846|67949938415113064293161178659030590691132496955041316494045733862875749417850747302562113500007310852668303846586641135508462313201852828769777121178050596003427926460422904475476244906898063142012649435038037100034350908875980928269206397866321214852019966694130786407505714074230941338096203488261864055662,53288668959102688425004591339691466327049075866255869214424335604117440952293373897678874847548640712084573721941183729796456325294146528429835461394439973255133211226526484818899123041166158632993340470979352834271983572524972059884357370847142645448863117621210245351327485761671145696210503054900410821273,105899036571802576293359771771735244647493044658191270723159384029727618422730315689072753328136534522456073200532359330590111785906447289835484981246848193838501538977975954024004079425925298710095769756420575788761877694146481988831153103750420171232975154220500803062063592047512891980560706613446433318602
1000253663479701075381410901780503799818388911512704954335021374915858764824090995263167708417293347017273433263645587016366542848367626143993424043714190337762737334693150155289579305664876408056173092807453213218218789600598025704962632695206955492435575043105375877466941810990278101450609180156411393563,66294252873466406327783927757894402143872047742685585398248434686370376436933447604037129338463580005900665059990247763362159976852149607009612276330769317942643706356713296053874697713940805071384498697200382739281769000631492714220560824564622672983217861541737814215572898066821664279189734871952442485,7449081821920052343907585734636804107890073716887030220252146886374375473495388497829441955869708386804952455148603275078999958645575875758803250484635047415319443379977946970239132988474813562402674036138638943113227930164450433318295035974410121827732702738775533740738542926454278142700154894632584181276846|1000253663479701075381410901780503799818388911512704954335021374915858764824090995263167708417293347017273433263645587016366542848367626143993424043714190337762737334693150155289579305664876408056173092807453213218218789600598025704962632695206955492435575043105375877466941810990278101450609180156411393563,66294252873466406327783927757894402143872047742685585398248434686370376436933447604037129338463580005900665059990247763362159976852149607009612276330769317942643706356713296053874697713940805071384498697200382739281769000631492714220560824564622672983217861541737814215572898066821664279189734871952442485,7449081821920052343907585734636804107890073716887030220252146886374375473495388497829441955869708386804952455148603275078999958645575875758803250484635047415319443379977946970239132988474813562402674036138638943113227930164450433318295035974410121827732702738775533740738542926454278142700154894632584181276846|24568037830590216352984530012697330969024585773239190902318728852976076281369516446912320948078334220155283803919583544158932277992855289960471883436534381687899324079630011764816867889328310023423094633012275199876596315083044545869380586009580913007036860399795245680314963399389559624688311082823805090231,5319068676363461453927187061672827259672166236556729558696928212559807675749791870496620364221934584448485936117599756917409724038460841591469075162277678937851596763739958878425260723977292640004766308405052660448827954872311329092739598965306131405515429262746842239243566030717413542127898656259746125971,303566913138393892567904204367686915490068122814370585780506941778399006742359108535463859108136357801343091343038391472615790503246239776473238906631454625779972045236751565874336398670607783613554147722203607531035833062634596664836955674449545888313212125443460195013735390947268982347767364377764736422042
10002641226772515081987795211537787929272477458505554463354638964352971364408874452069546961937801811210947177338408164991078687591091465516969203874900752888301636133298179753283838003443413422949614854305289101035884523695670918489325845677592608946818353360132477183288514801318828834214935649039394032252,-8793160452550363276528664072517898739234784407606709040941098303790678596260001324417462973553168029853952326856848991111004093395583096302100461452777142804629182141499607986715453131122448708636069213611853518781262192482364818383993101471525466753092118188242931192181704912063647353300605222746836800483,492078265126922274690434467399394077805701275647322071646319840779745006934618899651871133218190471317339124114044099413606811819906582945782428482112475530640807894231223382852644187084233002016394775416098135698147532762509163053201184493973160623592655199338520312133914851239167130412730662124292772722504|10002641226772515081987795211537787929272477458505554463354638964352971364408874452069546961937801811210947177338408164991078687591091465516969203874900752888301636133298179753283838003443413422949614854305289101035884523695670918489325845677592608946818353360132477183288514801318828834214935649039394032252,-8793160452550363276528664072517898739234784407606709040941098303790678596260001324417462973553168029853952326856848991111004093395583096302100461452777142804629182141499607986715453131122448708636069213611853518781262192482364818383993101471525466753092118188242931192181704912063647353300605222746836800483,492078265126922274690434467399394077805701275647322071646319840779745006934618899651871133218190471317339124114044099413606811819906582945782428482112475530640807894231223382852644187084233002016394775416098135698147532762509163053201184493973160623592655199338520312133914851239167130412730662124292772722504|33269093498653459355911056721677057317009942094586213583836482429509057025072754420372439736248690513834971332175814464148672813487558426999636798377556094849446738441259743858358991688742216573871382813744898911570710319471125784318155373816902285919608190930249032332855663246217414413642466621378338134637,-10949330241414165733888189262458140426986707558351886540903470879800574033213186052244846799127577601176842705714647638204280400911455131674484085082600626371557414203990940725212684526037217982855212341310843343357217588085473017983047320842712153347738590477893040712557903922232099275263522420010197087053,148267471797952946823163847078479485183284021963476657656706944246030488584019895488346778002211592139277760491813666056346782934726026456786554441575227882221237740554377749215785707126496176370984922985820419829339644729974154901755996939823200818910973576565060260711661905159023290114040762532541467088824
100032603932113584190385248548088424648269645571686859576017823592423034520849963520508387815309023735382902503732005885189155388332561494704539042592634007656219743816845911733895132144423102052942452746877943975353248517709377531317937542644854604549820822373960740354167669496547979026679046866602436687763,-99537978095529356699713913260068351078290498972088228356731296595606062051578098868796341286417844471545193824704430742131836251590438154579238324251435089098889846479244366361006756968943661462663756515208457066560709300104052348033879750430334191090716067038009316021882909761152311655341491437691827562957,100461141672958569681488420113742834080404730978030677210672600173957843011309217083950874294428866093615815291020711039763544235459696431813304652678133959812856917140520431023445877504376180839416510225066460002908711498876105285713692498849763216560421523587971326926569083287005470828615251682690932454480|100032603932113584190385248548088424648269645571686859576017823592423034520849963520508387815309023735382902503732005885189155388332561494704539042592634007656219743816845911733895132144423102052942452746877943975353248517709377531317937542644854604549820822373960740354167669496547979026679046866602436687763,-99537978095529356699713913260068351078290498972088228356731296595606062051578098868796341286417844471545193824704430742131836251590438154579238324251435089098889846479244366361006756968943661462663756515208457066560709300104052348033879750430334191090716067038009316021882909761152311655341491437691827562957,100461141672958569681488420113742834080404730978030677210672600173957843011309217083950874294428866093615815291020711039763544235459696431813304652678133959812856917140520431023445877504376180839416510225066460002908711498876105285713692498849763216560421523587971326926569083287005470828615251682690932454480|83415806280351408759589239958761219329310176984650613508633653230456890652830525586600995644504636518476026029385588047137454270096528621205370620292951275504650266248010650846690600983384462303830915876850693795019055500604246841544238285169828416374845816289496545562107780789460316448092131365832361151375,-74625562140946530658296843057459607794092129677035083950600450768713067569753818651802415894941493999582236546770594323673470134033058099517659971836561944651594028658674853294680303580112276880640835753725828631472628486095723473976221487197988748307970291488083264976555432132424815586850501052682570560083,107469811246399151523671670639445335406080264077456915839785825558020206498489889359444002816596192076606675057819088885526103113392920720840544571898931473254561406865074149733521627542981016723238264871496686055481103379945620155327472162297506458535202575738651893005921523712726080367985636694514383291872
10003476324006195750203056589672528920142608070881173628253070002202847822896965018507956629750620754180015153597378490052619698657641883238019501085375230761464051022240631149609917748136390010621917552270797301343624990317089853119601059038653584566960989367701622621948512038032835888249299441269693147481,8948477894687501835769347042476812359286265266925800130378128090450514350343716170849427570408163707014128103924229513747579348337292452228930399170228437675863524232253003114523522760158376999688617602181401251377230973508602086745348949552684443228687100653278976227886870750067529496753791759215379958009,452977737155070764205462061852384767406000511527628419268926246340664360293838298755195741559726771936393803381121945775594031166662560564547853061983512305458290529662211961236299108870033900884457317683226459798783650763565076645131166564022405125204306354508519035128680777341173496414054336245228904798396|10003476324006195750203056589672528920142608070881173628253070002202847822896965018507956629750620754180015153597378490052619698657641883238019501085375230761464051022240631149609917748136390010621917552270797301343624990317089853119601059038653584566960989367701622621948512038032835888249299441269693147481,8948477894687501835769347042476812359286265266925800130378128090450514350343716170849427570408163707014128103924229513747579348337292452228930399170228437675863524232253003114523522760158376999688617602181401251377230973508602086745348949552684443228687100653278976227886870750067529496753791759215379958009,452977737155070764205462061852384767406000511527628419268926246340664360293838298755195741559726771936393803381121945775594031166662560564547853061983512305458290529662211961236299108870033900884457317683226459798783650763565076645131166564022405125204306354508519035128680777341173496414054336245228904798396|5651402082864001341383043857276519034370923662130513841623791595519661596270558403629904832806805434101124739144545597592273345291679321664787896528184481483087832442891723960004144034071036416654549567647433046035924426144596821847342448417665300158067728473706875334422169591609969538712389716925515442159,1090636869023214934530000512317584955330428598448445756182897777909589608376391586933678383330159027516570062459675025398064909568706408769200853022274439337235651672149891920445243421589467522791785184925567074521782213195039081340473683210796200673383772228925769534634646704414996683315287011695982045215,798320586788500330131894474104550120349737015590338005277237799938184156294041064946603812109197024144698401875127120433554460509300984485272200798966972702950997831115495437993447800151856526214460125938349981191215783025651707239371732305323555609927700663473758594406982664526774948117622844814657936546368
10003857993456427654260743531593175331844381828365670865226962439897092670436459982112189381696267158765639464830025128699564487196364496581401927783840749033897594251479939418637644343310965529659395490594160241233118920895398385679767173659034336248678548857485551806702464695049628038493630764757131936433,499412956562517742917849279756715433309262335746117865845799881793024584024558389384536935608560698495018673505480555335883339312289660314988198774876439555916228389426783735627572745304130362478355104078356335948823975431983850031098878540627311553089477219658101715631431867688289331308014437329410794367,428065574132217643458625663050023831718642242887566540643235772550790937328471994487142052675941441071975523602876098842203000859003355118835451924426231099194913042875268766884651796522017073832982218720474562973379560560341143898312656272368395693435837758889298389279644428917154166725285871991579086938078|10003857993456427654260743531593175331844381828365670865226962439897092670436459982112189381696267158765639464830025128699564487196364496581401927783840749033897594251479939418637644343310965529659395490594160241233118920895398385679767173659034336248678548857485551806702464695049628038493630764757131936433,499412956562517742917849279756715433309262335746117865845799881793024584024558389384536935608560698495018673505480555335883339312289660314988198774876439555916228389426783735627572745304130362478355104078356335948823975431983850031098878540627311553089477219658101715631431867688289331308014437329410794367,428065574132217643458625663050023831718642242887566540643235772550790937328471994487142052675941441071975523602876098842203000859003355118835451924426231099194913042875268766884651796522017073832982218720474562973379560560341143898312656272368395693435837758889298389279644428917154166725285871991579086938078|5985067419244985135241171028798929574240680468883302468191968098879216438700233164875805694297003438862738484975665356224507623680806342430269752869889205306990703427045634087633153837909332034829737848013329051690528535659192743560129505700514703339932109459152656849997168043791609090148125676966411164474,-3013789663785982033470828503772197819235935022596925513202295899674251698616743229507943605240952571134961898221616756365279257136756498538053825862952363683344784599061589171181375336294364884944425024815089748650913141333142482818080242503626668488451409454453378105252995530177887117956522924628476106577,715867557387629444794828253143137494171652360384349041477991757900406478237922421388389881678979412011018924778952400351577186261046593876844081918575484239857072969176632122684840733871691016063878843026835488228409619596420110671483199617250854032506474798364927317129700200264636864303167131823097056257391
100039629164915279615632745626755403195135344051296300065703707540722103090866387847978086519807842461360227602981314815898651188162817881999812578911179147999641525372151514639575701701027057192828570924656410854140601616073626299097374452319600612002632648030238739679305929396591878384845108611708173073473,-99956757702796747144330474031362091634322580823618978945421296776762235722820502139320048823797118970112849105309821058917042066320137328941305079762427354700730983116887319872947138001541985096571674792479594585340751798952938060950882542376800246430517653157385999869147535721348848735105635711972964679549,102428094420528235210038473992722778047449595066683562474358311327561453376741151333873834215335094090938635116665776111534217214948922896682406927145735733279560659220902423840693623822669973775960053647983979336042821226775972118591820157680473747907152458057697531888053067296726895267408102940444171410942|100039629164915279615632745626755403195135344051296300065703707540722103090866387847978086519807842461360227602981314815898651188162817881999812578911179147999641525372151514639575701701027057192828570924656410854140601616073626299097374452319600612002632648030238739679305929396591878384845108611708173073473,-99956757702796747144330474031362091634322580823618978945421296776762235722820502139320048823797118970112849105309821058917042066320137328941305079762427354700730983116887319872947138001541985096571674792479594585340751798952938060950882542376800246430517653157385999869147535721348848735105635711972964679549,102428094420528235210038473992722778047449595066683562474358311327561453376741151333873834215335094090938635116665776111534217214948922896682406927145735733279560659220902423840693623822669973775960053647983979336042821226775972118591820157680473747907152458057697531888053067296726895267408102940444171410942|59758487461561694442379025688208789272805646117766841371919206129104643340187013959248829747415979662207515324483234883850993532329266696739297473585807619628400010464577117227971680163239657561855113693233183544551556435408658445465178524557249837569329921343630595316681776567395248915519114258200940556334,-22671153376331064045596883212849524458683137875144383539728632975135493675352244172470558064096651200683764074233134897430860850593927295220691708458835598930765635309529560060316074048705829611628256591181426206810132007799209323907835404383161225433151628885627129593154801395506335278453552670824539376361,131822706075099232761447085662042248387269214384273446870979850351593187356535380305031128889463232587293325792397508871970239127171842305342534211852386333093595103295196214505820601536505750244236747510387243858827641299979267104558491688743963318805624534666949772263803599250156326714304699457238299478944
10004832714804908103723742535198592770160203517705805986990840545592954373052531534772757807185128680232142411531940850138353354052288042367716414491900227710660117192168358032143450533265736882961031789512953512836372805323721228539257249690634554067409180163736018674169229333523619015614939108311094404955,-4106122534013672070279170985250180991164806091813516237606357362858804809149171076685686783446662860787711693312632306442369721226548746949829113367814838200945066703674460902843843266912498986340273761329459609877828321975866552396500360382623866557971900410837449507727615090091955001901337773500512564083,735528321490864741305341471765335107420487103909921951579694743548116478766357351448185791472115882125120532716552174779001460694927011404974670401193452353207309236668713919095870342289746072100419468138261516298395168201040490324057099586440436334562163475983175689744239719212727501982130267247535538654526|10004832714804908103723742535198592770160203517705805986990840545592954373052531534772757807185128680232142411531940850138353354052288042367716414491900227710660117192168358032143450533265736882961031789512953512836372805323721228539257249690634554067409180163736018674169229333523619015614939108311094404955,-4106122534013672070279170985250180991164806091813516237606357362858804809149171076685686783446662860787711693312632306442369721226548746949829113367814838200945066703674460902843843266912498986340273761329459609877828321975866552396500360382623866557971900410837449507727615090091955001901337773500512564083,735528321490864741305341471765335107420487103909921951579694743548116478766357351448185791472115882125120532716552174779001460694927011404974670401193452353207309236668713919095870342289746072100419468138261516298395168201040490324057099586440436334562163475983175689744239719212727501982130267247535538654526|49571248488801947323762143907209086317313166403240424924024453432101823875387693931106394388064932448674243115016411805337571297304108452331736192767907165219921775519019524307831072755876229558621548399009624087618962075649066655387832586784423916396427426550173498305707525522262009377144776100617511504479,-29828959784506381554151288596212589266056524896738496309595862456247322273883550277461362725785642216517361460931008602989968457887994880159243708746757201494721079152033527869271494859280160324467867179845744346034683576782637256359631403582150391967236780147449482496203963125132702633751829108018063107905,152851999786112534607728017818026345885853920855328921975341927606898018268835818661916681924713268354620755264611816045133624308753790454966902035653944158070765154497702110731650604894939030177902410742021315843443639601716505769494787447868225921446367758854610060178076102048397807948745556177069401434816
10005026798525081885012940723882427584501711356233986451433820326862561577003483273848888665415005023331324845917111198606297565890343057122006058437816088078150993643095110440273546307247953190370321453395387856022986496964659738868016549698302294761145902566546443562453064814285197415999088360521895892448,-2012773415393071452341702894100369945009950648974284842979647951404344133571843387257391629610481617222572984474542523680934261770552452770758419481294248980432288030428538457156536090278813518012614750771478130023297469887908317305397718948039728500945544029263259198696111632370324283021118376979818613221,535224191733498084376882360698126323023228440191548650672747703583096856785431353632400792141685069598130344590929419053715450660967162173014581599286976146407034427713180051638727241035734570695485508350936098840329272631647750135734419630658939038108543820389342159392044477918576834926838103968922627914592|10005026798525081885012940723882427584501711356233986451433820326862561577003483273848888665415005023331324845917111198606297565890343057122006058437816088078150993643095110440273546307247953190370321453395387856022986496964659738868016549698302294761145902566546443562453064814285197415999088360521895892448,-2012773415393071452341702894100369945009950648974284842979647951404344133571843387257391629610481617222572984474542523680934261770552452770758419481294248980432288030428538457156536090278813518012614750771478130023297469887908317305397718948039728500945544029263259198696111632370324283021118376979818613221,535224191733498084376882360698126323023228440191548650672747703583096856785431353632400792141685069598130344590929419053715450660967162173014581599286976146407034427713180051638727241035734570695485508350936098840329272631647750135734419630658939038108543820389342159392044477918576834926838103968922627914592|22336292342012135551012779505885821083546735296581603650297115029465681138287871430168423025904988089547671399414611655350486697669350669877738276496552244732628186316333718561702084292478964766694437983324796248956801158028485684181499933232337147261336601523192790302252474972512181980447183622505293176152,-11674427075188626733931744428592651339949229796533683950532721050654863919331228509781516498261584604218739331608896593403871873856541410150113580209210756699310754431102708096662231135908839829374052715278169746619957236796967122303020947804850902024480676480363166504231340429878256710974972888619078138229,241221441172507985920847839600569201674621990755660781190984844223834501365279182693592593623964679309297220103180052193705500388401906318363940879681334805954355205327811300356578283407461158222974345862172435329520610152326479352290565487656045066487426033103805627728579179611865031310778705197856088085583
10006672794990347502279526000879267078734551177313370372283212271611928222796898904661389050998596001740140300896360857122349676163698172929644657861948036337955651058773337605834505825285215111994884147090626904932283811767278804138486301736275150746935294318794069137540121225700303083939876242601120625682,-9838237801085818249924597009069669407425270661770560087620729925196161025957715438545136585598174869667669532449305460474170293173380362768481774634876936899174710462784386243070041206971463923591073715195084153396862556329146939171493281676244388685209328525900813769124322086835985741784348578408662428059,491155226409710325351546145673359292444301383692142579605004960553566299358747456958419756937691174297624212871558627081110141997099054271399339089662075140351079784991312987158527194379830582795343003721494456884032748354538831215203553329779263289722351779436025499608302937937453427548391343898256662436681|10006672794990347502279526000879267078734551177313370372283212271611928222796898904661389050998596001740140300896360857122349676163698172929644657861948036337955651058773337605834505825285215111994884147090626904932283811767278804138486301736275150746935294318794069137540121225700303083939876242601120625682,-9838237801085818249924597009069669407425270661770560087620729925196161025957715438545136585598174869667669532449305460474170293173380362768481774634876936899174710462784386243070041206971463923591073715195084153396862556329146939171493281676244388685209328525900813769124322086835985741784348578408662428059,491155226409710325351546145673359292444301383692142579605004960553566299358747456958419756937691174297624212871558627081110141997099054271399339089662075140351079784991312987158527194379830582795343003721494456884032748354538831215203553329779263289722351779436025499608302937937453427548391343898256662436681|31407608254280798910068647236171832681250921019767339322092058225211898617080663268645257485291372241381998253211825069099135787304279471888561584499577479790815455728926265455210044341705458408895536936732959677488304976642419035897631658694309182269500334892813396007185893728237634667266625229835842258012,-22092195466303851660176460286320107196721548719910482849923927669374860570040607441847880914766942886335893807802817619964909625774361248243281497972957437956640995020582500875700785617741050040570062784832399237969854446892064368205401494750753136317996032567462911904310221537322445611817601703460856421217,159599806073129555202146898538117276396235868652725582464386632067108341746813360586970644466851546908557689300426749066266037355857824949308514825360431584985378792225819436535456535877098069496677684472533670862820828085751117871568305588734769334428789980131666205325600082215182496839515396421731764800737
10007655975072154117483238977535537637081635031134550457387493208328357153313126763724056490057039627482071052486779071595119245261713445964779121986765033599055846695490518512461118572219672259974233020703702627262496120864385268977830794693731299984872419878272800221037178910859958719636556859814167846842,-8361996877393239419962455468169075798408150795370677399435249551651328619535668258497248839588331109071829636371568824578953377032648893445576430394495769342785817892484051892349027624952023346102193243274713308717688268734992258026540569970994360123565176304254781068869111211172521527332383420931814632155,527575030718114283859783398581144142162250986653324445494333022369741458612967189239531512810665999743981788039851897018720856433180698951454061341786291502239652788707044944021930279936172715091766668769968367606820938741461139670556714129528610125247077397188304136573449554427712758172626387820770141650206|10007655975072154117483238977535537637081635031134550457387493208328357153313126763724056490057039627482071052486779071595119245261713445964779121986765033599055846695490518512461118572219672259974233020703702627262496120864385268977830794693731299984872419878272800221037178910859958719636556859814167846842,-8361996877393239419962455468169075798408150795370677399435249551651328619535668258497248839588331109071829636371568824578953377032648893445576430394495769342785817892484051892349027624952023346102193243274713308717688268734992258026540569970994360123565176304254781068869111211172521527332383420931814632155,527575030718114283859783398581144142162250986653324445494333022369741458612967189239531512810665999743981788039851897018720856433180698951454061341786291502239652788707044944021930279936172715091766668769968367606820938741461139670556714129528610125247077397188304136573449554427712758172626387820770141650206|34241072322144183964883259292388971270387490908021459682602920713448556112203521610314068181522265567865990070656464669642401927077378188525809052299062988871029831250362663444310773841166814396928628138166361702759595641474414467093470838454994055079747035830130336863078894622890889652436509718402679470062,1655044484629008994406707658240182084237566731635262662670986570402287449045651466425429233810999012995111207637792772902737734854633738760139439026788661518884592067665179528199667479368791803292009159500093938626059289257062277449763464663360562677734593664715953368375153510854218241931074507165471380277,153704107279914282661047729774770107006301606465000116416112632832793659221845961744254897413922500063463878032418234980336383112232225712099359203910269544199247014938285831933417628129448739918915220344920675471322163945672122675565456045357008398369947791399948189771245653263744530465795945375711800221494
10007966435478170058236863959453072022400241955644959598691575049123018331553853255192930054734316870465371869338898000445140839711278341717767617282979890871322011741629926128943966839416929813730135095452717804664810492420201325502018871240152164282158649420833075991948508448454814819879697083763652090752,7668231477440831839423530692551370703245159224024821557501520508935072774934016430350932340192015949812739085292897564854127442271354000519287430094037838940253057942410525639491576166138997981100229304259461266977184946214511723634011266273522059488169041964372462366036564169749432744133670979109152595493,447718029574060000854039425364603339241323607028045749886344661853336043472604487444001370995744392053933719052361283419535725001600963164946166051448582948801443754508763343722896658178932382756498803522119159379373755295799841416904795415386643502857959662236798809639975132008241096398997653679085633708897|10007966435478170058236863959453072022400241955644959598691575049123018331553853255192930054734316870465371869338898000445140839711278341717767617282979890871322011741629926128943966839416929813730135095452717804664810492420201325502018871240152164282158649420833075991948508448454814819879697083763652090752,7668231477440831839423530692551370703245159224024821557501520508935072774934016430350932340192015949812739085292897564854127442271354000519287430094037838940253057942410525639491576166138997981100229304259461266977184946214511723634011266273522059488169041964372462366036564169749432744133670979109152595493,447718029574060000854039425364603339241323607028045749886344661853336043472604487444001370995744392053933719052361283419535725001600963164946166051448582948801443754508763343722896658178932382756498803522119159379373755295799841416904795415386643502857959662236798809639975132008241096398997653679085633708897|40511141969971494931196941724119791194752303140317604712667802312789797258087471388916305711860938934695113621471555129205767772174234194577636062024449049659844773057153826765602668788474097413358584157199226050803019714953337366130977602640661927789662051175267419967969752702153115129111296636218703221612,-10457935161594282983478001185436442312204066321569717319909561123122508532580035425990850447859762708795499274494409851573173766858979090795797351580839052039648316518437023326040967891533445612383815607198257699325318317220032705269084861881246335591645639989108557010113256147197407668582018981690523309277,110917353905486580092614272588489684725195855203152146381960572034045032865176004516881779898341056044802327638909692940931520745099129277448149432184154526338845672459752333598562775198340962552587031950250223610238795938815226253408453715102541267901432200534831078606195360844918970056237910632079232669397
10008244313737062814090386880777002042274406310106728621588663972235471114422710824990333652789716385198940169070112715764189602790244309290680116655115170883594213904067142922764109544956215574952085160301875958128721493047843010586892757750339772804652221926614373576181872540979939178502806140149454950631,-2481333037464667013966629436643252131544342493286852105020088420979287811035788180793459525355154058635281869829040750298007562342275673082167816644462962921681726865943832615136603374637684966019868013077849325437190351276393203980513956812271998916894664710817164796538864396449149557648172823426916063171,517388856778664723601259064328056938198839891258102587545663260307743028813773980886782766877880248247356976487931222165792012525513693034189039784629831615801247177080220119155265743113547860287043754078724492811312457109356002302194457816150319735657096232303313256118001093875043014711306978887626524797260|10008244313737062814090386880777002042274406310106728621588663972235471114422710824990333652789716385198940169070112715764189602790244309290680116655115170883594213904067142922764109544956215574952085160301875958128721493047843010586892757750339772804652221926614373576181872540979939178502806140149454950631,-2481333037464667013966629436643252131544342493286852105020088420979287811035788180793459525355154058635281869829040750298007562342275673082167816644462962921681726865943832615136603374637684966019868013077849325437190351276393203980513956812271998916894664710817164796538864396449149557648172823426916063171,517388856778664723601259064328056938198839891258102587545663260307743028813773980886782766877880248247356976487931222165792012525513693034189039784629831615801247177080220119155265743113547860287043754078724492811312457109356002302194457816150319735657096232303313256118001093875043014711306978887626524797260|64779254867032834011440641150787867084487920384040666681242863744168381419066139445297813847374258248415619741363374551837200937516385938256833819108665346550630274436247175069020139650724403378810927075885582938267576954742862532587966930483553143703545329576408261048628895456023143683431401990598479630366,24927519754546965921961831708915463327214053646451495956699845075284971443847002280078538714647321447563383780925628397892739377674787824980025060340980938596623558107083184245064110657008379362919768477366918649506291628246060968841505524504481964062641513562929769991452205428879332678008403472520391251145,82309686205222727769575596923556209136176331852352419263671129190093456370915941776219688571948801625823542691573133895930427074460493264530457559070546811793879069016319253690636501038391024472030629593224593147217100960263693987497514077967804017050957134551364124670419141176242216681820543629095623072541
10008352850657920583191404584913972319002983012580386292746025042416454380781500166787911252581886951373899680476686789855174455691633284341038191233672952065406558892215211615248443825941676410729187290225060888418790745853338806784833379906941049072152726050837490871126796612653775780560679723194628349029,-9709060422739575026005372809573612137660920177893029425373199378974797630708961048789082569968621509437270608151157000245230087521990222886335775421061577025607819009612244487407314145511220306148818899675596604132364981950337516654200767452148218615182517964628917157152074917236803799933149738760713914115,671115082942262350108425488433280481526339397188879799636007596624691786030758042881307602706684291172315374822828497006497958099138318651797094407888149790626224845978208367284081376364107905539290535619502916118224586762249253502377439399087435554291997555942600131361589961111751560971988821471576625969886|10008352850657920583191404584913972319002983012580386292746025042416454380781500166787911252581886951373899680476686789855174455691633284341038191233672952065406558892215211615248443825941676410729187290225060888418790745853338806784833379906941049072152726050837490871126796612653775780560679723194628349029,-9709060422739575026005372809573612137660920177893029425373199378974797630708961048789082569968621509437270608151157000245230087521990222886335775421061577025607819009612244487407314145511220306148818899675596604132364981950337516654200767452148218615182517964628917157152074917236803799933149738760713914115,671115082942262350108425488433280481526339397188879799636007596624691786030758042881307602706684291172315374822828497006497958099138318651797094407888149790626224845978208367284081376364107905539290535619502916118224586762249253502377439399087435554291997555942600131361589961111751560971988821471576625969886|16114275461489124968204609015452254643913218363912153828520620336762113684215205643094736684144935580728436126433843432822838401301502605946365466722979644980151185661620762014580187078928560591048729719792010275975517300898462040047538702188845074821092289043342754604938854931775373800424648368644203310763,13547284929895770484441101131779787363607604008853234716726800689182086390631494419380414868563006093483607315075063367989733593307441496946636597309123175793027336201138908596859844194042146843338047555922226658114601025214153360367295508810902077991437858537936819515034120605401664389985997179289268252367,418205108772032981216907044691421436420223410030163644353520139623926934302604091399665635789664245218369914570143791026851295152484545480995319870729672449287479092631425718630481935403940901614139408947960419781742920397934070995211934874602805252466775364873888815295833211854864682623780313523183909895620
10008513012069041332156344897527216827073553214887592180214088737934259014714007486627977262733380816543933881903835772165306652083392244023687978336905351870998572186485570559256669905157006164174099943880073052263685924132434457096891529676454801384608866315724043225840413063557160938985851639441472622874,4312440429846754396035977404383353442711216523950513352151701783462030788529545110163564186199448542666033789397218053312248834710387435083551347290942668449155398673665487605130911092851155993391138549740383991056332072450757325017931588809593307558375428030693435084458386227675282989067613496797817920303,522058710434436061847099419719287842052400501259816466826452187248685474462894015989166683733824910524432920930163132078895575756633553848962708405953874665062957204347147145554667232000278570561581943016274309565656027423053224928776350261510971295444303769013653510888595366416887399411638422346190508715452|10008513012069041332156344897527216827073553214887592180214088737934259014714007486627977262733380816543933881903835772165306652083392244023687978336905351870998572186485570559256669905157006164174099943880073052263685924132434457096891529676454801384608866315724043225840413063557160938985851639441472622874,4312440429846754396035977404383353442711216523950513352151701783462030788529545110163564186199448542666033789397218053312248834710387435083551347290942668449155398673665487605130911092851155993391138549740383991056332072450757325017931588809593307558375428030693435084458386227675282989067613496797817920303,522058710434436061847099419719287842052400501259816466826452187248685474462894015989166683733824910524432920930163132078895575756633553848962708405953874665062957204347147145554667232000278570561581943016274309565656027423053224928776350261510971295444303769013653510888595366416887399411638422346190508715452|56624718412625747746001342620243125157932460809156476585686153252078788391585133765039303843105555487145302765475232301210334902069549060211140618709834572969221737838704380629832808447436726398836532031324189279819743594568958857642880728907272717965484249241620624993448126533648876371412676969976240808091,11251560979241989333315174860442827950692807971893794693178074029555222489351465658673586544289854384482236484135520000810924047294537285452423708542539424019529971512734796753346419671011832872098038047241101770150064698634673955572614027093346044433647412285209492755021945840975963737352969268461227245507,92751569706316371333649854241258112606711033359078430605766627827390581284909646252513959841970681664755979852330064323247275252913920697545008377769665486889671185641317526987823359091775252097776601502427528886408060350050959249578998479135473207338710170069765535652326679605884886200884837141964865764438
10008863920545293758159888428446364046156260276486716019468090049016703539043486840953638396736429084536043888977532647111473229479529562166982909202873868243789742163658153824593686536088450915373691535781953841623992587097366077922476705574496276542011226471851020760887612018025249445972903686455787297913,2645740853855108763896589086717998001934973089513790734148937968197932490008236360599464772889429848037464262397763532307275971891237738829761101393275168415676294997564886931379267812086428886706751772215615432393366054082725778686112559307784475932288658665407220266586240637350907136870607040913290590611,793400754874236243676721564968016542454513488899050997526586540816446069760957715423992612546686769171106427349384375943641326144133116588670645501231299064478777846694278704641598622565613076600211712243453441442617903127555189233115008530187155578099336294750097716133611190867259168037807083105588642566246|10008863920545293758159888428446364046156260276486716019468090049016703539043486840953638396736429084536043888977532647111473229479529562166982909202873868243789742163658153824593686536088450915373691535781953841623992587097366077922476705574496276542011226471851020760887612018025249445972903686455787297913,2645740853855108763896589086717998001934973089513790734148937968197932490008236360599464772889429848037464262397763532307275971891237738829761101393275168415676294997564886931379267812086428886706751772215615432393366054082725778686112559307784475932288658665407220266586240637350907136870607040913290590611,793400754874236243676721564968016542454513488899050997526586540816446069760957715423992612546686769171106427349384375943641326144133116588670645501231299064478777846694278704641598622565613076600211712243453441442617903127555189233115008530187155578099336294750097716133611190867259168037807083105588642566246|27460683971089209913632788439277008206698726108421557048449583612748157436343375175859322164187154644764726127789104341389062435393682455959407312665088265825287372841830854948020646918675509930411197475014852013755108095396665264198600695220092526372517655520066812589582003333706156211987354238157895214440,-18754257799889030610388359385148211437538401837086321292345976113516028840634213460141894145979065231860481969629551490782467029876512509259774443102990636739699402915097564612184570929798790707857065137355337741260683852677325380877763634549633686621832440525952151518844155190936539038380094790162128388423,292316854113502420768516012912807278549304319263771926401370626456917590670162968070277533769157336622178624301667258725748409713154982300194605653065586096039574795291737865145837966259393195694514901162748686464295686525957546330665390520676177065848461958642958875916650558856747431365214941153816669348325
10009505680139870683354483014980979080857116598143181111545123603173294088551257446784978515102956309603131729036042239470868522730508351640411841336927180142285333130556003408088825172687266397290471685595705033772539426652454509785808561354205994913107889793645231496289597484325916247643676615653797810040,-3204245228048542338423395469208468824364162898707311656951717207097770099550386735738728259011638956652924858793824233816950950613612534337274326306432643930039092581092193180132506302083387198832944317276664858711681950020725043153356848379502277900787129851654969895020729278524823784274520152043485072291,452691911613679447746063326513639174263793060004909642518772775706171480163325072807358357220816303993075973139644460675947299910587502105955195991864534504547078402941938298035649970749378328953718405749778603278187778609058449113337901162098857859007739511955733974919843773983479386171581120876366473480535|10009505680139870683354483014980979080857116598143181111545123603173294088551257446784978515102956309603131729036042239470868522730508351640411841336927180142285333130556003408088825172687266397290471685595705033772539426652454509785808561354205994913107889793645231496289597484325916247643676615653797810040,-3204245228048542338423395469208468824364162898707311656951717207097770099550386735738728259011638956652924858793824233816950950613612534337274326306432643930039092581092193180132506302083387198832944317276664858711681950020725043153356848379502277900787129851654969895020729278524823784274520152043485072291,452691911613679447746063326513639174263793060004909642518772775706171480163325072807358357220816303993075973139644460675947299910587502105955195991864534504547078402941938298035649970749378328953718405749778603278187778609058449113337901162098857859007739511955733974919843773983479386171581120876366473480535|57325550832595720002282991260198520855619892385753125887287449562869890287547556782700649421653735594090065432438621527792246214244092693717739414731384442034231735428582082971424584764012096459469280873967739009228670210741931717901688698237272251048307176343047617528247235108742851430347676100126914108357,40951175564652222245195473979961933400303424050552593889813171845223826940735103640121837889061263540857785714549429721536079825338211400035410823730435714524768011703151474601155984454456549759808694516594213778747991012336774365782807914607474811422076337673527879293888167855766653181026300408358374972063,86312387529619002943462127766854108620725875072481894074267557421849877085810739137001331161310595596779531729111999016553742317053715695938778491822422663861385491102185170957066107188324354310777066756950531425606616940837381593339739089909995724195482868610730939023987110641593221757790669575104910938446
1000951516029909402241580153254201911805533650981363847468064026947791885513152190496939080952901855372998038682278000380636609527998130327379270561313029246942896140134101369621908911346125374976926115893278132230058065500703131104226075681633220114919188893134454475954292791954736302126634675741318978601,-932129972046203740107893826647984861393190609401184260933369527488206703962436872059299754006964658145411135715285131543309666916261147162906324852866784469362588174806798886084835311322495644384917815753456114043848321591684728503353583125390553182460085266457044328481386164295062361453557198381234996483,7741880922056878066612714130026240867522108473639420974553105203701418374724364127305856418938534523230858044879263234730427059699274843010051016880192588782731180142670836033616687676672699018701220814586539096635490574816118709819174615703862984275251303192202153140463446907523629847791487096446425558516238|1000951516029909402241580153254201911805533650981363847468064026947791885513152190496939080952901855372998038682278000380636609527998130327379270561313029246942896140134101369621908911346125374976926115893278132230058065500703131104226075681633220114919188893134454475954292791954736302126634675741318978601,-932129972046203740107893826647984861393190609401184260933369527488206703962436872059299754006964658145411135715285131543309666916261147162906324852866784469362588174806798886084835311322495644384917815753456114043848321591684728503353583125390553182460085266457044328481386164295062361453557198381234996483,7741880922056878066612714130026240867522108473639420974553105203701418374724364127305856418938534523230858044879263234730427059699274843010051016880192588782731180142670836033616687676672699018701220814586539096635490574816118709819174615703862984275251303192202153140463446907523629847791487096446425558516238|15746368080076547639613112548931198412928034872598867786846558772081390410891968919792236071990423045407820022126215168896502300352310051471939494022340800892491023480415508952796942181491516127339639471207019480870149174572084740672853889392694282271865099892527052018243852819055812247442628083006705785149,-1817913436531155250968687681482056128774282329369952888473920830262042372654938097136436607889208234812116291336524382413655603485552821293038078939629653209114696856829043835764482596948782168253580822692634503701439593841617763234039276530741649509861202111285883608345674200240173376261557395276050534745,492167869580416546150864341469450817106189778801161330939305290046708175512988010176297694665433672849671984872726657705850871343875774836983621356338570200418265577466209423429850230482380970478840847989123705290014954835386530282830688430538273550828822069628430975922343455045834201595340872511606366704728
10009614232615212022005150149343932420969657134336251266196874043830583063114875468409344410544755395263952674188421355541706476649104687178621105860662213481607819203924674901060643908339267017280510002551378392012520463262809409257654601850085574494274200629627329653203473234690149811173235149360768384838,836267856629353024976937718074908246524235283001080657657057590803147642759710349203535369107634985057019274642907780561827986871269168282562729482602832882014993174240061797035451659603107102838592209619951864142851506020290496133563766536500833473922797379921857659870104796371847757654270012370698502999,784213921791375719854653276558811892255578032965532623567863494564671611248783758720878204565462346000781224582747048981949572160149632172258392213554094289354008679022701865566865099047150582908470578815534139684037571258726801746576984534581957278215217261339431677162978264928931155436559875241964125506266|91259641317840920388592572245493602418223311736654347455817117920969722081887399519379251381184940824844626111264019221904601665534920622151118371387906395484279959508114917794568416938471005687918332893135141888811509257566326226278046422522746020345472499138217410394253037717517813153026786742476211897426,65560628471815349730768404773504307627679453655870244754876894481952096786914419991524915369113837577161059316635270325176467655387763062001209403412378388608286732350937986269983898741335821089925199082458466627097168531389395465235586971316043725352106687336132311388859476958068300601993983492409770068953,97787509018580500559531280765247530593654008165836933101614934455794219747727474184974783904602569289723706867556213004773348953706945069163461128745310430174496134494281188144065521418637123474052338785100571778752720085930925320282428718659058820028049740359320116709840549247824331580105759766861379891210|75062088452630474843888448210053283462706588708992115575383926339301467347310815006622009334498696501710113137263962332974627478074375539845396462501277814094889463218705190380441269364077952749970929670210201903809188825244244127139203763727765293010747505303529125943832432756718681546490336041697468666190,5541281329506174033291380410034395388042944047800558435987093009948507724655465795692214345462752044394730637949505190953507095375192582819240934021514991426264136507386865262105651669874195906257084096658225527132816732104755767839079135854552727988309212343735183861434005237105894184406202983254934534757,104675750550793205502943520352684154101269712315945996783868759572927470248283594480842218327785617106312969404704918354113342765451442832450177716298160659447475598063377646514258038986139271814855804490712610499304684910754302950004231911223315677097295880861233808821150324765848314271787214250899197923793
10009735080309013514440203870605983374104835055250399704317172848646825795572764221124512471397022599041102696110601760496809311877056400885225531243115647095694305859001567326435058426543669680082356076887117616533496794600222886637873441727978976019755009690240085029104982970925792121991104293242809524644,6716504442878527910519807778046246423810093302344836517925018933141102172400301207571530237654753113978791017298256211048865142019514745459130820608857728114059755451415522450033212605102272496818594519931368393561070233092047087381778868100623694505448318327728934167707696920045126563192647607794472189195,721610628334648695598193480418084731432879897882901829331594044580759141755040057210356863808123513214754128306537665937117531576524824114459745892010308401743734165555223754018460218362992047097741240949227118743681363740856040612578898979577195958019157067541288613303223475902295909138865214617457058483843|10009735080309013514440203870605983374104835055250399704317172848646825795572764221124512471397022599041102696110601760496809311877056400885225531243115647095694305859001567326435058426543669680082356076887117616533496794600222886637873441727978976019755009690240085029104982970925792121991104293242809524644,6716504442878527910519807778046246423810093302344836517925018933141102172400301207571530237654753113978791017298256211048865142019514745459130820608857728114059755451415522450033212605102272496818594519931368393561070233092047087381778868100623694505448318327728934167707696920045126563192647607794472189195,721610628334648695598193480418084731432879897882901829331594044580759141755040057210356863808123513214754128306537665937117531576524824114459745892010308401743734165555223754018460218362992047097741240949227118743681363740856040612578898979577195958019157067541288613303223475902295909138865214617457058483843|27431399959730041618757181598450126761864467783308250953166653158864868050165660437728250584906458406104160649372946064796764756251284036703521851065427172085011598154374858106257477054034049690307574700876194576753048475242472071051384544187235302865991596395901667453599382886279428660852987448092730327814,-12178152192814077151051956033210165813331619111090720689608458837738277955478946125067643676733373652534546194632007566276305197498317660468910084573634326652156582085984031315753626693903214933704476608819110626280721237157346811918265527840918335083118991187163668918374733603234110068582400025069332861471,264256662843741154538126874284653325441730644362235064492791411891511464369737085603945845443869261733906715033378896197504349395743395072323232105722154314007209047495860245950090828739984743068229024820070744102308175917924790982043751500738655732108120833669083027766207125418432774798887679934336031211189
100097767925729329322181122349613179670027446504792908817095637890752573498574361347439148152051968207056866825997618536117991814714859714673883034645066867063812091504212589938420469209673745687587262010655197327448038749016704401923718318821311108473542621283106029369259039074767836862058509435455755610726,-100049042457569505632055807384899059068938967940837318894350268996535213352709148936435708901083176589583550587767198440304487034715449239754368855557475044885723026390661018171437823688972174609609018769743817618355306963644565862125983532960059011062792908538954329635940471395263688377520252608542030523093,101825233069512741038457795802309532831632092007485080725676678162290037786417230184436300741781748657320031840082727976574819880666874823641143033563613526015930298529985774382970686476257558271965201142223855170907771875249088691707619925926120372987467772228909661019762594761741996613700919454999805975044|100097767925729329322181122349613179670027446504792908817095637890752573498574361347439148152051968207056866825997618536117991814714859714673883034645066867063812091504212589938420469209673745687587262010655197327448038749016704401923718318821311108473542621283106029369259039074767836862058509435455755610726,-100049042457569505632055807384899059068938967940837318894350268996535213352709148936435708901083176589583550587767198440304487034715449239754368855557475044885723026390661018171437823688972174609609018769743817618355306963644565862125983532960059011062792908538954329635940471395263688377520252608542030523093,101825233069512741038457795802309532831632092007485080725676678162290037786417230184436300741781748657320031840082727976574819880666874823641143033563613526015930298529985774382970686476257558271965201142223855170907771875249088691707619925926120372987467772228909661019762594761741996613700919454999805975044|84308318710770953640248175476462028139373764391035194691231680218526343685551415536853656437464155941615590227223191821309564306137129412203074445224501367988293836354108333795252385654176431244360276218862523025987282479232565449230085787098609814824691928891608841637881937218976744434331438048491668714172,78229471895771291032128733343240907956513700512674961776679342047382405281968278678548353708794851883965121941126776164617402656831058062037098035411278996202926380143407188337949264849125051865072631849969234447888440699755954052452126159543200468837557873802507174337535425627611660644229281086936050355075,109360363649395746265656497473367613906192696966623732296103764282264963662145240362278977792876351026988778202744708027814748063715992412060773465595050876884872367497101878287000352814221891140816680001766329736587915177644869655423120132329944663172310205372239088325795595410385678741576083941746461375629
1000990088197024747059083499592558231720263720277516776155079181049136503434198702340667607714363713879340855424897665647049377714485771691188931707633550660945052279457196551479047254741496420585602556120439906566870228385196796680534214981451257503126475671546702014976009092407415021171352670275245814728,725466386677782932169006961452587026457506864587404408874444216403861787891316322821563900402539391905854377725716394516795127638578550566829765062852138101610829715414344025748861390095121907615243675775588453320217679236986850051456109259336757301010447881360582473998540771452509411313781955577190588933,5517508390471385461294072894661016222336566054567430728481305159339660984012399389945095200514405410813099792232460346983221900276173777626934161693012967410321899909279792957271372152068664807744591895618427921351514391226515490690862669088614356482368865242803422288159831017511240290921861425877221350767081|1000990088197024747059083499592558231720263720277516776155079181049136503434198702340667607714363713879340855424897665647049377714485771691188931707633550660945052279457196551479047254741496420585602556120439906566870228385196796680534214981451257503126475671546702014976009092407415021171352670275245814728,725466386677782932169006961452587026457506864587404408874444216403861787891316322821563900402539391905854377725716394516795127638578550566829765062852138101610829715414344025748861390095121907615243675775588453320217679236986850051456109259336757301010447881360582473998540771452509411313781955577190588933,5517508390471385461294072894661016222336566054567430728481305159339660984012399389945095200514405410813099792232460346983221900276173777626934161693012967410321899909279792957271372152068664807744591895618427921351514391226515490690862669088614356482368865242803422288159831017511240290921861425877221350767081|46386382398471210654004936862977280764038033260370855702299152174715903684807635787033726061221737095817373565974565953991423132816014499962739297327315390959305555345973541148973281098200177613839273688191655843120140926599099288046020383471244522466342336148402764983519506510433171993666037668400990623062,30909786208868059159308250284546387617592958673051467586322533557805038169619650467442753505158926723729781335720702109207080121759415266351938588413071223894526233303271669156163543157906212613065654926067039001367294657463422342698879421926602847752406836893005886958919719183994605725308548242138957881171,124210879529497457542798731661855988692615123385567383434289407838970666113795793650595394981286850762118704131523110658152541154934468138859842609878663166338576053338898592108554591614195107201143517584467526852469899754023757894264352510613574752993978429183938806214485060920755151052534935466538850750938
10010004064090651409010594639848304417245586560948860214310742766846249258119176243618948796060231286565945627267454791543296430719743208401586187196864109595450365240377376347430379493062158659135705093920261708675191488141331016387425285934969492844933812420736541635790559026628543841128935951718908539896,-1498575286639922441240963650822632036400568058110825911189335188996116649771598943688044499782411654295552472829397529434461014441578505662359180553723401992140786537396607735356416120600823531080136067285152784381639454281243980298334520221160338176676576774798710776186339169032737324810281860916038070823,768468744922072210410085870438045813460934852024069843981629956982064663744441536899640311347039303574749086761908444837858696612124820590763553776868490058405671131188766507451909827840059264627966884129949211264617246300058675643121776631374263858887287691658300066890342985411108805960696775940061827501049|10010004064090651409010594639848304417245586560948860214310742766846249258119176243618948796060231286565945627267454791543296430719743208401586187196864109595450365240377376347430379493062158659135705093920261708675191488141331016387425285934969492844933812420736541635790559026628543841128935951718908539896,-1498575286639922441240963650822632036400568058110825911189335188996116649771598943688044499782411654295552472829397529434461014441578505662359180553723401992140786537396607735356416120600823531080136067285152784381639454281243980298334520221160338176676576774798710776186339169032737324810281860916038070823,768468744922072210410085870438045813460934852024069843981629956982064663744441536899640311347039303574749086761908444837858696612124820590763553776868490058405671131188766507451909827840059264627966884129949211264617246300058675643121776631374263858887287691658300066890342985411108805960696775940061827501049|28314042997988233306636589016992476577770908296597830278146083272521268550372497996517202454826620755010065709821222609305573779332296860088326682557505516615132304908709189030516196077907461669993069872444768482204126654812645619744037494119483770734571472757955818228427379193994724836630122637837874512512,-3910830326710790111629753186982470489266159472894461132493344186147852161393575078274643639038642275689976708947162470525418556533103511874282953768387384089989557162835543128542264012421515524615699954054931189762734554550136613958599656445264920707571157499612722532218838749658906057952745224391208374423,271795782638036641105135359411824479015439355083041167763715963674151201738370794758665358014925962658456682314365819593590637317922383444961883165716906142863933218099402568928834160919844733051508148071302780085990761872080854429570287769745420760134784589649743625063761926379339662449726354233483569572692
10010469709639397131321593392335940518221591944212653476848636010049901173327189141010003266402662587851391795365145565853592244249890218572600240492819519129624586319882991468883851157495158734614747790710618700576914513912845835699748008363226744953360119054075282875557290214809856164142199477757165509164,7505657900398833324827399204281082596119737445028635348485466721806081208043020690125518041418692182505619967598743043368451311836537618411006688337064144530591029793349206581566058245087905481171249541532084530428115422022022771262499445387394812364092046818720427959757560293344117843608115308687123143421,553113242511887630245562923692119334560619363555162251614925548023827683747558857060226873484593892808999168052131745589052836855443167606888604202950573221560622773360660465500305832700518144444548624823481416168401044677399877530532448619602616847965589554700283201541685397541240490155576228110029131773379|63201743899616470908035016615759783248572310773988939570648682086965508954735585744990615463863202134213890574490859916770336808958389758836363215334497075053557112818568576204445815232807749791417195377923291221271056534552496867547808556556792554364734430966783089440150789750091730879530896624414277659061,-55856955103087382729788364385235549210397677016869607285896429414455503436682728351867754944498329815149524455764192011560832811681933262606199210273482312024649522293283703849873542800068494104680666316436079341962770915103078184937312059708038123793720277348890693601123206211567358221715195838805665244815,99725721230004762208212433032530958477513183167215245049998941633413237167002350956483975841846292547322289722635488222088283425749457741260773683563042470151127137265045721725293085765918300826804733069413639039496778512157339321750973991239393851776816288547058721349853339439566413417882881431596395398482|10058483900212848371336105395105034597443877759659095074874545915088017898536154919284167493951088960283199509655255215299440632845548287448716500241460028925186589031890037337660582657444623147488470508614291087038125788600526809670994940639159256871538287711131658514500837340353796975836990505301624273881,-157799394991431658935500911446539445587307591494655221580870826914115793039596841571933100144135016253304167518063315606333327146563644719359095984750603598277704663545389186967829006269785943764149594510946914419779083189746476236548753466257639182993421200334901817261951648692278188884421732061466347929,549073390680838282030926276806663190640362547475399531148862958328951733805907419890212210186161292258493318221366553074237370828617692229205217240695895636477792753409007387702564155250318872755670718485591591748806803837858464359711143468897253705933551825195496604931204015549587680036788025676123194339726
10010496751485016737255498721953568674323163915462879922384146496780957659766649785727318078913117215770623612059774196084160730194502430474210832948012098222392905483059314666266093994762308130821733627116456649448335020123456572070799012785074345756980230844151670979497392292798505519219012749959532875338,799688122820510610823764584829566759424107985411345815493636913295490164723810636027858758547620320075665083037412723404618585417481351642215686069179403481765070501469154817238059870792625025657772680475594951623612932084444307492923899340395814785386177783715246947669812896758158101579611206283404125383,756465676775987727565397432418408198121332665761199779426305954315978948084770158074763521327096161584122642931162604561074895576932338265005852611804594502809713943064130145585384616864112057298562543101439879468994210857521510834193578678095039312141817959445372442666042645305218271194929494814070515333525|10010496751485016737255498721953568674323163915462879922384146496780957659766649785727318078913117215770623612059774196084160730194502430474210832948012098222392905483059314666266093994762308130821733627116456649448335020123456572070799012785074345756980230844151670979497392292798505519219012749959532875338,799688122820510610823764584829566759424107985411345815493636913295490164723810636027858758547620320075665083037412723404618585417481351642215686069179403481765070501469154817238059870792625025657772680475594951623612932084444307492923899340395814785386177783715246947669812896758158101579611206283404125383,756465676775987727565397432418408198121332665761199779426305954315978948084770158074763521327096161584122642931162604561074895576932338265005852611804594502809713943064130145585384616864112057298562543101439879468994210857521510834193578678095039312141817959445372442666042645305218271194929494814070515333525|88526457805417802579401128655636200680578875592064917653502726799402631022732331707242469404309708934422669188417199074013672835521067841289769648786519913947468121765630841991231363845393790849492596901524640146832343923907202043034825750225542103503647484110551329413090031876302117118017242617457435270440,-55270872554503717308092985383981103433537850547649491053003970562528650386510337748001788465211336165026556518877922750831164872435215600571701093825986357449663403092607944719717658773706993903771608486872517959780200593880280040497747294339054563275578214457748886755324708980839180036767067720944832209613,94165686390158171873356770999242344439144784888928297429784348143756989501060133555039087406934644294830253094462126060631940792293289142829036758298101067851753964448066092115935075783351846337421975097419550731994478824011482838934049698582968608287926659413694080435137971696387627102349753238458722293238
10010579112627452164700751672418124874438960016155391309411143579238371993812216949415371161492459719515415809121706298625750585115724165801767312632070537335293199529430577590690991572481217905708780746070115008642386973910356482808275744430781549387996153714070117005169542728240082244119738613459581149403,2350957735421970008675187616979703886327431020247822920032684793437439591770682963150195069182216167082120247951141628182676139493494439884424368912802413855370850694844333281369444099710260137140856858089878674493931790511953123605380418199403899915269505474711266010465371671818915910810005642457030207323,611423654589890839284741885001129722618409625326976389817674733477626186444470464645132913394627656053210319902647997769502456733804852681598112059600692683589494771437615834703370743285630660946188840487388799145726650756609808617614030574039934664771328233896579676781994740365464050319193605788676121096976|10010579112627452164700751672418124874438960016155391309411143579238371993812216949415371161492459719515415809121706298625750585115724165801767312632070537335293199529430577590690991572481217905708780746070115008642386973910356482808275744430781549387996153714070117005169542728240082244119738613459581149403,2350957735421970008675187616979703886327431020247822920032684793437439591770682963150195069182216167082120247951141628182676139493494439884424368912802413855370850694844333281369444099710260137140856858089878674493931790511953123605380418199403899915269505474711266010465371671818915910810005642457030207323,611423654589890839284741885001129722618409625326976389817674733477626186444470464645132913394627656053210319902647997769502456733804852681598112059600692683589494771437615834703370743285630660946188840487388799145726650756609808617614030574039934664771328233896579676781994740365464050319193605788676121096976|8039922802491265414309990967793279613501148402448480465019122506003939256870540144853780285033203931808455458595860030453208550342558408097242925918803433428637982781245121194507511100106884732787332881816376538778408183713312626895063525916116529477067428617194552870724443468826009500481151973572267660629,7782542056885878734681190877592906346631460224605439140627247356888850052165135682978538906914658013311431434956582299659243906965976772069489496351182726287233109256230929112390639759813836413367620416284403736856845659506160807594525033721234682734219240024280033734701579761670420320393555156688458386939,763000498381829086301710784279931419423976764939217073711509076091719761279556145759370750276614372372724227557071534934449510558501017918011817000937860419860520748646784487080323157808376840620794576624474012291138723116851111311356377966880000941424814810860193927148425226557672422373368027666445875216544
10011186832308679529580531778689417394449477080570215256255872899524060756354513251052234139190381882237674326102549194541918465150411281044342531791718191209528218579215954684479017629118919205540336463087633388203942961094184672710469514635568862008937176486425382826532999400454876885123467677882356280867,-9760739041412831860016040329300538464595968662597654195818825742388623357499061055114241473465244979572894681398742727120008689894660036669893911021076723092236596538937507422477033501397620347314916527511417876669224922540378674704881346598392965888769411037021701309263621236037226524490335501235413158317,618797456627391285757491837806082074086781183030320963821992656495001963414332567515207750538267219197978733813073360730643354769504354220428586481088489050423524166052003546758616279336334294024003134192912678054276268653141558092399335706944717740861723542047714673114465932057975066598256237991004833528194|10011186832308679529580531778689417394449477080570215256255872899524060756354513251052234139190381882237674326102549194541918465150411281044342531791718191209528218579215954684479017629118919205540336463087633388203942961094184672710469514635568862008937176486425382826532999400454876885123467677882356280867,-9760739041412831860016040329300538464595968662597654195818825742388623357499061055114241473465244979572894681398742727120008689894660036669893911021076723092236596538937507422477033501397620347314916527511417876669224922540378674704881346598392965888769411037021701309263621236037226524490335501235413158317,618797456627391285757491837806082074086781183030320963821992656495001963414332567515207750538267219197978733813073360730643354769504354220428586481088489050423524166052003546758616279336334294024003134192912678054276268653141558092399335706944717740861723542047714673114465932057975066598256237991004833528194|16023810805641333724336357094511552886496985977223317205804900540875359074549841799895438359675279197334185032768159914670757201278192258514539721858337894442748764924011517017369466984819970583389409069776399176053947560735257602992978470081403520015409641979689232868403667818818613535419071872687266278871,-7532673756475565262302348084703438182578166716950696747316478761861175843795966574151023129542515752521204794815061142348575304950316771972303577053107419061405627955596801577300288807854600908796497666677601605740930719732644371749303298593761133443055158847238113190613766743442416892398264321417028494683,386004572289283022539377207289773679498488550299986782511093221618938108821853499898482934516175608928422720022347987369229961237741779367136076661442684969604660313702194515039707016073494920297591526290529740277402244949703587380758181579357976708139982649833967127198595634906215849970601175752843362414638
10011352260197967961196723001882777157351136553686255118590538903088960848511094106778638364952379274889738636611531352467905470187088001978395724543759615578178012440339389212117360666565610883522821465968556183822388268042856072812425704980952391373927012924156734141733616109526841203308615171993851798580,-7221676671346271775547094631755878098073875121922187404285664906337078018452572717764275630077273635227060270555255283560769931807823554231983067592327106941484374528295871153247243771907559825959222732921231505238074239141672724791953035282099263068621712554135551648164407808630494744659356436708196075003,491103641942430897255353076452858177434280940975186423223949785500010643311551520732003340225232164561507795653594281473147298622615199173589020255105363616020518202959139902358320338695214760426102498591057589117988289772846024859991303086757574971564242450863802854515962057480781826855732055129393601722620|10011352260197967961196723001882777157351136553686255118590538903088960848511094106778638364952379274889738636611531352467905470187088001978395724543759615578178012440339389212117360666565610883522821465968556183822388268042856072812425704980952391373927012924156734141733616109526841203308615171993851798580,-7221676671346271775547094631755878098073875121922187404285664906337078018452572717764275630077273635227060270555255283560769931807823554231983067592327106941484374528295871153247243771907559825959222732921231505238074239141672724791953035282099263068621712554135551648164407808630494744659356436708196075003,491103641942430897255353076452858177434280940975186423223949785500010643311551520732003340225232164561507795653594281473147298622615199173589020255105363616020518202959139902358320338695214760426102498591057589117988289772846024859991303086757574971564242450863802854515962057480781826855732055129393601722620|47792242549528045573835222090102709180753366247917233792162207697772127315858077638348932444421521322861739464396186442116808539325522348191328660258855448870212049194866543072912231226457359914737534217070905308248553545640574239424386722275092722710319161088562287826715987711727881278079923845948791676890,8254269885969125051120540706292376386106399376632912551223385556280906209369492834220174830708813086153383708455555132979546664334186800724505969898808175578003259356450761612161617233904190263463404177018953974392386560633539661122851396041321655235390273818809845177966554527106703090511634271703426366333,102958270685953367083211535309354861429334576908033521565612066728144639011805671376037609804664223083707360606267980895711740633481159521495849279040716328723662579233841335201356070651023351445332747117601073346257424542725915546556026838056238556081287286460939074972020327613774707117438966240554700925838
10011859648773232442448733215609838143695842496672408041181163963731715385957428830906426802116840506850796500226397482148532808790741216756533590408501689411024510944680051255986998627975919616236379312627952364824369227089618523233361113970064976301643797723660966748317498805671195280559795030489377669812,1389268097793948084201915587623858469968349389719030883277892933626050552994624565080658001697742466760286196070343106937791393185285082388402785127475337008454634105961822228566730985518119778298380464943436464040236734762976514693785454254940058632017513195975469702286256915116671279121716893380760195997,798259439380551890168577021365722645610234093426080631569938818141778075039283575889046619146360005141391892307832892070793699590106322160142086889812498495186005607708401945977916695847229243650515563078729723204186390753029064543583093290363210178756937751032079469629502953157831010865389293997646642560816|10011859648773232442448733215609838143695842496672408041181163963731715385957428830906426802116840506850796500226397482148532808790741216756533590408501689411024510944680051255986998627975919616236379312627952364824369227089618523233361113970064976301643797723660966748317498805671195280559795030489377669812,1389268097793948084201915587623858469968349389719030883277892933626050552994624565080658001697742466760286196070343106937791393185285082388402785127475337008454634105961822228566730985518119778298380464943436464040236734762976514693785454254940058632017513195975469702286256915116671279121716893380760195997,798259439380551890168577021365722645610234093426080631569938818141778075039283575889046619146360005141391892307832892070793699590106322160142086889812498495186005607708401945977916695847229243650515563078729723204186390753029064543583093290363210178756937751032079469629502953157831010865389293997646642560816|42206894030530619844844137895190664968269730414499521872109243265156383878372533066719066634351278056931106119952256575854241753055519807843572490047146976978089248439736200704784039417511594978273239033477711961360762067155137236184651290217781497985287933853456015958183471535758824703982061917287661765041,40970642478148233733033585114396071242748464687693709425944631778683899124773146938566992970029345645063087493796799166205427214444613129772321140093187953348169602638764727669726146858903079780374349625954437240902856681427277267635228715453381995681831199770224812459964590952867744306421769761996026104513,199285626990423651406783664663645910990492228214328517061400776387771491511391310851645339521126305819574623301901411324234792418046438608476979083398394165188934652648732128312553721596148859379616564443828216278968549632096439205379175627317399435861673444161870109940456991316291287290279435962880377080302
10011942112859072995258791154733863477789940396938883213028206575320538554823437297402241742896497695874369416027516907850508925314968512498072222974096801648178807861791486753853486254133021354211722209138812867027895370716192265840613761606054294753819681190630045043947858812851889188252918713433862450937,-5571668968866828804921046721301654575883923332633233994134906673281267773210784380932788963105885600448276206900049033963090555880641132208787100277713410661373854250945949489885604664165828601242508315193830303811886340805084372525080806602568264342555171074951419758002241352180046540480238252242954050299,447717522759824444351173111605711384841786993787566688069178368722388364402515540644758414533643421974927299526439953604872416797996604293432960735663438930460329264500528581210531189312463600150764233828882749159851806734992346380036786298515789780808132282396713107095426662454069422796780131140784450873310|10011942112859072995258791154733863477789940396938883213028206575320538554823437297402241742896497695874369416027516907850508925314968512498072222974096801648178807861791486753853486254133021354211722209138812867027895370716192265840613761606054294753819681190630045043947858812851889188252918713433862450937,-5571668968866828804921046721301654575883923332633233994134906673281267773210784380932788963105885600448276206900049033963090555880641132208787100277713410661373854250945949489885604664165828601242508315193830303811886340805084372525080806602568264342555171074951419758002241352180046540480238252242954050299,447717522759824444351173111605711384841786993787566688069178368722388364402515540644758414533643421974927299526439953604872416797996604293432960735663438930460329264500528581210531189312463600150764233828882749159851806734992346380036786298515789780808132282396713107095426662454069422796780131140784450873310|27084975518223203685159476564968667757147005650320881882446538924664746760650597697153771281773275150298344920435750377585362202361041033907635631944580948271756519774659017735803323446011519248098440794538345241902148398434473456015090213973679829939390143526742895252747749904765235510343943624603085395760,-12790519385524034711380512698893130061457017090294213212099271214034680483663421242204264773620969593678221374876014811278470247764306480672296083402927981473695204988274213121345880281894543363725179804965957322222445321774678314607579703404237389600553993220560492758375020231080071561518133534954466259951,166721966963161057002408800656254458745347212698279982813080522419206471402712564010508086006697422863841361930966373632778322663543126671570353059325275245779405843551444614505569300692917404907917428765459530333591345110277642064762234238705296425159456946404870175457906061825086330206230526422507612458697
10011955414042796957539613462833567748978021174979466353940011258968857683495843510716962870026112990120612239420094468274757074371715099897797764809018818677244411173050607051965491060861928470702220861911485527125770697960299381766502895029523905888655809759985815187019718331529320273577105879315557816044,-2903598288233181369386909069725761325455718972241715705067575929894098338713960225913955377920698582104810776546675110854231130224088963639880575858411672466883767586627134811452446768341259728766799505769981364639560814489840847334997666650046443822662727211952763808116443820225341403833059567092278686013,716711840847237503666263684416016435149389642949031161572660687058464860752744538837256522716160171257335781518708196625364621151126528577774399883526209845714231475374012476325785739496418344991482641972669482173664514234171584896006659617692101904655946713038460582513645370686741753929246439907983936752037|10011955414042796957539613462833567748978021174979466353940011258968857683495843510716962870026112990120612239420094468274757074371715099897797764809018818677244411173050607051965491060861928470702220861911485527125770697960299381766502895029523905888655809759985815187019718331529320273577105879315557816044,-2903598288233181369386909069725761325455718972241715705067575929894098338713960225913955377920698582104810776546675110854231130224088963639880575858411672466883767586627134811452446768341259728766799505769981364639560814489840847334997666650046443822662727211952763808116443820225341403833059567092278686013,716711840847237503666263684416016435149389642949031161572660687058464860752744538837256522716160171257335781518708196625364621151126528577774399883526209845714231475374012476325785739496418344991482641972669482173664514234171584896006659617692101904655946713038460582513645370686741753929246439907983936752037|83377818300427508414411209474182765418541299931790991979162498055814470115047955070666996621536705209820738216257135146862349180486198221400982101436215575798938096836021071281557720129695222554778979084677391347787960453403954349664348198928269790759939576077051077722913333980873848885097124565249932890109,-30688215255611971606034471669429848439589330363616017559694024730487742561639314516549592500671986661135255749032859202031979689977991786343363266117721953715761747898795102634113940122259396542403236218273245556434610755838474462460273735366438965428724794482250645649141152999575795556913839603294733616297,88860815315671630897460232604076507207530961201107386907073059232104245557771716637121266612833291311086440284416177092484049670682110328081485080434205469417936503447466464463362446293805166057694349242947508206617775986775538756539497474332372390720218420029346868304694279430904189373022716924576015411382
10012228673376152026567450992902390970336864997567041834794435762949115261281228493411090141625349816927161690458296667158108080969724709444972658280448694411038715631967371509920701285876643071095813601274276803568595952200658716678278724478871970783503276566469041579910541903097002012017970816393023705126,-1525621196152714906745704861653134857598506051934926836340086172347518826544771422485438019089512861580045344082067612865732790885320087313117232977161635917848068594652072218066650842997301426696286712170439049522381084448274527064469835335059461198790200539335886996343589558210546809155519571241608841115,566490489998797306378193876913958339109032806676495000099448643263727848667893470101258216128095777975779077696408017781065855401798377205019264716443061687881268372472869438487229092017706767156974596159933038800310353717032995999433855144018018195220506116678554717313645342356609548972497509792111447080303|10012228673376152026567450992902390970336864997567041834794435762949115261281228493411090141625349816927161690458296667158108080969724709444972658280448694411038715631967371509920701285876643071095813601274276803568595952200658716678278724478871970783503276566469041579910541903097002012017970816393023705126,-1525621196152714906745704861653134857598506051934926836340086172347518826544771422485438019089512861580045344082067612865732790885320087313117232977161635917848068594652072218066650842997301426696286712170439049522381084448274527064469835335059461198790200539335886996343589558210546809155519571241608841115,566490489998797306378193876913958339109032806676495000099448643263727848667893470101258216128095777975779077696408017781065855401798377205019264716443061687881268372472869438487229092017706767156974596159933038800310353717032995999433855144018018195220506116678554717313645342356609548972497509792111447080303|43590031232680232081751882157307176889837208488946678228473969287186808910765585247541543237267000539198165783309913805801898560564494504170518670105700488271939383325260531063287350050801106407955825720824399992214830540252117419097263989404727460007269455161541372200543947623309137659512638261713267690824,-14075226919726761245118463757100097494169008867441262054574698130139530299753414803053777844415814847468435199262862690860015506966052100586678181635131495519430715844772863497248903106204345001653326109572317033217334530762155783910231739525445183612742122146838723561339801552140211476495875670393868085081,131240521940112916676543723913094551994900810880147949771730918304609983182487804507629012504949522364314455047343021279573082629269863237002108329413796491307563278912051552679953053070493799302202693873331428377723854674840449409246578209307981263784655485960382622975619701504230119584672038533695429676088
1001288292714450803721216442216625955625371798611921786124245018047248562264647981975960215285171753909781321204807230585425114478278803844011930274438946371170816602064333453376960652483578633927890649034364140705267107257789492504807548712851379509812488664968862197781823935761608178854275129769647589581,118977223991225808492576983063622698908224268079465629025347336989392083161221074952362214752172730464574518166801398443928377167452950936101606770394549907364810511870992758058622270316795961219734709916323416843582267371642230512848102350867740488489154654911017481701711273952134350507762249130961129603,4253782247854217005640367062054391551273020323289717198551116404593406680781947315659948108589518702797872582317228254446273819182123102223859859093093126618316964313793208051942159218633324159151062222504543999694994085787779078206117679218461273671966899590739444942724001001618068559652898782396232628519674|1001288292714450803721216442216625955625371798611921786124245018047248562264647981975960215285171753909781321204807230585425114478278803844011930274438946371170816602064333453376960652483578633927890649034364140705267107257789492504807548712851379509812488664968862197781823935761608178854275129769647589581,118977223991225808492576983063622698908224268079465629025347336989392083161221074952362214752172730464574518166801398443928377167452950936101606770394549907364810511870992758058622270316795961219734709916323416843582267371642230512848102350867740488489154654911017481701711273952134350507762249130961129603,4253782247854217005640367062054391551273020323289717198551116404593406680781947315659948108589518702797872582317228254446273819182123102223859859093093126618316964313793208051942159218633324159151062222504543999694994085787779078206117679218461273671966899590739444942724001001618068559652898782396232628519674|28938807607695569686193558386017186559599585089880944105080644798657187851944851177349121001670507484268388813019981112914318210410185959709469975835597908447130200721022330232315439534240435891776843814205222365393996713243986623555128903274366840091822641672516816965782305494688964249039137567600077936606,24347068586442893587653361936682544233359974224524919385561963293036974216353969467745312829316424149479715944098504674533950906586338239024243122404600846692591968993298391467756407074710363297328032595080001517924404972784909440292445668484007116372818768610926770836254572445727057593300358575616247842763,152302535148483948223815371530668367432578267200771233287129083802472440010529096619024512937585549897229409792244544585546299937914900082139679373959823145377421946865824314455823557999559223736926801877211472988708620154393053288483777738533792797643686229459318486035573754517579909390578108894692032268889
10012892006475941528884203206760641995368133321794055404979199342382084602756352644705532078779012887564604213637869579074484075768567055417796954674356138026767547529561933792018043105730958440781327057508393480700527196787164950646236383499370902496883935791129999602941562207002549251300455418372635519273,1454009605238489140114391427335527519147008275556174452371701295849315335234637169205945347453687617440824028465168238395128115858746597274081455839498538752590048744221995446875637484166488769782049750872805524958169087781809205120801537577068712904423342748390795604976651954642488089689583155223913397665,647808943230731060739626381975524675037163647891128462337945233305926315404323308376753006196333731632781667393569616294591379982170007646969372304454389485880137478967587874806562743050788204733473153064889810620961745850926397404102543921057382519028198560438333275110757811110797391594327323261044640054976|10012892006475941528884203206760641995368133321794055404979199342382084602756352644705532078779012887564604213637869579074484075768567055417796954674356138026767547529561933792018043105730958440781327057508393480700527196787164950646236383499370902496883935791129999602941562207002549251300455418372635519273,1454009605238489140114391427335527519147008275556174452371701295849315335234637169205945347453687617440824028465168238395128115858746597274081455839498538752590048744221995446875637484166488769782049750872805524958169087781809205120801537577068712904423342748390795604976651954642488089689583155223913397665,647808943230731060739626381975524675037163647891128462337945233305926315404323308376753006196333731632781667393569616294591379982170007646969372304454389485880137478967587874806562743050788204733473153064889810620961745850926397404102543921057382519028198560438333275110757811110797391594327323261044640054976|62940556237396653206223780718542562667295386352158429493270469961690767724114029222148067827069562399174914339449248246366326268552997433890745884344199015208364859348865726612586847277646257664344896903583225600388420348724002194132332892190932637136851080726053181726410409254132012307744554948406613929323,-48701511676436282890206508014619418354003032902027055232648782348677470406094053907961181547187251236573045647699655583258566497581891423764342023041779904338115306722370857935574573523817812044494597510209680776289279513137149479122384803569185846747971729826779306714510975413862168549755168167117700353327,112469164343071489234368373987004423456191302343816707379444012274611228263948855290569720261858996544051020707105809245289927202553907369725233852283792575569835413308417689095793467463934173594106404637573580430116767215310604286894257928685108943559541701617509990028119392117707508006024253191362515564488
10012909351086759965456044227627057711408098785482672328633074337493434448564318338609803059310568728348413958910299881715937715018572879175542723270961874435550327968633029584188957768139340259030454592302362749027465867807734115139476094923287105973980458884201581736181829195017361330152871853820144480008,4004735351364710265644908449319598352103612215188460925760295665563484237162745827742855116753659687319941982652183152982522805963387540988424745778802028813186258777373064074552858455437921359277118582292259532327491507456668283228943221341315392967683928177537547570473748486481294902027111753951887811107,625070500924631773027293646808528931297961990338169633089637061010766445639876245993583660254312851352153995204943188734825803541904480394551165674837469282411059121521375161737576421883549419892239480294917943542161102975888315623576549465990742662361177906359742645436834392762941048730926726541953775339985|10012909351086759965456044227627057711408098785482672328633074337493434448564318338609803059310568728348413958910299881715937715018572879175542723270961874435550327968633029584188957768139340259030454592302362749027465867807734115139476094923287105973980458884201581736181829195017361330152871853820144480008,4004735351364710265644908449319598352103612215188460925760295665563484237162745827742855116753659687319941982652183152982522805963387540988424745778802028813186258777373064074552858455437921359277118582292259532327491507456668283228943221341315392967683928177537547570473748486481294902027111753951887811107,625070500924631773027293646808528931297961990338169633089637061010766445639876245993583660254312851352153995204943188734825803541904480394551165674837469282411059121521375161737576421883549419892239480294917943542161102975888315623576549465990742662361177906359742645436834392762941048730926726541953775339985|50884288706475165946257509654999208555658693396648687044835752784386552584102384977309647778026166442592405819250800637374065583324042092667913200394806282864115429746583280943890188029227669788614986056318825797041482189685920834253378958370006347565609320222176974991924753600658153514244660657255122224708,38124750578737274821917753227232162791003089617481557231259566762030985520934492451354616032457170217275564281951330766101660738724598191687885679545346283525262542724874642642872748420737930473130307644519437933305026842012536784886496944579276550709211116316390318564020889816097235068462785319614865578597,130062522389522343683740057432381314776477134408262105090740417520527750971142246152091337403925616258740469387086918783120971977871460574454924803144389152275224257452330149332865693355986252454785361887191345579925263888502541640915087986171712168495464223258466766753612088491549102305993177855419426172515
10012949731508230844521554364973074187572984168621445800774150709798807735949381704091845966274845524513566631062798752350499554699759712145607818652191568463373664709797900265336143905874117568859521742454341137224521191983729963831041097053387797083787709902762145306866562987693831491238763225325353128845,-7151999616242866495807184767334673387014110620932054515899434747323053830494035687486485101495361247552977403879925385683437335608704813457204456533123612810231681288244199329093278043176840326889166441056953674708680650112341950599518566211501622893081961748190383051196092405691509055911825933224776999729,728959856841002416924230811929428724002543698647639902715200337469187398607311841753203087774058534727465005007422722827247541795373827101651083024979629054119806748202357685733330535940416577507509240075110229140018035405816024445205831928017961602089222683008780078758377712656395593651285944681456109357272|78605684766061357400507779695495682929810684632437884872357120089392494231881706222602069457907886449103098011256954019318391632581377073457287658351584831830230683661446071913790640516272177525020187886119102997352695696049059080937602038841787771510139456284931095360062636771451048097974369276252684666749,12001075534855282519055781006726767731199194746822836204491410167536180166431388377323739159072959927587441133024108242424202303987846968293631866746295774320809136575432861690259530718674237632206265488487198601880322884976030897140623633254152458705315742157972429278484090634288310049511931491105240527901,93151749819352486101012886560489221249552002889236789406862251708880381277922290057447780576080950571200028266859881169907512608303652032886801146810143008245384785580165444902988038417617761865310968792125862316413739796643982228185896004498606219961899388723793207292461251691711779811000343374670531988570|95620961524949716684140097524982794699249535271050516669544121744125934159117898820120095869213277316814159636331359612088008309956314498753337898007810553303289522178449103493384329227781778413500531168007453332099452587335790687068580171335323542117871903087433014777736086345342400718427907876478857651725,93982690612240904950679627999951286744516720026289165825378439518867065181987722717690665329424786689958612327347934970490613914683496125042910877240489318265091859294188434182919729530207613831730142844292090902152344156800509267822168626995816691703927249712872762026654985358484494213663737589506902782009,99292425117587212531473852181491241954331600716435740239461638370783102438068248269577051049726048567729703659744591520045688390816935889052570162756642088994924462717034854539966002991020871080627249804440896263676225604896518999268622239261793212314602300584784534836058487675621509713476733501463323785340
10013285697697981291514875192049827757071760177573323421009966878146856227693938310986650067592898605619488251263628358029535725840627847357496217367653253065239804661689467675594407401100934372130923704422822224913415836705341468552018728686468194407664564227575182128302559705354560745061529474614082985076,6561642167054255252332139226189226301150630422474494620863616714017817447379372804603010573956570809208555270847201719676149529315047658055027624866235618098171962008631941847341271231615706090718182990766223922159167490454724094386151343698580819149354278973243680974477529170554988807127882542455236037061,528470097447394031501467541165507900676972213983504375431777006857690508074506764381712795328953309294516807977445847891975262681647237636757123951794958241571326610288116591734368211279530252114133992576937361883752806300690109922381969083425358175983601420535008716582685323406262131690670391327047692590496|10013285697697981291514875192049827757071760177573323421009966878146856227693938310986650067592898605619488251263628358029535725840627847357496217367653253065239804661689467675594407401100934372130923704422822224913415836705341468552018728686468194407664564227575182128302559705354560745061529474614082985076,6561642167054255252332139226189226301150630422474494620863616714017817447379372804603010573956570809208555270847201719676149529315047658055027624866235618098171962008631941847341271231615706090718182990766223922159167490454724094386151343698580819149354278973243680974477529170554988807127882542455236037061,528470097447394031501467541165507900676972213983504375431777006857690508074506764381712795328953309294516807977445847891975262681647237636757123951794958241571326610288116591734368211279530252114133992576937361883752806300690109922381969083425358175983601420535008716582685323406262131690670391327047692590496|34436981724331071994857876336695803178232447897168183469251879445354282383737983320261577504714614276116113259188008664067129808039959751651485877586471601565784430914037035998508212337945584341667506911125463475285113792006322617814372685212577273915390962094210529917778766692621996665878783549527139893242,32421657027122874777191628085590775058881834171831914535958291812982208823927027425208685420460283486647223529499620732980942837410329269106357656112224843439688604221190662744374320594231296457180058248568608247918397639378809724702503728912863511608290047988244839274296444657984762607288102260430546556327,160982437047557923662754621724904101004108273738876884592163845288132647289990060919034667221490978793506721749816537966400403944327808168366534024580437483775879522831741601830069730429889808208871000895202628107312664119771131677027106136972021612902580949354880064038858290748071858588504931122717671875719
10013409568078797146570807857755720961248912529367151061974511181033586582464029378963193763825696350496154303179345126636835517120186897096948192379786846194127995559270109497428813513500508574813803534331316886434340387606885978254975074973425350503976585044856706375756665039166645930515210729176181994797,6863076338634175024934436723026392698236823689304369693969685928390616820215350991816780229964708018996782742906430454861638727991380590099557403163016242141034822837520016392592164770889783961757225608245037212056737255646000577024303400659319142788815209178052443133447533618473993771130005829940742472843,518144219445747450843112374880923475954988909716176430338161904285754222207619744119028881545602958596524518340559183715691125114950676034953086100367357569860971147170398898521979791627387469550508096062409978585338647803044577182942437027156401628087522267601972713267759073787404132654921721043098478369296|10013409568078797146570807857755720961248912529367151061974511181033586582464029378963193763825696350496154303179345126636835517120186897096948192379786846194127995559270109497428813513500508574813803534331316886434340387606885978254975074973425350503976585044856706375756665039166645930515210729176181994797,6863076338634175024934436723026392698236823689304369693969685928390616820215350991816780229964708018996782742906430454861638727991380590099557403163016242141034822837520016392592164770889783961757225608245037212056737255646000577024303400659319142788815209178052443133447533618473993771130005829940742472843,518144219445747450843112374880923475954988909716176430338161904285754222207619744119028881545602958596524518340559183715691125114950676034953086100367357569860971147170398898521979791627387469550508096062409978585338647803044577182942437027156401628087522267601972713267759073787404132654921721043098478369296|29934292569471815703363755226997845073545738667501237803957680847283080542129475423696483417806010171923751057450372494361758724728289501602492090448848706266885172109480272010048281849170055027096272553904872380723830007840644079815126735090510221286243662888112310922242506575820245103502418648518037684112,-21627427564859692871607980544502391995135725746472152647532172629071699503752589147589008201502208786678594136605740253912219755939688067145589663222363251747851181456245722891111913772396992196602024806546104102083185098682262204868868794139167512528524369543939531083241005579818092881356982615423576691605,176839029147532789455522785442738478049409371224700882039503756023790320876676330359714505430586793397649436855899139335082011213013721973064579158662211626800445041202290699798718862085318933995294002499387627536860514923891246937832235709964008507131234282169012371627871115559920941075179401745449676837538
10013439159433989368964725373563382887574891949489700677050044742848904863973460805304293375442411192907083507310299969395983146408589524560833202656559624127327840001867965274370013167539210363322627273718141213894086509619780941576547772641539573210833142422223317097724915074066448586076045470572140906640,8310509330265721057433243761087295977033094222529694041792873186617167079529403730551603568975196878825930300295178836012162497002423788954615523897720318575793014458944774857654309162161287534450951840479782552544416928129945375223479302487034431413802055998746646446418560576461091628250104710978988283711,729371463016273963110544177662324936807730201765611306002068268068668637824971025044896789932884019488152669624502699796991126775679816762002628560217169359562928488795097209366461843162752726085374841269043547767926070040941464791696126630730708190840765048657149163857767697743125679328771823496672841634424|53070231924347082568804835060631378289496498123832644772276016787246416299549861270518581840230464146779761127524498364504195386387182521904349896158340177993161553682765729098600652803891496382298875979768509788803608935382898072295003870146958848103249920622300892108001270267505518700281027764636096833740,-10417045904363157434661773205739749791733323923523249180794936274249482583161962687848890485454386657190132561052636607343240275768181642068289523597327390757351630390400726183726689859598985450769013120294233573698641240921187000189001584616004996169093549349734180954432033587699679729849675222478884233311,137805678896928752296520072917407826444192224958002583188528402832110905130383122933446618731410797305667977506853537200263986333845054038041545138300862253525372279908216585177453144947870717454801757363277754721032068341587435554423804921498405475740879440309992782986462772299747827377706986933475774033684|56482649708459145913698445611252485312060512622120077359133908474066254680736347932747096146010188731146496181655662751016088725094095969432429720148408144169456178462601187248728823790080612841522193324466093276526908124707660336237710411213793152471895601301243018110500181075901054216803639852864737028850,49500528206529841911957152384541310290857923328806104231198472543790151686945922117895513040239668591093558926952515368216015961042415506812499837082111798870583213244606704215667322437109994138978691823955863634369767001231824513186587618556524171225612093890634215231765102523588484540352521700864775908391,139845177982276960575270039101197150993163035851524438788484301872591911839811648314287998492505051870128263318114638169162126726205946284015475459749582002542133038527256092765477445685371965587948783428628744556595668607565825917211361759008178572918967281201176709071648799305995083323084664578756735938622
100137176306265990029733961444031383061223366889811053704411233166327830634077756142922727010656909223245031237249254709133350667800868491437148280477941194204587700926281351055456250199609042270725753605165960788792303060065875576152280599302149022622498012279559937562935558359151996671916418735428920407874,97779166460841276445850871197751897473918068054418745266060401791237288238653436085640513289818870139139618919771865928628062692360137571273452019987828179736062700190532592747648476510214800565987627353502647292543809222510700867942163153624606570877663088964161374448935565221244874684751958995844140920147,102256681515788126438883260779614224655986266663397201843001234522477597459794964756711032437403434184534404583233460968937962164574558546102488980641209149336930446800149993628815025349402768080588150480797996340762754608056907877670259116917971852689279794852877026737551375891068290636218096081379871615065|100137176306265990029733961444031383061223366889811053704411233166327830634077756142922727010656909223245031237249254709133350667800868491437148280477941194204587700926281351055456250199609042270725753605165960788792303060065875576152280599302149022622498012279559937562935558359151996671916418735428920407874,97779166460841276445850871197751897473918068054418745266060401791237288238653436085640513289818870139139618919771865928628062692360137571273452019987828179736062700190532592747648476510214800565987627353502647292543809222510700867942163153624606570877663088964161374448935565221244874684751958995844140920147,102256681515788126438883260779614224655986266663397201843001234522477597459794964756711032437403434184534404583233460968937962164574558546102488980641209149336930446800149993628815025349402768080588150480797996340762754608056907877670259116917971852689279794852877026737551375891068290636218096081379871615065|90230316563580194408667213300439360765549943827123723976699582813489678898952655680387614045807099591452452020884059027873359796950334151880947386773848115789736943898016681027189561282963394481712553688761042044178529870890932063063291912576811880180339151930033798900788177324802354824840693823677567948727,-51250096968515553727207440971544562384114008768089106206247467547899665759345213630706768471270630937078525436219387041016063211534659780348494492859921683763678230787094584046438254568966852960609578580031708027705688875405694260795850267621602038107210044773776590144869507841095128986805399917716889737097,94271497992835932562874103278757400032116756041765039747726332995183554964390204442288393334665236335700063020174534799860251424117225874828741908247259400897208844068836969114844343301370484015148786737029807531127609578040269356203181806490127049090765570457173053771731322678344641402857532580837050951380
1001395889265586485395767421092943095772484906688205160639025138850588355434167443569518670890639224060287615982046173119211466447418875356487968111638376610456681184419174307282534045999642719677458693603373061246804412063778941537663208494251233702824916937867260454282227810431834716831538058300952240529,60445540632407873888807630431208524230030823670563578058253542014522089940657440267941912297376844686920437735513309169811551129412183931683096248710036617268265519243947751270645191479229689326385715524956466565650374324873653293511970021452999675894489762841364719216977754928108945414058693987652866277,5401452543992462314517473547060846830682300053665170002473827326781788915141651047957910827411217522592705590143110487190395657380723574363184777022159851917393607961064987992588915644654812213550360705959643031621136573608890274219923270810168453305278905475435769643968988593393956330128341342800859836282482|1001395889265586485395767421092943095772484906688205160639025138850588355434167443569518670890639224060287615982046173119211466447418875356487968111638376610456681184419174307282534045999642719677458693603373061246804412063778941537663208494251233702824916937867260454282227810431834716831538058300952240529,60445540632407873888807630431208524230030823670563578058253542014522089940657440267941912297376844686920437735513309169811551129412183931683096248710036617268265519243947751270645191479229689326385715524956466565650374324873653293511970021452999675894489762841364719216977754928108945414058693987652866277,5401452543992462314517473547060846830682300053665170002473827326781788915141651047957910827411217522592705590143110487190395657380723574363184777022159851917393607961064987992588915644654812213550360705959643031621136573608890274219923270810168453305278905475435769643968988593393956330128341342800859836282482|43569972642791160005757596858255828258440677425601503825448806514649923603624018287716685991744061240705340542732331922577472226472918231509238166036331218027449035406029770845535194662631393899654058445399116462950394778843477054303490660149914576382156352231393154632904722395547296167018467287872528029256,-25416175075838450919641769013264410597729745958193362136948110865397498509541978552163608664910111097484344111265508414674502206468095426484449495661952091027512836383946952942259134571474962916748153155124469369237399224386694894533985438381306408742628779331072259662078374717232763484127547679303302310423,127851513581210146707222534812462714415549658228702116548129323569875687997527570139914376876955894345964691178029394628745573178902316765592327648023513178993717765546280790932769863585265709550819660882599525799584893587529991012504312937097442098858522399473806578431530443021404617174701716319817659510588
10014457466865501413264699180995213607651643403581155351850240885586127254516466035686557278805989563280873217997386135507560429328380625332058111008767730524810617486297285562994007263758369576890950982876431843971907525378186076190945281470031905336296565482376151661355756246367703162199805483942789509516,-9493045169000225624825724585241654877107258957466554573322941788423005986836702078635071088783742277452705183557515581054220105186163500969879785143181676844657120253295906990349839818041129525896218008774011956975336293108128480236859770511279248182237458109627660116415432972887068943678814730002774447323,568058498128347562017983106577404112679290790118077765226872096344304166614495246835964393367142362074124393647429278191341969083397190437238809441291521483431836555168421336650034272837791888742028164348356631901893675815620388348481938896223555723594783353067563133868242273893775394833482067029611721906579|10014457466865501413264699180995213607651643403581155351850240885586127254516466035686557278805989563280873217997386135507560429328380625332058111008767730524810617486297285562994007263758369576890950982876431843971907525378186076190945281470031905336296565482376151661355756246367703162199805483942789509516,-9493045169000225624825724585241654877107258957466554573322941788423005986836702078635071088783742277452705183557515581054220105186163500969879785143181676844657120253295906990349839818041129525896218008774011956975336293108128480236859770511279248182237458109627660116415432972887068943678814730002774447323,568058498128347562017983106577404112679290790118077765226872096344304166614495246835964393367142362074124393647429278191341969083397190437238809441291521483431836555168421336650034272837791888742028164348356631901893675815620388348481938896223555723594783353067563133868242273893775394833482067029611721906579|53924208564494923109968517258991384333718615783597634502228353963509962336751805354923463494565719411128406689879296751392427452179492575502279868846589843663305526485431433798862642111241114809566645178986499564696116126963309686958809916838000470566457881788520159467305886335238376585070031885019107861839,-39165088112891919485404645022206551911392044983195122526582505244941571614658605614311191813725723193620640489676510478992438060577861340792571425647895723271516089195795031639152263494946222662918005100610385322895768473350699779206361702599565733658715228168714169147264299885332019593127372341848528310877,112189763824528641217468278574322392988954546777239131658850758660466358827365295080995339889134329849615042048060538504294364321483596732194229239161149447040110980960983657967678809117682823152517826486688609621632734218254085881353576474560418869461310902870862203604502294697766172436420730459846253285376
10014524612435081655051402581388141399758826121078479680077428037590919760198044078469208114625992172565561472610137633731570114446039320551421576820201144498480274752068507237188168464666743295560743051180514619150806895664325776982239371917265280309982409950396003685063877356037007592827997650696359708648,-1151946584820929060448198375444913319887694243637725495546164532401952339142382368891700429417009398962503441132652463153588614606824550308747271936296460648801898782148675402610858915130433609314541230955826121143276189468724039832396682232064702428868374548095200287491142543410829209121388657552507539861,755148183880958266120452185655234110618667867205538459331580575221728013160051641776310146717168795492323023035012567121444609095123943446710618919745199683082156201032014589922592096239933647413759449971964484414757026090967529868635390069577397530636511831668757182454799405458183267048363982001659170207347|10014524612435081655051402581388141399758826121078479680077428037590919760198044078469208114625992172565561472610137633731570114446039320551421576820201144498480274752068507237188168464666743295560743051180514619150806895664325776982239371917265280309982409950396003685063877356037007592827997650696359708648,-1151946584820929060448198375444913319887694243637725495546164532401952339142382368891700429417009398962503441132652463153588614606824550308747271936296460648801898782148675402610858915130433609314541230955826121143276189468724039832396682232064702428868374548095200287491142543410829209121388657552507539861,755148183880958266120452185655234110618667867205538459331580575221728013160051641776310146717168795492323023035012567121444609095123943446710618919745199683082156201032014589922592096239933647413759449971964484414757026090967529868635390069577397530636511831668757182454799405458183267048363982001659170207347|46183360432532901454553912811649590320395866004347241196844991991079215314437275037790647677890495653136878666779844887628869070006778207117633836660092513861015319661569732287838772799418674107359979430356246346034550280154482402202513605341927486676571446547869725605869822695502032982833841088921112910317,-14839171560103132001614843311520281027921489422034665235320812512225719145369465447283012912841921017696170329655940078247191555778130550993274994429848671209676820244675419866031667103832358269654123112505016252317575238332509399397558348115029597533711563469431946692326093523953990323828622920869190596305,164933181779897671999712222932130083401866004577771560343160060853528269308468525452931360567865498324819919495168385048274257865546801611749112060417208336526645794766502287072279593583106527746581118239327199774476900334621937982627978739872164479446504941326886004356233761306601172587310954186017120057146
10015153163121593836478079113660124757348318592530821165639828390191159358973882062973457665510869038410016978521906069415643885467466803613263638452835291035274253082105374798431579187029855868716866951698965254377198199868261126247017409456764474165861037253182443325274363795830109568972878953062238823520,2382294090568001333199894323474279123934374114667847405540440750564854209907703388935432920732110218963078674073256448624811505546395497000378710736855311825351193195350046490926404354706980500837042629648272073851723169837427468358824989832884534921916167168920876623159906890551519514875606250679556403973,773658465692173962483130527303229646901934499596511207834787839028928145069426505005504820136922810366817841934360207193839133022641619097494932108724559232945611195348726835877676174729010759098808115181632361389730445448407363060843805088069390583778242530477288002693827656348092952397617162960252636436602|10015153163121593836478079113660124757348318592530821165639828390191159358973882062973457665510869038410016978521906069415643885467466803613263638452835291035274253082105374798431579187029855868716866951698965254377198199868261126247017409456764474165861037253182443325274363795830109568972878953062238823520,2382294090568001333199894323474279123934374114667847405540440750564854209907703388935432920732110218963078674073256448624811505546395497000378710736855311825351193195350046490926404354706980500837042629648272073851723169837427468358824989832884534921916167168920876623159906890551519514875606250679556403973,773658465692173962483130527303229646901934499596511207834787839028928145069426505005504820136922810366817841934360207193839133022641619097494932108724559232945611195348726835877676174729010759098808115181632361389730445448407363060843805088069390583778242530477288002693827656348092952397617162960252636436602|2334289880943001376407857326996263570161383789108737840675851906077977981768540714248105544895055900962482225672861273136265466132609608331964249615854131927898907957201650301595252550620756829520427054784019840985991520693282395588941752214974743008251596421642708049368885083348322205731564243670420111453,1451720076983591598762998723081545117923198868478265830640664361188690301293679623937617406037087334975387230852094993435248087727723628228521184122895045650428549727009619829664472593953602490826316016345941727517760259061554173070969494032097919619747777129170826368624036489935713881661043471800066640125,3318960568956834644312274599956969298741234864897695465866703354170475923995521916039531437101483638236150279927673715871252637092748519401149230098061946550109095773979423194478592673363716301124276065026975130628863523060647342416992862735921072287765667600233548851774826575592417995450427441845506696081388
10015239581157875832393535763226085031936027674008799231064578015529654192320817181717861924169857992310709531421935508097069554814977182072669044193680614850544453265357095259368437732015348877933787885875170804438256215681419620514332393733243248548151757671725579685427667920968624432291421418590675885300,5094068907677575740286879080674249533942090145311835759008798415694966420126408035500684853222542571817165748053609110326610732625612063208376418866488998532875479258993000620044826461966140228426897339103003926919606128736757098245146058573375685873266553963971816210554103991392539430164989850926128708273,793368698167290739626939845245925598679004619304386735598558585912760256279890735283141314660505981777266664338091862952502183635644778863932176282239208069911448671090051312086285039683208751050938084831532228722294544316547609430035555984901118374565436615559075980852757981922632778527357570396074193505873|10015239581157875832393535763226085031936027674008799231064578015529654192320817181717861924169857992310709531421935508097069554814977182072669044193680614850544453265357095259368437732015348877933787885875170804438256215681419620514332393733243248548151757671725579685427667920968624432291421418590675885300,5094068907677575740286879080674249533942090145311835759008798415694966420126408035500684853222542571817165748053609110326610732625612063208376418866488998532875479258993000620044826461966140228426897339103003926919606128736757098245146058573375685873266553963971816210554103991392539430164989850926128708273,793368698167290739626939845245925598679004619304386735598558585912760256279890735283141314660505981777266664338091862952502183635644778863932176282239208069911448671090051312086285039683208751050938084831532228722294544316547609430035555984901118374565436615559075980852757981922632778527357570396074193505873|54841829397576178848410586601034860596951681568779361478370108261032921497569280442168530570346157404440784855573637229833444102498053726559151577392605738325853410653119896676062193149054976747541732412004218217068288550127184839213667255982218678702854737220904918059908451831872125006158411607941690397052,-13987639594862577439517093919564754940146287009709146462369986810150221519296281298521622497304190878362220137401179604871651085725669668566995040192751337189374220954170616856835063054456944563624013156491483611079953326833211481288513306777121436082074004700443915242579221138749893848640705537321387708809,145658957896464652977038505022308448361415349923894631554394890309500215673949920864830014124570888235622920757378372327525946059952077895236293799705256119864823158645268515234330467061529263252614881624406296566043408419602845128600163566622927193489899129202143975708704672075445501568437520798105023647844
10016254093062341091793169016069728267098466973354611327776341296362926980734885768145505535610323176943330336454162903286601650062616238131379152236760546371204482195908361542328829078490793642835057146484428739306586521325328236448343779367153378279828280298660045704810418678221790320328995853516877961219,5290291792844776128036538578818355234036731339837804827682257620535756451822532868533550409363458436730292692155637706486234356872153487706954079157252741244973963860424508734267445638531496348565715559236158994920739250737957339663944820624379832490664101888239401802029497939684558696213321821587965089165,649562196414599732260624464563141423074514382020176141033151990702926870363780837252385965871530682720560442789827097838322398249975199460284454895932864056555126156062190575895999061116214790474483579500239339070750293285631666586984632253828693474154470829221739655058926181416125562534958534381263761974132|10016254093062341091793169016069728267098466973354611327776341296362926980734885768145505535610323176943330336454162903286601650062616238131379152236760546371204482195908361542328829078490793642835057146484428739306586521325328236448343779367153378279828280298660045704810418678221790320328995853516877961219,5290291792844776128036538578818355234036731339837804827682257620535756451822532868533550409363458436730292692155637706486234356872153487706954079157252741244973963860424508734267445638531496348565715559236158994920739250737957339663944820624379832490664101888239401802029497939684558696213321821587965089165,649562196414599732260624464563141423074514382020176141033151990702926870363780837252385965871530682720560442789827097838322398249975199460284454895932864056555126156062190575895999061116214790474483579500239339070750293285631666586984632253828693474154470829221739655058926181416125562534958534381263761974132|4371923964825216081284965901486251829658920327478160330494959761785570498729926171763697403539994609514035386549444286899305836316283570402957212167175599769519526858160920653621106184279087086218630872059466833612874880235324503114394586087353649281136173057014948419793113247251617601913225740371158264594,-1777711233855585326424402788112018092969733488690398670027508570423282261674718543600694888501454195345939794788269076453964223553057248156896791027286117126036185606587718958830247368692129308590218482424190086311842595428742140075700660885589198113766412954745249944832418277914084817045523687626938171785,1486753504481531714235052666066139608869409848938074431937349188798515713076253106271449862728854109674272536360912828894345019832890057397353770574425655506024994198304163182702822689738838001321557096641997078734385067590564038418788081682782254559978113888414124552326849527747130706995014118004294289090507
100168933817004159727571823870862212374515071383247163682233493029515956409883385367746187285740348786673303354766599662884032925310153869913659930858915269690815416234679514078167380783771768659750083394948158950008326340270387586985723448583932705818464704601214600293828130344813737095058092807371622380596,94832715670637342331954204053963565603302480280224254821703778448479787031215111088413069986664424694762700821340882966261664606716747356784210807087846121536668261049472463334524682357378613143974178468771819549191894308095591279746614292380149290609465170348542192697415722868093623009037253233869856957249,102860441967964242444445722269341757702905607863364253263839843561869841563005656247302036622183568251273499262767768690361280263007610763737074443848261770701568579600837276156244861738658629562432640564576786387713071777708265072467592751700403901387393831303255944800743982818455033707731784929932463764787|100168933817004159727571823870862212374515071383247163682233493029515956409883385367746187285740348786673303354766599662884032925310153869913659930858915269690815416234679514078167380783771768659750083394948158950008326340270387586985723448583932705818464704601214600293828130344813737095058092807371622380596,94832715670637342331954204053963565603302480280224254821703778448479787031215111088413069986664424694762700821340882966261664606716747356784210807087846121536668261049472463334524682357378613143974178468771819549191894308095591279746614292380149290609465170348542192697415722868093623009037253233869856957249,102860441967964242444445722269341757702905607863364253263839843561869841563005656247302036622183568251273499262767768690361280263007610763737074443848261770701568579600837276156244861738658629562432640564576786387713071777708265072467592751700403901387393831303255944800743982818455033707731784929932463764787|77074101972769923370658023573461029047908280864501436531886214070884695444419790476920141159581106162534554398040667029684395317753749995140975694643351101153246406361333865778019332847126758508398386399309944270422140994351224794089223904030644354844471144608782627152160492615030406249102513998568586126653,41985809674026851301068939458342266766093613320697544468890621111459064094913132603897896518617407840492037076180430740254366932298578105226006922522339189157081422030305375009727018508446301230399756872145212262654632874007091596766171377732560260349745066521408866260391195589212337788533541057115385883425,110229138576369926974358954548772667512560757802376313780826844717365768043167923353943051327604684088175403151021231033281660580097059744410859188703138886987578267563448651782227630417696079180690392826925010189611494463744920925421564075513181916017454497019126236913116432477001913262238126225201422341436
10016905787587129103970068378589209223718079791180726370802218768976971488497998963132244508629494308529380628538141221743580243393344335649567002150936320257090927900467530902572471077942584896593451110546304416815718151825873142786318484895510554032583903064792109176935301749381314577344473149515437073560,-4606191417439560848418163571752652850846391635765859587403508494460979835111500495993727812816590518091323150783186546267331220869638878833615969103418728210432746474134652280483753966001415196686238333974286033749286862708642243562674370580850529480084335445537434013760930078201975018692661527689582576651,605629172398620500162437997408160351967898827176789386195142449064206069917749164747262079121234714184955198496120255981525746584380916729025666697652941726995464456228081635615903549843932017595245592861355354651584306759089064045480854767640497444940703279199283744488071666641763271403206424800946819221209|10016905787587129103970068378589209223718079791180726370802218768976971488497998963132244508629494308529380628538141221743580243393344335649567002150936320257090927900467530902572471077942584896593451110546304416815718151825873142786318484895510554032583903064792109176935301749381314577344473149515437073560,-4606191417439560848418163571752652850846391635765859587403508494460979835111500495993727812816590518091323150783186546267331220869638878833615969103418728210432746474134652280483753966001415196686238333974286033749286862708642243562674370580850529480084335445537434013760930078201975018692661527689582576651,605629172398620500162437997408160351967898827176789386195142449064206069917749164747262079121234714184955198496120255981525746584380916729025666697652941726995464456228081635615903549843932017595245592861355354651584306759089064045480854767640497444940703279199283744488071666641763271403206424800946819221209|46304687373394436931218438666336335256163483212484332920442711829320278593351077938042811198542492407186729960199059393629663370119443451307712349370714705707036441431251782566272288509732854919564985572759872505231639307883389746522852343879592729064407291688011480357040596643477509242715875322162180945750,-27559962602683142671407402152656684625711978340483108455301920226275039655520624691717381412007576185077377268485337641259513780832297300630514833099989822452624240349981167585374487019267119021970798715861631920467292530317231419988216997273247875678528676583110608263771292353047679830100015076536212572871,134999594026951253395775325545499481323026670784912424362786946325493588697203309584859459643146426717172468824814166286260797091069281816967149658244654968987888219904891951992996909324931101736714925044299968419433398393443198400917682271553527341988170608553689440600718627726318712053029382276372293927321
10018204832407485307717168433283551951171211565712475881182623460525924044598415564148247583748572210844295784844361310074903318189804960966908772513031346031383059069976302114174587533940128565286800673190990221782901119861314311455679210523773394109738879256410739142961640761546729001001316019848803176862,5319904375533742100925641023534751951391638893478820023967035481652261436239987131193126434052892185984232529181792190920674907331089418651303709226767934571557921846173913244300134187483219524696758678859856206200663423378880336983240402046185791279466371047694436246549133924131892629303395892591776395187,649443554629399472805877307531888884997294549224205118199170867300682218925831813905978113513120968194233947187441042861450829488125193696091497608405966874500722600331516590109468259720034716473854550338705028445661682847162605116427138852824514186119049574433700978648124399292078009263486664308050317605762|10018204832407485307717168433283551951171211565712475881182623460525924044598415564148247583748572210844295784844361310074903318189804960966908772513031346031383059069976302114174587533940128565286800673190990221782901119861314311455679210523773394109738879256410739142961640761546729001001316019848803176862,5319904375533742100925641023534751951391638893478820023967035481652261436239987131193126434052892185984232529181792190920674907331089418651303709226767934571557921846173913244300134187483219524696758678859856206200663423378880336983240402046185791279466371047694436246549133924131892629303395892591776395187,649443554629399472805877307531888884997294549224205118199170867300682218925831813905978113513120968194233947187441042861450829488125193696091497608405966874500722600331516590109468259720034716473854550338705028445661682847162605116427138852824514186119049574433700978648124399292078009263486664308050317605762|2096824613311195474736703091933491927179118439681576075463684305365113996801091784928235546455105051723066941197368294736517297176841884535935805063900042702255946184765201041823632273617760317603104813509978347996857764943233871467178918416729927262302333533232369242879390413535385046393166248041635195052,106494743809548339750384465880660679449902990323530191499768868050880389213560457433755933556230921885636912867886887645004590062925256300108980851523487384554584007694663026566980186001150284697993766392145530903618307059918756399086400576557720952521322359177695970013138988731324890614696675530003172189,3099537274480186341907264372921810635861168363663532429504499040028118656288725100184032700559268063816635775634703345843577214400172811320277070043994325333354476328328682954931303645039746659585813529747367061450073478508564524387846459195219414272058883943010351216728564728313947382708438971484753032540491
10018324718324265352080889354041349230495045650756363847859249064826167700621077306379636998633382620068424485758426219639651755498284131150741688356919555549109464768469845299901089390604198312107185124929799165529332689261450442020302769382765032211061987664530506790585428478002180255625233322864976647458,-1506556466689461719964363510118987647616549995746954868616471745983245113792074110437071688516535364802439931589935160320446594866789971924891832800418288544496229576060497571654938278590804451001178571222736016531030712235951293438712713277945256316492298818368402112911658258565046390998975710669014707937,708633648140842422465025989226402132551754445128385378651747216241166649232185357696677838986015643979480257385865744447602978939236447538983280973796461564754777224324765925807967303202117722154439166886733422154436177593473337680099402130518111476687602398807958385973240844776043934886139211712396905414373|10018324718324265352080889354041349230495045650756363847859249064826167700621077306379636998633382620068424485758426219639651755498284131150741688356919555549109464768469845299901089390604198312107185124929799165529332689261450442020302769382765032211061987664530506790585428478002180255625233322864976647458,-1506556466689461719964363510118987647616549995746954868616471745983245113792074110437071688516535364802439931589935160320446594866789971924891832800418288544496229576060497571654938278590804451001178571222736016531030712235951293438712713277945256316492298818368402112911658258565046390998975710669014707937,708633648140842422465025989226402132551754445128385378651747216241166649232185357696677838986015643979480257385865744447602978939236447538983280973796461564754777224324765925807967303202117722154439166886733422154436177593473337680099402130518111476687602398807958385973240844776043934886139211712396905414373|27695493339474189059880649994786373673681195258723034498967136263221174895242876882887946040754182923842018399590448977999734476968405279409965275664350294423197625592498762797252651752487096596479518881899735472134497736489815871889587384160668070191112126826489102305651218385469424433736996571142100268141,4244952032054732923978416579691917713463067102733490131769022354718180777349838220573662792933493750823939044158056520471214587505994364897599832929831064732609354344151098280452640031958247121275726298011899146169585223669027857229201360814944532694404419990370729211245101258947186079227140704211123597077,256477087542010205875387979681474864287758986482727894664413009819175948644274490742191718780565989800083756066810584023109412061717270312386676508030363737098913494555400729954736934622756650518307368707185355806725304278546342578972238562139946071381611959969612417306120634997866733933066171286156441897864
100183725937805337440102832154923451468884088040067509735031176134138272029603097931029532527171620687937178427853408917605171373483732022096443082050272616813579999826937201905718430121138104894761796713162794983612090638008542903172271321979734531328047767185223183894705715872373581190063338544430105324944,97967360545064065581782092795782542381718050317435898718948431525445051912029574864522929506831468927036372238440312318277489221772379035158891587900186742286147138092170859279721424649522055176445825889170777870731814816272149484567390197282747308726861433765864290861778135213069453090668850681241158130141,102026058802637364547431940124628332383045736950389197653455431566764985503089749509318465184383586821649550424369391712983254618997917250229615538329822378126555642981029789087346297188093481472570239624171949132198549570384613605722016512646835562730355439782372504448945801732597394795504733391497603335093|100183725937805337440102832154923451468884088040067509735031176134138272029603097931029532527171620687937178427853408917605171373483732022096443082050272616813579999826937201905718430121138104894761796713162794983612090638008542903172271321979734531328047767185223183894705715872373581190063338544430105324944,97967360545064065581782092795782542381718050317435898718948431525445051912029574864522929506831468927036372238440312318277489221772379035158891587900186742286147138092170859279721424649522055176445825889170777870731814816272149484567390197282747308726861433765864290861778135213069453090668850681241158130141,102026058802637364547431940124628332383045736950389197653455431566764985503089749509318465184383586821649550424369391712983254618997917250229615538329822378126555642981029789087346297188093481472570239624171949132198549570384613605722016512646835562730355439782372504448945801732597394795504733391497603335093|88007552516538570862938195555687347843271125145294862509637863339852312849461683699513427251868777755449793173646890377883712394792262777503483942996934326765981582162423696391672000556247247431253370862284402004050248548817767631668543644528300726312835546938100615886799945875203418182610947796762957426066,46229538931090505519067196461411597385016117678710797853895441617844339335997518932818211184588127766146461427860967017470462043930326616555616035492326025837765159149630918451827844844437116744925433303753825438769925710637787423788344940219740545569047456022116580673560308925831201666938083175493702647671,94949150488319392606413346466333119512866765599276437121309157049458742789511630485348500087618567561361017601972082423173906361345987933875129792711583865107081204947273992176380167405635064486260061816002217859656028475745573246943400761862339441042416462774614661346152692808807449954694367626488600259377
10018622993047838712433185410421446815061984959152870777572656734193435222251946970691795794836467121595552277401220487788714277091933394850502637162917792769686767139849624312881217655116086523917779102305498425044983500792458780789534783880422443059521517950075233845690825129430658238084704480639376209109,-5642888291743578132708587871691433542854601085995709323535797030150736747981212204721414421313379808144339701595994626772514328521365374368168430420450149143091140909885716813202658261033852230689379211692039890782701731228409652608328076923100699005939261407374626950263084881921749869854247192520776393467,584355741641273221932263410866659097943618996328052690659780811632775391934038170008705223727517700749237903184431819452649538607172642783739379843963426355234430525043677403033326216332450474494227299404505243469315575849027861412999876408965870212198057391050926245137105584182883631254668161360450853213630|10018622993047838712433185410421446815061984959152870777572656734193435222251946970691795794836467121595552277401220487788714277091933394850502637162917792769686767139849624312881217655116086523917779102305498425044983500792458780789534783880422443059521517950075233845690825129430658238084704480639376209109,-5642888291743578132708587871691433542854601085995709323535797030150736747981212204721414421313379808144339701595994626772514328521365374368168430420450149143091140909885716813202658261033852230689379211692039890782701731228409652608328076923100699005939261407374626950263084881921749869854247192520776393467,584355741641273221932263410866659097943618996328052690659780811632775391934038170008705223727517700749237903184431819452649538607172642783739379843963426355234430525043677403033326216332450474494227299404505243469315575849027861412999876408965870212198057391050926245137105584182883631254668161360450853213630|24492216963212266409994030118552483730975075727585752220177989563872338705971497453471962798275543072636175655672560120906290569324009187038649563218726182874757477950170840864973817320145411108769238293767323154108926503045123037222803844779103784397763216133236290396907058542243428101056150879809315089176,-17735224044627622852810014209171696937481849587925646605967048837801771413294839162751742330787917315172217980725109761639973896911760524548506285715284414033504356013230406678376141516049028049732948719065205234900025147050216480775931691209693009856949654955944471263615211623003442072374457069595919699233,241918233622395884761827246850514897219165802162342296635123580790888932192977763833922926853355444881644755349323889380463316458550630788255600843973415342916444918642659362862569058232566277775534472941540495721557558697754452057639207696448965752690070221361062821443638513586031328286832012283835743514220
10018933732727277902205269315771289076593947560040587959114941078087116999373425488340685401505876624281584630582917353725134238041079746342415896279966203184863826892445916822683268888700587092452305745538315423010290563725863170080340035065039975298577793326244665530455537053974727163555479979119191279926,-2305656050929911594001774361902538333750937712118410383814661797948886130836022054225957304174319742645328482100663492843669952358370802861270894168816436326458990297136526459920949376942432261379981780315229778535749028029896216855337892147060100885167806805043764484945583720350824386167496969085180728505,426903073734578001112620417146509321508736309565051582451873814142074420259405364041324675206078055851221135785335125834745297538613608978468731354815366776968439807098716134814276564770795992539739869501301828055278204465499226602180360134210119244471648153940999928351968352054963731820177407885865927236658|10018933732727277902205269315771289076593947560040587959114941078087116999373425488340685401505876624281584630582917353725134238041079746342415896279966203184863826892445916822683268888700587092452305745538315423010290563725863170080340035065039975298577793326244665530455537053974727163555479979119191279926,-2305656050929911594001774361902538333750937712118410383814661797948886130836022054225957304174319742645328482100663492843669952358370802861270894168816436326458990297136526459920949376942432261379981780315229778535749028029896216855337892147060100885167806805043764484945583720350824386167496969085180728505,426903073734578001112620417146509321508736309565051582451873814142074420259405364041324675206078055851221135785335125834745297538613608978468731354815366776968439807098716134814276564770795992539739869501301828055278204465499226602180360134210119244471648153940999928351968352054963731820177407885865927236658|26579833924289520389972900117950394438805828628221899849785251193277262506904016180015838661767033925903809658684422106275456221210787145479887893793178117616282806012189342470201902133434844784106437109753666637085736679857929223320267986046560553880930252162405414807068330327382869655263308507921578124762,-12071122961357042682227388807856025622183781701383406123339407125622773263556987057807120839167314088703384163940961495607053608272112660158109007999608142815575559883680071225874610842202742230050716632165554413346974345932440553672309803223445371844345386485359912292135145947019769810450457220546043659979,162236250544606905260439724773080091403174351417582646687611423124289071438608418146998192800378143503443566522030518800544598083530735564341780541276153264296511032654040655556029284610154943880012602862804365596003928006715967740792065055405085248350810462900711904458160412653922105321414238780026013533451
10018948288270418016780081341685235002997245256040164792426543952818991311558791493453519174957285944783722833865026222848031081817691340856453828555107871396513690880005707344898646359417008593189440903277104626759357903337151059344508962185668959714673026792114793015152022487676173726198202553281736763192,-6995555163054430382942870868581755160069395592106884274460542261252343393118569480209218511916560630596078206970035597385154389463448089846021818488631352733935369530889081823095829009383638648970953617256944401187962256866752201837099775227177656065063350644379695273754386677388279021465213328634933930909,721042528909917874686430575245079781825221838112029624394686069315349560814178350680306853206143047638999149938695007663434153092166743090545673695580676514178586788701941454964134693721185647384090760708127649587795147765724504088383646300322664057264796405575462352962768416720670014119545119956267157763268|33152009177899700335521286237987596749114678289874326434440918518081126413178191723162867529955418655435996482622593235632019894996887430996202492483564865515014035645906573982414795827153656592748272697286574461771116159112804016039989028059075628750439940373451196506327787093378094310321443683918398305578,19078728942670828368834699251746230066071047051172922041653025393624623551743744386999716370764191631344442619983012078124921474009852416209669177199713374821106687471027572426997637428928400364743864020836844501941937756570061589022465875716319591910681201998018650317776190333584438330413688185262916051155,220283868712478416207788658621383280997894846941561822444891957123908778028879195278346553006033805168466857198910274082404942136780954015736899511278911633428569844883635491399257549871333616419819287122510218677255768780334985075712076521491595155945026941146633288297234150638278140903654693829381901681364|86660112777924566325641144753803400410997086305075442702977432289312131972915955256795072094482313726948480079751898750790544713440908592818334342498838917381523558133222779818572943010979268307136948067185583734409642160207725489813897991564467762533071090190022128208402492072833343072675416905847421692846,-52778887618554305290105838041380262564458801465646670949464065301477666757134518520029567230285725793439487930254994645696418125229532386083964770290005616954332222417663293453485136710527439679565903814537080125880293745499032607178356596254426977323351345945596998496291222195474053846483056964155485024969,91256009874012914314189895519654249139544913048606429213352879670217368386794747037392624823085153501261342847050224541672528576684432409807110715865396865727844957353872518329845940826549252426734698443465027159176074936925639415490497467627459134074448093109088470713684894800193345119623601342741289991431
10019019997781066559943515640881506642517558843222778169026234770851975313720579259773361086779089551884331113250530982852069738010518159622349375335824689350970737457654843734623714224913981064444982445158390435699719229301999181267314607899665318687660691355693147862987025822541914292231182646321427861873,-3157363997717363888291408594979293600171398541934051160356171159608233287859036491344319963143369936444410446129850053542356863751408144208404845266526711359417425663346085658910109244458752728340593138106611282955961606114280076234921423984338932045399865574815874428373668830300085650219459974701588901291,427660300107522994538791232761616142662131142234945666620460681757069587002421636449099874675218488912225359428713775902235016576565531397345002001166527254555699729200052739867740788272516457497859568251192144704431298212101856469342734690447583085607097591547685515622397916186942279884556709767139560196364|10019019997781066559943515640881506642517558843222778169026234770851975313720579259773361086779089551884331113250530982852069738010518159622349375335824689350970737457654843734623714224913981064444982445158390435699719229301999181267314607899665318687660691355693147862987025822541914292231182646321427861873,-3157363997717363888291408594979293600171398541934051160356171159608233287859036491344319963143369936444410446129850053542356863751408144208404845266526711359417425663346085658910109244458752728340593138106611282955961606114280076234921423984338932045399865574815874428373668830300085650219459974701588901291,427660300107522994538791232761616142662131142234945666620460681757069587002421636449099874675218488912225359428713775902235016576565531397345002001166527254555699729200052739867740788272516457497859568251192144704431298212101856469342734690447583085607097591547685515622397916186942279884556709767139560196364|21550716916645018398165650019236850766796511258117069952017796540701386085912310717417651598467640925140901250417026118119274327376121328459299004640348530767025071918784935281870705231282717494840395458987826494640924389129904911635742804398745940919397702998940021391844339448198369222701583556010313045812,17308540888407999086403450710891722292596558140904996642436794702554735336548386086410226733754785281982433279805336861038046891710619959255360830608311138886000204010857210058502793117398659272632248311839231357476736302883731390652600445524351263663967663494261178750828036606884450644013387538641171794195,202180803355870010447215408817189049345827932931561109501494466474799106708426285256026437292412097802628616665602361337631758401467452446995726703770591794057694222974232570992815439680545736890553211079290478720762205284250715176457370298196341449115424087895906723941555883338741498383975320110297668277534
10019269520234431826137367355034420920528860342846780753959912064827599010243316724633755419135436935645907443407020572618899291215095816080730065338555965834485853320180090560809076866724238012634325051855947616588404872824038021038592555404461140712393653058441964129349148722979422040489509372096847725674,4522869991076735362499160116541059903683984737748984347542239263701333187108105456062644949444149453629982469461841568384073346981390834850295332934943879978241839313265925834724485912067878288054867100877621399054735204930899125650232136163964080568519169554901660276496750207252542508193487574803619459009,749663683253588383775532442379228650764046549728574777396900821733935114135159669567652069917832665405176945410288020981482404785970875873582684426212358839598234585501899432885966938532819200647768194074040482435441119436072379143147234400064595949108182133121869311200924895068707591158185629325001898213097|10019269520234431826137367355034420920528860342846780753959912064827599010243316724633755419135436935645907443407020572618899291215095816080730065338555965834485853320180090560809076866724238012634325051855947616588404872824038021038592555404461140712393653058441964129349148722979422040489509372096847725674,4522869991076735362499160116541059903683984737748984347542239263701333187108105456062644949444149453629982469461841568384073346981390834850295332934943879978241839313265925834724485912067878288054867100877621399054735204930899125650232136163964080568519169554901660276496750207252542508193487574803619459009,749663683253588383775532442379228650764046549728574777396900821733935114135159669567652069917832665405176945410288020981482404785970875873582684426212358839598234585501899432885966938532819200647768194074040482435441119436072379143147234400064595949108182133121869311200924895068707591158185629325001898213097|16642018863761441710765797012067927359722077189969631448415362616699814913503672898852374525215334055299068298216385689523710707393718883505223743676435071846547044089283998146628167129062401919282532587286538467437993909697773987546172287165832896898434018866746267084068433592983100742343012553891013967598,4279618085412193426188644638927864595084294097891450444438077735383453062127268915528450003127312343513730070105859170701493137563013978799842440344152818674511355384686181809257130294212609318791976849425989687196701708107582124757707100916931554678238461537620568164241235565012338998887375426548345583339,451300244762011954040540232948856842185637826616664360199909803894796107535366932948228367749161671550552967885565839529658452718412544695138612399812114901538129955756634712380719016039028157710981132001101643596366369267735875381875175432502771795477425963992931644164806539340880034536557519705047322385756
10019417926514296392019946929112818021632198703101505458649653394849455829204203329294836960034957633501294764450648155864378373289178486051989714219614702737597295310475376780688730971937576079121199314793519307265245938553456529418922522984552293638273911817508398110317305685502955048568809327523071451646,7901274255200127696618788587659559342110188499337362982289909048078505324309251529636836412429419509644512565320215289593933580545899621400755280134055539493035902983697255734323738954580031486643652880504218537900293807494750583881428021909372888539470375818772560108989429450107579283565673329101511361623,623699550931583586227312516211712634135558043787600676758608115259112248746313728815655527067581286781548781459656217474418345498402764321216306327583412055637930534007526887412883845579485648951016708462255973917762702757210736584322682381497339273737323760137458761222143566171226992185720766268284746949539|33994172292722720621983078916917152805135157553786453695681859425113486805780487896660717595372501233092400041645960826591356846046682770081212496668808601116475820169782887756136359474132767453083956483565660497074117273547864843066209384954581834231890370515327604527171929343867967182910635357940103381259,31993846672125961531384598386820046988679306439927918439126442104342750287165534338581303476671621941233213276321267207968356271919850887377330275696357098758109012385572207725576199219446164534402970313646005215676387512077572153065651471880735849343888575800500099273015977254516159942552263434250458169021,190897440537416564844354648094133803032782149306929915760090455032909782181885170078703110757010607891226613247221902350507051587112666985339761578838390574506735798985627221778883031220656445342689661417080864579978266745285225101384742969161503945655665695989381533846227380883303389726073267640913232240808|46223752318790909370837447383363380695209474743451082994109239582734730617406604327737568722130199854939421799114849872972877989567189718205858628003551407137904188277330292052370440786619825504842930785565096667031645779355485895793277208105594179243179236367866554346063343397949912203277267219196168228342,-11006265064354212636439188801633654461277681721343546696389358983928696946083632218719947786058303199938972841132237674419697191902116627029793522898887023505508883048022803011324802659223889838681052775013756116093960676539648227562055647315361638076266948642978861465645013053193461759019970585499519918551,135510058813836316466595636693848570774859961098724584660465530747418644245153590246150906297996570248784693174475582519076799984652691145697384165112598092893383581702308752699625740019767305915611482144859189733431647333812818245189583002227073705672065057825892795634209388635037930002295896526893410999911
10019602901864092738325953873535047812547299524695025320532290515768840900630595544396879008556083370139972255849271116199083634435552540915196064651229780380925328336224573551564497154428220750159228126503023660786371036661986963326869101885946108118123565859605937169197265825780593487194236118858010532600,385562394428775749047853575173957314087625602564743010180946094529317438985024787344743900106472493168796231871305499111699051361035813309229378162588371556942740300961721890004066420192802443990741112403096930009444198021764517249355582327168404565052575639878289683556483174213973783173191751884045426337,783418388779217407199495491198572563161785093246466615634830075323053502538909242522004194931674520522772536562755280126097220160459899598091584353065112800205031495803329979380114748688327366649214078234380064643848371559165846159884696566323937944146599304471519733682046929885711023157291005000370881207583|10019602901864092738325953873535047812547299524695025320532290515768840900630595544396879008556083370139972255849271116199083634435552540915196064651229780380925328336224573551564497154428220750159228126503023660786371036661986963326869101885946108118123565859605937169197265825780593487194236118858010532600,385562394428775749047853575173957314087625602564743010180946094529317438985024787344743900106472493168796231871305499111699051361035813309229378162588371556942740300961721890004066420192802443990741112403096930009444198021764517249355582327168404565052575639878289683556483174213973783173191751884045426337,783418388779217407199495491198572563161785093246466615634830075323053502538909242522004194931674520522772536562755280126097220160459899598091584353065112800205031495803329979380114748688327366649214078234380064643848371559165846159884696566323937944146599304471519733682046929885711023157291005000370881207583|19818230550133203045823734101898906263121512206428289485014719092970295967340599816897147977749512129070950063889339566610951920388554330328298156066258170373411927366975503222525343688945315211747565841144619516815319867733346621311891854079913905473945585105165350274151561111090081792706060108559348689465,3535705381589141871228391312322719660822687473426523492896512078425893509048104602680687792493669387659393458499063851065894084002514574997947346565631807028562721897282782831306960899838643543821499923380013426924166037069379808013932912663720597103553887305082262913905822119893857258661880909162082386383,396232614221934638032209379440961132627800399045535096109310461742382984824006540071415151913091585171033970335144034008200593280126662125846778006926029922409396791751216059456912978293211117174561768028351334637727875808828406496707486419218523437819900629926847694284488804630237181598046520852448325184912
10019618759445604574695938593576587154046024907827143734869384751181580594765954554297229655147503034078881467428687208204647162639839815171638500727552711523715462319701731893862102462479728615304020826611064530542284194703939928285119162487825469366941939907341692107287635698074740058272417655173119766470,-1495231899271916161022455577964100860902948284811380648472435397705462086200159484323324090415310461943736883556854457678257712744145878200402349694425772714427495950140611274533744925805188738644517051127445631541048041016411029423836592778690668280454275321001430386581000830461603779827661500573849313313,783469223238034771138196543049546952638608016561545783572815717469547125551690528706587314602219345674223915943792376346892343135362218779360461138111067908088830730205053230437782849794424701715846764766896886615248793041482000930114725702333293352788421520623938402925312326001614873502389289399996101695820|10019618759445604574695938593576587154046024907827143734869384751181580594765954554297229655147503034078881467428687208204647162639839815171638500727552711523715462319701731893862102462479728615304020826611064530542284194703939928285119162487825469366941939907341692107287635698074740058272417655173119766470,-1495231899271916161022455577964100860902948284811380648472435397705462086200159484323324090415310461943736883556854457678257712744145878200402349694425772714427495950140611274533744925805188738644517051127445631541048041016411029423836592778690668280454275321001430386581000830461603779827661500573849313313,783469223238034771138196543049546952638608016561545783572815717469547125551690528706587314602219345674223915943792376346892343135362218779360461138111067908088830730205053230437782849794424701715846764766896886615248793041482000930114725702333293352788421520623938402925312326001614873502389289399996101695820|42753617832955580018896456376048021312038672906196490293353833260191208069121641097415768067383199309083970209480148720670849061245193936234205337011636997701073642429299438906449136644520319530218401933372485811940869805081506160718825508067884253210821932270118450554609943933258707984251287707298966456434,17230882403850817862353558174953648187864024855604030801497255731670352761964080837026196910757872387822284474688098560486179344653906733048259368377140267627812727873134204479739477928295254560644024291521347574950750033700697110313592478883239065168888362080121017118321399563553912315660492325767550439625,185334720796235401233770375301583579692277465177160979515315309579304038663377302594175210667527463523713902806451243556694869849316694559583762178930255061453115298736511664428765337617081386042405590606496094216885684005811351670599975552269701611841562351169528636440894665534868320186990351387365005093446
10019692946699738437088786776088494849594837049086417807717694310404351446172508582779767667693745900344488207593378322991177040183985344860702086830308533532509706853397521152883298228273128452797173239342923997882671035778655648164732292144430552486960912845252279998708953177942214236682313539500552760871,2604527605619485478722364121534608303298155156200794123073555280322873845863667712157493176540131822726294136122515227024701303496679207443255980148330176850776277321446427192954383305967741429509598325549628410919591073607402118557146971439755257250099080900555940132394424289156437827280461319685081840835,500718425039020767061203454192505123268716467124573838196978962956303476515938135055207132642966201859533626566887497521633145487747565092871485790754737106452537951081291971352805654412531250563576927867442028177911508524615458471957056998884949042800057393476930961808638050281181278355398049850987480026266|10019692946699738437088786776088494849594837049086417807717694310404351446172508582779767667693745900344488207593378322991177040183985344860702086830308533532509706853397521152883298228273128452797173239342923997882671035778655648164732292144430552486960912845252279998708953177942214236682313539500552760871,2604527605619485478722364121534608303298155156200794123073555280322873845863667712157493176540131822726294136122515227024701303496679207443255980148330176850776277321446427192954383305967741429509598325549628410919591073607402118557146971439755257250099080900555940132394424289156437827280461319685081840835,500718425039020767061203454192505123268716467124573838196978962956303476515938135055207132642966201859533626566887497521633145487747565092871485790754737106452537951081291971352805654412531250563576927867442028177911508524615458471957056998884949042800057393476930961808638050281181278355398049850987480026266|15699856336284744968275216258343503146645953756650748657692246165468174044843605062520381697859516745152728271221936503804746010309726370554190521588468426695997279591480421106636754720909204606127286384900034321176510676319624471022876412905986167145718126102692531020933251202001854123564019876070185880355,-14062166839366990397106911248374270143217677864591057546982352524148999437729801685798965579843060529335708158623771293637111706433187114619631528674568287241750380206758693785598159577574034470606603276333153981703961125634290277406642003061722480822932526131741380714977106447263763374124622526844984498859,322600729981396869806359195462894217882445977495880795669692121484810837171658548584546952485525802042033579797467228310295552846960328437752401071423653349872764602844139832402563063433112043761099494603274082871711473366936549010464198833941650861319850342621348528624209403813616631484437129382551268946870
10019878828465334585310006306241539349820320632176313877609501227637096062920082798688866463474161563221707726590576927421178038553651876427988000587231398238649949818114022781306536860520405792494648694702226319794624629000713829609168795402418848754413215058377284034953425744232395623600320736707606263601,1457969396702138085449463993396644727452880810876852537963663018612951369129008613129868381569339225995112076334917995066335564006261425730889703965704362733694154907573251182502287488642500690958462811412545500622611307129116327910472660655763332350656262023349742750811995788737019311563028749123005882623,450291340913970001914821927902049497930656487941189505155449421740207064831253795807819514379798428822187833726946052293837627776646264129023306160855543475421211570474321370516290659041655321190880413623652464931091503946846331738732993987858421621514193715128900207229532916132573315382608752305324170212688|10019878828465334585310006306241539349820320632176313877609501227637096062920082798688866463474161563221707726590576927421178038553651876427988000587231398238649949818114022781306536860520405792494648694702226319794624629000713829609168795402418848754413215058377284034953425744232395623600320736707606263601,1457969396702138085449463993396644727452880810876852537963663018612951369129008613129868381569339225995112076334917995066335564006261425730889703965704362733694154907573251182502287488642500690958462811412545500622611307129116327910472660655763332350656262023349742750811995788737019311563028749123005882623,450291340913970001914821927902049497930656487941189505155449421740207064831253795807819514379798428822187833726946052293837627776646264129023306160855543475421211570474321370516290659041655321190880413623652464931091503946846331738732993987858421621514193715128900207229532916132573315382608752305324170212688|42833037907205783423276083695584027308854900022881436412191284154327219859963073830726581978719142468079055995456299937273491938799745755641832339881754413481117724798837471944396287268574687471412696368395253559323362777618554120629431245413190434891698142985970974309630607227057049486649455303551234276454,39533289765204979838239940217464189791925681811448897199438008522556423440885704979337332145873978223602711609006720684578384015360399795422483770905500296209984111909778890881255526888804755991926913525266473446809003766056812782710240729514579954010888129016691348159521572577875112811888010834450317724241,114445618247053384708154338158850812121782306445016732813783780022720172489813267526238634887903604880900808775058943405768328545540868455633901730958967680579278364092793074061036266572372464072327099841482886966487871555516444733955521438600902217517451457471166242011115873608622049499975622745683155293044
10020286611438471830628019358455663881253310586699113562825236385112929540691864656311239753327727457544039348532845219250052901384983806849838772233628634015372101882756673893804993295286755978494686187836862364142553996432815511321224683238615875757382081170105089085250727802357622063598298344850144933258,-3518711690583590719591097309663537838033234040270517781284035777894691716513958367977437977244707408588621580445912322309023058291956527967904833369032334021917801602130557563969030363343390282689269679494383594614447232630864097161162053988664606910387710340058810601198928739842230703566256279504206597349,624519074467883157241759882142650482668439956786299222741478860768930417779553600133573019763129305374619657419598952403430928431333332942138935285782814167747294995855160857963617057240775629113016734743963566849367848417555290458534979590030936513460373735155075741191499370817771701007396549636851814063246|8984140046463484249883815882793946664284637844291004682379330614023973939307670161213321888699915249072065095665013984357459013131040423611078930602512682262356539184355252741789076484547599307370908468303880417320438645852556648240043112769759543510509999231273948875843246292758661134579579434257790056943,1015829211229239775971450394627474475125445320143707214965330038892897841144751214160653701706601947354240523693277132829250608515076685164228306669891554248890083979225036216154539270241518786129131737028646904986272214000689553330402618431223976598945398343370629254397826639390022921851207744783430299181,696229436805911789845333715373446839368886781044433762113742356470360747294068486152977041956647781976745992022313448046591023280602965461797453603661925762491060402477228052040796508933029960965488494546655270327536485285614615574903948243360057525231142937895796209410153481097105649076038536726330776071856|54848884991217637960566999744777250759299676195564728508167267655054271555707478739692179275489551583228746099712696785024768087317010330909987410610335755940330039266190842809649304513680352828151859917245186776225281746820196246056188053726348717015680880973426980177317094806038726097322528009147634772745,-6297694570572926762876118238570574530971092334512760425031884066392157325338148271545111848669911902764684562706179269339278979620083804367858431071965438609706945865206821584390347519912299967269039438763099113180095159546022212222371772149775642184659607016581991317838734844206339663600961049231899483767,114217089877346912860627247021964232304547591103532855496244374445579581677534108677722729277710412822218846458954885849274521645333106817369257230151814552428619784818123898009869914417388072106361002314975966932911313776975771180600386738223895005689517440276702703392932181245821359844597699717902940161882
10020350829980446730171851653876883566847163081423697114380946239282341122006641305758856122547334357120649922140862854047676100901410759420113771337592330434048703781028710403003719890979006119445870636592350392949743016116360518402562929646175152381835283065319457849053035555929737557936105886116269575510,5109280702416633154295665717802160083976280911440360164357040723966034505263983198614731009455276771449649216657900445462253241694441028125347117381803166387820276260518904247537793302370100297043111469835733504997940289628818493126591029673530532890213508380205622484398576652164337711722991311438354895077,783009249844890893386725492620727464553802137797080547324163831661264002221403011235072342035014102836039015675936188668078646910670188403603171656900915122608838040537846311585633442130109085368959065613240580402159306705278726186443869273434480098383561830991110484097132938532579731404550435571781667457120|10020350829980446730171851653876883566847163081423697114380946239282341122006641305758856122547334357120649922140862854047676100901410759420113771337592330434048703781028710403003719890979006119445870636592350392949743016116360518402562929646175152381835283065319457849053035555929737557936105886116269575510,5109280702416633154295665717802160083976280911440360164357040723966034505263983198614731009455276771449649216657900445462253241694441028125347117381803166387820276260518904247537793302370100297043111469835733504997940289628818493126591029673530532890213508380205622484398576652164337711722991311438354895077,783009249844890893386725492620727464553802137797080547324163831661264002221403011235072342035014102836039015675936188668078646910670188403603171656900915122608838040537846311585633442130109085368959065613240580402159306705278726186443869273434480098383561830991110484097132938532579731404550435571781667457120|15925442580907323476159397125803944340654208405155024852617286343514956884706735535756801413937274485810029110697926230088903038708172843921662902925858010133310107241826173293821650453674715296467364194160263065021258375363251922427504055324499581378214158250201451314577475359578763255572268099357250433862,-7555018813268449946347299883155637510823174468910058845458344328340586029132905296413170968626375161086356436888766911933184468019856845539645923943455062521960029199818385839225962202237763532700191551972267033706448220551883282613693004882011515763441495954827960366711246754821589418038272565907011571371,493158713590448502858812148491777446425856175908645102112390069549258575786631074217529579034304661646702428496672314797453719364387931287920597953147023776521758543809562386644010437874871311725548645377471116791426470171042917330992088151061235643311858502168972419940204783448967903363982044887911681560644
10020520888850607221318889209733010855356370939979030352174416847268871176606842611908448929226351061331244222832181615393476121893202716429497688626737367070357875341852767661277331348237224754401428337725087948250057680576003972340744936007808116625981445480427395587481367415686693519322831225744083857506,-3510865184553106032575534381192821350315875177100225193260562098432442799313338094676188269972656054940854032321449718355451351690660219631429988981801589127116014570347706272895437608443770068021130141264825492984427313262655182236186480543751195475768423487011396127341338009641051881511727659162848161119,631736658355910953992723930048397079196586052511742763210137641692860240361410089621711682505909275894759266095700988382555714505394268624248297891868203056209475282038131157087467910727013960998888913755441699771876897234334835639550616100989309716008969633105517000398222168491114030388197708472040972683126|10020520888850607221318889209733010855356370939979030352174416847268871176606842611908448929226351061331244222832181615393476121893202716429497688626737367070357875341852767661277331348237224754401428337725087948250057680576003972340744936007808116625981445480427395587481367415686693519322831225744083857506,-3510865184553106032575534381192821350315875177100225193260562098432442799313338094676188269972656054940854032321449718355451351690660219631429988981801589127116014570347706272895437608443770068021130141264825492984427313262655182236186480543751195475768423487011396127341338009641051881511727659162848161119,631736658355910953992723930048397079196586052511742763210137641692860240361410089621711682505909275894759266095700988382555714505394268624248297891868203056209475282038131157087467910727013960998888913755441699771876897234334835639550616100989309716008969633105517000398222168491114030388197708472040972683126|7743624975856046040306859618381122855435839505066655963077953345318192394961725484815279361678840380508650449544352702656790861663924047145774380332205220566837995316217250717822771650639012193352578327705393209628172084550305955102732361657948117240351750958876943333563882332223706621973470079325216233558,-1302101084353535785220069078550654080595332453473298993211431176604229397211571627224468015823760998656644913758576425096529602829962318111227560243799515644278666734720045652589883053894188670485823003998604116205699634345292108055002592831517880997584910995083278522924829895139882422136963697022188627761,817146068444645002282702401442161961453363715531517354922416373299365609662611633811411725714915989553805697260975442785287852917015804775140015044436435034561860932937633743951090004573111260937285724402644730836466114286731010063169028245934842509507242843981736397798548000353928823827450308171577842094862
10020928293252284825691361744328291985679526412406671670547266480511907045983316758483586023724996977667177961315263269397743828323222195866600241379821175298238115703011379072606569390759148045042025527825985903353933863183965714600189445609817913064133950477152949408914363876047922634974111379776851043444,8142743010559227647391965354039043610167208616578224783916189122845589179285287981476385252457789283574398377141778580365522603626148442954692842646237080732477747098895946414915542936790529750280288364463486949414374698119959104763454330750738981793594749326992763123032351693132354526673391669903228534689,592964939014299189950759948556152413778070028508201513223477782517837089792535061751235218815245724595945353108562584681842937744985593454797280372456160144528618905336752579099036263281502692258180148097231362749391384857475259373320991218168838336648271137666762974150421876463236269917491554488254970217679|1349884692028663713443418855258970852876197688505766806916101525225125648882224033090914393786384981404185367136201476426040087000294669320520442557740324611111940178669433599306350594555401574017007121415045406126185440950248044705540071793090107212207268142684391021538262661004297297377597036659211434174,875208077680684118200876261868445011629698306468238985964846580756586701312125036248886125282325554453814339944800057599270619114144498434513170361313175501368378946075602194132049645256086611958223310749365652107262190169934699379958455541016773996539749758645125590779000274985163557422936755735709025447,4389763511378485954501282191747251660999265924712682485695638493214865378547677386856476228802410653501422368180730844272453992845175409659922990510986478738442978379229425566565975718386747664393902959866984083918397026705604419570614664652992630348606149487368881973666571039701786237266865588917768672714852|5132295574467316848841777686734617679960174295612803556136691640948831222631657128041983413228627956037030789543068853182770008751639881188344733284990628383483491534738190385257771536358960825091917844011611151709882253457446948086421180899165481250089224998180312937340245384853080966454437114981749282088,4739229759958591334649295599424854432655955954287517912213597569502250150023192426249576133181257597090869245470242256174272934097508617180274802785425851556700817333154643929185825330049486269453049410315760063060060300773867433992976428473895933388104059320286367359084036012644394853593574323294698599047,1155642354763640840161317866632512711606463189115904666846240158382151567767869875575965412366883980252176109447698054839109820546539837615968386168917753356894372414795267678454138557008897676758489406076799290056896394919016510966326013771652656266881913835619564662608220574395369543699406086980500479286021
1002117978472811787753331928095730917976095264113100009019616793747721435107135088389509812754479746771762680547024275550906766428627777497396364614972130274470274918515966945652987824482224985008334448385591915791378703701911471719689908547324909949135740705163689874051360252727792128439306172396510982072,-605384264858430906616142488992272359132356724983679496986875094989266808748892270936577381465129550495430948251840196888998891525556778784313001078991820767039598015715393254809115469379426480017252950332375890914475777381882010670869152139638115965300974540658001803028482400664131564914546111105190254697,5913050976191825085156815974405378266929897129377882420061135471366299940142986781640170880340909029950997987433372868814199338484242838439841578708925504283923079897355159590243914836924282498902916652661483948536914918309139164893684671128828548900808846820323860573206533041501286493089345814823705125482184|1002117978472811787753331928095730917976095264113100009019616793747721435107135088389509812754479746771762680547024275550906766428627777497396364614972130274470274918515966945652987824482224985008334448385591915791378703701911471719689908547324909949135740705163689874051360252727792128439306172396510982072,-605384264858430906616142488992272359132356724983679496986875094989266808748892270936577381465129550495430948251840196888998891525556778784313001078991820767039598015715393254809115469379426480017252950332375890914475777381882010670869152139638115965300974540658001803028482400664131564914546111105190254697,5913050976191825085156815974405378266929897129377882420061135471366299940142986781640170880340909029950997987433372868814199338484242838439841578708925504283923079897355159590243914836924282498902916652661483948536914918309139164893684671128828548900808846820323860573206533041501286493089345814823705125482184|40380288636863554747802272146363479186663329648459490067115808757434033306882038739884681373117979723495792330864501446629245889731229516933727403492773771957483850679041758865017396807842498482944854723605982182982516939476048881995525535805104281408686338183559590430185038164235953706463250800021094604474,-39534865948835591455192703514729394748021266253728249692602243000799548352268225360374954844443730084878434721021241498114475458481167089270721522242274850596448738616202710373135498775106936938952151771547223007405550740805387552512761050820125134092471485389585963771433812018574391368483598373549383847189,156418754990595886837540510636676538980249340054775526675231187766083040611703861850669234853631535367187296945071108522620946681763860321505477715553908841995650918300850635601347255855518666703848642329714582982193362014895765955759528160104377932684150225067984397783920984799879483126817672124425872829049
10021358599463053436428121851639014288861925656265693598359693460594603335959883569550641125363212428397536880700859686977743945025535807563785786052244914761332363029072620567677261483868230251440566526595521949067385197316983806258145013751454322468391099167319094251906044804264200412596430324237392628100,709083183297048652772820333122772466256400885278203522245823989743215866042577745109340161132152908476855845193022669210873284198994493560336775521366659865852432460708969754436068709338598181470025481044065851120985245468046464349075382208377683917405549429133970439515821299430661611942330536123845644949,516570730285299534762323653103362077033679349887441156383985263227144702832028548168588332437855509742797208817471793880841971810641558363411834198813856099949994799818753787070184420373328485385171466383296907894871575302325766835865200237080249407408770698788688709844525521993129914019403957225364497263784|10021358599463053436428121851639014288861925656265693598359693460594603335959883569550641125363212428397536880700859686977743945025535807563785786052244914761332363029072620567677261483868230251440566526595521949067385197316983806258145013751454322468391099167319094251906044804264200412596430324237392628100,709083183297048652772820333122772466256400885278203522245823989743215866042577745109340161132152908476855845193022669210873284198994493560336775521366659865852432460708969754436068709338598181470025481044065851120985245468046464349075382208377683917405549429133970439515821299430661611942330536123845644949,516570730285299534762323653103362077033679349887441156383985263227144702832028548168588332437855509742797208817471793880841971810641558363411834198813856099949994799818753787070184420373328485385171466383296907894871575302325766835865200237080249407408770698788688709844525521993129914019403957225364497263784|45614503146354773723748422556503247371485318543120586857419562717702458851951901017328552145694380945314803604713256441070275022414069445773768101699000362770774983002903055045789385932735047082208988353464300453066243128392263161058473354625441431303590972274514200470903553097396578608004283743393727480965,-18121746874119905746733087661833019801123133290011543785996868679743860577167772600952885673213204134707814090152450287251108460725457761668330446170883400606809709199165941064933022535458655256850936026007055165113021346772772048647561510274730081303287537167422875133875982474754404203878182518086566378039,115286014209231820841785285504789236723202458419099047051127275140595097884705397561562945865060894329450657461353202401141562369532605474636151114816630008035888537731586842019104642780200033707263419710825605300157241899226642312799356394901240315456385563221341513078098381767868711376025198760539717198382
10021467180917602737976485607440169246689782775819592060097133723376896163041617997117690261968456452635527584517534178504548298348503697184587408892932776130526709512085862666360259215825375712520283335147827351975626062358619071671249870717811464295853663335144999169566479738875598518880232950110692415860,5837741371138928752178739797917364838658798118140089345232324713852930065920933839519905580179654383108038638880741427980662680469791777270068068248248823295528533080598248956003543247574941878960563240116001302598572351690506654603050328390643642345907246472180377442808566360199364409627306574545050404961,447367712945794368035040617182455309390859836657260473211881159345841479208328013611245196832742331205848397804369783648021077720443154207595416670723327933025826385393654289188255079761853719682847837385185400997339750661153486494578411301935184740783631461198583032914565210707960404049019611688784713553950|10021467180917602737976485607440169246689782775819592060097133723376896163041617997117690261968456452635527584517534178504548298348503697184587408892932776130526709512085862666360259215825375712520283335147827351975626062358619071671249870717811464295853663335144999169566479738875598518880232950110692415860,5837741371138928752178739797917364838658798118140089345232324713852930065920933839519905580179654383108038638880741427980662680469791777270068068248248823295528533080598248956003543247574941878960563240116001302598572351690506654603050328390643642345907246472180377442808566360199364409627306574545050404961,447367712945794368035040617182455309390859836657260473211881159345841479208328013611245196832742331205848397804369783648021077720443154207595416670723327933025826385393654289188255079761853719682847837385185400997339750661153486494578411301935184740783631461198583032914565210707960404049019611688784713553950|37349917633767587717677900017226055640277491797128368066909216648299856708848885314856667952257677125356703617528489552040640666031343260644627231518748509259039268948250724796991429094425535890736981916444739110193691988414365116633947866879178749608358114634543684726462828729304210028284694641568628398966,28432301470760114127472799211494908630719349909135890789013779669649467182102043473145513283547284407986093529470668063517370252190889483927419539271833812410008532555047333957640590516339384293520187649830718680466604203963675273404448810489933228206090139475240540056839557201036234130668781355507913201183,125217411042216743409615853418748212447815557938720716586287232669270939052168073429461670911284540249994159813915524580152040717865022372477773851596046555005754956888615646701914356508633194785367798807957000924761874706728044310360895862676117058335122487191434401996751617050877596333038588838996255145412
10021498468260956088123000232540981309673362233093607160766199611849988598018670545801586655713528191099718167654049219862424879654097800612715754405882205966256512537388088543329708772570689386840584832681600027519346949153293344313097460804932850840053785736778266237521116511372386612740914586110495537184,3731424607272136278046418371062826309603938690430502989163037797814883875895107208656392082954628965555189423854897982564780098075475012739517997385664143357277834178448678167762594236943371764347482562787414335427396456552673654489280935057856453787409277651050808844230948476551514072021069206021678774679,804130312590685641878596579775606667166276173286759021130255643061750446804433775305738231667374247846782607238734204509216228540137516790899866440807044660490591982953819190288555363659024778526537985822773652575997791262130221988665167762257066646395773224522658242462757313827560884465576118125526400301268|34167053368438934062493883132954265990697806318308586148616977663701145830016368570117108522767165162437388551633476818714638781998737588453423052906955047313659481428825017492981415212399429876112133486106544289854247118707826610748061980313138870978861241099932331052851628733408772936072321439631381625681,-3231990625187035132148669134941674343311291560670575472626948487039873506375201953961203524971750773872175368844083313789606744945666601496978495543448223413432959722175027775640416642119534579082078058359377011061266769493053544073177090778768228650034186796092538667273516567672252447273843436045477135595,235833074847574898390813679013790646015645150909185733872405459206523708909325302363230937825102097363178252008781874033668789787718772243559737247157023625992313606650868510119173526138833975525463395139358451436580786324137262685697090102400693677208248369147898653293586089386800659102730021728025849255818|64608837982278224108987963939830921137767130655870201859314566649037112194604993755919994541029928783963356571015929786284493006279718103094473109088356869444636451105877134516067500703977445578997872357043341015093673550983708510265625469154579844276561631683451922580837098594165662625287526508058436293986,15854906341458894966500422391448052536768193946037447623218750633953720338742777805649471066920966160101792990529839212517155533383911249825767111242302747793376405376781322851763232537121183798411448041082168628199040455135693063512226758138709898399548068871039436946823094929235771529576088321067557016361,125647737690478667744295859750549841902875194170056775019306475803353424716724181236654109541003077830795994847519888612974479612555855274394676374638319448048091194349835875247946393849792063872096400150096455332718354245732182310596592154379165437563189009506346555534189191250868232374253149843604451203312
100215518435515616798081693150831119413586767021678884124518533924984792516593586077070489902053827517598088670562746849336597165534172718871853401767137095032008213339529086616777467841346280017019578258259797551450310087222690828893461467525694138266456717327225955476876417507053206969995585955166268406129,95057958551667401403353090513192344071592935246219146691681088413017107538601166978955721880254187942559271242509539286042857509266018196345088028113071042234423096387755035509877692642793106294014825987119124937967036662120185797721977723389759564327297787909379686186622926363357951464215904895677999421567,102919326722329333489116060760618421823222867295966177344707558731080005177983472593218329502964236109795974387237881276225611846575332218440299281932674994159773703889896299379022277106535867836949285795306043775879545666098740309487810106763993748938964994198360229518682147400433454886610366004026941047356|100215518435515616798081693150831119413586767021678884124518533924984792516593586077070489902053827517598088670562746849336597165534172718871853401767137095032008213339529086616777467841346280017019578258259797551450310087222690828893461467525694138266456717327225955476876417507053206969995585955166268406129,95057958551667401403353090513192344071592935246219146691681088413017107538601166978955721880254187942559271242509539286042857509266018196345088028113071042234423096387755035509877692642793106294014825987119124937967036662120185797721977723389759564327297787909379686186622926363357951464215904895677999421567,102919326722329333489116060760618421823222867295966177344707558731080005177983472593218329502964236109795974387237881276225611846575332218440299281932674994159773703889896299379022277106535867836949285795306043775879545666098740309487810106763993748938964994198360229518682147400433454886610366004026941047356|97265337163108204413956364816446311461172514617683583383746668715450840222180976393430496104553022674333721978573099848181220662887846947468935453182046364733749916475895309307017567642434296055225121834950440706059303257140878621147190170027097598386070490643511792242136161870345758898813890460055238965518,87547457109798873839305649757452333043926932497015596041815056726077989206997009131840148396020804211298638181409067017194388111483773222118240882283209994405160200490126585806391098433830826470475358556954973925001096433563812177048160467037091694157852152308504545492956027258260588167152638099756708452923,102515957029857878751803789736896993327202543313952394340885451428025600212535749454672085478483321275958139112689603772374702592116757008616636478536965453679964666255956305064090090239129654015924433954512354305722977754010864408774189090428174122344384620043576093595618564991259055360564491303523423085863
100215518435515616798081693150831119413586767021678884124518533924984792516593586077070489902053827517598088670562746849336597165534172718871853401767137095032008213339529086616777467841346280017019578258259797551450310087222690828893461467525694138266456717327225955476876417507053206969995585955166268406129,95057958551667401403353090513192344071592935246219146691681088413017107538601166978955721880254187942559271242509539286042857509266018196345088028113071042234423096387755035509877692642793106294014825987119124937967036662120185797721977723389759564327297787909379686186622926363357951464215904895677999421567,102919326722329333489116060760618421823222867295966177344707558731080005177983472593218329502964236109795974387237881276225611846575332218440299281932674994159773703889896299379022277106535867836949285795306043775879545666098740309487810106763993748938964994198360229518682147400433454886610366004026941047356|97265337163108204413956364816446311461172514617683583383746668715450840222180976393430496104553022674333721978573099848181220662887846947468935453182046364733749916475895309307017567642434296055225121834950440706059303257140878621147190170027097598386070490643511792242136161870345758898813890460055238965518,87547457109798873839305649757452333043926932497015596041815056726077989206997009131840148396020804211298638181409067017194388111483773222118240882283209994405160200490126585806391098433830826470475358556954973925001096433563812177048160467037091694157852152308504545492956027258260588167152638099756708452923,102515957029857878751803789736896993327202543313952394340885451428025600212535749454672085478483321275958139112689603772374702592116757008616636478536965453679964666255956305064090090239129654015924433954512354305722977754010864408774189090428174122344384620043576093595618564991259055360564491303523423085863|36966589133632021596451231446360613869218644305972974964188922476722370035917724082641341991636532809500406571267262673636673259154835535079572834230006192461227395506315158937114124659074990425552664025796331234355303904150803244972310400202941266552149385712614489884410598364289566113507512621328083820598,-21149549205459986335385704446469107610959268704221609170214996514478740430167085550085863459876947711137447213809502018277525104101042350103376631096271919925064995296178696672186362840988476041323653097243744018198278462448741240768165379772727430920245528842325914682295445854217287403981994755438946746143,220927487842748418739085114242513506611909793723984315299233121420377274197319470229298268289856409101985756388437199198962449705412131211265923072982106236351953282676471404053070507026981693842676184502073850443982862759823135849927410711140706664324113248738142786497634534093355523248932828221913746822818
1002171279912987474674729832690970557140429555644292059472271841324924331291685060249454596336585889404705002700240738701699260928512934819245660001207610075089195766056310376194900771895925996113770666776022108500330653518924376342638824072832759321658474598385675431858595122771183526939999696158578609708,826219028959713490046361889088584439498783654783530925153550597879152616132729000468702177706363955325292708928091882754198698376648310966516057873159349764829040425546512821864182430231493467696041840597321743210951783900165181749863389211006249005916285731575237461143803624956905795631847651371075603271,8037828098286918052259824988376802356784599160404526733485731117320394626772712632224126968007402853349764765913068975115077635719542022449549397610278043584259551667143554443745235133704301422592616247052815801996895563245349515275951060813799742580455732670079073038616591480535324416008144264918698168050014|1002171279912987474674729832690970557140429555644292059472271841324924331291685060249454596336585889404705002700240738701699260928512934819245660001207610075089195766056310376194900771895925996113770666776022108500330653518924376342638824072832759321658474598385675431858595122771183526939999696158578609708,826219028959713490046361889088584439498783654783530925153550597879152616132729000468702177706363955325292708928091882754198698376648310966516057873159349764829040425546512821864182430231493467696041840597321743210951783900165181749863389211006249005916285731575237461143803624956905795631847651371075603271,8037828098286918052259824988376802356784599160404526733485731117320394626772712632224126968007402853349764765913068975115077635719542022449549397610278043584259551667143554443745235133704301422592616247052815801996895563245349515275951060813799742580455732670079073038616591480535324416008144264918698168050014|56177784089692916832266345214421120674340798487038570515623153805048107174705903801913422904686022519185882309714950449353350144136176082122642988743155385846519789014579069658520240091050781441562176069717906258293112423657764692478227614483398005555460543943687308770699629754468588531994448652035243537193,-1367086938896255072793415069058299472671169571526909227192393757206171174220534221238412428332819898373711167739278653738196147736460040492805449727552702294473184951105379473908985544436596593693459127262500591594358945429165046595165680187593280155590732587752336804926254680443537232304173256876819864345,143394353759539327949427865403227850259090677769631111628953936665415814894670562885615312902238352976078395198035416430261300974094600135242231268642783230986499797624830094698405716034919055851528418996945744623233014619026973652777892429824489371625486460871462705495597542593148226840678864076948049036056
10022430537581100668502883292824778933607339338765926026805737984600928768394291101969168677779321137283218236917508266473465030665219284863536608447940487677072083129795072785840083494425556238492937940196822995238448372796541954279303435932510765640503040286741618037016213243353519162818665268721728774804,1745450390765598318476765814191109791291817192933930838487529317598912090407141417101048723630667618601898718290746648849351810269839537783425961583377520701947088669609241693035013571476458016904170389418378228794668337339954300480921565354479003099904568784841604791321827362751710640603340143528678878307,505461416773210200375665916297012066614237052797213136609066313311545733018491487357728242574093909073856795981653867763762281713211234379922321747443616377604676750509494828442443340820844933440417718090216464110039019539088373064239526712549777394214168807828906636896179669124200810156121848745927583143473|10022430537581100668502883292824778933607339338765926026805737984600928768394291101969168677779321137283218236917508266473465030665219284863536608447940487677072083129795072785840083494425556238492937940196822995238448372796541954279303435932510765640503040286741618037016213243353519162818665268721728774804,1745450390765598318476765814191109791291817192933930838487529317598912090407141417101048723630667618601898718290746648849351810269839537783425961583377520701947088669609241693035013571476458016904170389418378228794668337339954300480921565354479003099904568784841604791321827362751710640603340143528678878307,505461416773210200375665916297012066614237052797213136609066313311545733018491487357728242574093909073856795981653867763762281713211234379922321747443616377604676750509494828442443340820844933440417718090216464110039019539088373064239526712549777394214168807828906636896179669124200810156121848745927583143473|62092481921639574438226283198332200678734028657724766941730022043809545444204108322446905830622252301375431538847493859046365695561521947886739278282380330944740137778796806258440017010320211759144908638103476555150573303911926239710190937911611647166321874200336757808613044926465128049757211183544247137033,-45250053315775064910191280612561362661486537888549446589078696876018947013616669550765115160411532144837380748629686624052593601626644191366587957076497250945144687082001936959339633808733565487985938465191480629685961056777143827741613522372695750936020580143021192692134512265227690413020620317312128938767,89818959533274049458857462069020739338602011671046728330943513188118466840658369260446327848180189713317967953477747595755322234416809755612045527023070344299134617743385420998285144607795275808302453674682604268889767229654448620219461284821255145925444306004911131336470833940664306256327917520781637949994
10022447467429108159774355787589122715485396978224199367300758397771363796346073591552810427326339622121413685155961164725589610901918895551781900417862806225664599680621980718988526130452221161919053852672286805155084312599146807342205269705230729665300558186233143844168304167857171548003707472393702474384,1188885044590400163258159304120537014931301063692806659646722818307638465604090862597898645794165661603569562151904733849823451481071963642820939826997500655539582070601901658042242359967350311563512079177663668335375683704849269904109356286951724174166294895547399547486092075854607019467491563004574181747,451886511793730238078310968270671960837012936994555807769579552350299617939295621484477388940254813126337697555682035175155312684470552706006082326229489214590934446980684912399661406451818153885180492656373585024394872163807899894979861799817481760468528780471201306793514412189815424515752868704991093442748|10022447467429108159774355787589122715485396978224199367300758397771363796346073591552810427326339622121413685155961164725589610901918895551781900417862806225664599680621980718988526130452221161919053852672286805155084312599146807342205269705230729665300558186233143844168304167857171548003707472393702474384,1188885044590400163258159304120537014931301063692806659646722818307638465604090862597898645794165661603569562151904733849823451481071963642820939826997500655539582070601901658042242359967350311563512079177663668335375683704849269904109356286951724174166294895547399547486092075854607019467491563004574181747,451886511793730238078310968270671960837012936994555807769579552350299617939295621484477388940254813126337697555682035175155312684470552706006082326229489214590934446980684912399661406451818153885180492656373585024394872163807899894979861799817481760468528780471201306793514412189815424515752868704991093442748|40311793122681847438147936825674014314470693373123318161207015676732082581716792137317735331938108693356512243120485847992937858572985495883514340613966135614307974866016309204238807033530669264492564117724246353883749827195305324197399377631361609176376894124562777952015115546002574992839306368859847102214,-33025539083635098527284543501358773726385310602673068647569756256609245347645406103541323476799319282115094670558563042038040727572072629107289743928712116480609261863925810781181839890265471330792670893248452312920468922228853995606392415425665874155050360471274554137526685669823510791388257867791420447345,119104774305358145853754696022566395542085319811674406549968528384273306539129655277119394569116384064134522924495522726505126314830673393570305912602792523829301472113875383292982915986048501532006750975293601050038174705411480721485112499986909208662941192321772927410908019836648310546774872889908741289549
10022730206246523605885847628248331589129959745152946800589982371582759735440896033124734292653525513269378463322751069994968860121969888496580966465696069881018097413525001416210515174455496944629883370533539582159385347137053307519490537337422600372155743988569466107652391801498216166822344049274248006914,729727310531644666459577636524370584122920562232400100508958613100574209791027073647329563436154072167135037277674792721862334569450792556614550488339055151138688316081220432057278684502305768700617734898572463248131416139418546546921772768563777642345566507958981323489827996692750181630164696164350792239,743420530670049129014551314283001582671251574132606225656558769248051872668919945335156046109684599461479010072698042194265131432439432111708952985059170648240550914992169145894926437588173425753889988734024781047390921725232442091277340971091116650569099484901188657501225210251920789312381353410873675482898|10022730206246523605885847628248331589129959745152946800589982371582759735440896033124734292653525513269378463322751069994968860121969888496580966465696069881018097413525001416210515174455496944629883370533539582159385347137053307519490537337422600372155743988569466107652391801498216166822344049274248006914,729727310531644666459577636524370584122920562232400100508958613100574209791027073647329563436154072167135037277674792721862334569450792556614550488339055151138688316081220432057278684502305768700617734898572463248131416139418546546921772768563777642345566507958981323489827996692750181630164696164350792239,743420530670049129014551314283001582671251574132606225656558769248051872668919945335156046109684599461479010072698042194265131432439432111708952985059170648240550914992169145894926437588173425753889988734024781047390921725232442091277340971091116650569099484901188657501225210251920789312381353410873675482898|72678153493282504157416115644391264652311137140691071678059939078869970502440343742868078709786102781757123551689967637475890683084227768997487411568948523707471659432320585674519265605598599734502760770267332905322559905487379207111063130039684891358469047921852095373415568614214678421199229135813148340086,-33947255666808860516772098102208086001134373039996489095024233296987004975315716216270171442041054094605710390151835995913332617034994068103936254773578912095997116516855870766220741602335129322709546766837859664219492792132163257557798382623121354098297535938342782377977312458602436715508338777893530715947,106484190269718620144286637065233814518223762302071472353291401620347574484719889974719727699170546479802692571973907348709106400438154108695479596777257546039047068390011589281587022778512291574952016353907379824791098458869045617748541670371657706126860369909581308416699070396340994092087729258233572584479
10022801037884735919398225401015346770690037220981230548926941756106963920408338416095733094536206053772963879852109190901255264805008288279841331919785607478274212775267264447609163695284184368267756738466008982331882800742073245734831347575593957813641726104668466028052775256385701674654962758632735214325,-1581758127940839328365881014818315360646059541554455415456767586268677829342640676667660057584626141079060910685268398574862315277919005616512245424342499450499940252940175197812452339693288044870174334000429767858420712066019926176503980859313840839446940401868444636117019979796283038985302067912785275287,496761537019467923365643288264945659788228256979170730808696057920098575449994591930452099194380843846370073248896650848520976197841222484748214967557803091427696552713317560221122191533744679546984546053333189737767090004462878944114371161170193473185997313558677097782867340116873490763865370370260817678938|10022801037884735919398225401015346770690037220981230548926941756106963920408338416095733094536206053772963879852109190901255264805008288279841331919785607478274212775267264447609163695284184368267756738466008982331882800742073245734831347575593957813641726104668466028052775256385701674654962758632735214325,-1581758127940839328365881014818315360646059541554455415456767586268677829342640676667660057584626141079060910685268398574862315277919005616512245424342499450499940252940175197812452339693288044870174334000429767858420712066019926176503980859313840839446940401868444636117019979796283038985302067912785275287,496761537019467923365643288264945659788228256979170730808696057920098575449994591930452099194380843846370073248896650848520976197841222484748214967557803091427696552713317560221122191533744679546984546053333189737767090004462878944114371161170193473185997313558677097782867340116873490763865370370260817678938|11794018787280482940784484560654447929703367834543013693618622456325444683498014462584498990809979794991029406828035162064888206099231897450516338131683344468341641773247077777974904033180523619849644665052604243871182886239709602918372696154159689574416694382901020412810986466933364313296340223658056711860,1521303582082972784094072429213245037004474422912041747980341661334088522130166480999863587718878595218681652383126000473728595142115360315778132844751721718890137106680913339185860894697918722593994440198312742439897553470706013918108591714015302153342792691194124679477731145179750991721088470556891980683,422154249545788907790313192562529747503206514258177376656051975747255059759645179919603489351691318624495599133821906453410850735326793444201922900151270842818708202863054380424556183873836633029531584190623724167592312286966999660766414372084390763660497972689763908414494950088490657933080790950343854684683
100229993686309443431652234853242745584964039848901396902154758000675611952948762456754223980100376888310959032918053199573371179952836402943594446966248713771392255748269391671122973567354604611827710836480143363448852247469233467634585666281897503837387248046923275198978369387627574778973203963568459570613,99141614774063628352404317381455383177814780210220526925227232275804977777537108958838490639289349073928621828114260050626184229387757267144939794360548040966543453766396248232212371430223357646841577045712198699745634479223254936354615654319866477688010773948549511551046967361375809493630740150224195152939,104882524400956127942658813062851389442407913609672222789148495255743494809906874598039501219688723468166574648371069153919928988258063568059818823680918241728433303999086584504182405446032391227196284068159574388579981415818096136448105143139694516800086480906674126689437313489030594417564677758780953521314|100229993686309443431652234853242745584964039848901396902154758000675611952948762456754223980100376888310959032918053199573371179952836402943594446966248713771392255748269391671122973567354604611827710836480143363448852247469233467634585666281897503837387248046923275198978369387627574778973203963568459570613,99141614774063628352404317381455383177814780210220526925227232275804977777537108958838490639289349073928621828114260050626184229387757267144939794360548040966543453766396248232212371430223357646841577045712198699745634479223254936354615654319866477688010773948549511551046967361375809493630740150224195152939,104882524400956127942658813062851389442407913609672222789148495255743494809906874598039501219688723468166574648371069153919928988258063568059818823680918241728433303999086584504182405446032391227196284068159574388579981415818096136448105143139694516800086480906674126689437313489030594417564677758780953521314|74350434749389969050012184990337127551177662105941520713519479144559556197790064845857130327167806787623076521428876751871163669518580183330141936425233250661556229643890019866856080560251792692090494599862764037832371889499003253542457382200017573287275373464647146587627430764219256453016377003846953421792,63957711791573361964387609614017192151897432836032720396105880275969302058600840013396804158201720534370023895822842857827830012733763196699928990175961939998886321856401382898475734879783268690655497427397663979021512999064707392335539401656442120559970485354029428771216688798043679886727502284879667604695,122094202522303244187343830185980046602374556531568820744954812272038371153739943186637285289631950376927966459293327247925407412742819149064968500238603572438294529950547276948751033111097715894035925769404645235126181286620345914299937264438033627270225587240098530161700877220337370607067995020225846162049
100236185197041329075554833621063049933091933804804579181020863476728313391686305869039610612323226747485959655907451027539483829746780221656275287251359920572256326848112354466643258852396004468792417619989592999892771161118188446161121453052287245392349650298061886772129843629230859327769032485896380376,-23246228755139486121091450291914215536752934295258164744923084651696211557139982911633633936256958755233390860799953871691506689375274550434281909010783595844874773750530708001462730196953616598369162178869242223651107363158755851755977149870788847101056032248840046983417481075963548958473469668684959891,56573523673680298471644280373809509686143659597565817726545502453421314503494549466829923326874504507298291631695935926527600390521472116074127195438583945763976558015737054829572336871056542824657451863625497940311479875421301704568832621760721804490304525701867696665290350769186367013604263730372702025776917|100236185197041329075554833621063049933091933804804579181020863476728313391686305869039610612323226747485959655907451027539483829746780221656275287251359920572256326848112354466643258852396004468792417619989592999892771161118188446161121453052287245392349650298061886772129843629230859327769032485896380376,-23246228755139486121091450291914215536752934295258164744923084651696211557139982911633633936256958755233390860799953871691506689375274550434281909010783595844874773750530708001462730196953616598369162178869242223651107363158755851755977149870788847101056032248840046983417481075963548958473469668684959891,56573523673680298471644280373809509686143659597565817726545502453421314503494549466829923326874504507298291631695935926527600390521472116074127195438583945763976558015737054829572336871056542824657451863625497940311479875421301704568832621760721804490304525701867696665290350769186367013604263730372702025776917|15573203821391096660668742152065727671791482748659900060639926963022005424305428598384096201045285103243110012385503647750757013115954608677386233978142224494513680866630913236076316930192686744226921983870965664346251492074685634583531334565997695428546882772894918870424603926033309071559111059501203642333,6451721584690521069581901111974092204654122587875579916279551744658661205413364185368986076832511568929170794843492990781144450828332965740817648161987976580582338126230945095334678085775013660661642032765404588316501300352495628863315640949745573214882043885532409624351786399389352651138436910377540588715,364800994330757396882653090957020494991186585063682233319677342832051344502776958834410035811370111943816463424448302716551318762170472662165419035921367121365358358160571142517808605560056227966869017916492144933000445349984077920674346135535102210585266868874844995392794923436866721883251932973852604825116
10023667082494025533694458923906062911614808800770741660171152481026059347510371753561616097379084784341713671154750835715019868680624888814365226032644794597463378220681171484265152741451558871527205613714299617780955377578029153710181790009777505367079339560569389236075705577562497976407198835496123421815,8237178824212969139758302266371465433903111044341794615829413365403141507594223080352356455683475273814082845524013102162873125179530876016035628585832833134556337909718743386830931466874558092486241907311137385119488677802975754525714977343935483066353264879509528297193753064624793968877384112576484389591,423224971588853021692214116546653537988666116441804013450094782696541031203993989512468938158606185066216192664407632356213925851579704646681338385590758369803509256824915492724160624602987883926813515751341908451718832678074898298694978135986894313441355375932022035725661361883088309484290780962315557040384|10023667082494025533694458923906062911614808800770741660171152481026059347510371753561616097379084784341713671154750835715019868680624888814365226032644794597463378220681171484265152741451558871527205613714299617780955377578029153710181790009777505367079339560569389236075705577562497976407198835496123421815,8237178824212969139758302266371465433903111044341794615829413365403141507594223080352356455683475273814082845524013102162873125179530876016035628585832833134556337909718743386830931466874558092486241907311137385119488677802975754525714977343935483066353264879509528297193753064624793968877384112576484389591,423224971588853021692214116546653537988666116441804013450094782696541031203993989512468938158606185066216192664407632356213925851579704646681338385590758369803509256824915492724160624602987883926813515751341908451718832678074898298694978135986894313441355375932022035725661361883088309484290780962315557040384|26149581659024134542252839056088737943459101230098434304929833472689045273647101980834416767117184344850968739815058973073425320764635194473778310753733774870500611744687135320440722493629102059325894273417025541554717397282491317870553755571826770905575804901409545560793682652830798005534542887045797606186,-1697969983698485305905454448895722929114256960413081228420951351866600414430800217182268923658152076765210118720420817273440690524435493363475828642615467592516719174944772197605654745416391960101282581330420264887754748587983051609045080004443224578293135292425351561632174977350140009380537152490928076887,161609629862554141142708472275797044218689904367615056614920333643328937851927686237891781051003871507296405842898237370248243352582987628460341700892139196626441792037632328670727659225186548971653052724874684965299456515833967561157293186033533538079205556741150926459475886439855496878616457828726831550112
10023862893594232582190646068648463209940952006884955056666263414474264317722655546318247009455771884983355234222787422801894657323776793269825967901010897328305149754199815134059038386803327107954623997783328925014573712361190412041544730846393144970158584993932522919092961533807689663994273510181230611975,-2760322820547873699921094239708262618123220686640344280427532457964735913231839541155448488755106353058077772483391926518490758309421884945189004380274532339303673658136307214150768559915038249044318636340829040623019533080008795877188365713108541851533478868182315253939354465782006188226272150540248455533,539774532098344028178575637715654362402942864818067869426574212334581836029933543954242820122684669884416483020859433711413498388105161261765872011520166122694643001745601237406507189268543940858796801993814111596277340371144355358041455940732653675597524992815557778776692308187755956982584432604519599405036|10023862893594232582190646068648463209940952006884955056666263414474264317722655546318247009455771884983355234222787422801894657323776793269825967901010897328305149754199815134059038386803327107954623997783328925014573712361190412041544730846393144970158584993932522919092961533807689663994273510181230611975,-2760322820547873699921094239708262618123220686640344280427532457964735913231839541155448488755106353058077772483391926518490758309421884945189004380274532339303673658136307214150768559915038249044318636340829040623019533080008795877188365713108541851533478868182315253939354465782006188226272150540248455533,539774532098344028178575637715654362402942864818067869426574212334581836029933543954242820122684669884416483020859433711413498388105161261765872011520166122694643001745601237406507189268543940858796801993814111596277340371144355358041455940732653675597524992815557778776692308187755956982584432604519599405036|48715243603698629821940426961114291788526831094737919680655564244368028434506892148169445801801507062147482077938401141271200004998443292904217897448972538551776558146708202066192286102689914350481841990540885514221263570815029978710961611989482704700171591369852446182654047272669614885074291437285365544460,15461979039278362276597154663342472093520340953601325231902305531667625678747495978358134272949704300055117324152966543774546452680787464009096008897144630532639259858616922948118805845884304673520502690819270668894425836172912196918903901652212033563796089034742441883378992888990103186375633458530164516317,112254170401540486949707124025758283679636240637378289192656933481574624585762302045534446659987957789349537165930984237831795400327841686426067814232036082567083362372524941094990583657803451112651533845361102072607539347050570081691100018981326399925221570110823787216043908322347678600920061436414622205345
10024289314253109068181408824584907548682813194738591861732979563130066037537322274697443177137048505246344585833979570630525401656305713560413859208020518275537432959569499157916033857588787751319126726484190263493857704290501320067515311770609186057345956871152108834406551727855172143151298819670712846606,250504711193651543885319560950205973661493792695329060474635142907355144915197487552594082031949875905008463463563678142215091936373578313885813322111597330162926418717728507984924427400756505737871837782137693463723537653383553918621336520844369928180694979696895523967764933497235970432812594037072497051,715621301200572432492975207084152505969843326949635795107806123209445143151718517449817068713936125495042559248838811939558778417894618132276860461288711015473626724568542195567695133648202437411311798035098899324593482673311597084169133485553033610858821471717692594066324611630669968328053616507731719142856|10024289314253109068181408824584907548682813194738591861732979563130066037537322274697443177137048505246344585833979570630525401656305713560413859208020518275537432959569499157916033857588787751319126726484190263493857704290501320067515311770609186057345956871152108834406551727855172143151298819670712846606,250504711193651543885319560950205973661493792695329060474635142907355144915197487552594082031949875905008463463563678142215091936373578313885813322111597330162926418717728507984924427400756505737871837782137693463723537653383553918621336520844369928180694979696895523967764933497235970432812594037072497051,715621301200572432492975207084152505969843326949635795107806123209445143151718517449817068713936125495042559248838811939558778417894618132276860461288711015473626724568542195567695133648202437411311798035098899324593482673311597084169133485553033610858821471717692594066324611630669968328053616507731719142856|69691918841176288984823797473901681196094628879675315489755259444998436434953893357490252440851727841764856894926617359858762775119043951866997363697297297444653923770370354552225052699848341814307273549886449783549055935119439453155817735871573060612568620074695549908654214345458834165261842993120064731877,29396998803244259208706324369693841135210373137766178345587378836957006029896347992580130862460199303906902776177861781944189386331882004200746161097147483839158568813322086972498062377955537624817737605600339132204987534032119897113967273038860438816060235575010015500174845850861550917579850703027368690837,106032740697299793989572674990101926746114173477172287236417937947154096127701068054351010022541808717403069236123423199088480578855329299917113038220143550055260783011691574203288951873393089140671443554631887510834797278656898859315134431047639142121497581377857339388563046962362704012299890107532747273864
10025428900225290685290151690469854982214932916715816521705584076773008242243937008766386881454192668460673460928145859037221457715710934570710912601758825277917537132977601878466722300639421318388444709119075347515835153260761313907776418189378977092187686581753209864749194659254262457796167519362282389944,8035407417908027120985682166291560102987169154314800046344974577695327891178900017914738842677039490694291401465931876496716613929624358740551659992744919248664062419629947961043318471204322567520912143542047278378993142962380418872588429956261466474640589358106914252999077869082097127384356318300378316515,526506212965607285294504652802203087863317784238837123201810456971631654056439372780456787465506517550858742170829690899565417756124817089047569475165769047941621936008499130409010932902058625548248971355379292220521819976269615165269965092960486278068237861168382524126578791019346639264332649030378056985183|10025428900225290685290151690469854982214932916715816521705584076773008242243937008766386881454192668460673460928145859037221457715710934570710912601758825277917537132977601878466722300639421318388444709119075347515835153260761313907776418189378977092187686581753209864749194659254262457796167519362282389944,8035407417908027120985682166291560102987169154314800046344974577695327891178900017914738842677039490694291401465931876496716613929624358740551659992744919248664062419629947961043318471204322567520912143542047278378993142962380418872588429956261466474640589358106914252999077869082097127384356318300378316515,526506212965607285294504652802203087863317784238837123201810456971631654056439372780456787465506517550858742170829690899565417756124817089047569475165769047941621936008499130409010932902058625548248971355379292220521819976269615165269965092960486278068237861168382524126578791019346639264332649030378056985183|22138319840700167895312881508181272807615611642960031764554010440709354488166777949391350577243475719290294812551529754345491786841502661934416467056115565617682227037416000132315258676326832664293472268496755124942179527934459542753167413348749025306046598965185451619481594689484505194124705909904529437016,-11131863740438194145696527360624732907005872365618169777307266620259512556501908857842536958655885195096195748687569086057992329814846073549253878495916056982261048696264863065937434987201822416655310303356962123778695372607503843603636308900759414300401601767853289915741229529512784406304245742359645877437,239100722014735247362237833086276623512072741916888955896402203382427372194255695065669877432592987292352301916479402236621014870053157629159394772682571609781590319296070407875820019520943129073048256367075297134176669670916790346961022995994025660850270895833918044332478002360056773821184240475743476227793
10025696373056081323076067608649787757301021243808185859274808349280293058956119916709251366791092102112010300737183625444037192198725817688527600134257833611989912831501342672141015848343142445555687647450237725473967806277927764282835935236016323094913726640542283793306041765928288192544236949963888652742,-7551573577419239436071851881922105087510160439185121186338107875456959549550841973546977393389532111591614312842887678906809652876632858754122403767673808362967953534249136664179536748454994677273595591516700421480181975305574013927943181245218443636797391029556909610245497977668952560989113626530355626403,488551202347944315504020596344859283372184958565644254623325222360870646703286196267475027122265755221917465236349901297478448862017138325309245093096937651510172757567584161967211867376922683411877153052678659984267061266457787269417246896692832538104568250487618601354692837088103049130077128213591142309282|10025696373056081323076067608649787757301021243808185859274808349280293058956119916709251366791092102112010300737183625444037192198725817688527600134257833611989912831501342672141015848343142445555687647450237725473967806277927764282835935236016323094913726640542283793306041765928288192544236949963888652742,-7551573577419239436071851881922105087510160439185121186338107875456959549550841973546977393389532111591614312842887678906809652876632858754122403767673808362967953534249136664179536748454994677273595591516700421480181975305574013927943181245218443636797391029556909610245497977668952560989113626530355626403,488551202347944315504020596344859283372184958565644254623325222360870646703286196267475027122265755221917465236349901297478448862017138325309245093096937651510172757567584161967211867376922683411877153052678659984267061266457787269417246896692832538104568250487618601354692837088103049130077128213591142309282|60393031392510595353689024388979736338459176869905458858711562614756995826747740419365757994707737913997543366818386810567166008495382740947599739430340534765458717365457600414802742877973222192406990314478073640352910084093417199594859293029865969059185936671473103965892459853411850141569702842003428649274,38329753573953857590669151489102652306888210200689056278625104334993443543324622863340848043537460677248162565965074671978338401303611611484783137870568580776992301362308417714890643838644524909137849140837295996399799637901901974938629017550061052634048860038885099946489697555545683915123490961748882032563,86948805727102164020528697795654924433436758890959241635759391106001442581272485956111792521204085749386969011988358799013634480122996757146530322550896381169828204152724081141046858586814946327125019525970600049950459272456428386457599502469581747116784271717706447744628609754739530433937342398267975398266
10025795277027889904587708106143218928217212795791943900096455901045016119560329143219194735847213817310006544292588010221295347093799623990992065640705758739633420740707391553060038825197435786302291280814741597987499076013530747593280825513696921556065232738339683658383829389180388637941998690144811369597,5684979695119467447669475199616030835217750876317308626399899267476547529035287916782085067945907170746605510283861183133612038067129245932165458949837306805149633974813244043762392619755476811530088171886491397765159164208502011381649757076514242464099478526057069033992519207091422655970324739132300656901,562007444349085595243678168150362315344210015071199683818344834829191775432825810670825147187078104135705553739701002486305372357596398874560795249464367016590567012959728033251032467564115881230202627660086530992291649152268041406000599974523312325932278194132351429623587227242904398909856612628818780435778|10025795277027889904587708106143218928217212795791943900096455901045016119560329143219194735847213817310006544292588010221295347093799623990992065640705758739633420740707391553060038825197435786302291280814741597987499076013530747593280825513696921556065232738339683658383829389180388637941998690144811369597,5684979695119467447669475199616030835217750876317308626399899267476547529035287916782085067945907170746605510283861183133612038067129245932165458949837306805149633974813244043762392619755476811530088171886491397765159164208502011381649757076514242464099478526057069033992519207091422655970324739132300656901,562007444349085595243678168150362315344210015071199683818344834829191775432825810670825147187078104135705553739701002486305372357596398874560795249464367016590567012959728033251032467564115881230202627660086530992291649152268041406000599974523312325932278194132351429623587227242904398909856612628818780435778|21268893649707309919570226960346372728495718162766890279898665692070832053021527941744710318344298178920800948932846738089018664772788493927580517099544523821251022066659574678369202749060209753445042621950578890219002532761197990179516522502045501310564866950615799259252489912339574839719060814022687315833,-16974163508967143175633640446755920949410222455507178592573412674696095005693865169009177473634493301741992193686041205183814819978515841920175784743689108590732720018205453159865088935842801461210617037675036778351747079803439546961298001090840400908639940207556458714733757110771041917290102952953525885901,267927541659497862467954399158595317217757334505550228883969422271210761133505257969057962914766286654857630940214532971487737583736851759345565614399969808206018020458924660929875641469250964043761370010683938550578868703713683401770700995854517531350144574746588257756156838858326386968013405064043171677102
10027231464587935675639730747678568553908782143975994882531107664457436183429164280181747996889942331170488347016005448660418260392761004178712470722876674735769717730721096608074660784751458654872470573207263246635112395824536847938300087322544843942058256547417838850894365569811278659238183569174057618461,-4440267082761131414853294025879558077404333378765096794740543986499915534978609296838455472705453725784503668845242671918380807204902116758601260037461056825902249629220350908043324356588944839161111532952326818438147003761862650635018374512533491039199092599100710336766544058009407418500582600655649176731,648644865497954786776779349508457974872894617589720812073415733603605246322174185807123848556285887617844905639166726609275182111944451202589938026255239735903760010573449137429043799240258539000988138770732321918291392488327546867698375214486961050410251228096630089455328472100573545758827677160537099320072|10027231464587935675639730747678568553908782143975994882531107664457436183429164280181747996889942331170488347016005448660418260392761004178712470722876674735769717730721096608074660784751458654872470573207263246635112395824536847938300087322544843942058256547417838850894365569811278659238183569174057618461,-4440267082761131414853294025879558077404333378765096794740543986499915534978609296838455472705453725784503668845242671918380807204902116758601260037461056825902249629220350908043324356588944839161111532952326818438147003761862650635018374512533491039199092599100710336766544058009407418500582600655649176731,648644865497954786776779349508457974872894617589720812073415733603605246322174185807123848556285887617844905639166726609275182111944451202589938026255239735903760010573449137429043799240258539000988138770732321918291392488327546867698375214486961050410251228096630089455328472100573545758827677160537099320072|46009921711915221172675762660378602913284935911769009327398886576025556944392570855250807675821524214292205195685897041743100957229886916848065466280285331142834500895832407569582736664860239313946858454701727263963934792933919730548918244937925570913918752904708052633399310307728141781833372082621654521012,23113475896105025107394605331889841460333790037514477610982037645403180016015663190091781841332002225731097821541822074963875072814544317858697958764287783670995655541483455486482934375887626558700537105583870368524253911345190227270218382103667348149461739557925536602713765457923023851021682724701425292285,144158936962616263074854848511540730235089365933518189341717329619972562457005307870230026030935456404849352326770086269924745439466300887545713518178631945541398236558781981355199214433550895067837895099984050382102279411033270720567051341019780619857285120976043103941344405749600962507460384488305160927409
10028350739307738239553437040783010537831658077620987335136512740169676263676747904072610524038617826531776850363823183733316438383606013506243196250082245650509414494066287488240898643357609392647649696817421880362011995934355791054933802156008906495889209763185641418699747996844644309107005112769042124318,-8707724909729199988066303291337645249173793540898282778024990496827621579508639942367666079187451324678862416133361451354021503910330702173658524643590899178624105480074443491370735876152164927759833250717689047284841393067105491783984924710355073809596596309834373465404107419929383484013294580151001556205,709758849546988349416271112886481225556022674837057904210411294800853958134290458192748393663317224087035819308413648727887254453418237510262143014913358121419251454923066768843049946946235581252429358021933518874438830803109875124372809973223871915099838973789742920465584130081571378073407884375094121268086|75318449301263415467735932548665333631833209464496019863964846786179367552717568503501179580307848690931127517090493242442668414948431300766436151276701082711193885234526326365772794857402011587084042826807831628195071551088506032974178171732912459672450935320336391563419572190330442739927553072512433668492,-37666884930926310053453757600840503983118095033807980727340808659295811653448510252245931091899049389573453471548035871058367468721695376360491358764096189091201995027259909431928638716214539254513869701208949761595174662474754859884399931318260163661631099379190898913272807941135716989109599181870658955411,98959195118263740892956000993748226884659367220332828268929254332674345256309662055166848715197441404549693155497652798902798133883715701424760429622411156195661335500009744018343869593442437677434882815576040667549098187431048868332096738149061496080175268157896224795266747997461998351291015430290846127991|78879828918733154172761232408717349879484411577276118445906917725867063887736403698268620449039366903222875325557071665537210036919488537356651491469585633888702020869953229589162929365722510146484615161939420331780149558523973332122378453822513488024388432239153051455307708434618917487055946350509115159954,76022832032228931560745697540761625684085285731069434889900171934534714627230254695020398894919788417337545845925550378316932977023401785630385785258013781974664129868656557307645950862628223235191878262315897562597443878541677560567949780990105397727409041603839660905756066382442879369790583798789010488305,108311876812780092185464248430819211209817518273155531596997245418001592611818208219323720419932959536655772814492616252593108875759365327114882816039706034356112007450695439375062874008822159624139628714241658551452565287963490475631456873365249553095821106476912177956653681222238113836907581862856535718737
10028851844651833483859929571953137249991455639548429827963027247884276614126582614765754168788406967864569784762670102265610798647378386836840906226432130520069813697908016956233348000504802826879321612396642793367212498698674853695626535119160503473498038239103440516242421347929877540717111105756485685416,2125595786027029524418010744012416366895751257304333344547068089057782417304598028459234751630103098379533864111162338454453990302791615035666668646880454521909199231924063610130346480860493194786475025500179927152042631414216166076205706865335089506746163544867373884186074330874303125032398057106297186863,800913161978634698742609378449357774955505407483415355913501780948951093468088505693408572348493350961801168010893237963412292289122055848739177106855852125098292236006510856110523212361731635197072591774393685461794786770421350652687522647241859653967881884006552182286419954577117744245767788677817306762852|50429916262905224121199165505326103712322633321578675412441680250060233972857110270845245669993781820897616267433177701631160063889458653764653687193369398981186203131244488744056545097485284912257268749768458331368107477031080466529105477483573960360042156349879055924595032652993263006931935621163071940669,-27065457947223595691396496360583757525811978893552969421355220262690251856919447274985744020030753772138102799000695707517100290349316439468276434701083568894717249805760937039437729313480400330251378090593495078991541936054800615447964857892934462412215184000258243195317080477356913381022045983896051265339,162884360410278142867611075754290453359699000687335791914852080089316910769333692647979960993562595617317591055325367385753910502341805589561432506963888415490402296553372275035046411345233183682360113909981999769321373626395576042577426393704313732652524189312065702142816306042456646293512481995292218184630|53997723292458827021420578276444072896002053124414909531202213558828743141566632795132611868503445251027453958158504792518315802051451653007369750551307662332396699632827748059470875485288011830316694909885816703989889585271656952405885761371722676008299809654786389827849524552375005490619782071967768476620,-3921961296864439599504210025762424797468664702267290731411285739993844771294339132594454147684650522033462891630908841344585194018116919380259122700777039543903609394837238783496880317096351827072103366260798880944073390853134441762823497871536553346031444078137460262118850735234076150428857645894786599751,148801743068668131617014767083337764289837422117725728166091414005082627848729316116752646484455568027336119364510594603975358934000097718262611755893849397982664596027513725455266261222215386005085253076887565120162601272630243587251846986242350641739720550891898677287459766121608903079025422071040317411427
10029389724354647916501896404393742667486460299990236556418317010668116357688170330436730152626311842309710400719826928488284825527027730454134618086311842571929328216480439284941404499751921093227604323134474990591797348436817566328316099817073417778247297081309102907064789976846493401165211794614652077581,-5748548483444797737722189452249937786310843486604864328602367281135708748614533947090219774019556230317272055169227525539578087511031078860820692360107715435130140444616499305586047090927584090418666083007681585523416727535418733837425822999564006750813702161869964846496575730545650729911357481033875975819,719895727819428792994563756994341424767785889195228293344753744212732679301708252203825226413012156273021174986595157595824763180256881701588113889797640827369987995936500880423386237711358833858185065722206691788564039408747808726964665919487597212670306097386648373066512338291830265434985728533154609458396|10029389724354647916501896404393742667486460299990236556418317010668116357688170330436730152626311842309710400719826928488284825527027730454134618086311842571929328216480439284941404499751921093227604323134474990591797348436817566328316099817073417778247297081309102907064789976846493401165211794614652077581,-5748548483444797737722189452249937786310843486604864328602367281135708748614533947090219774019556230317272055169227525539578087511031078860820692360107715435130140444616499305586047090927584090418666083007681585523416727535418733837425822999564006750813702161869964846496575730545650729911357481033875975819,719895727819428792994563756994341424767785889195228293344753744212732679301708252203825226413012156273021174986595157595824763180256881701588113889797640827369987995936500880423386237711358833858185065722206691788564039408747808726964665919487597212670306097386648373066512338291830265434985728533154609458396|8560998041202342563145796199673331908087223591151890019844277290088279806853407215903188817680041281745686724901293662893322531582604865370359246593736212994518909947445852055733198112706083016676348016714291995623917124402224705247934604030962953619706293397331305385867121828720733169551586472433525366937,-537975643989974344334263003423538768209474800355518283566587248897859525466409192148505701554962331296631250873445941844817525452815362174465113061273994639614043454341045805645253425898526417994404807933232055819444976823823121190979410608683098711316112363065614462414343124780847750195760827288806749811,842416466225224033183393216850362224780744722633748075411867357471068659147784175969996596348967969848559647034288532517371764252498077837862667546193299637156461175039504339023851201930547252305821527420041035325847162633397442876512610187216200063222815713605031344575281997919080197584636819283493689893368
10029462828108406279939177067115161395010840703955688660855251935920272008672857135011101256731718086932191566776707625465927083826902687987460773347952918706606341231446896979494902183159052228641287627294356517943283997224691515527031637969828335115038316970291491432668820800917926368076854280638205187309,-6629646230072911423556297764360629625589965368903862583111147478898388162363395818084398589541887766856708633717083099875720612184669212924373539095145308857941719336023981955297255371765324592355503775749174475673743444341624220885937903545914339945102711106579165895756968511409705213351719512183267438507,782742743661597372172423816386424221021017552503284524697466177183281891845425353410464186233869636520966594583971179297268228166989165546064661406781232750204176842910595282543729669785450570724055031796400642778914378223882150571438409693254554219540729724954243581265311980228274664427499269984624348473720|10029462828108406279939177067115161395010840703955688660855251935920272008672857135011101256731718086932191566776707625465927083826902687987460773347952918706606341231446896979494902183159052228641287627294356517943283997224691515527031637969828335115038316970291491432668820800917926368076854280638205187309,-6629646230072911423556297764360629625589965368903862583111147478898388162363395818084398589541887766856708633717083099875720612184669212924373539095145308857941719336023981955297255371765324592355503775749174475673743444341624220885937903545914339945102711106579165895756968511409705213351719512183267438507,782742743661597372172423816386424221021017552503284524697466177183281891845425353410464186233869636520966594583971179297268228166989165546064661406781232750204176842910595282543729669785450570724055031796400642778914378223882150571438409693254554219540729724954243581265311980228274664427499269984624348473720|78667156036256111077611624900655903416490936286908879028793529978954307476546731244382117972535629204391216663640753691624585098486838208251820032478479477157140644001833697695041181016581251701307504852404041540782811897181398727717806959310986773271700555774873273014053192416692372242335858566589217791557,-11681938670990905592355073596188490162953864508666802257304897456361955348551384361326321552281799532866414312577544184561189074950098884814900830627703536569755802878449922371901033061871486784064588452214883192668082672979794267084922475962025561930112420060063420934779749780994794637529679089941387143427,100087743332058471063169855843669770171915090829420561680411008586982501053400685795132793033729482971332564612241450018617179058547543051543609602249472699027915450803902552375241387388609502154707845080333148480015751381946173697011349301767118798190494650916047348538729674905622316757245591467381527471900

46
crates/vdf/Cargo.toml Normal file
View File

@ -0,0 +1,46 @@
# Copyright 2018 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
# and limitations under the License.
[package]
name = "vdf"
version = "0.1.0"
authors = ["Demi M. Obenour <demiobenour@gmail.com>"]
readme = "README.md"
keywords = ["vdf", "classgroup", "crypto", "cryptography"]
repository = "https://github.com/poanetwork/vdf"
license = "Apache-2.0"
edition = "2018"
description = "An implementation of Verifiable Delay Functions (VDFs) in Rust"
[lib]
crate-type = ["lib", "staticlib"]
name = "vdf"
[dependencies]
classgroup = { path = "../classgroup", version = "^0.1.0" }
num-traits = "0.2"
sha2 = "0.8"
bit-vec = "0.5"
uniffi = { version= "0.25", features = ["cli"]}
[build-dependencies]
uniffi = { version = "0.25", features = [ "build" ] }
[dev-dependencies]
criterion = ">=0.2"
hex = "0.3"
[[bench]]
name = "classgroup-bench"
harness = false
path = "bench/bench.rs"

223
crates/vdf/README.md Normal file
View File

@ -0,0 +1,223 @@
# Verifiable Delay Function (VDF) Implementation in Rust
## What is a VDF?
A Verifiable Delay Function (VDF) is a function that requires substantial time
to evaluate (even with a polynomial number of parallel processors) but can be
very quickly verified as correct. VDFs can be used to construct randomness
beacons with multiple applications in a distributed network environment. By
introducing a time delay during evaluation, VDFs prevent malicious actors from
influencing output. The output cannot be differentiated from a random number
until the final result is computed. See <https://eprint.iacr.org/2018/712.pdf>
for more details.
## Description
This VDF implementation is written in Rust. The GMP library is used for
arithmetic and greatest common divisor (GCD) calculations. We use class groups
to implement the approaches described in the following papers:
1. [Simple Verifiable Delay Functions](https://eprint.iacr.org/2018/627.pdf). Pietrzak, 2018
2. [Efficient Verifiable Delay Functions](https://eprint.iacr.org/2018/623.pdf). Wesolowski, 2018
The chosen generator is (2, 1, c), where c is calculated from the provided
discriminant. A form is represented internally (a, b, c), with the
discriminant not being used in most omputations. This implementation performs
reduction is performed after every multiplication and squaring, as not doing so
did not give any gains in our benchmarks.
This repo includes three crates:
* `classgroup`: a class group implementation, as well as a trait for class
groups.
* `vdf`: a Verifyable Delay Function (VDF) trait, as well as an
implementation of that trait.
* `vdf-cli`: a command-line interface to the vdf crate. It also includes
additional commands, which are deprecated and will be replaced by a CLI to
the classgroup crate.
## Usage
- Install [Rust]. We (POA Networks) have tested the code with the latest
stable, beta, and nightly versions of Rust. It may work with older
versions, but this is not guaranteed.
- Install the [GNU Multiple Precision Library](https://gmplib.org/)
* On Debian and derivatives (including Ubuntu):
```sh
$ sudo apt-get install -y libgmp-dev
```
* On Red Hat and derivatives (Fedora, CentOS)
```sh
$ sudo dnf -y install gmp-devel
```
- Download and prepare the repository
```sh
$ git clone https://github.com/poanetwork/vdf.git
$ cargo install --path=vdf-cli
$ # or for the competition binary
$ cargo install --path=vdf-competition
```
### Command Line Interface
To initiate, use the `vdf-cli` command followed by 2 arguments:
- _challenge_: byte string of arbitrary length
- _difficulty_: number of iterations, each iteration requires more time to evaluate
This generates the Weslowski proof of time. To generate the Pietrzak proof of
time, pass `-tpietrzak`. For detailed usage information, run `vdf-cli --help`.
Once complete you will see the output, returned as a `Vec<u8>`. The CLI tool
hex-encodes its output.
**Example**
```sh
$ vdf-cli aa 100
005271e8f9ab2eb8a2906e851dfcb5542e4173f016b85e29d481a108dc82ed3b3f97937b7aa824801138d1771dea8dae2f6397e76a80613afda30f2c30a34b040baaafe76d5707d68689193e5d211833b372a6a4591abb88e2e7f2f5a5ec818b5707b86b8b2c495ca1581c179168509e3593f9a16879620a4dc4e907df452e8dd0ffc4f199825f54ec70472cc061f22eb54c48d6aa5af3ea375a392ac77294e2d955dde1d102ae2ace494293492d31cff21944a8bcb4608993065c9a00292e8d3f4604e7465b4eeefb494f5bea102db343bb61c5a15c7bdf288206885c130fa1f2d86bf5e4634fdc4216bc16ef7dac970b0ee46d69416f9a9acee651d158ac64915b
```
To verify, use the `vdi-cli` command with the same arguments and include the
output.
**Example**
```sh
$ vdf-cli aa 100 005271e8f9ab2eb8a2906e851dfcb5542e4173f016b85e29d481a108dc82ed3b3f97937b7aa824801138d1771dea8dae2f6397e76a80613afda30f2c30a34b040baaafe76d5707d68689193e5d211833b372a6a4591abb88e2e7f2f5a5ec818b5707b86b8b2c495ca1581c179168509e3593f9a16879620a4dc4e907df452e8dd0ffc4f199825f54ec70472cc061f22eb54c48d6aa5af3ea375a392ac77294e2d955dde1d102ae2ace494293492d31cff21944a8bcb4608993065c9a00292e8d3f4604e7465b4eeefb494f5bea102db343bb61c5a15c7bdf288206885c130fa1f2d86bf5e4634fdc4216bc16ef7dac970b0ee46d69416f9a9acee651d158ac64915b
Proof is valid
```
### VDF Library
<!--
Keep as is, and possibly include argument explanations as well (for byte_length for example). May not be needed though is CLI is main user interaction tool.
-->
```rust
extern crate vdf;
use vdf::{InvalidProof, PietrzakVDFParams, VDFParams, WesolowskiVDFParams, VDF};
/// The correct solution.
const CORRECT_SOLUTION: &[u8] =
b"\x00\x52\x71\xe8\xf9\xab\x2e\xb8\xa2\x90\x6e\x85\x1d\xfc\xb5\x54\x2e\x41\x73\xf0\x16\
\xb8\x5e\x29\xd4\x81\xa1\x08\xdc\x82\xed\x3b\x3f\x97\x93\x7b\x7a\xa8\x24\x80\x11\x38\
\xd1\x77\x1d\xea\x8d\xae\x2f\x63\x97\xe7\x6a\x80\x61\x3a\xfd\xa3\x0f\x2c\x30\xa3\x4b\
\x04\x0b\xaa\xaf\xe7\x6d\x57\x07\xd6\x86\x89\x19\x3e\x5d\x21\x18\x33\xb3\x72\xa6\xa4\
\x59\x1a\xbb\x88\xe2\xe7\xf2\xf5\xa5\xec\x81\x8b\x57\x07\xb8\x6b\x8b\x2c\x49\x5c\xa1\
\x58\x1c\x17\x91\x68\x50\x9e\x35\x93\xf9\xa1\x68\x79\x62\x0a\x4d\xc4\xe9\x07\xdf\x45\
\x2e\x8d\xd0\xff\xc4\xf1\x99\x82\x5f\x54\xec\x70\x47\x2c\xc0\x61\xf2\x2e\xb5\x4c\x48\
\xd6\xaa\x5a\xf3\xea\x37\x5a\x39\x2a\xc7\x72\x94\xe2\xd9\x55\xdd\xe1\xd1\x02\xae\x2a\
\xce\x49\x42\x93\x49\x2d\x31\xcf\xf2\x19\x44\xa8\xbc\xb4\x60\x89\x93\x06\x5c\x9a\x00\
\x29\x2e\x8d\x3f\x46\x04\xe7\x46\x5b\x4e\xee\xfb\x49\x4f\x5b\xea\x10\x2d\xb3\x43\xbb\
\x61\xc5\xa1\x5c\x7b\xdf\x28\x82\x06\x88\x5c\x13\x0f\xa1\xf2\xd8\x6b\xf5\xe4\x63\x4f\
\xdc\x42\x16\xbc\x16\xef\x7d\xac\x97\x0b\x0e\xe4\x6d\x69\x41\x6f\x9a\x9a\xce\xe6\x51\
\xd1\x58\xac\x64\x91\x5b";
fn main() {
// The length of the prime numbers generated, in bits.
let num_bits: u16 = 2048;
// An instance of the VDF. Instances can be used arbitrarily many times.
let pietrzak_vdf = PietrzakVDFParams(num_bits).new();
// Solve for the correct answer. This will take a minute or two.
assert_eq!(
&pietrzak_vdf.solve(b"\xaa", 10000).unwrap()[..],
CORRECT_SOLUTION
);
// Verify the answer. This should be far faster (less than a second).
assert!(pietrzak_vdf.verify(b"\xaa", 10000, CORRECT_SOLUTION).is_ok());
}
```
## Benchmarks
Benchmarks are provided for the classgroup operations. To run benchmarks:
```sh
$ ./bench.sh <your challenge here>
```
Additional benchmarks are under development.
### Current Benchmarks
These were generated by `./bench.sh aadf`. Outliers could be due to preemption
by the OS and/or hypervisor. Changes are relative to the previous test run
done on the same machine. Since the previous run was done with different
settings and/or code than reported here, these changes are not meaningful.
```text
Benchmarking square with seed aadf: 512: Collecting 100 samples in estimated 5.0439 s (374k iteratio square with seed aadf: 512
time: [13.301 us 13.333 us 13.372 us]
change: [-22.286% -21.745% -21.225%] (p = 0.00 < 0.05)
Performance has improved.
Found 22 outliers among 100 measurements (22.00%)
5 (5.00%) high mild
17 (17.00%) high severe
Benchmarking multiply with seed aadf: 512: Collecting 100 samples in estimated 5.0452 s (293k iterat multiply with seed aadf: 512
time: [17.219 us 17.251 us 17.287 us]
change: [-24.323% -23.739% -23.149%] (p = 0.00 < 0.05)
Performance has improved.
Found 10 outliers among 100 measurements (10.00%)
4 (4.00%) high mild
6 (6.00%) high severe
Benchmarking square with seed aadf: 1024: Collecting 100 samples in estimated 5.0822 s (177k iterati square with seed aadf: 1024
time: [28.672 us 28.716 us 28.767 us]
change: [-29.947% -29.339% -28.708%] (p = 0.00 < 0.05)
Performance has improved.
Found 8 outliers among 100 measurements (8.00%)
1 (1.00%) low mild
1 (1.00%) high mild
6 (6.00%) high severe
Benchmarking multiply with seed aadf: 1024: Collecting 100 samples in estimated 5.0886 s (136k itera multiply with seed aadf: 1024
time: [37.163 us 37.207 us 37.254 us]
change: [-21.403% -20.750% -20.170%] (p = 0.00 < 0.05)
Performance has improved.
Found 8 outliers among 100 measurements (8.00%)
1 (1.00%) low mild
1 (1.00%) high mild
6 (6.00%) high severe
Benchmarking square with seed aadf: 2048: Collecting 100 samples in estimated 5.2519 s (76k iteratio square with seed aadf: 2048
time: [69.115 us 69.254 us 69.430 us]
change: [-28.091% -27.738% -27.341%] (p = 0.00 < 0.05)
Performance has improved.
Found 8 outliers among 100 measurements (8.00%)
1 (1.00%) low mild
1 (1.00%) high mild
6 (6.00%) high severe
Benchmarking multiply with seed aadf: 2048: Collecting 100 samples in estimated 5.0554 s (56k iterat multiply with seed aadf: 2048
time: [90.922 us 91.057 us 91.201 us]
change: [-25.236% -24.794% -24.336%] (p = 0.00 < 0.05)
Performance has improved.
Found 13 outliers among 100 measurements (13.00%)
2 (2.00%) low mild
5 (5.00%) high mild
6 (6.00%) high severe
```
[Rust]: <https://doc.rust-lang.org/cargo/getting-started/installation.html>
## License
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.

54
crates/vdf/bench/bench.rs Normal file
View File

@ -0,0 +1,54 @@
// Copyright 2018 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.
#[macro_use]
extern crate criterion;
use hex;
use classgroup::{gmp_classgroup::GmpClassGroup, ClassGroup};
use criterion::Criterion;
use std::{cell::RefCell, env, rc::Rc};
use vdf::create_discriminant;
fn bench_square(c: &mut Criterion) {
let bench_params = |c: &mut Criterion, len: u16, seed: &[u8]| {
let i = Rc::new(RefCell::new(GmpClassGroup::generator_for_discriminant(
create_discriminant(seed, len),
)));
{
let i = i.clone();
c.bench_function(
&format!("square with seed {}: {}", hex::encode(seed), len),
move |b| b.iter(|| i.borrow_mut().square()),
);
}
{
let multiplier = i.borrow().clone();
c.bench_function(
&format!("multiply with seed {}: {}", hex::encode(seed), len),
move |b| b.iter(|| *i.borrow_mut() *= &multiplier),
);
}
};
let seed = env::var("VDF_BENCHMARK_SEED")
.ok()
.and_then(|x| hex::decode(x).ok())
.expect("bug in calling script");
for &i in &[512, 1024, 2048] {
bench_params(c, i, &seed)
}
}
criterion_group!(benches, bench_square);
criterion_main!(benches);

115
crates/vdf/build.rs Normal file
View File

@ -0,0 +1,115 @@
// 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.
use std::{env, fs::File, io::Write, path::PathBuf, u16};
/// The number of odd primes less than 65536.
const PRIMES_LEN: usize = 6541;
/// The number of integers that are:
///
/// * equal to 7 mod 8
/// * not divisible by any prime number less than or equal to 13.
/// * less than 8 * 3 * 5 * 7 * 11 * 13
const RESIDUES_LEN: usize = 5760;
/// The number of odd prime numbers between 13 and 65536 exclusive.
const SIEVE_INFO_LEN: usize = PRIMES_LEN - 5;
fn odd_primes_below_65536() -> Vec<usize> {
const N: usize = 1 << 16;
let mut sieve = vec![true; N >> 1];
let mut q = (N as f64).powf(0.5) as usize;
assert!(q * q <= N);
q += 1;
assert!(q * q > N);
for i in (3..q).step_by(2) {
if sieve[i >> 1] {
for i in ((i * i >> 1)..sieve.len()).step_by(i) {
sieve[i] = false;
}
}
}
// mega cheat ― we know the exact size of this vector
let res: Vec<_> = (1..N / 2)
.filter(|&i| sieve[i])
.map(|i| 2 * i + 1)
.collect();
assert_eq!(res.len(), PRIMES_LEN);
res
}
fn mod_exponentiation(base: usize, exponent: usize, modulus: usize) -> usize {
assert!(base < u16::MAX.into());
assert!(exponent < u16::MAX.into());
assert!(modulus < u16::MAX.into());
let (mut base, mut exponent, modulus) = (base as u32, exponent as u32, modulus as u32);
let mut state = 1;
loop {
if exponent & 1 != 0 {
state *= base;
state %= modulus;
}
exponent >>= 1;
if exponent == 0 {
return state as _;
}
base *= base;
base %= modulus;
}
}
macro_rules! const_fmt {
() => {
"#[allow(warnings)]\nconst {}: [{}; {}] = {:#?};\n\n";
};
}
/// A product of many small prime numbers. We precompute the numbers between
/// `1` and `M` that are coprime to `M`. Any number whose residue modulo `M` is
/// one of these is not divisible by any of the prime factors of `M`. This
/// speeds up the generation of random prime numbers.
const M: usize = 8 * 3 * 5 * 7 * 11 * 13;
fn emit<T: std::fmt::Debug>(f: &mut dyn Write, name: &str, t: &str, obj: &[T]) {
write!(f, const_fmt!(), name, t, obj.len(), obj).expect("i/o error in build script");
}
/// Write the generated code to `f`.
fn generate(f: &mut dyn Write) {
write!(f, "const M: u32 = 8 * 3 * 5 * 7 * 11 * 13;\n\n").expect("i/o error");
let residues: Vec<usize> = {
let primes = [3, 5, 7, 11, 13];
let not_divisible = |&x: &usize| primes.iter().all(|p| x % p != 0);
(7..M).step_by(8).filter(not_divisible).collect()
};
assert_eq!(residues.len(), RESIDUES_LEN);
emit(f, "RESIDUES", "u32", &residues[..]);
let sieve_info: Vec<(usize, usize)> = odd_primes_below_65536()[5..]
.iter()
.map(|&i| (i, mod_exponentiation(M % i, i - 2, i)))
.collect();
assert_eq!(sieve_info.len(), SIEVE_INFO_LEN);
emit(f, "SIEVE_INFO", "(u16, u16)", &sieve_info[..]);
}
fn main() {
println!("cargo:rerun-if-changed=build.rs");
uniffi::generate_scaffolding("src/lib.udl").expect("uniffi generation failed");
let manifest_path = env::var("OUT_DIR").expect("cargo should have set this");
let mut path = PathBuf::from(&manifest_path);
path.push("constants.rs");
let mut f = File::create(path).expect("cannot create constants.rs");
generate(&mut f);
}

View File

@ -0,0 +1,199 @@
// 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.
//! Creation of discriminants.
//!
//! The [`pot`] tool does not accept a discriminant as a command-line argument.
//! Instead, we generate the discriminant from a (much smaller) seed.
//!
//! For performance, we follow the Chia network's [`inkfish`] implementation
//! of ["Close to Uniform Prime Number Generation With Fewer Random Bits"][1]
//! by Pierre-Alain Fouque and Mehdi Tibouchi.
//! We employ a table of precomputed constants generated by `build.rs`.
//!
//! [1]: https://eprint.iacr.org/2011/481.pdf
//! [`inkfish`]: <https://github.com/Chia-Network/vdf-competition/blob/003b0d202d3b27058159f7a3f6a838e312e7d79e/inkfish/create_discriminant.py>
//! [`pot`]: <https://github.com/Chia-Network/vdf-competition/blob/003b0d202d3b27058159f7a3f6a838e312e7d79e/inkfish/cmds.py>
include!(concat!(env!("OUT_DIR"), "/constants.rs"));
use classgroup::BigNumExt;
use num_traits::Zero;
use sha2::{digest::FixedOutput, Digest, Sha256};
use std::u16;
fn random_bytes_from_seed(seed: &[u8], byte_count: usize) -> Vec<u8> {
assert!(byte_count <= 32 * ((1 << 16) - 1));
let mut blob = Vec::with_capacity(byte_count);
let mut extra: u16 = 0;
while blob.len() < byte_count {
let mut hasher = Sha256::new();
hasher.input(seed);
let extra_bits: [u8; 2] = [((extra & 0xFF00) >> 8) as _, (extra & 0xFF) as _];
hasher.input(&extra_bits);
blob.extend_from_slice(&hasher.fixed_result()[..]);
extra += 1;
}
blob.resize(byte_count, 0);
blob
}
/// Create a discriminant from a seed (a byte string) and a bit length (a
/// `u16`). The discriminant is guaranteed to be a negative prime number that
/// fits in `length` bits, except with negligible probability (less than
/// 2^(-100)). It is also guaranteed to equal 7 modulo 8.
///
/// This function uses sha256 to expand the seed. Therefore, different seeds
/// will result in completely different discriminants with overwhelming
/// probability, unless `length` is very small. However, this function is
/// deterministic: if it is called twice with identical seeds and lengths, it
/// will always return the same discriminant.
///
/// This function is guaranteed not to panic for any inputs whatsoever, unless
/// memory allocation fails and the allocator in use panics in that case.
pub fn create_discriminant<T: BigNumExt>(seed: &[u8], length: u16) -> T {
let (mut n, residue) = {
// The number of “extra” bits (that dont evenly fit in a byte)
let extra: u8 = (length as u8) & 7;
// The number of random bytes needed (the number of bytes that hold `length`
// bits, plus 2).
let random_bytes_len = ((usize::from(length) + 7) >> 3) + 2;
let random_bytes = random_bytes_from_seed(seed, random_bytes_len);
let (n, last_2) = random_bytes.split_at(random_bytes_len - 2);
let numerator = (usize::from(last_2[0]) << 8) + usize::from(last_2[1]);
// If there are any extra bits, right shift `n` so that it fits
// in `length` bits, discarding the least significant bits.
let n = T::from(n) >> usize::from((8 - extra) & 7);
(n, RESIDUES[numerator % RESIDUES.len()])
};
n.setbit(usize::from(length - 1));
debug_assert!(n >= Zero::zero());
let rem = n.frem_u32(M);
// HACK HACK `rust-gmp` doesnt expose += and -= with i32 or i64
if residue > rem {
n = n + u64::from(residue - rem);
} else {
n = n - u64::from(rem - residue);
}
debug_assert!(n >= Zero::zero());
// This generates the smallest prime ≥ n that is of the form n + m*x.
loop {
// Speed up prime-finding by quickly ruling out numbers
// that are known to be composite.
let mut sieve = ::bit_vec::BitVec::from_elem(1 << 16, false);
for &(p, q) in SIEVE_INFO.iter() {
// The reference implementation changes the sign of `n` before taking its
// remainder. Instead, we leave `n` as positive, but use ceiling
// division instead of floor division. This is mathematically
// equivalent and potentially faster.
let mut i: usize = (n.crem_u16(p) as usize * q as usize) % p as usize;
while i < sieve.len() {
sieve.set(i, true);
i += p as usize;
}
}
for (i, x) in sieve.iter().enumerate() {
if !x {
let q = u64::from(M) * u64::from(i as u32);
n = n + q;
if n.probab_prime(1) {
return -n;
}
n = n - q;
}
}
// M is set to a number with many prime factors so the results are
// more uniform https://eprint.iacr.org/2011/481.pdf
// TODO: Explain previous reference to https://eprint.iacr.org/2011/401.pdf
n = n + (u64::from(M) * (1 << 16)) as u64
}
}
#[cfg(test)]
mod test {
use super::*;
use classgroup::{gmp_classgroup::GmpClassGroup, ClassGroup};
type Mpz = <GmpClassGroup as ClassGroup>::BigNum;
use std::str::FromStr;
#[test]
fn check_discriminant_1() {
assert_eq!(
create_discriminant::<Mpz>(b"\xaa", 40),
(-685_537_176_559i64).into()
);
}
#[test]
fn check_discriminant_3() {
assert_eq!(
create_discriminant::<Mpz>(b"\xaa", 1024),
Mpz::from_str(
"-112084717443890964296630631725167420667316836131914185144761\
7438378168250988242739496385274308134767869324152361453294226\
8295868231081182819214054220080323345750407342623884342617809\
8794592117225058677336074005099949757067786815439982423354682\
0386024058617141397148586038290164093146862666602485017735298\
03183"
)
.unwrap()
)
}
#[test]
fn check_discriminant_2() {
assert_eq!(
create_discriminant::<Mpz>(b"\xaa", 2048),
-Mpz::from_str(
"201493927071865251625903550712920535753645598483515670853547009\
878440933309489362800393797428711071833308081461824159206915864\
150805748296170245037221957772328044276705571745811271212292422\
075849739248257870371300001313586036515879618764093772248760562\
386804073478433157526816295216137723803793411828867470089409596\
238958950007370719325959579892866588928887249912429688364409867\
895510817680171869190054122881274299350947669820596157115994418\
034091728887584373727555384075665624624856766441009974642693066\
751400054217209981490667208950669417773785631693879782993019167\
69407006303085854796535778826115224633447713584423"
)
.unwrap()
);
}
#[test]
fn check_random_bytes() {
assert_eq!(
&random_bytes_from_seed(b"\xaa", 7),
b"\x9f\x9d*\xe5\xe7<\xcb"
);
assert_eq!(
&random_bytes_from_seed(b"\xaa", 258)[..],
&b"\x9f\x9d*\xe5\xe7<\xcbq\xa4q\x8e\
\xbc\xf0\xe3:\xa2\x98\xf8\xbd\xdc\xaa\xcbi\xcb\x10\xff\x0e\xafv\xdb\xec!\xc4K\
\xc6Jf\xf3\xa5\xda.7\xb7\xef\x87I\x85\xb8YX\xfc\xf2\x03\xa1\x8f4\xaf`\xab\xae]n\
\xcc,g1\x12EI\xc7\xd5\xe2\xfc\x8b\x9a\xde\xd5\xf3\x8f'\xcd\x08\x0fU\xc7\xee\xa85\
[>\x87]\x07\x82\x00\x13\xce\xf7\xc3/@\xef\x08v\x8f\x85\x87dm(1\x8b\xd9w\xffA]xzY\
\xa0,\xebz\xff\x03$`\x91\xb66\x88-_\xa9\xf1\xc5\x8e,\x15\xae\x8f\x04\rvhnU3f\x84\
[{$\xa6l\x95w\xa9\x1f\xba\xa8)\x05\xe6\x8f\x167o\x11/X\x9cl\xab\x9c\xcb}\xec\x88\
\xf8\xa5\xabXpY\xb0\x88\xed@r\x05\xba\\\x03\xf6\x91\xf8\x03\xca\x18\x1c\xcdH\x1c\
\x91\xe1V\xed;\x94oJ\xa8 \xa4\x97\xb7K\xce\xc4e\xea\xa2\xbf\x8b\x1f\x90\x87\xc8\
\x15\xee\x0e\x0fPC:\xb5\xe1g\x97\xea/_\x86c\xaf\x12Wp\xfd\x11\xdb\x17\xe6\x9f\
\xa5\x8a"[..]
);
}
}

261
crates/vdf/src/lib.rs Normal file
View File

@ -0,0 +1,261 @@
// 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(warnings)]
//! # Rust implementations of class groups and verifyable delay functions
//!
//! This repo includes three crates
//!
//! * `classgroup`, which includes a class group implementation, as well as a
//! trait for class groups.
//! * `vdf`, which includes a Verifyable Delay Function (VDF) trait, as well as
//! an implementation of that trait.
//! * `vdf-cli`, which includes a command-line interface to the `vdf` crate. It
//! also includes additional commands, which are deprecated and will later be
//! replaced by a CLI to the `classgroup` crate.
//!
//! ## Usage
//!
//! First, install Rust, Cargo, and the GNU Multiprecision Library (GMP). Then,
//! follow one of the below steps.
//!
//! ### To use the command line interface
//!
//! ```sh
//! $ git clone https://github.com/poanetwork/vdf
//! $ cd vdf
//! $ cargo install
//! $ vdf-cli aa 100
//! 005271e8f9ab2eb8a2906e851dfcb5542e4173f016b85e29d481a108dc82ed3b3f97937b7aa824801138d1771dea8dae2f6397e76a80613afda30f2c30a34b040baaafe76d5707d68689193e5d211833b372a6a4591abb88e2e7f2f5a5ec818b5707b86b8b2c495ca1581c179168509e3593f9a16879620a4dc4e907df452e8dd0ffc4f199825f54ec70472cc061f22eb54c48d6aa5af3ea375a392ac77294e2d955dde1d102ae2ace494293492d31cff21944a8bcb4608993065c9a00292e8d3f4604e7465b4eeefb494f5bea102db343bb61c5a15c7bdf288206885c130fa1f2d86bf5e4634fdc4216bc16ef7dac970b0ee46d69416f9a9acee651d158ac64915b
//! $ vdf-cli aa 100 005271e8f9ab2eb8a2906e851dfcb5542e4173f016b85e29d481a108dc82ed3b3f97937b7aa824801138d1771dea8dae2f6397e76a80613afda30f2c30a34b040baaafe76d5707d68689193e5d211833b372a6a4591abb88e2e7f2f5a5ec818b5707b86b8b2c495ca1581c179168509e3593f9a16879620a4dc4e907df452e8dd0ffc4f199825f54ec70472cc061f22eb54c48d6aa5af3ea375a392ac77294e2d955dde1d102ae2ace494293492d31cff21944a8bcb4608993065c9a00292e8d3f4604e7465b4eeefb494f5bea102db343bb61c5a15c7bdf288206885c130fa1f2d86bf5e4634fdc4216bc16ef7dac970b0ee46d69416f9a9acee651d158ac64915b
//! Proof is valid
//! ```
//!
//! ### To use the VDF library
//!
//! ```rust
//! extern crate vdf;
//! use vdf::{InvalidProof, PietrzakVDFParams, VDFParams, WesolowskiVDFParams, VDF};
//! const CORRECT_SOLUTION: &[u8] =
//! b"\x00\x52\x71\xe8\xf9\xab\x2e\xb8\xa2\x90\x6e\x85\x1d\xfc\xb5\x54\x2e\x41\x73\xf0\x16\
//! \xb8\x5e\x29\xd4\x81\xa1\x08\xdc\x82\xed\x3b\x3f\x97\x93\x7b\x7a\xa8\x24\x80\x11\x38\
//! \xd1\x77\x1d\xea\x8d\xae\x2f\x63\x97\xe7\x6a\x80\x61\x3a\xfd\xa3\x0f\x2c\x30\xa3\x4b\
//! \x04\x0b\xaa\xaf\xe7\x6d\x57\x07\xd6\x86\x89\x19\x3e\x5d\x21\x18\x33\xb3\x72\xa6\xa4\
//! \x59\x1a\xbb\x88\xe2\xe7\xf2\xf5\xa5\xec\x81\x8b\x57\x07\xb8\x6b\x8b\x2c\x49\x5c\xa1\
//! \x58\x1c\x17\x91\x68\x50\x9e\x35\x93\xf9\xa1\x68\x79\x62\x0a\x4d\xc4\xe9\x07\xdf\x45\
//! \x2e\x8d\xd0\xff\xc4\xf1\x99\x82\x5f\x54\xec\x70\x47\x2c\xc0\x61\xf2\x2e\xb5\x4c\x48\
//! \xd6\xaa\x5a\xf3\xea\x37\x5a\x39\x2a\xc7\x72\x94\xe2\xd9\x55\xdd\xe1\xd1\x02\xae\x2a\
//! \xce\x49\x42\x93\x49\x2d\x31\xcf\xf2\x19\x44\xa8\xbc\xb4\x60\x89\x93\x06\x5c\x9a\x00\
//! \x29\x2e\x8d\x3f\x46\x04\xe7\x46\x5b\x4e\xee\xfb\x49\x4f\x5b\xea\x10\x2d\xb3\x43\xbb\
//! \x61\xc5\xa1\x5c\x7b\xdf\x28\x82\x06\x88\x5c\x13\x0f\xa1\xf2\xd8\x6b\xf5\xe4\x63\x4f\
//! \xdc\x42\x16\xbc\x16\xef\x7d\xac\x97\x0b\x0e\xe4\x6d\x69\x41\x6f\x9a\x9a\xce\xe6\x51\
//! \xd1\x58\xac\x64\x91\x5b";
//!
//! fn main() {
//! let pietrzak_vdf = PietrzakVDFParams(2048).new();
//! assert_eq!(
//! &pietrzak_vdf.solve(b"\xaa", 100).unwrap()[..],
//! CORRECT_SOLUTION
//! );
//! assert!(pietrzak_vdf.verify(b"\xaa", 100, CORRECT_SOLUTION).is_ok());
//! }
//! ```
//!
//! ### To run the benchmarks
//!
//! Benchmarks are provided for the classgroup operations. Run `cargo bench`
//! to run them. Additional benchmarks are under development.
use classgroup;
mod create_discriminant;
use std::fmt::Debug;
pub use self::{
create_discriminant::create_discriminant,
proof_pietrzak::{PietrzakVDF, PietrzakVDFParams},
proof_wesolowski::{WesolowskiVDF, WesolowskiVDFParams},
};
/// Message used to report an internal miscalculation of serialization buffer
/// sizes.
const INCORRECT_BUFFER_SIZE: &str =
"internal error: incorrect buffer size calculation (this is a bug)";
mod proof_of_time;
mod proof_pietrzak;
mod proof_wesolowski;
uniffi::include_scaffolding!("lib");
/// An empty struct indicating verification failure.
///
/// For security reasons, the functions that perform verification *do not*
/// return any information on failure. Use `VDF::validate_params` to check if
/// the parameters are correct.
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Debug)]
pub struct InvalidProof;
/// An error return indicating an invalid number of iterations. The string is a
/// human-readable message describing the valid iterations. It should not be
/// interpreted by programs.
#[derive(Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Debug)]
pub struct InvalidIterations(String);
/// The type of VDF parameters.
///
/// Parameters represent public information that can be shared by all users
/// of the protocol. As such, they must implement `Clone`, so that they can
/// be duplicated. They also must implement `Send`, so that a parallel
/// application can send them safely across threads.
///
/// The parameters *do not* include the difficulty level (usually an
/// iteration count), since that can be separate for each invocation.
///
/// This must implement `Clone` and `Eq`.
pub trait VDFParams: Clone + Eq {
type VDF: VDF + Sized;
/// Creates an instance of this VDF from the given parameters.
///
/// # Performance
///
/// This method is expected to be fairly cheap. For example, it is okay if
/// it allocates memory, but it should not perform expensive computations or
/// I/O.
///
/// # Panics
///
/// This method **MUST NOT** fail due to invalid values for `params`. Such
/// errors should be checked by the factory functions for `Self::Params`.
///
/// This function **MAY** panic for other reasons. For example, it is
/// allowed to panic if an allocation fails, or if a needed external library
/// could not be dynamically loaded.
fn new(self) -> Self::VDF;
}
/// A Verifiable Delay Function (VDF).
///
/// VDFs are problems that require a certain amount of time to solve, even on a
/// parallel machine, but can be validated much more easily.
///
/// While VDFs are considered to be cryptographic primitives, they generally do
/// *not* operate on highly sensitive data. As such, implementers of this trait
/// **do not** guarantee that they will be immune to side-channel attacks, and
/// consumers of this trait **MUST NOT** expect this.
///
/// Instances of this trait are *not* expected to be `Sync`. This allows them
/// to reuse allocations (such as scratch memory) accross invocations without
/// the need for locking. However, they **MUST** be `Send` and `Clone`, so that
/// consumers can duplicate them and send them across threads.
pub trait VDF: Send + Debug {
/// Solve an instance of this VDF, with challenge `challenge` and difficulty
/// `difficulty`.
///
/// The output is to be returned in a `Vec<u8>`, so it can be stored to disk
/// or sent over the network.
///
/// # Challenge format
///
/// The challenge is an opaque byte string of arbitrary length.
/// Implementors **MUST NOT** make any assumptions about its contents,
/// and **MUST** produce distinct outputs for distinct challenges
/// (except with negiligible probability).
///
/// This can be most easily implemented by using the challenge as part of
/// the input of a cryptographic hash function. The VDFs provided in this
/// crate use this strategy.
///
/// The difficulty must be checked before performing any expensive
/// computations.
///
/// Most applications will generate the challenge using a
/// cryptographically-secure pseudorandom number generator, but implementors
/// **MUST NOT** rely on this. In particular, this function must be secure
/// even if `challenge` is chosen by an adversary. Excessive values for
/// `difficulty` may cause excessive resource consumption, but must not
/// create any other vulnerabilities.
///
/// # Complexity
///
/// The VDFs in this crate consume memory that does not depend on
/// `difficulty`, and time linearly proportional to `difficulty`.
/// Implementors of this trait should document the resource use.
///
/// # Purity
///
/// This method must have no side effects. In particular, it must be
/// **deterministic**: it must always return the same output for the same
/// inputs, except with negligible probability. Furthermore, while it may
/// change `self` via interior mutability, such changes must not affect
/// future calls to this method, `Self::check_difficulty`, or
/// `Self::verify`. They *may* affect the `Debug` output.
fn solve(&self, challenge: &[u8], difficulty: u64) -> Result<Vec<u8>, InvalidIterations>;
/// Check that the difficulty is valid.
///
/// This must return `Ok` if and only if `difficulty` is valid. Otherwise,
/// it must return `Err`.
///
/// # Rationale
///
/// It would be more ideomatic Rust to use the type system to enforce that a
/// difficulty has been validated before use. However, I (Demi) have not
/// yet figured out an object-safe way to do so.
fn check_difficulty(&self, difficulty: u64) -> Result<(), InvalidIterations>;
/// Verifies an alleged solution of this VDF, with challenge `challenge` and
/// difficulty `difficulty`. Return `Ok(())` on success, or
/// `Err(InvalidProof)` on failure.
///
/// This function *does not* return any extended error information for
/// security reasons. To check that the difficulty is correct, call
/// `Self::check_difficulty`.
///
/// # Uniqueness of valid solutions
///
/// For any `(challenge, difficulty)` tuple, there must be at most one
/// `alleged_solution` (as measured by `Eq`) that causes this function to
/// return `Ok(())`. If the difficulty is valid (as determined by
/// `check_difficulty`), there must be exactly one such solution; otherwise,
/// there must be none.
///
/// # Purity
///
/// This method must have no side effects. In particular, it must be
/// **deterministic**: it must always return the same output for the same
/// inputs. Furthermore, while it may change `self` via interior
/// mutability, such changes must not affect future calls to this method,
/// `Self::prove`, or `Self::check_difficulty`. Such changes **MAY** affect
/// debugging output.
fn verify(
&self,
challenge: &[u8],
difficulty: u64,
alleged_solution: &[u8],
) -> Result<(), InvalidProof>;
}
/// Solve and prove with the Wesolowski VDF using the given parameters.
/// Outputs the concatenated solution and proof (in this order).
pub fn wesolowski_solve(int_size_bits: u16, challenge: &[u8], difficulty: u32) -> Vec<u8> {
let vdf = WesolowskiVDFParams(int_size_bits).new();
vdf.solve(challenge, difficulty.into()).expect("invalid difficulty")
}
/// Verify with the Wesolowski VDF using the given parameters.
/// `alleged_solution` is the output of `wesolowski_solve`.
pub fn wesolowski_verify(int_size_bits: u16, challenge: &[u8], difficulty: u32, alleged_solution: &[u8]) -> bool {
let vdf = WesolowskiVDFParams(int_size_bits).new();
vdf.verify(challenge, difficulty.into(), alleged_solution).is_ok()
}

4
crates/vdf/src/lib.udl Normal file
View File

@ -0,0 +1,4 @@
namespace vdf {
sequence<u8> wesolowski_solve(u16 int_size_bits, [ByRef] sequence<u8> challenge, u32 difficulty);
boolean wesolowski_verify(u16 int_size_bits, [ByRef] sequence<u8> challenge, u32 difficulty, [ByRef] sequence<u8> alleged_solution);
};

View File

@ -0,0 +1,88 @@
// 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.
use super::classgroup::ClassGroup;
use std::{collections::HashMap, usize};
pub fn serialize<V: ClassGroup>(proof: &[V], y: &V, int_size_bits: usize) -> Vec<u8> {
let proof_len = proof.len();
let element_length = 2 * ((int_size_bits + 16) >> 4);
let proof_len_in_bytes = (proof_len + 1) * element_length;
let mut v = vec![0; proof_len_in_bytes];
y.serialize(&mut v[0..element_length])
.expect(super::INCORRECT_BUFFER_SIZE);
for (index, group) in proof.iter().enumerate() {
let offset = (index + 1) * element_length;
group
.serialize(&mut v[offset..offset + element_length])
.expect(super::INCORRECT_BUFFER_SIZE)
}
v
}
pub fn deserialize_proof<T>(
proof_blob: &[u8],
discriminant: &T::BigNum,
orig_length: usize,
) -> Result<Vec<T>, ()>
where
T: ClassGroup,
for<'a, 'b> &'a T: std::ops::Mul<&'b T, Output = T>,
for<'a, 'b> &'a T::BigNum: std::ops::Mul<&'b T::BigNum, Output = T::BigNum>,
{
let length = T::size_in_bits(discriminant);
if length > usize::MAX - 16 {
return Err(());
}
let length = (length + 16) >> 4;
if length == 0 {
return Err(());
}
if orig_length != length {
return Err(());
}
let length = length * 2;
let proof_blob_length = proof_blob.len();
let rem = proof_blob_length % length;
if rem != 0 {
return Err(());
}
let proof_len = proof_blob_length / length;
let mut v = Vec::with_capacity(proof_len);
for i in 0..proof_len {
let offset = i * length;
v.push(T::from_bytes(
&proof_blob[offset..offset + length],
discriminant.clone(),
))
}
Ok(v)
}
pub fn iterate_squarings<V, U>(mut x: V, powers_to_calculate: U) -> HashMap<u64, V>
where
V: ClassGroup,
for<'a, 'b> &'a V: std::ops::Mul<&'b V, Output = V>,
for<'a, 'b> &'a V::BigNum: std::ops::Mul<&'b V::BigNum, Output = V::BigNum>,
U: Iterator<Item = u64>,
{
let mut powers_calculated = HashMap::new();
let mut powers_to_calculate: Vec<u64> = powers_to_calculate.collect();
powers_to_calculate.sort_unstable();
let mut previous_power: u64 = 0;
for &current_power in &powers_to_calculate {
x.repeated_square(current_power - previous_power);
powers_calculated.insert(current_power, x.clone());
previous_power = current_power
}
powers_calculated
}

View File

@ -0,0 +1,466 @@
// 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.
use super::proof_of_time::{deserialize_proof, iterate_squarings, serialize};
use classgroup::{gmp_classgroup::GmpClassGroup, BigNumExt, ClassGroup};
use num_traits::{One, Zero};
use std::{fmt, num::ParseIntError, ops::Index, str::FromStr, u64, usize};
#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone, Debug)]
pub struct Iterations(u64);
#[derive(PartialEq, Eq, Hash, Ord, PartialOrd, Copy, Clone, Debug)]
pub enum InvalidIterations {
OddNumber(u64),
LessThan66(u64),
}
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct ParseIterationsError {
kind: Result<InvalidIterations, ParseIntError>,
}
impl From<InvalidIterations> for ParseIterationsError {
fn from(t: InvalidIterations) -> Self {
Self { kind: Ok(t) }
}
}
impl From<ParseIntError> for ParseIterationsError {
fn from(t: ParseIntError) -> Self {
Self { kind: Err(t) }
}
}
impl fmt::Display for InvalidIterations {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
InvalidIterations::OddNumber(s) => {
write!(f, "Pietrzak iterations must be an even number, not {}", s)
}
InvalidIterations::LessThan66(s) => write!(
f,
"Pietrzak proof-of-time must run for at least 66 iterations, not {}",
s
),
}
}
}
impl From<Iterations> for u64 {
fn from(t: Iterations) -> u64 {
t.0
}
}
impl fmt::Display for ParseIterationsError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.kind {
Ok(ref q) => <InvalidIterations as fmt::Display>::fmt(q, f),
Err(ref q) => <ParseIntError as fmt::Display>::fmt(q, f),
}
}
}
impl FromStr for Iterations {
type Err = ParseIterationsError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::new(s.parse::<u64>().map_err(ParseIterationsError::from)?)
.map_err(ParseIterationsError::from)
}
}
impl Iterations {
pub fn new<T: Into<u64>>(iterations: T) -> Result<Iterations, InvalidIterations> {
let iterations = iterations.into();
if iterations & 1 != 0 {
Err(InvalidIterations::OddNumber(iterations))
} else if iterations < 66 {
Err(InvalidIterations::LessThan66(iterations))
} else {
Ok(Iterations(iterations))
}
}
}
/// Selects a reasonable choice of cache size.
fn approximate_i(t: Iterations) -> u64 {
let x: f64 = (((t.0 >> 1) as f64) / 8.) * 2.0f64.ln();
let w = x.ln() - x.ln().ln() + 0.25;
(w / (2. * 2.0f64.ln())).round() as _
}
fn sum_combinations<'a, T: IntoIterator<Item = &'a u64>>(numbers: T) -> Vec<u64> {
let mut combinations = vec![0];
for i in numbers {
let mut new_combinations = combinations.clone();
for j in combinations {
new_combinations.push(i + j)
}
combinations = new_combinations
}
combinations.remove(0);
combinations
}
fn cache_indices_for_count(t: Iterations) -> Vec<u64> {
let i: u64 = approximate_i(t);
let mut curr_t = t.0;
let mut intermediate_ts = vec![];
for _ in 0..i {
curr_t >>= 1;
intermediate_ts.push(curr_t);
if curr_t & 1 != 0 {
curr_t += 1
}
}
let mut cache_indices = sum_combinations(&intermediate_ts);
cache_indices.sort();
cache_indices.push(t.0);
cache_indices
}
fn generate_r_value<T>(x: &T, y: &T, sqrt_mu: &T, int_size_bits: usize) -> T::BigNum
where
T: ClassGroup,
for<'a, 'b> &'a T: std::ops::Mul<&'b T, Output = T>,
for<'a, 'b> &'a T::BigNum: std::ops::Mul<&'b T::BigNum, Output = T::BigNum>,
{
use sha2::{digest::FixedOutput, Digest, Sha256};
let size = (int_size_bits + 16) >> 4;
let mut v = Vec::with_capacity(size * 2);
for _ in 0..size * 2 {
v.push(0)
}
let mut hasher = Sha256::new();
for i in &[&x, &y, &sqrt_mu] {
i.serialize(&mut v).expect(super::INCORRECT_BUFFER_SIZE);
hasher.input(&v);
}
let res = hasher.fixed_result();
T::unsigned_deserialize_bignum(&res[..16])
}
fn create_proof_of_time_pietrzak<T>(
challenge: &[u8],
iterations: Iterations,
int_size_bits: u16,
) -> Vec<u8>
where
T: ClassGroup,
<T as ClassGroup>::BigNum: BigNumExt,
for<'a, 'b> &'a T: std::ops::Mul<&'b T, Output = T>,
for<'a, 'b> &'a T::BigNum: std::ops::Mul<&'b T::BigNum, Output = T::BigNum>,
{
let discriminant = super::create_discriminant::create_discriminant(&challenge, int_size_bits);
let x = T::from_ab_discriminant(2.into(), 1.into(), discriminant);
let delta = 8;
let powers_to_calculate = cache_indices_for_count(iterations);
let powers = iterate_squarings(x.clone(), powers_to_calculate.iter().cloned());
let proof: Vec<T> = generate_proof(
x,
iterations,
delta,
&powers,
&generate_r_value,
usize::from(int_size_bits),
);
serialize(
&proof,
&powers[&iterations.into()],
usize::from(int_size_bits),
)
}
pub fn check_proof_of_time_pietrzak<T>(
challenge: &[u8],
proof_blob: &[u8],
iterations: u64,
length_in_bits: u16,
) -> Result<(), super::InvalidProof>
where
T: ClassGroup,
T::BigNum: BigNumExt,
for<'a, 'b> &'a T: std::ops::Mul<&'b T, Output = T>,
for<'a, 'b> &'a T::BigNum: std::ops::Mul<&'b T::BigNum, Output = T::BigNum>,
{
let discriminant = super::create_discriminant::create_discriminant(&challenge, length_in_bits);
let x = T::from_ab_discriminant(2.into(), 1.into(), discriminant);
let iterations = Iterations::new(iterations).map_err(|_| super::InvalidProof)?;
if usize::MAX - 16 < length_in_bits.into() {
// Proof way too long.
return Err(super::InvalidProof);
}
let length: usize = (usize::from(length_in_bits) + 16usize) >> 4;
if proof_blob.len() < 2 * length {
// Invalid length of proof
return Err(super::InvalidProof);
}
let result_bytes = &proof_blob[..length * 2];
let proof_bytes = &proof_blob[length * 2..];
let discriminant = x.discriminant().clone();
let proof =
deserialize_proof(proof_bytes, &discriminant, length).map_err(|()| super::InvalidProof)?;
let y = T::from_bytes(result_bytes, discriminant);
verify_proof(
&x,
&y,
proof,
iterations,
8,
&generate_r_value,
length_in_bits.into(),
)
.map_err(|()| super::InvalidProof)
}
fn calculate_final_t(t: Iterations, delta: usize) -> u64 {
let mut curr_t = t.0;
let mut ts = vec![];
while curr_t != 2 {
ts.push(curr_t);
curr_t >>= 1;
if curr_t & 1 == 1 {
curr_t += 1
}
}
ts.push(2);
ts.push(1);
assert!(ts.len() >= delta);
ts[ts.len() - delta]
}
pub fn generate_proof<T, U, V>(
x: V,
iterations: Iterations,
delta: usize,
powers: &T,
generate_r_value: &U,
int_size_bits: usize,
) -> Vec<V>
where
T: for<'a> Index<&'a u64, Output = V>,
U: Fn(&V, &V, &V, usize) -> V::BigNum,
V: ClassGroup,
for<'a, 'b> &'a V: std::ops::Mul<&'b V, Output = V>,
for<'a, 'b> &'a V::BigNum: std::ops::Mul<&'b V::BigNum, Output = V::BigNum>,
{
let identity = x.identity();
let i = approximate_i(iterations);
let mut mus = vec![];
let mut rs: Vec<V::BigNum> = vec![];
let mut x_p = vec![x];
let mut curr_t = iterations.0;
let mut y_p = vec![powers[&curr_t].clone()];
let mut ts = vec![];
let final_t = calculate_final_t(iterations, delta);
let mut round_index = 0;
while curr_t != final_t {
assert_eq!(curr_t & 1, 0);
let half_t = curr_t >> 1;
ts.push(half_t);
assert!(round_index < 63);
let denominator: u64 = 1 << (round_index + 1);
mus.push(if round_index < i {
let mut mu = identity.clone();
for numerator in (1..denominator).step_by(2) {
let num_bits = 62 - denominator.leading_zeros() as usize;
let mut r_prod: V::BigNum = One::one();
for b in (0..num_bits).rev() {
if 0 == (numerator & (1 << (b + 1))) {
r_prod *= &rs[num_bits - b - 1]
}
}
let mut t_sum = half_t;
for b in 0..num_bits {
if 0 != (numerator & (1 << (b + 1))) {
t_sum += ts[num_bits - b - 1]
}
}
let mut power = powers[&t_sum].clone();
power.pow(r_prod);
mu *= &power;
}
mu
} else {
let mut mu = x_p.last().unwrap().clone();
for _ in 0..half_t {
mu *= &mu.clone()
}
mu
});
let mut mu: V = mus.last().unwrap().clone();
let last_r: V::BigNum = generate_r_value(&x_p[0], &y_p[0], &mu, int_size_bits);
assert!(last_r >= Zero::zero());
rs.push(last_r.clone());
{
let mut last_x: V = x_p.last().unwrap().clone();
last_x.pow(last_r.clone());
last_x *= &mu;
x_p.push(last_x);
}
mu.pow(last_r);
mu *= y_p.last().unwrap();
y_p.push(mu);
curr_t >>= 1;
if curr_t & 1 != 0 {
curr_t += 1;
y_p.last_mut().unwrap().square();
}
round_index += 1
}
if cfg!(debug_assertions) {
let mut last_y = y_p.last().unwrap().clone();
let mut last_x = x_p.last().unwrap().clone();
let one: V::BigNum = 1u64.into();
last_y.pow(one.clone());
assert_eq!(last_y, y_p.last().unwrap().clone());
last_x.pow(one << final_t as usize);
}
mus
}
pub fn verify_proof<T, U, V>(
x_initial: &V,
y_initial: &V,
proof: T,
t: Iterations,
delta: usize,
generate_r_value: &U,
int_size_bits: usize,
) -> Result<(), ()>
where
T: IntoIterator<Item = V>,
U: Fn(&V, &V, &V, usize) -> V::BigNum,
V: ClassGroup,
for<'a, 'b> &'a V: std::ops::Mul<&'b V, Output = V>,
for<'a, 'b> &'a V::BigNum: std::ops::Mul<&'b V::BigNum, Output = V::BigNum>,
{
let mut one: V::BigNum = One::one();
let (mut x, mut y): (V, V) = (x_initial.clone(), y_initial.clone());
let final_t = calculate_final_t(t, delta);
let mut curr_t = t.0;
for mut mu in proof {
assert!(
curr_t & 1 == 0,
"Cannot have an odd number of iterations remaining"
);
let r = generate_r_value(x_initial, y_initial, &mu, int_size_bits);
x.pow(r.clone());
x *= &mu;
mu.pow(r);
y *= &mu;
curr_t >>= 1;
if curr_t & 1 != 0 {
curr_t += 1;
y.square();
}
}
one <<= final_t as _;
x.pow(one);
if x == y {
Ok(())
} else {
Err(())
}
}
#[derive(Debug, Clone)]
pub struct PietrzakVDF {
int_size_bits: u16,
}
use super::InvalidIterations as Bad;
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Debug)]
pub struct PietrzakVDFParams(pub u16);
impl super::VDFParams for PietrzakVDFParams {
type VDF = PietrzakVDF;
fn new(self) -> Self::VDF {
PietrzakVDF {
int_size_bits: self.0,
}
}
}
impl super::VDF for PietrzakVDF {
fn check_difficulty(&self, difficulty: u64) -> Result<(), Bad> {
Iterations::new(difficulty)
.map_err(|x| Bad(format!("{}", x)))
.map(drop)
}
fn solve(&self, challenge: &[u8], difficulty: u64) -> Result<Vec<u8>, Bad> {
Ok(create_proof_of_time_pietrzak::<GmpClassGroup>(
challenge,
Iterations::new(difficulty).map_err(|x| Bad(format!("{}", x)))?,
self.int_size_bits,
))
}
fn verify(
&self,
challenge: &[u8],
difficulty: u64,
alleged_solution: &[u8],
) -> Result<(), super::InvalidProof> {
check_proof_of_time_pietrzak::<GmpClassGroup>(
challenge,
alleged_solution,
difficulty,
self.int_size_bits,
)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn check_approximate_i() {
assert_eq!(approximate_i(Iterations(534)), 2);
assert_eq!(approximate_i(Iterations(134)), 1);
assert_eq!(approximate_i(Iterations(1024)), 2);
}
#[test]
fn check_cache_indices() {
assert_eq!(cache_indices_for_count(Iterations(66))[..], [33, 66]);
assert_eq!(
cache_indices_for_count(Iterations(534))[..],
[134, 267, 401, 534]
);
}
#[test]
fn check_calculate_final_t() {
assert_eq!(calculate_final_t(Iterations(1024), 8), 128);
assert_eq!(calculate_final_t(Iterations(1000), 8), 126);
assert_eq!(calculate_final_t(Iterations(100), 8), 100);
}
#[test]
fn check_assuptions_about_stdlib() {
assert_eq!(62 - u64::leading_zeros(1024u64), 9);
let mut q: Vec<_> = (1..4).step_by(2).collect();
assert_eq!(q[..], [1, 3]);
q = (1..3).step_by(2).collect();
assert_eq!(q[..], [1]);
q = (1..2).step_by(2).collect();
assert_eq!(q[..], [1]);
}
}

View File

@ -0,0 +1,316 @@
// Copyright 2018 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.
use super::proof_of_time::{iterate_squarings, serialize};
use classgroup::{gmp_classgroup::GmpClassGroup, BigNum, BigNumExt, ClassGroup};
use sha2::{digest::FixedOutput, Digest, Sha256};
use std::{cmp::Eq, collections::HashMap, hash::Hash, mem, u64, usize};
use std::convert::TryInto;
#[derive(Debug, Clone)]
pub struct WesolowskiVDF {
int_size_bits: u16,
}
use super::InvalidIterations as Bad;
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Debug)]
pub struct WesolowskiVDFParams(pub u16);
impl super::VDFParams for WesolowskiVDFParams {
type VDF = WesolowskiVDF;
fn new(self) -> Self::VDF {
WesolowskiVDF {
int_size_bits: self.0,
}
}
}
impl super::VDF for WesolowskiVDF {
fn check_difficulty(&self, _difficulty: u64) -> Result<(), Bad> {
Ok(())
}
fn solve(&self, challenge: &[u8], difficulty: u64) -> Result<Vec<u8>, Bad> {
if difficulty > usize::MAX as u64 {
Err(Bad("Cannot have more that usize::MAX iterations".to_owned()))
} else {
Ok(create_proof_of_time_wesolowski::<
<GmpClassGroup as ClassGroup>::BigNum,
GmpClassGroup,
>(
challenge, difficulty as usize, self.int_size_bits
))
}
}
fn verify(
&self,
challenge: &[u8],
difficulty: u64,
alleged_solution: &[u8],
) -> Result<(), super::InvalidProof> {
check_proof_of_time_wesolowski::<<GmpClassGroup as ClassGroup>::BigNum, GmpClassGroup>(
challenge,
alleged_solution,
difficulty,
self.int_size_bits,
)
.map_err(|()| super::InvalidProof)
}
}
/// To quote the original Python code:
///
/// > Create `L` and `k` parameters from papers, based on how many iterations
/// > need to be performed, and how much memory should be used.
pub fn approximate_parameters(t: f64) -> (usize, u8, u64) {
let log_memory = (10_000_000.0f64).log2();
let log_t = (t as f64).log2();
let l = if log_t - log_memory > 0. {
2.0f64.powf(log_memory - 20.).ceil()
} else {
1.
};
let intermediate = t * (2.0f64).ln() / (2.0 * l);
let k = (intermediate.ln() - intermediate.ln().ln() + 0.25)
.round()
.max(1.);
let w = (t / (t / k + l * (2.0f64).powf(k + 1.0)) - 2.0).floor();
(l as _, k as _, w as _)
}
fn u64_to_bytes(q: u64) -> [u8; 8] {
if false {
// This use of `std::mem::transumte` is correct, but still not justified.
unsafe { std::mem::transmute(q.to_be()) }
} else {
[
(q >> 56) as u8,
(q >> 48) as u8,
(q >> 40) as u8,
(q >> 32) as u8,
(q >> 24) as u8,
(q >> 16) as u8,
(q >> 8) as u8,
q as u8,
]
}
}
/// Quote:
///
/// > Creates a random prime based on input s.
fn hash_prime<T: BigNum>(seed: &[&[u8]], t: u32) -> T {
let mut j = 0u64;
loop {
let mut hasher = Sha256::new();
hasher.input(b"prime");
hasher.input(u64_to_bytes(j));
for i in seed {
hasher.input(i);
}
hasher.input(t.to_be_bytes());
let n = T::from(&hasher.fixed_result()[..16]);
if n.probab_prime(1) {
break n;
}
j += 1;
}
}
/// Quote:
///
/// > Get“s the ith block of `2^T // B`, such that `sum(get_block(i) * 2^(k*i))
/// > = t^T // B`
fn get_block<T: BigNumExt>(i: u64, k: u8, t: u64, b: &T) -> T {
let mut res = T::from(0);
let two = T::from(2);
res.mod_powm(&two, &T::from(t - u64::from(k) * (i + 1)), b);
res *= &((two >> 1) << (k as usize));
res / b
}
fn eval_optimized<T, U: BigNumExt, L: ClassGroup<BigNum = U> + Eq + Hash>(
h: &L,
b: &U,
t: usize,
k: u8,
l: usize,
powers: &T,
) -> L
where
T: for<'a> std::ops::Index<&'a u64, Output = L>,
{
assert!(k > 0, "k cannot be zero");
assert!(l > 0, "l cannot be zero");
let kl = (k as usize)
.checked_mul(l)
.expect("computing k*l overflowed a u64");
assert!(kl <= u64::MAX as _);
assert!((kl as u64) < (1u64 << 53), "k*l overflowed an f64");
assert!((t as u64) < (1u64 << 53), "t overflows an f64");
assert!(
k < (mem::size_of::<usize>() << 3) as u8,
"k must be less than the number of bits in a usize"
);
let k1 = k >> 1;
let k0 = k - k1;
let mut x = h.identity();
let identity = h.identity();
let k_exp = 1usize << k;
let k0_exp = 1usize << k0;
let k1_exp = 1usize << k1;
for j in (0..l).rev() {
x.pow(U::from(k_exp as u64));
let mut ys: HashMap<U, L> = HashMap::new();
for b in 0..1usize << k {
ys.entry(U::from(b as u64))
.or_insert_with(|| identity.clone());
}
let end_of_loop = ((t as f64) / kl as f64).ceil() as usize;
assert!(end_of_loop == 0 || (end_of_loop as u64 - 1).checked_mul(l as u64).is_some());
for i in 0..end_of_loop {
if t < k as usize * (i * l + j + 1) {
continue;
}
let b = get_block((i as u64) * (l as u64), k, t as _, b);
*ys.get_mut(&b).unwrap() *= &powers[&((i * kl) as _)];
}
for b1 in 0..k1_exp {
let mut z = identity.clone();
for b0 in 0..k0_exp {
z *= &ys[&U::from((b1 * k0_exp + b0) as u64)]
}
z.pow(U::from((b1 as u64) * (k0_exp as u64)));
x *= &z;
}
for b0 in 0..k0_exp {
let mut z = identity.clone();
for b1 in 0..k1_exp {
z *= &ys[&U::from((b1 * k0_exp + b0) as u64)];
}
z.pow(U::from(b0 as u64));
x *= &z;
}
}
x
}
pub fn generate_proof<U, T: BigNumExt, V: ClassGroup<BigNum = T> + Eq + Hash>(
x: &V,
iterations: u64,
k: u8,
l: usize,
powers: &U,
int_size_bits: usize,
) -> V
where
U: for<'a> std::ops::Index<&'a u64, Output = V>,
{
let element_len = 2 * ((int_size_bits + 16) >> 4);
let mut x_buf = vec![0; element_len];
x.serialize(&mut x_buf[..])
.expect(super::INCORRECT_BUFFER_SIZE);
let mut y_buf = vec![0; element_len];
powers[&iterations]
.serialize(&mut y_buf[..])
.expect(super::INCORRECT_BUFFER_SIZE);
let b = hash_prime(
&[&x_buf[..], &y_buf[..]],
iterations.try_into().expect("iterations fit into u32")
);
eval_optimized(&x, &b, iterations as _, k, l, powers)
}
/// Verify a proof, according to the Wesolowski paper.
pub fn verify_proof<T: BigNum, V: ClassGroup<BigNum = T>>(
mut x: V,
y: &V,
mut proof: V,
t: u64,
int_size_bits: usize,
) -> Result<(), ()> {
let element_len = 2 * ((int_size_bits + 16) >> 4);
let mut x_buf = vec![0; element_len];
x.serialize(&mut x_buf[..])
.expect(super::INCORRECT_BUFFER_SIZE);
let mut y_buf = vec![0; element_len];
y.serialize(&mut y_buf[..])
.expect(super::INCORRECT_BUFFER_SIZE);
let b = hash_prime(
&[&x_buf[..], &y_buf[..]],
t.try_into().expect("iterations fit into u32")
);
let mut r = T::from(0);
r.mod_powm(&T::from(2u64), &T::from(t), &b);
proof.pow(b);
x.pow(r);
proof *= &x;
if &proof == y {
Ok(())
} else {
Err(())
}
}
pub fn create_proof_of_time_wesolowski<T: BigNumExt, V: ClassGroup<BigNum = T> + Eq + Hash>(
challenge: &[u8],
iterations: usize,
int_size_bits: u16,
) -> Vec<u8>
where
for<'a, 'b> &'a V: std::ops::Mul<&'b V, Output = V>,
for<'a, 'b> &'a V::BigNum: std::ops::Mul<&'b V::BigNum, Output = V::BigNum>,
{
let discriminant = super::create_discriminant::create_discriminant(&challenge, int_size_bits);
let x = V::from_ab_discriminant(2.into(), 1.into(), discriminant);
assert!((iterations as u128) < (1u128 << 53));
let (l, k, _) = approximate_parameters(iterations as f64);
let q = l.checked_mul(k as _).expect("bug");
let powers = iterate_squarings(
x.clone(),
(0..=iterations / q + 1)
.map(|i| i * q)
.chain(Some(iterations))
.map(|x| x as _),
);
let proof = generate_proof(&x, iterations as _, k, l, &powers, int_size_bits.into());
serialize(&[proof], &powers[&(iterations as _)], int_size_bits.into())
}
pub fn check_proof_of_time_wesolowski<T: BigNum, V: ClassGroup<BigNum = T>>(
challenge: &[u8],
proof_blob: &[u8],
iterations: u64,
int_size_bits: u16,
) -> Result<(), ()>
where
T: BigNumExt,
{
let discriminant: T = super::create_discriminant::create_discriminant(challenge, int_size_bits);
let x = V::from_ab_discriminant(2.into(), 1.into(), discriminant.clone());
if (usize::MAX - 16) < int_size_bits.into() {
return Err(());
}
let int_size = (usize::from(int_size_bits) + 16) >> 4;
if int_size * 4 != proof_blob.len() {
return Err(());
}
let (result_bytes, proof_bytes) = proof_blob.split_at(2 * int_size);
let proof = ClassGroup::from_bytes(proof_bytes, discriminant.clone());
let y = ClassGroup::from_bytes(result_bytes, discriminant);
verify_proof(x, &y, proof, iterations, int_size_bits.into())
}

811
docker/rustup-init.sh Executable file
View File

@ -0,0 +1,811 @@
#!/bin/sh
# shellcheck shell=dash
# shellcheck disable=SC2039 # local is non-POSIX
# This is just a little script that can be downloaded from the internet to
# install rustup. It just does platform detection, downloads the installer
# and runs it.
# It runs on Unix shells like {a,ba,da,k,z}sh. It uses the common `local`
# extension. Note: Most shells limit `local` to 1 var per line, contra bash.
# Some versions of ksh have no `local` keyword. Alias it to `typeset`, but
# beware this makes variables global with f()-style function syntax in ksh93.
# mksh has this alias by default.
has_local() {
# shellcheck disable=SC2034 # deliberately unused
local _has_local
}
has_local 2>/dev/null || alias local=typeset
is_zsh() {
[ -n "${ZSH_VERSION-}" ]
}
set -u
# If RUSTUP_UPDATE_ROOT is unset or empty, default it.
RUSTUP_UPDATE_ROOT="${RUSTUP_UPDATE_ROOT:-https://static.rust-lang.org/rustup}"
# NOTICE: If you change anything here, please make the same changes in setup_mode.rs
usage() {
cat <<EOF
rustup-init 1.27.1 (a8e4f5c64 2024-04-24)
The installer for rustup
Usage: rustup-init[EXE] [OPTIONS]
Options:
-v, --verbose
Enable verbose output
-q, --quiet
Disable progress output
-y
Disable confirmation prompt.
--default-host <default-host>
Choose a default host triple
--default-toolchain <default-toolchain>
Choose a default toolchain to install. Use 'none' to not install any toolchains at all
--profile <profile>
[default: default] [possible values: minimal, default, complete]
-c, --component <components>...
Component name to also install
-t, --target <targets>...
Target name to also install
--no-update-default-toolchain
Don't update any existing default toolchain after install
--no-modify-path
Don't configure the PATH environment variable
-h, --help
Print help
-V, --version
Print version
EOF
}
main() {
downloader --check
need_cmd uname
need_cmd mktemp
need_cmd chmod
need_cmd mkdir
need_cmd rm
need_cmd rmdir
get_architecture || return 1
local _arch="$RETVAL"
assert_nz "$_arch" "arch"
local _ext=""
case "$_arch" in
*windows*)
_ext=".exe"
;;
esac
local _url="${RUSTUP_UPDATE_ROOT}/dist/${_arch}/rustup-init${_ext}"
local _dir
if ! _dir="$(ensure mktemp -d)"; then
# Because the previous command ran in a subshell, we must manually
# propagate exit status.
exit 1
fi
local _file="${_dir}/rustup-init${_ext}"
local _ansi_escapes_are_valid=false
if [ -t 2 ]; then
if [ "${TERM+set}" = 'set' ]; then
case "$TERM" in
xterm*|rxvt*|urxvt*|linux*|vt*)
_ansi_escapes_are_valid=true
;;
esac
fi
fi
# check if we have to use /dev/tty to prompt the user
local need_tty=yes
for arg in "$@"; do
case "$arg" in
--help)
usage
exit 0
;;
*)
OPTIND=1
if [ "${arg%%--*}" = "" ]; then
# Long option (other than --help);
# don't attempt to interpret it.
continue
fi
while getopts :hy sub_arg "$arg"; do
case "$sub_arg" in
h)
usage
exit 0
;;
y)
# user wants to skip the prompt --
# we don't need /dev/tty
need_tty=no
;;
*)
;;
esac
done
;;
esac
done
if $_ansi_escapes_are_valid; then
printf "\33[1minfo:\33[0m downloading installer\n" 1>&2
else
printf '%s\n' 'info: downloading installer' 1>&2
fi
ensure mkdir -p "$_dir"
ensure downloader "$_url" "$_file" "$_arch"
ensure chmod u+x "$_file"
if [ ! -x "$_file" ]; then
printf '%s\n' "Cannot execute $_file (likely because of mounting /tmp as noexec)." 1>&2
printf '%s\n' "Please copy the file to a location where you can execute binaries and run ./rustup-init${_ext}." 1>&2
exit 1
fi
if [ "$need_tty" = "yes" ] && [ ! -t 0 ]; then
# The installer is going to want to ask for confirmation by
# reading stdin. This script was piped into `sh` though and
# doesn't have stdin to pass to its children. Instead we're going
# to explicitly connect /dev/tty to the installer's stdin.
if [ ! -t 1 ]; then
err "Unable to run interactively. Run with -y to accept defaults, --help for additional options"
fi
ignore "$_file" "$@" < /dev/tty
else
ignore "$_file" "$@"
fi
local _retval=$?
ignore rm "$_file"
ignore rmdir "$_dir"
return "$_retval"
}
check_proc() {
# Check for /proc by looking for the /proc/self/exe link
# This is only run on Linux
if ! test -L /proc/self/exe ; then
err "fatal: Unable to find /proc/self/exe. Is /proc mounted? Installation cannot proceed without /proc."
fi
}
get_bitness() {
need_cmd head
# Architecture detection without dependencies beyond coreutils.
# ELF files start out "\x7fELF", and the following byte is
# 0x01 for 32-bit and
# 0x02 for 64-bit.
# The printf builtin on some shells like dash only supports octal
# escape sequences, so we use those.
local _current_exe_head
_current_exe_head=$(head -c 5 /proc/self/exe )
if [ "$_current_exe_head" = "$(printf '\177ELF\001')" ]; then
echo 32
elif [ "$_current_exe_head" = "$(printf '\177ELF\002')" ]; then
echo 64
else
err "unknown platform bitness"
fi
}
is_host_amd64_elf() {
need_cmd head
need_cmd tail
# ELF e_machine detection without dependencies beyond coreutils.
# Two-byte field at offset 0x12 indicates the CPU,
# but we're interested in it being 0x3E to indicate amd64, or not that.
local _current_exe_machine
_current_exe_machine=$(head -c 19 /proc/self/exe | tail -c 1)
[ "$_current_exe_machine" = "$(printf '\076')" ]
}
get_endianness() {
local cputype=$1
local suffix_eb=$2
local suffix_el=$3
# detect endianness without od/hexdump, like get_bitness() does.
need_cmd head
need_cmd tail
local _current_exe_endianness
_current_exe_endianness="$(head -c 6 /proc/self/exe | tail -c 1)"
if [ "$_current_exe_endianness" = "$(printf '\001')" ]; then
echo "${cputype}${suffix_el}"
elif [ "$_current_exe_endianness" = "$(printf '\002')" ]; then
echo "${cputype}${suffix_eb}"
else
err "unknown platform endianness"
fi
}
# Detect the Linux/LoongArch UAPI flavor, with all errors being non-fatal.
# Returns 0 or 234 in case of successful detection, 1 otherwise (/tmp being
# noexec, or other causes).
check_loongarch_uapi() {
need_cmd base64
local _tmp
if ! _tmp="$(ensure mktemp)"; then
return 1
fi
# Minimal Linux/LoongArch UAPI detection, exiting with 0 in case of
# upstream ("new world") UAPI, and 234 (-EINVAL truncated) in case of
# old-world (as deployed on several early commercial Linux distributions
# for LoongArch).
#
# See https://gist.github.com/xen0n/5ee04aaa6cecc5c7794b9a0c3b65fc7f for
# source to this helper binary.
ignore base64 -d > "$_tmp" <<EOF
f0VMRgIBAQAAAAAAAAAAAAIAAgEBAAAAeAAgAAAAAABAAAAAAAAAAAAAAAAAAAAAQQAAAEAAOAAB
AAAAAAAAAAEAAAAFAAAAAAAAAAAAAAAAACAAAAAAAAAAIAAAAAAAJAAAAAAAAAAkAAAAAAAAAAAA
AQAAAAAABCiAAwUAFQAGABUAByCAAwsYggMAACsAC3iBAwAAKwAxen0n
EOF
ignore chmod u+x "$_tmp"
if [ ! -x "$_tmp" ]; then
ignore rm "$_tmp"
return 1
fi
"$_tmp"
local _retval=$?
ignore rm "$_tmp"
return "$_retval"
}
ensure_loongarch_uapi() {
check_loongarch_uapi
case $? in
0)
return 0
;;
234)
echo >&2
echo 'Your Linux kernel does not provide the ABI required by this Rust' >&2
echo 'distribution. Please check with your OS provider for how to obtain a' >&2
echo 'compatible Rust package for your system.' >&2
echo >&2
exit 1
;;
*)
echo "Warning: Cannot determine current system's ABI flavor, continuing anyway." >&2
echo >&2
echo 'Note that the official Rust distribution only works with the upstream' >&2
echo 'kernel ABI. Installation will fail if your running kernel happens to be' >&2
echo 'incompatible.' >&2
;;
esac
}
get_architecture() {
local _ostype _cputype _bitness _arch _clibtype
_ostype="$(uname -s)"
_cputype="$(uname -m)"
_clibtype="gnu"
if [ "$_ostype" = Linux ]; then
if [ "$(uname -o)" = Android ]; then
_ostype=Android
fi
if ldd --version 2>&1 | grep -q 'musl'; then
_clibtype="musl"
fi
fi
if [ "$_ostype" = Darwin ]; then
# Darwin `uname -m` can lie due to Rosetta shenanigans. If you manage to
# invoke a native shell binary and then a native uname binary, you can
# get the real answer, but that's hard to ensure, so instead we use
# `sysctl` (which doesn't lie) to check for the actual architecture.
if [ "$_cputype" = i386 ]; then
# Handling i386 compatibility mode in older macOS versions (<10.15)
# running on x86_64-based Macs.
# Starting from 10.15, macOS explicitly bans all i386 binaries from running.
# See: <https://support.apple.com/en-us/HT208436>
# Avoid `sysctl: unknown oid` stderr output and/or non-zero exit code.
if sysctl hw.optional.x86_64 2> /dev/null || true | grep -q ': 1'; then
_cputype=x86_64
fi
elif [ "$_cputype" = x86_64 ]; then
# Handling x86-64 compatibility mode (a.k.a. Rosetta 2)
# in newer macOS versions (>=11) running on arm64-based Macs.
# Rosetta 2 is built exclusively for x86-64 and cannot run i386 binaries.
# Avoid `sysctl: unknown oid` stderr output and/or non-zero exit code.
if sysctl hw.optional.arm64 2> /dev/null || true | grep -q ': 1'; then
_cputype=arm64
fi
fi
fi
if [ "$_ostype" = SunOS ]; then
# Both Solaris and illumos presently announce as "SunOS" in "uname -s"
# so use "uname -o" to disambiguate. We use the full path to the
# system uname in case the user has coreutils uname first in PATH,
# which has historically sometimes printed the wrong value here.
if [ "$(/usr/bin/uname -o)" = illumos ]; then
_ostype=illumos
fi
# illumos systems have multi-arch userlands, and "uname -m" reports the
# machine hardware name; e.g., "i86pc" on both 32- and 64-bit x86
# systems. Check for the native (widest) instruction set on the
# running kernel:
if [ "$_cputype" = i86pc ]; then
_cputype="$(isainfo -n)"
fi
fi
case "$_ostype" in
Android)
_ostype=linux-android
;;
Linux)
check_proc
_ostype=unknown-linux-$_clibtype
_bitness=$(get_bitness)
;;
FreeBSD)
_ostype=unknown-freebsd
;;
NetBSD)
_ostype=unknown-netbsd
;;
DragonFly)
_ostype=unknown-dragonfly
;;
Darwin)
_ostype=apple-darwin
;;
illumos)
_ostype=unknown-illumos
;;
MINGW* | MSYS* | CYGWIN* | Windows_NT)
_ostype=pc-windows-gnu
;;
*)
err "unrecognized OS type: $_ostype"
;;
esac
case "$_cputype" in
i386 | i486 | i686 | i786 | x86)
_cputype=i686
;;
xscale | arm)
_cputype=arm
if [ "$_ostype" = "linux-android" ]; then
_ostype=linux-androideabi
fi
;;
armv6l)
_cputype=arm
if [ "$_ostype" = "linux-android" ]; then
_ostype=linux-androideabi
else
_ostype="${_ostype}eabihf"
fi
;;
armv7l | armv8l)
_cputype=armv7
if [ "$_ostype" = "linux-android" ]; then
_ostype=linux-androideabi
else
_ostype="${_ostype}eabihf"
fi
;;
aarch64 | arm64)
_cputype=aarch64
;;
x86_64 | x86-64 | x64 | amd64)
_cputype=x86_64
;;
mips)
_cputype=$(get_endianness mips '' el)
;;
mips64)
if [ "$_bitness" -eq 64 ]; then
# only n64 ABI is supported for now
_ostype="${_ostype}abi64"
_cputype=$(get_endianness mips64 '' el)
fi
;;
ppc)
_cputype=powerpc
;;
ppc64)
_cputype=powerpc64
;;
ppc64le)
_cputype=powerpc64le
;;
s390x)
_cputype=s390x
;;
riscv64)
_cputype=riscv64gc
;;
loongarch64)
_cputype=loongarch64
ensure_loongarch_uapi
;;
*)
err "unknown CPU type: $_cputype"
esac
# Detect 64-bit linux with 32-bit userland
if [ "${_ostype}" = unknown-linux-gnu ] && [ "${_bitness}" -eq 32 ]; then
case $_cputype in
x86_64)
if [ -n "${RUSTUP_CPUTYPE:-}" ]; then
_cputype="$RUSTUP_CPUTYPE"
else {
# 32-bit executable for amd64 = x32
if is_host_amd64_elf; then {
echo "This host is running an x32 userland; as it stands, x32 support is poor," 1>&2
echo "and there isn't a native toolchain -- you will have to install" 1>&2
echo "multiarch compatibility with i686 and/or amd64, then select one" 1>&2
echo "by re-running this script with the RUSTUP_CPUTYPE environment variable" 1>&2
echo "set to i686 or x86_64, respectively." 1>&2
echo 1>&2
echo "You will be able to add an x32 target after installation by running" 1>&2
echo " rustup target add x86_64-unknown-linux-gnux32" 1>&2
exit 1
}; else
_cputype=i686
fi
}; fi
;;
mips64)
_cputype=$(get_endianness mips '' el)
;;
powerpc64)
_cputype=powerpc
;;
aarch64)
_cputype=armv7
if [ "$_ostype" = "linux-android" ]; then
_ostype=linux-androideabi
else
_ostype="${_ostype}eabihf"
fi
;;
riscv64gc)
err "riscv64 with 32-bit userland unsupported"
;;
esac
fi
# Detect armv7 but without the CPU features Rust needs in that build,
# and fall back to arm.
# See https://github.com/rust-lang/rustup.rs/issues/587.
if [ "$_ostype" = "unknown-linux-gnueabihf" ] && [ "$_cputype" = armv7 ]; then
if ensure grep '^Features' /proc/cpuinfo | grep -E -q -v 'neon|simd'; then
# At least one processor does not have NEON (which is asimd on armv8+).
_cputype=arm
fi
fi
_arch="${_cputype}-${_ostype}"
RETVAL="$_arch"
}
say() {
printf 'rustup: %s\n' "$1"
}
err() {
say "$1" >&2
exit 1
}
need_cmd() {
if ! check_cmd "$1"; then
err "need '$1' (command not found)"
fi
}
check_cmd() {
command -v "$1" > /dev/null 2>&1
}
assert_nz() {
if [ -z "$1" ]; then err "assert_nz $2"; fi
}
# Run a command that should never fail. If the command fails execution
# will immediately terminate with an error showing the failing
# command.
ensure() {
if ! "$@"; then err "command failed: $*"; fi
}
# This is just for indicating that commands' results are being
# intentionally ignored. Usually, because it's being executed
# as part of error handling.
ignore() {
"$@"
}
# This wraps curl or wget. Try curl first, if not installed,
# use wget instead.
downloader() {
# zsh does not split words by default, Required for curl retry arguments below.
is_zsh && setopt local_options shwordsplit
local _dld
local _ciphersuites
local _err
local _status
local _retry
if check_cmd curl; then
_dld=curl
elif check_cmd wget; then
_dld=wget
else
_dld='curl or wget' # to be used in error message of need_cmd
fi
if [ "$1" = --check ]; then
need_cmd "$_dld"
elif [ "$_dld" = curl ]; then
check_curl_for_retry_support
_retry="$RETVAL"
get_ciphersuites_for_curl
_ciphersuites="$RETVAL"
if [ -n "$_ciphersuites" ]; then
_err=$(curl $_retry --proto '=https' --tlsv1.2 --ciphers "$_ciphersuites" --silent --show-error --fail --location "$1" --output "$2" 2>&1)
_status=$?
else
echo "Warning: Not enforcing strong cipher suites for TLS, this is potentially less secure"
if ! check_help_for "$3" curl --proto --tlsv1.2; then
echo "Warning: Not enforcing TLS v1.2, this is potentially less secure"
_err=$(curl $_retry --silent --show-error --fail --location "$1" --output "$2" 2>&1)
_status=$?
else
_err=$(curl $_retry --proto '=https' --tlsv1.2 --silent --show-error --fail --location "$1" --output "$2" 2>&1)
_status=$?
fi
fi
if [ -n "$_err" ]; then
echo "$_err" >&2
if echo "$_err" | grep -q 404$; then
err "installer for platform '$3' not found, this may be unsupported"
fi
fi
return $_status
elif [ "$_dld" = wget ]; then
if [ "$(wget -V 2>&1|head -2|tail -1|cut -f1 -d" ")" = "BusyBox" ]; then
echo "Warning: using the BusyBox version of wget. Not enforcing strong cipher suites for TLS or TLS v1.2, this is potentially less secure"
_err=$(wget "$1" -O "$2" 2>&1)
_status=$?
else
get_ciphersuites_for_wget
_ciphersuites="$RETVAL"
if [ -n "$_ciphersuites" ]; then
_err=$(wget --https-only --secure-protocol=TLSv1_2 --ciphers "$_ciphersuites" "$1" -O "$2" 2>&1)
_status=$?
else
echo "Warning: Not enforcing strong cipher suites for TLS, this is potentially less secure"
if ! check_help_for "$3" wget --https-only --secure-protocol; then
echo "Warning: Not enforcing TLS v1.2, this is potentially less secure"
_err=$(wget "$1" -O "$2" 2>&1)
_status=$?
else
_err=$(wget --https-only --secure-protocol=TLSv1_2 "$1" -O "$2" 2>&1)
_status=$?
fi
fi
fi
if [ -n "$_err" ]; then
echo "$_err" >&2
if echo "$_err" | grep -q ' 404 Not Found$'; then
err "installer for platform '$3' not found, this may be unsupported"
fi
fi
return $_status
else
err "Unknown downloader" # should not reach here
fi
}
check_help_for() {
local _arch
local _cmd
local _arg
_arch="$1"
shift
_cmd="$1"
shift
local _category
if "$_cmd" --help | grep -q 'For all options use the manual or "--help all".'; then
_category="all"
else
_category=""
fi
case "$_arch" in
*darwin*)
if check_cmd sw_vers; then
case $(sw_vers -productVersion) in
10.*)
# If we're running on macOS, older than 10.13, then we always
# fail to find these options to force fallback
if [ "$(sw_vers -productVersion | cut -d. -f2)" -lt 13 ]; then
# Older than 10.13
echo "Warning: Detected macOS platform older than 10.13"
return 1
fi
;;
11.*)
# We assume Big Sur will be OK for now
;;
*)
# Unknown product version, warn and continue
echo "Warning: Detected unknown macOS major version: $(sw_vers -productVersion)"
echo "Warning TLS capabilities detection may fail"
;;
esac
fi
;;
esac
for _arg in "$@"; do
if ! "$_cmd" --help "$_category" | grep -q -- "$_arg"; then
return 1
fi
done
true # not strictly needed
}
# Check if curl supports the --retry flag, then pass it to the curl invocation.
check_curl_for_retry_support() {
local _retry_supported=""
# "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc.
if check_help_for "notspecified" "curl" "--retry"; then
_retry_supported="--retry 3"
if check_help_for "notspecified" "curl" "--continue-at"; then
# "-C -" tells curl to automatically find where to resume the download when retrying.
_retry_supported="--retry 3 -C -"
fi
fi
RETVAL="$_retry_supported"
}
# Return cipher suite string specified by user, otherwise return strong TLS 1.2-1.3 cipher suites
# if support by local tools is detected. Detection currently supports these curl backends:
# GnuTLS and OpenSSL (possibly also LibreSSL and BoringSSL). Return value can be empty.
get_ciphersuites_for_curl() {
if [ -n "${RUSTUP_TLS_CIPHERSUITES-}" ]; then
# user specified custom cipher suites, assume they know what they're doing
RETVAL="$RUSTUP_TLS_CIPHERSUITES"
return
fi
local _openssl_syntax="no"
local _gnutls_syntax="no"
local _backend_supported="yes"
if curl -V | grep -q ' OpenSSL/'; then
_openssl_syntax="yes"
elif curl -V | grep -iq ' LibreSSL/'; then
_openssl_syntax="yes"
elif curl -V | grep -iq ' BoringSSL/'; then
_openssl_syntax="yes"
elif curl -V | grep -iq ' GnuTLS/'; then
_gnutls_syntax="yes"
else
_backend_supported="no"
fi
local _args_supported="no"
if [ "$_backend_supported" = "yes" ]; then
# "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc.
if check_help_for "notspecified" "curl" "--tlsv1.2" "--ciphers" "--proto"; then
_args_supported="yes"
fi
fi
local _cs=""
if [ "$_args_supported" = "yes" ]; then
if [ "$_openssl_syntax" = "yes" ]; then
_cs=$(get_strong_ciphersuites_for "openssl")
elif [ "$_gnutls_syntax" = "yes" ]; then
_cs=$(get_strong_ciphersuites_for "gnutls")
fi
fi
RETVAL="$_cs"
}
# Return cipher suite string specified by user, otherwise return strong TLS 1.2-1.3 cipher suites
# if support by local tools is detected. Detection currently supports these wget backends:
# GnuTLS and OpenSSL (possibly also LibreSSL and BoringSSL). Return value can be empty.
get_ciphersuites_for_wget() {
if [ -n "${RUSTUP_TLS_CIPHERSUITES-}" ]; then
# user specified custom cipher suites, assume they know what they're doing
RETVAL="$RUSTUP_TLS_CIPHERSUITES"
return
fi
local _cs=""
if wget -V | grep -q '\-DHAVE_LIBSSL'; then
# "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc.
if check_help_for "notspecified" "wget" "TLSv1_2" "--ciphers" "--https-only" "--secure-protocol"; then
_cs=$(get_strong_ciphersuites_for "openssl")
fi
elif wget -V | grep -q '\-DHAVE_LIBGNUTLS'; then
# "unspecified" is for arch, allows for possibility old OS using macports, homebrew, etc.
if check_help_for "notspecified" "wget" "TLSv1_2" "--ciphers" "--https-only" "--secure-protocol"; then
_cs=$(get_strong_ciphersuites_for "gnutls")
fi
fi
RETVAL="$_cs"
}
# Return strong TLS 1.2-1.3 cipher suites in OpenSSL or GnuTLS syntax. TLS 1.2
# excludes non-ECDHE and non-AEAD cipher suites. DHE is excluded due to bad
# DH params often found on servers (see RFC 7919). Sequence matches or is
# similar to Firefox 68 ESR with weak cipher suites disabled via about:config.
# $1 must be openssl or gnutls.
get_strong_ciphersuites_for() {
if [ "$1" = "openssl" ]; then
# OpenSSL is forgiving of unknown values, no problems with TLS 1.3 values on versions that don't support it yet.
echo "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384"
elif [ "$1" = "gnutls" ]; then
# GnuTLS isn't forgiving of unknown values, so this may require a GnuTLS version that supports TLS 1.3 even if wget doesn't.
# Begin with SECURE128 (and higher) then remove/add to build cipher suites. Produces same 9 cipher suites as OpenSSL but in slightly different order.
echo "SECURE128:-VERS-SSL3.0:-VERS-TLS1.0:-VERS-TLS1.1:-VERS-DTLS-ALL:-CIPHER-ALL:-MAC-ALL:-KX-ALL:+AEAD:+ECDHE-ECDSA:+ECDHE-RSA:+AES-128-GCM:+CHACHA20-POLY1305:+AES-256-GCM"
fi
}
main "$@" || exit 1

35
node/build.sh Executable file
View File

@ -0,0 +1,35 @@
#!/bin/bash
set -euxo pipefail
# This script builds the node binary for the current platform and statically links it with VDF static lib.
ROOT_DIR="${ROOT_DIR:-$( cd "$(dirname "$(realpath "$( dirname "${BASH_SOURCE[0]}" )")")" >/dev/null 2>&1 && pwd )}"
NODE_DIR="$ROOT_DIR/node"
BINARIES_DIR="$ROOT_DIR/target/release"
pushd "$NODE_DIR" > /dev/null
export CGO_ENABLED=1
export GOEXPERIMENT=arenas
os_type="$(uname)"
case "$os_type" in
"Darwin")
# Check if the architecture is ARM
if [[ "$(uname -m)" == "arm64" ]]; then
# MacOS ld doesn't support -Bstatic and -Bdynamic, so it's important that there is only a static version of the library
go build -ldflags "-linkmode 'external' -extldflags '-L$BINARIES_DIR -lvdf -ldl -lm'" "$@"
else
echo "Unsupported platform"
exit 1
fi
;;
"Linux")
go build -ldflags "-linkmode 'external' -extldflags '-L$BINARIES_DIR -Wl,-Bstatic -lvdf -Wl,-Bdynamic -ldl -lm'" "$@"
;;
*)
echo "Unsupported platform"
exit 1
;;
esac

View File

@ -13,11 +13,11 @@ import (
"github.com/pkg/errors"
"go.uber.org/zap"
"golang.org/x/crypto/sha3"
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/vdf"
"source.quilibrium.com/quilibrium/monorepo/node/config"
"source.quilibrium.com/quilibrium/monorepo/node/keys"
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
"source.quilibrium.com/quilibrium/monorepo/node/tries"
"source.quilibrium.com/quilibrium/monorepo/vdf"
)
type WesolowskiFrameProver struct {
@ -42,9 +42,7 @@ func (w *WesolowskiFrameProver) ProveMasterClockFrame(
input = append(input, previousFrame.Output[:]...)
b := sha3.Sum256(input)
v := vdf.New(difficulty, b)
v.Execute()
o := v.GetOutput()
o := vdf.WesolowskiSolve(b, difficulty)
previousSelectorBytes := [516]byte{}
copy(previousSelectorBytes[:], previousFrame.Output[:516])
@ -113,11 +111,10 @@ func (w *WesolowskiFrameProver) VerifyMasterClockFrame(
}
b := sha3.Sum256(input)
v := vdf.New(frame.Difficulty, b)
proof := [516]byte{}
copy(proof[:], frame.Output)
if !v.Verify(proof) {
if !vdf.WesolowskiVerify(b, frame.Difficulty, proof) {
w.logger.Error("invalid proof",
zap.Binary("filter", frame.Filter),
zap.Uint64("frame_number", frame.FrameNumber),
@ -159,10 +156,7 @@ func (w *WesolowskiFrameProver) CreateMasterGenesisFrame(
error,
) {
b := sha3.Sum256(seed)
v := vdf.New(difficulty, b)
v.Execute()
o := v.GetOutput()
o := vdf.WesolowskiSolve(b, difficulty)
inputMessage := o[:]
w.logger.Debug("proving genesis frame")
@ -178,10 +172,7 @@ func (w *WesolowskiFrameProver) CreateMasterGenesisFrame(
}
b = sha3.Sum256(input)
v = vdf.New(difficulty, b)
v.Execute()
o = v.GetOutput()
o = vdf.WesolowskiSolve(b, difficulty)
frame := &protobufs.ClockFrame{
Filter: filter,
@ -248,10 +239,7 @@ func (w *WesolowskiFrameProver) ProveDataClockFrame(
input = append(input, commitmentInput...)
b := sha3.Sum256(input)
v := vdf.New(difficulty, b)
v.Execute()
o := v.GetOutput()
o := vdf.WesolowskiSolve(b, difficulty)
// TODO: make this configurable for signing algorithms that allow
// user-supplied hash functions
@ -341,10 +329,7 @@ func (w *WesolowskiFrameProver) CreateDataGenesisFrame(
}
b := sha3.Sum256(input)
v := vdf.New(difficulty, b)
v.Execute()
o := v.GetOutput()
o := vdf.WesolowskiSolve(b, difficulty)
commitments := []*protobufs.InclusionCommitment{}
for i, commit := range inclusionProof.InclusionCommitments {
@ -438,7 +423,6 @@ func (w *WesolowskiFrameProver) VerifyDataClockFrame(
}
b := sha3.Sum256(input)
v := vdf.New(frame.Difficulty, b)
proof := [516]byte{}
copy(proof[:], frame.Output)
@ -458,7 +442,7 @@ func (w *WesolowskiFrameProver) VerifyDataClockFrame(
)
}
}
if !v.Verify(proof) {
if !vdf.WesolowskiVerify(b, frame.Difficulty, proof) {
return errors.Wrap(
errors.New("invalid proof"),
"verify clock frame",
@ -585,11 +569,10 @@ func (w *WesolowskiFrameProver) VerifyWeakRecursiveProof(
}
b := sha3.Sum256(input[:len(input)-516])
v := vdf.New(difficulty, b)
output := [516]byte{}
copy(output[:], input[len(input)-516:])
if v.Verify(output) {
if vdf.WesolowskiVerify(b, difficulty, output) {
w.logger.Debug("verification succeeded")
return true
} else {
@ -613,10 +596,7 @@ func (w *WesolowskiFrameProver) CalculateChallengeProof(
instanceInput := binary.BigEndian.AppendUint32([]byte{}, core)
instanceInput = append(instanceInput, input...)
b := sha3.Sum256(instanceInput)
v := vdf.New(uint32(calibratedDifficulty), b)
v.Execute()
o := v.GetOutput()
o := vdf.WesolowskiSolve(b, uint32(calibratedDifficulty))
output := make([]byte, 516)
copy(output[:], o[:])
@ -653,15 +633,13 @@ func (w *WesolowskiFrameProver) VerifyChallengeProof(
skew := (assertedDifficulty * 12) / 10
calibratedDifficulty := (int64(proofDuration) * 10000) / skew
v := vdf.New(uint32(calibratedDifficulty), b)
check := v.Verify([516]byte(proof[i]))
check := vdf.WesolowskiVerify(b, uint32(calibratedDifficulty), [516]byte(proof[i]))
if !check {
// TODO: Remove after 2024-05-28
if time.Now().Before(config.GetMinimumVersionCutoff()) {
calibratedDifficulty = (int64(proofDuration) / skew) * 10000
v = vdf.New(uint32(calibratedDifficulty), sha3.Sum256(input))
check = v.Verify([516]byte(proof[i]))
check = vdf.WesolowskiVerify(sha3.Sum256(input), uint32(calibratedDifficulty), [516]byte(proof[i]))
if !check {
return false
}

View File

@ -5,6 +5,8 @@ go 1.20
// A necessary hack until source.quilibrium.com is open to all
replace source.quilibrium.com/quilibrium/monorepo/nekryptology => ../nekryptology
replace source.quilibrium.com/quilibrium/monorepo/vdf => ../vdf
replace github.com/libp2p/go-libp2p => ../go-libp2p
replace github.com/libp2p/go-libp2p-gostream => ../go-libp2p-gostream
@ -23,6 +25,7 @@ require (
gopkg.in/yaml.v2 v2.4.0
source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub v0.0.0-00010101000000-000000000000
source.quilibrium.com/quilibrium/monorepo/nekryptology v0.0.0-00010101000000-000000000000
source.quilibrium.com/quilibrium/monorepo/vdf v0.0.0-00010101000000-000000000000
)
require (
@ -64,7 +67,7 @@ require (
github.com/quic-go/qtls-go1-19 v0.3.3 // indirect
github.com/quic-go/qtls-go1-20 v0.2.3 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
golang.org/x/term v0.16.0
golang.org/x/term v0.21.0
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
@ -144,7 +147,7 @@ require (
github.com/onsi/ginkgo/v2 v2.11.0 // indirect
github.com/opencontainers/runtime-spec v1.1.0 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58
github.com/pkg/errors v0.9.1
github.com/polydawn/refmt v0.89.0 // indirect
github.com/prometheus/client_golang v1.16.0 // indirect
@ -164,14 +167,14 @@ require (
go.uber.org/fx v1.20.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.26.0
golang.org/x/crypto v0.18.0
golang.org/x/crypto v0.24.0
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/net v0.20.0 // indirect
golang.org/x/sync v0.6.0
golang.org/x/sys v0.16.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sync v0.7.0
golang.org/x/sys v0.21.0
golang.org/x/text v0.16.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
gonum.org/v1/gonum v0.11.0 // indirect
google.golang.org/grpc v1.58.2
lukechampine.com/blake3 v1.2.1 // indirect

View File

@ -111,6 +111,7 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@ -161,6 +162,7 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
@ -229,11 +231,14 @@ github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZl
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
@ -315,6 +320,7 @@ github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dz
github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
@ -353,6 +359,7 @@ github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXS
github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8=
github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@ -512,6 +519,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ=
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8=
@ -528,6 +537,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -548,6 +559,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@ -563,6 +576,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -585,14 +600,20 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -616,6 +637,8 @@ golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E=
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

17
node/test.sh Executable file
View File

@ -0,0 +1,17 @@
#!/bin/bash
set -euxo pipefail
# Run tests for the node package. Takes care of linking the native VDF.
# Assumes that the VDF library has been built by running the generate.sh script in the `../vdf` directory.
ROOT_DIR="${ROOT_DIR:-$( cd "$(dirname "$(realpath "$( dirname "${BASH_SOURCE[0]}" )")")" >/dev/null 2>&1 && pwd )}"
NODE_DIR="$ROOT_DIR/node"
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_ENABLED=1 \
GOEXPERIMENT=arenas \
go test "$@"

1
vdf/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
generated

9
vdf/REAMDE.md Normal file
View File

@ -0,0 +1,9 @@
# VDF
Wrapper for the Rust implementation of the VDF (Verifiable Delay Function) in [crates/vdf](../crates/vdf).
## Generate Go bindings
```sh
go generate
```

14
vdf/generate.sh Executable file
View File

@ -0,0 +1,14 @@
#!/bin/bash
set -euxo pipefail
ROOT_DIR="${ROOT_DIR:-$( cd "$(dirname "$(realpath "$( dirname "${BASH_SOURCE[0]}" )")")" >/dev/null 2>&1 && pwd )}"
RUST_VDF_PACKAGE="$ROOT_DIR/crates/vdf"
BINDINGS_DIR="$ROOT_DIR/vdf"
# Build the Rust VDF package in release mode
RUSTFLAGS='-L /opt/homebrew/Cellar/gmp/6.3.0/lib' cargo build -p vdf --release
# Generate Go bindings
pushd "$RUST_VDF_PACKAGE" > /dev/null
uniffi-bindgen-go src/lib.udl -o "$BINDINGS_DIR"/generated

12
vdf/go.mod Normal file
View File

@ -0,0 +1,12 @@
module source.quilibrium.com/quilibrium/monorepo/vdf
go 1.20
// A necessary hack until source.quilibrium.com is open to all
replace source.quilibrium.com/quilibrium/monorepo/nekryptology => ../nekryptology
require (
golang.org/x/crypto v0.24.0 // indirect
golang.org/x/sys v0.21.0 // indirect
source.quilibrium.com/quilibrium/monorepo/nekryptology v0.0.0-00010101000000-000000000000 // indirect
)

4
vdf/go.sum Normal file
View File

@ -0,0 +1,4 @@
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=

17
vdf/test.sh Executable file
View File

@ -0,0 +1,17 @@
#!/bin/bash
set -euxo pipefail
# 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 )}"
NODE_DIR="$ROOT_DIR/vdf"
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_ENABLED=1 \
GOEXPERIMENT=arenas \
go test "$@"

21
vdf/vdf.go Normal file
View File

@ -0,0 +1,21 @@
package vdf
import (
generated "source.quilibrium.com/quilibrium/monorepo/vdf/generated/vdf"
)
//go:generate ./generate.sh
const intSizeBits = uint16(2048)
// WesolowskiSolve Solve and prove with the Wesolowski VDF using the given parameters.
// Outputs the concatenated solution and proof (in this order).
func WesolowskiSolve(challenge [32]byte, difficulty uint32) [516]byte {
return [516]byte(generated.WesolowskiSolve(intSizeBits, challenge[:], difficulty))
}
// WesolowskiVerify Verify with the Wesolowski VDF using the given parameters.
// `allegedSolution` is the output of `WesolowskiSolve`.
func WesolowskiVerify(challenge [32]byte, difficulty uint32, allegedSolution [516]byte) bool {
return generated.WesolowskiVerify(intSizeBits, challenge[:], difficulty, allegedSolution[:])
}

53
vdf/vdf_test.go Normal file
View File

@ -0,0 +1,53 @@
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"
)
func getChallenge(seed string) [32]byte {
return sha3.Sum256([]byte(seed))
}
func TestProveVerify(t *testing.T) {
difficulty := uint32(10000)
challenge := getChallenge("TestProveVerify")
solution := vdf.WesolowskiSolve(challenge, difficulty)
isOk := vdf.WesolowskiVerify(challenge, difficulty, solution)
if !isOk {
t.Fatalf("Verification failed")
}
}
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[:])
}
}
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[:])
}
}