Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RSA based VDF and refactor #808

Closed
wants to merge 12 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ members = [
# Dependencies that should be kept in sync through the whole workspace
[workspace.dependencies]
rand = { version = "0.8.5", features = ["std"] }
serde = { version = "1.0.152", features = ["derive"] }
serde = { version = "1.0.152", features = ["derive", "rc"] }
bincode = "1.3.3"
typenum = "1.16.0"
zeroize = "1.5.7"
Expand Down
6 changes: 3 additions & 3 deletions fastcrypto-cli/src/vdf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
// SPDX-License-Identifier: Apache-2.0

use clap::Parser;
use fastcrypto_vdf::class_group::discriminant::{Discriminant, DISCRIMINANT_3072};
use fastcrypto_vdf::class_group::QuadraticForm;
use fastcrypto_vdf::math::parameterized_group::{Parameter, ParameterizedGroupElement};
use fastcrypto_vdf::groups::class_group::discriminant::{Discriminant, DISCRIMINANT_3072};
use fastcrypto_vdf::groups::class_group::QuadraticForm;
use fastcrypto_vdf::groups::ParameterizedGroupElement;
use fastcrypto_vdf::vdf::wesolowski::DefaultVDF;
use fastcrypto_vdf::vdf::VDF;
use std::io::{Error, ErrorKind};
Expand Down
4 changes: 2 additions & 2 deletions fastcrypto-vdf/benches/class_group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use num_traits::Num;
use rand::{thread_rng, RngCore};

use fastcrypto::groups::Doubling;
use fastcrypto_vdf::class_group::discriminant::Discriminant;
use fastcrypto_vdf::class_group::QuadraticForm;
use fastcrypto_vdf::groups::class_group::discriminant::Discriminant;
use fastcrypto_vdf::groups::class_group::QuadraticForm;

fn class_group_ops_single<M: Measurement>(
discriminant_string: &str,
Expand Down
53 changes: 25 additions & 28 deletions fastcrypto-vdf/benches/vdf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,19 @@
#[macro_use]
extern crate criterion;

use std::rc::Rc;

use criterion::measurement::Measurement;
use criterion::{BenchmarkGroup, BenchmarkId, Criterion};
use fastcrypto_vdf::class_group::discriminant::Discriminant;
use fastcrypto_vdf::class_group::QuadraticForm;
use fastcrypto_vdf::math::parameterized_group::Parameter;
use fastcrypto_vdf::vdf::wesolowski::DefaultVDF;
use fastcrypto_vdf::vdf::VDF;
use num_bigint::BigInt;
use criterion::{BenchmarkGroup, Criterion};
use num_bigint::{BigInt, BigUint};
use num_traits::Num;
use rand::{thread_rng, RngCore};

use fastcrypto_vdf::groups::class_group::discriminant::Discriminant;
use fastcrypto_vdf::groups::class_group::QuadraticForm;
use fastcrypto_vdf::groups::rsa_group::modulus::GOOGLE_RSA_MODULUS_4096;
use fastcrypto_vdf::groups::rsa_group::RSAGroupElement;
use fastcrypto_vdf::vdf::wesolowski::{DefaultRSABasedVDF, DefaultVDF};
use fastcrypto_vdf::vdf::VDF;

struct VerificationInputs {
iterations: u64,
Expand Down Expand Up @@ -85,31 +88,25 @@ fn verify(c: &mut Criterion) {
}, &mut group);
}

fn sample_discriminant(c: &mut Criterion) {
let bit_lengths = [512, 1024, 2048, 2400, 3072];

let mut seed = [0u8; 32];

let mut rng = thread_rng();

for bit_length in bit_lengths {
c.bench_with_input(
BenchmarkId::new("Sample class group discriminant".to_string(), bit_length),
&bit_length,
|b, n| {
b.iter(|| {
rng.try_fill_bytes(&mut seed).unwrap();
Discriminant::from_seed(&seed, *n).unwrap();
})
},
);
}
fn rsa_vdf(c: &mut Criterion) {
let modulus = Rc::new(GOOGLE_RSA_MODULUS_4096.clone());
let vdf = DefaultRSABasedVDF::new(modulus.clone(), 1000);

let input = RSAGroupElement::new(BigUint::from(2u64), &modulus);

println!("Modulus bits: {}", modulus.value.bits());

let (output, proof) = vdf.evaluate(&input).unwrap();

c.bench_function("RSA VDF verify", move |b| {
b.iter(|| vdf.verify(&input, &output, &proof))
});
}

criterion_group! {
name = vdf_benchmarks;
config = Criterion::default().sample_size(100);
targets = verify, sample_discriminant
targets = verify, rsa_vdf
}

criterion_main!(vdf_benchmarks);
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use crate::class_group::bigint_serde;
use crate::groups::class_group::bigint_serde;
use crate::math::hash_prime;
use crate::math::hash_prime::is_probable_prime;
use crate::math::parameterized_group::Parameter;
use fastcrypto::error::FastCryptoError::InvalidInput;
use fastcrypto::error::{FastCryptoError, FastCryptoResult};
use lazy_static::lazy_static;
use num_bigint::{BigInt, ToBigInt};
use num_integer::Integer;
use num_traits::{One, Signed};
use serde::{Deserialize, Serialize};
use std::ops::Neg;
use std::str::FromStr;

/// A discriminant for an imaginary class group. The discriminant is a negative integer congruent to
/// 1 mod 8.
#[derive(PartialEq, Eq, Debug, Clone, Serialize)]
pub struct Discriminant(#[serde(with = "crate::class_group::bigint_serde")] BigInt);
pub struct Discriminant(#[serde(with = "bigint_serde")] BigInt);

lazy_static! {
/// Fixed 3072 bit discriminant. Generated from the seed [1,2,3] using [Discriminant::from_seed].
Expand Down Expand Up @@ -53,6 +51,20 @@ impl TryFrom<BigInt> for Discriminant {
}

impl Discriminant {
/// Compute a valid discriminant (aka a negative prime equal to 1 mod 8) based on the given seed.
/// The size_in_bits must be divisible by 8.
pub fn from_seed(seed: &[u8], size_in_bits: usize) -> FastCryptoResult<Discriminant> {
if size_in_bits % 8 != 0 {
return Err(InvalidInput);
}
// Set the lower three bits to ensure that the prime is 7 mod 8 which makes the discriminant 1 mod 8.
Ok(Self(
-hash_prime::hash_prime(seed, size_in_bits / 8, &[0, 1, 2, size_in_bits - 1])
.to_bigint()
.expect("Never fails"),
))
}

/// Return the number of bits needed to represent this discriminant, not including the sign bit.
pub fn bits(&self) -> u64 {
self.0.bits()
Expand All @@ -72,23 +84,6 @@ impl Discriminant {
}
}

impl Parameter for Discriminant {
/// Compute a valid discriminant (aka a negative prime equal to 1 mod 8) based on the given seed.
/// The size_in_bits must be divisible by 8.
fn from_seed(seed: &[u8], size_in_bits: usize) -> FastCryptoResult<Discriminant> {
if size_in_bits % 8 != 0 {
return Err(InvalidInput);
}
// Set the lower three bits to ensure that the prime is 7 mod 8 which makes the discriminant 1 mod 8.
Ok(Self(
hash_prime::hash_prime(seed, size_in_bits / 8, &[0, 1, 2, size_in_bits - 1])
.to_bigint()
.expect("Never fails")
.neg(),
))
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ use fastcrypto::error::FastCryptoResult;
use fastcrypto::hash::HashFunction;
use fastcrypto::hash::Sha256;

use crate::class_group::discriminant::Discriminant;
use crate::class_group::QuadraticForm;
use crate::groups::class_group::discriminant::Discriminant;
use crate::groups::class_group::QuadraticForm;
use crate::math::crt::solve_congruence_equation_system;
use crate::math::hash_prime::is_probable_prime;
use crate::math::jacobi;
Expand Down Expand Up @@ -178,9 +178,9 @@ mod tests {
use rand::thread_rng;
use rand::RngCore;

use crate::class_group::discriminant::Discriminant;
use crate::class_group::QuadraticForm;
use crate::math::parameterized_group::{Parameter, ParameterizedGroupElement};
use crate::groups::class_group::discriminant::Discriminant;
use crate::groups::class_group::QuadraticForm;
use crate::groups::ParameterizedGroupElement;

#[test]
fn test_qf_from_seed() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
//! binary quadratic forms which forms a group under composition. Here we use additive notation
//! for the composition.

use crate::groups::ParameterizedGroupElement;
use crate::math::extended_gcd::{extended_euclidean_algorithm, EuclideanAlgorithmOutput};
use crate::math::parameterized_group::ParameterizedGroupElement;
use core::cell::OnceCell;
use discriminant::Discriminant;
use fastcrypto::error::FastCryptoError::InvalidInput;
Expand Down Expand Up @@ -38,7 +38,7 @@ pub(crate) mod reduction;
pub mod discriminant;

/// Serialization and deserialization for `num_bigint::BigInt`. The format used in num_bigint is
/// a serialization of the u32 words which is hard to port to other platforms. Instead we serialize
/// a serialization of the u32 words which is hard to port to other platforms. Instead, we serialize
/// a big integer as the two's-complement byte representation in big-endian byte order. See also
/// [BigInt::to_signed_bytes_be].
mod bigint_serde;
Expand Down Expand Up @@ -104,12 +104,16 @@ impl QuadraticForm {
}

/// Compute the composition of this quadratic form with another quadratic form.
///
/// This panics if the discriminants of the two forms do not match.
pub fn compose(&self, rhs: &QuadraticForm) -> QuadraticForm {
// Slightly optimised version of Algorithm 1 from Jacobson, Jr, Michael & Poorten, Alfred
// (2002). "Computational aspects of NUCOMP", Lecture Notes in Computer Science.
// (https://www.researchgate.net/publication/221451638_Computational_aspects_of_NUCOMP)
// The paragraph numbers and variable names follow the paper.

assert_eq!(self.discriminant(), rhs.discriminant());

let u1 = &self.a;
let v1 = &self.b;
let w1 = &self.c;
Expand Down Expand Up @@ -295,8 +299,6 @@ impl ParameterizedGroupElement for QuadraticForm {
/// The discriminant of a quadratic form defines the class group.
type ParameterType = Discriminant;

type ScalarType = BigInt;

fn zero(discriminant: &Self::ParameterType) -> Self {
Self::from_a_b_and_discriminant(BigInt::one(), BigInt::one(), discriminant)
.expect("Doesn't fail")
Expand All @@ -315,14 +317,6 @@ impl Add<&QuadraticForm> for QuadraticForm {
}
}

impl Add<QuadraticForm> for QuadraticForm {
type Output = QuadraticForm;

fn add(self, rhs: QuadraticForm) -> Self::Output {
self.compose(&rhs)
}
}

impl Add<&QuadraticForm> for &QuadraticForm {
type Output = QuadraticForm;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use crate::class_group::QuadraticForm;
use crate::groups::class_group::QuadraticForm;
use num_bigint::BigInt;
use num_integer::Integer;
use num_traits::{One, Signed};
Expand Down Expand Up @@ -74,8 +74,8 @@ fn increment_and_shift_right(mut x: BigInt) -> BigInt {

#[cfg(test)]
mod tests {
use crate::class_group::Discriminant;
use crate::class_group::QuadraticForm;
use crate::groups::class_group::Discriminant;
use crate::groups::class_group::QuadraticForm;
use num_bigint::BigInt;

#[test]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

use num_bigint::BigInt;

use crate::class_group::discriminant::{Discriminant, DISCRIMINANT_3072};
use crate::class_group::QuadraticForm;
use crate::math::parameterized_group::ParameterizedGroupElement;
use crate::groups::class_group::discriminant::{Discriminant, DISCRIMINANT_3072};
use crate::groups::class_group::QuadraticForm;
use crate::groups::ParameterizedGroupElement;

#[test]
fn test_composition() {
Expand Down
25 changes: 25 additions & 0 deletions fastcrypto-vdf/src/groups/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use std::ops::Add;

use fastcrypto::groups::Doubling;

pub mod class_group;
pub mod rsa_group;

/// Trait implemented by elements of an additive group where the group is parameterized: Concretely,
/// 1) RSA groups parameterized by the modulus and
/// 2) class groups parameterized by a discriminant.
pub trait ParameterizedGroupElement:
Sized + Clone + for<'a> Add<&'a Self, Output = Self> + Eq + Doubling
{
/// The type of the parameter which uniquely defines this group.
type ParameterType;

/// Return an instance of the identity element in this group.
fn zero(parameter: &Self::ParameterType) -> Self;

/// Returns true if this is an element of the group defined by `parameter`.
fn is_in_group(&self, parameter: &Self::ParameterType) -> bool;
}
49 changes: 49 additions & 0 deletions fastcrypto-vdf/src/groups/rsa_group/biguint_serde.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use num_bigint::BigUint;
use serde::Deserialize;
use serde::Deserializer;
use serde::Serialize;
use serde::Serializer;

pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result<BigUint, D::Error>
where
D: Deserializer<'de>,
{
Ok(BigUint::from_bytes_be(&<Vec<u8>>::deserialize(
deserializer,
)?))
}

pub(crate) fn serialize<S>(value: &BigUint, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
value.to_bytes_be().serialize(serializer)
}

#[cfg(test)]
mod tests {
use super::*;

#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
#[serde(transparent)]
struct TestStruct(
#[serde(serialize_with = "serialize", deserialize_with = "deserialize")] BigUint,
);

#[test]
fn test_serde() {
let test_values = vec![
TestStruct(BigUint::from(0u8)),
TestStruct(BigUint::from(1234567890u128)),
TestStruct(BigUint::from(1234567890123456789u128)),
];
for value in test_values {
let serialized = bcs::to_bytes(&value).unwrap();
let deserialized: TestStruct = bcs::from_bytes(&serialized).unwrap();
assert_eq!(value, deserialized);
}
}
}
Loading
Loading