diff --git a/fastcrypto-cli/src/vdf.rs b/fastcrypto-cli/src/vdf.rs index 4e0b0cbe3..7554b88f3 100644 --- a/fastcrypto-cli/src/vdf.rs +++ b/fastcrypto-cli/src/vdf.rs @@ -185,11 +185,8 @@ fn execute(cmd: Command) -> Result { Command::Hash(arguments) => { let input = hex::decode(arguments.message) .map_err(|_| Error::new(ErrorKind::InvalidInput, "Invalid message."))?; - let output = - QuadraticForm::hash_to_group_with_default_parameters(&input, &DISCRIMINANT_3072) - .map_err(|_| { - Error::new(ErrorKind::InvalidInput, "The k parameter was too big") - })?; + let output = QuadraticForm::hash_to_group(&input, &DISCRIMINANT_3072) + .map_err(|_| Error::new(ErrorKind::InvalidInput, "The discriminant is invalid."))?; let output_bytes = hex::encode(bcs::to_bytes(&output).unwrap()); @@ -266,7 +263,7 @@ mod tests { message: seed.clone(), })) .unwrap(); - let expected = "Output: bc010082ee2d187c87dd0253b19d73db019c2f11e29ee9a70ff48082860c05c17f8e786276e999605f086e3d58124f378e06ff904aa3f623f5fd1903d23b381a2b1abc23ea3004f84defb5d1c7c825134305373308a7c287110cce7ff96fed79b366d4272ef03226aecdce76b5f6f946bff527e56391a3f72682403f8f48a584ba6769a96ed0742d299060759f8ba227ff87011035dc097b54a76f4c7ed7d60a530f92500d7228b15ac3addceea196a341b4f06217d5881952025e650e81ea02247f8e37e7ddede21f1f8e34fc1d23aafcfddd9cae9c9fe068b069591abd638bf143b2e7ca646c298a69883dac05dec9b9c77d211f06dd0325b851a464b34d0a4084363c5b8c4fea79d38544f7d583d55931374c467239fd4ba7ba3a9d2ef0457d910c18e42575ff039da6814e585238647f910eb90bd78b750ee315ebbb67703168c9f25d3484191093d7e99ed160041d27188165eef767d6cfe735037a8d33c670087a0c4be4c404022525f2261ce411d4f2afa2c450891eed6ad1fe2ec72d361e3d73a63da32fc8e5f445fe1d559dcc41a13e87bba38827cc5da40ad097da50617b216c4ad7aa6c50a20b0b840273b671e2027f8a3acb3651d9fc8e45ede649d232df111bf9c49c68afc0e699ef359e86e8912d0902b6e908988f6994b51ae2f8ab1a26a0bf96ee722d05f7cddf61d25899645648de8821de536d6175d2d28729c6f56a99fbf383043bccc3183a45ea3b3b4d599443c5672d9a26e6e2d7475bb8b76bcc5d393bc3939904028b278613c65986c0529d0ed75d26567154d61029833cff4bda9e3649b2b7196e43b5182b2b2b27020cf99d90de2aa3f927ea03453352855508a39466098b211f486a5c83ce48005287a2d941c734d93abe091e08860f28a462ea061f060129da80d7998d7cf036be70248c5b96582de577929fae4e77e8ea61419dd6571894e892c57153e79fd80ab68bc1b248a15841e5f91943fc4b71d6e5f841ed6dffca3bef0dafa79211aa607f55d5fa5cd0225d9a9cb26d0438ebaa402019f84ac75aeecb40d2fc75fc9449f117f98c230ad561771a8c621a3bfc2116017549eccd9a52f51a6eb0992d57042f684e95f5a12481c570ff57167be444c7f0b71c2aba4178253f577b488d6007f1ea4d8c05b663c539c334a8fcbb91284881dda609ee18f8133c98dc815ce17154a5bbfb380250895455b6c6ce227de43e8fa0b593e39deb4d280e92579dc344972361372ee1cd1c40197bcbec2262d43331acab5ae8bb0a70b87e7d503c40867b43febefedf7a59dabab669c6e94fc321d2a67816e36b982b21a5914eb0f5e5b343f5d6e0c7db24476ca3a18ae3f4d5fff78d7fc917272db5f21db999faa6626243aeb3d9f2939c0ddc06c94aae74fa58c903fd56ff634ec1eaafb3a7965318946f45473fc3ddea8f9972ea73645bfe132569514e40ac9b9abddcd6fe5623573e3ab724eb2adab38d9064b259952ac83ee999ddea5edae12a0e4d08822c4c9e499f498ca66da90272bf6d3d41ad0d86"; + let expected = "Output: 227afa0a257a3fa140fad0ba29ade524a7cc097c706a7c59c363fede402870cbf192ef33fc06eddf144b2023a50256b388f8fd5a6ef59dd7275e2f7ae1288bef605158fa97e2af2684604395314a5176a655a940bb3ac3de025d92c53e95f69368f53575775e965be811f89c08d0c9dc702daea57afb3d6e5e48b8255fc93901580f01837abf0a6e94e3a29d6a9bcca669c611d3f94256b72c7a67415391607d89e15a3f82880bae011276e96f097895311e45caaa81dc7b35e3fe97d83cd392e7b94e1ddfa0f684be3e9106e0bda15c0153d2f8a6ba1528b796ca6bd24a5164eed50e63f7cd5837ef7c9a6d52451d66fca2221f04efe44b446896843b1bbf4ebc322d80781259afcc1a5780eedd3cde2cd98e44d3bfadb19a0253b6f0e7f957469e41ce8bc48f9516412b61097c858cc9fac2489f5a6467e1516d8ab93cf7849c34428589110b9d1e3d4d4e114480fe14db77eb545cd13b3a4f6fe43dc9002ec52d1400fbdba8a34ffab8b5200a002f0b13691f635304a2d266bee80263dbe996e03fe8840902922d814d5535f97a2602c24a276b95e48dc802d9e09288f411360ae69357d0c0018474992daa45dc6cde5a2fe02ae9d2"; assert_eq!(expected, result); } } diff --git a/fastcrypto-vdf/benches/class_group.rs b/fastcrypto-vdf/benches/class_group.rs index 5c60d3699..f12c5ae28 100644 --- a/fastcrypto-vdf/benches/class_group.rs +++ b/fastcrypto-vdf/benches/class_group.rs @@ -18,10 +18,8 @@ fn class_group_ops_single( let discriminant = Discriminant::try_from(BigInt::from_str_radix(discriminant_string, 10).unwrap()).unwrap(); let discriminant_size = discriminant.bits(); - let x = - QuadraticForm::hash_to_group_with_default_parameters(&[0, 1, 2], &discriminant).unwrap(); - let y = - QuadraticForm::hash_to_group_with_default_parameters(&[3, 4, 5], &discriminant).unwrap(); + let x = QuadraticForm::hash_to_group(&[0, 1, 2], &discriminant).unwrap(); + let y = QuadraticForm::hash_to_group(&[3, 4, 5], &discriminant).unwrap(); let z = y.clone(); group.bench_function(format!("Compose/{}", discriminant_size), move |b| { @@ -42,27 +40,27 @@ fn class_group_ops(c: &mut Criterion) { class_group_ops_single("-3956718340719431033560816005739172412770466038703883350122595604635576709778731043309649272634605425735063624961596232735523376358742586480084965522907889249504047757258883253188259997112353246294323895993621766064597867526555590598296171109353515435289599237581716817331650248439511065683812661746851260538223197043808247010651962962398117206670503394901226393544809521031397039151671384417895714291888633743136733122871000628264376743806741659217599861141099968091237561343232177937280916663464976799422526037223295835103220909629798144507776992742385829474209304917863091971426479552645067278361106093545925188309289850090156462919761399169738282697646499095260815062205117198915610910901974886408275636330747461116245431578813689565691787676837733109337359377237752443898143986060895378572144245069588193342265623936118710486379006798704589510096698445426370143184307451927004120706539519891935325715903611926844068327127", & mut group); } -fn qf_from_seed_single(discriminant_string: &str, group: &mut BenchmarkGroup) { - for k in [1, 2, 4, 8, 16, 32, 64] { - let discriminant = - Discriminant::try_from(BigInt::from_str_radix(discriminant_string, 10).unwrap()) - .unwrap(); +fn hash_to_class_group_single( + discriminant_string: &str, + group: &mut BenchmarkGroup, +) { + let discriminant = + Discriminant::try_from(BigInt::from_str_radix(discriminant_string, 10).unwrap()).unwrap(); + let bits = discriminant.bits(); - let bits = discriminant.bits(); - group.bench_function(format!("{} bits/{}", bits, k), move |b| { - let mut seed = [0u8; 32]; - thread_rng().fill_bytes(&mut seed); - b.iter(|| QuadraticForm::hash_to_group(&seed, &discriminant, k)) - }); - } + group.bench_function(format!("{} bits, default", bits), move |b| { + let mut seed = [0u8; 32]; + thread_rng().fill_bytes(&mut seed); + b.iter(|| QuadraticForm::hash_to_group(&seed, &discriminant)) + }); } fn qf_from_seed(c: &mut Criterion) { let mut group: BenchmarkGroup<_> = c.benchmark_group("QF from seed".to_string()); - qf_from_seed_single("-177936553897922261333164712410242884021141613334565149505848952826212491241771489747671651876796162246463307642229416178115038439759411468976306741727054586407871065937781422970533238726218439981299971510624199735799141406458705159532021234549127390010928558972193365915987838285442951665356778289757172235943", & mut group); - qf_from_seed_single("-23847247576959809407620518371643827142851600013982827283452201808476362679737007351478256611970011299818463606695939850757804842744423478520579143718664008954313076284985803848944695073539132381339505840123539160487844863469984182420796118328898791241477525662002452306976347345400556627774302685021609312012814515255952971689521318993322456321786703461532401532357072300154368747634872702010117806469012662322855405602958496469070700447595558569638530268626808054913729109827208897181454138769346082237168707092766224594001630621792974930286552997453103372073081585433844131063808863644588266240224171853046660887399", & mut group); - qf_from_seed_single("-197094279717529776652945533421408519016291293185778176422038767173246838389717778782272450609952179792102389097362657787152898007436991089430517979761145200893975140029279440383697629952398509684430189989830512427761221044255503309237697000446508821686655886069366603792908696660367648281136978401042076354619587515552611650395121072487799107192700364331538210709886133279169829259881605487142555274403314509719321602412760314496712012939372327177464352472192738122541539747842405435171078768578664156285412471750348778431888800482596404122201686947621151032470989798594881908508768154982514267787085456831726879055929531619461354230569362180363281846948763424056650300352728927552479847814231289623672826128091486169286759", & mut group); - qf_from_seed_single("-3956718340719431033560816005739172412770466038703883350122595604635576709778731043309649272634605425735063624961596232735523376358742586480084965522907889249504047757258883253188259997112353246294323895993621766064597867526555590598296171109353515435289599237581716817331650248439511065683812661746851260538223197043808247010651962962398117206670503394901226393544809521031397039151671384417895714291888633743136733122871000628264376743806741659217599861141099968091237561343232177937280916663464976799422526037223295835103220909629798144507776992742385829474209304917863091971426479552645067278361106093545925188309289850090156462919761399169738282697646499095260815062205117198915610910901974886408275636330747461116245431578813689565691787676837733109337359377237752443898143986060895378572144245069588193342265623936118710486379006798704589510096698445426370143184307451927004120706539519891935325715903611926844068327127", & mut group); + hash_to_class_group_single("-177936553897922261333164712410242884021141613334565149505848952826212491241771489747671651876796162246463307642229416178115038439759411468976306741727054586407871065937781422970533238726218439981299971510624199735799141406458705159532021234549127390010928558972193365915987838285442951665356778289757172235943", & mut group); + hash_to_class_group_single("-23847247576959809407620518371643827142851600013982827283452201808476362679737007351478256611970011299818463606695939850757804842744423478520579143718664008954313076284985803848944695073539132381339505840123539160487844863469984182420796118328898791241477525662002452306976347345400556627774302685021609312012814515255952971689521318993322456321786703461532401532357072300154368747634872702010117806469012662322855405602958496469070700447595558569638530268626808054913729109827208897181454138769346082237168707092766224594001630621792974930286552997453103372073081585433844131063808863644588266240224171853046660887399", & mut group); + hash_to_class_group_single("-197094279717529776652945533421408519016291293185778176422038767173246838389717778782272450609952179792102389097362657787152898007436991089430517979761145200893975140029279440383697629952398509684430189989830512427761221044255503309237697000446508821686655886069366603792908696660367648281136978401042076354619587515552611650395121072487799107192700364331538210709886133279169829259881605487142555274403314509719321602412760314496712012939372327177464352472192738122541539747842405435171078768578664156285412471750348778431888800482596404122201686947621151032470989798594881908508768154982514267787085456831726879055929531619461354230569362180363281846948763424056650300352728927552479847814231289623672826128091486169286759", & mut group); + hash_to_class_group_single("-3956718340719431033560816005739172412770466038703883350122595604635576709778731043309649272634605425735063624961596232735523376358742586480084965522907889249504047757258883253188259997112353246294323895993621766064597867526555590598296171109353515435289599237581716817331650248439511065683812661746851260538223197043808247010651962962398117206670503394901226393544809521031397039151671384417895714291888633743136733122871000628264376743806741659217599861141099968091237561343232177937280916663464976799422526037223295835103220909629798144507776992742385829474209304917863091971426479552645067278361106093545925188309289850090156462919761399169738282697646499095260815062205117198915610910901974886408275636330747461116245431578813689565691787676837733109337359377237752443898143986060895378572144245069588193342265623936118710486379006798704589510096698445426370143184307451927004120706539519891935325715903611926844068327127", & mut group); } criterion_group! { diff --git a/fastcrypto-vdf/src/class_group/discriminant.rs b/fastcrypto-vdf/src/class_group/discriminant.rs index af2aaca03..87d979254 100644 --- a/fastcrypto-vdf/src/class_group/discriminant.rs +++ b/fastcrypto-vdf/src/class_group/discriminant.rs @@ -20,7 +20,7 @@ use std::str::FromStr; pub struct Discriminant(#[serde(with = "crate::class_group::bigint_serde")] BigInt); lazy_static! { - /// Fixed 3072 bit discriminant. Generated from the seed [1,2,3] using [Discriminant::from_seed]. + /// Fixed 3072 bit discriminant. Generated from the seed `[1,2,3]` using [Discriminant::from_seed]. // TODO: Generate this using a seed that we provably cannot influence. pub static ref DISCRIMINANT_3072: Discriminant = Discriminant(BigInt::from_str("-4080390101490206102067801750685552291425412528983716161454985565795560716833845004659207152503580931176637478422335625954692628868126419714053340412299850300602673802493259771830686596468801304317015718872352674945215883546019961626928140286675493693757393881479657605888983279619347902770789061953207866325747708864327315769009839190765716943013935708854055658243676903245686125751909996824976354309908771869043784640567352757672203749399825983258156684652782580603170228640173640869773628592618889352385821753919281706169861276929330689892675986265846043432389737049521845230769417696140636288030698887830215613149485135897148487896368642774768920061430225392365148291796645740474628778185683682893521776342856643134668770656709308404166182149870849376649591338267281149794078240401323227967073641261327798339424740171219484355109588337730742391198073121589465833677609362668436116144203312494461735357918360857667357985711").unwrap()); } diff --git a/fastcrypto-vdf/src/class_group/hash.rs b/fastcrypto-vdf/src/class_group/hash.rs index bebdf09f8..7f593e65d 100644 --- a/fastcrypto-vdf/src/class_group/hash.rs +++ b/fastcrypto-vdf/src/class_group/hash.rs @@ -1,14 +1,13 @@ // Copyright (c) 2022, Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -use std::ops::{AddAssign, ShlAssign, Shr}; - -use num_bigint::{BigInt, UniformBigInt}; +use lazy_static::lazy_static; +use num_bigint::{BigInt, Sign}; use num_integer::Integer; -use num_traits::Signed; -use rand::distributions::uniform::UniformSampler; +use num_traits::{One, Signed}; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; +use std::ops::{Shl, Shr}; use fastcrypto::error::FastCryptoError::InvalidInput; use fastcrypto::error::FastCryptoResult; @@ -22,106 +21,119 @@ use crate::math::hash_prime::is_probable_prime; use crate::math::jacobi; use crate::math::modular_sqrt::modular_square_root; -impl QuadraticForm { - /// Generate a random quadratic form from a seed with the given discriminant. This method is deterministic and it is - /// a random oracle on a large subset of the class group, namely the group elements whose `a` coordinate is a - /// product of `k` primes all smaller than `(sqrt(|discriminant|)/2)^{1/k}`. - /// - /// Increasing `k` speeds-up the function (at least up to some break even point), but it also decreases the size of - /// the range of the hash function, so `k` must be picked no larger than the `k` computed in [largest_allowed_k]. If - /// it is larger, an [InvalidInput] error is returned. If in doubt, use the [hash_to_group_with_default_parameters] - /// instead. - /// - /// The algorithm is taken from https://eprint.iacr.org/2024/295.pdf. - pub fn hash_to_group( - seed: &[u8], - discriminant: &Discriminant, - k: u16, - ) -> FastCryptoResult { - // Sample a and b such that a < sqrt(|discriminant|)/2 and b is the square root of the discriminant modulo a. - let (a, mut b) = sample_modulus(discriminant, seed, k)?; - - // b must be odd but may be negative - if b.is_even() { - b -= &a; - } +/// The security parameter for the hash function in bits. The image will be at least +/// 2^{2*SECURITY_PARAMETER} large to ensure that the hash function is collision resistant. +const SECURITY_PARAMETER_IN_BITS: u64 = 128; - Ok(QuadraticForm::from_a_b_and_discriminant(a, b, discriminant) - .expect("a and b are constructed such that this never fails")) - } +/// This lower limit ensures that the default, secure parameters set below give valid results, +/// namely a reduced quadratic form. +const MINIMAL_DISCRIMINANT_SIZE: u64 = 600; - /// Generate a random quadratic form from a seed with the given discriminant. This method is deterministic, and it - /// is a random oracle on a large subset of the class group. This method picks a default `k` parameter and calls the - /// [hash_to_group](QuadraticForm::hash_to_group) function with this `k`. +/// The image size of the hash function will be "Number of primes of size at most +/// DEFAULT_PRIME_FACTOR_SIZE_IN_BYTES" * DEFAULT_PRIME_FACTORS, so these have been set such that +/// the image is ~260 bits. See [n_bit_primes] for the details of this computation. +const DEFAULT_PRIME_FACTORS: u64 = 2; + +/// The default size of the prime factors should be set such that it is not possible for an +/// adversary to precompute the VDF on all quadratic forms with the first coordinate being the +/// primes of this size. This is an issue because if an adversary can precompute (a1, _, _)^T and +/// (a2, _, _)^T then it is possible to compute (a1*a2, _, _)^T as the composition (a1, _, _)^T * +/// (a2, _, _)^T. +const DEFAULT_PRIME_FACTOR_SIZE_IN_BYTES: u64 = 17; + +impl QuadraticForm { + /// Generate a random quadratic form from a seed with the given discriminant. This method is + /// deterministic, and it is a random oracle on a large subset of the class group. /// - /// This method returns an InvalidInput error if the discriminant is smaller than 800 bits. - pub fn hash_to_group_with_default_parameters( - seed: &[u8], - discriminant: &Discriminant, - ) -> FastCryptoResult { - let k = get_default_k(discriminant.bits() as usize); - Self::hash_to_group(seed, discriminant, k) + /// This method returns an [InvalidInput] error if the discriminant is so small that there are + /// no secure parameters, and it may also happen if the discriminant is not a prime. + pub fn hash_to_group(seed: &[u8], discriminant: &Discriminant) -> FastCryptoResult { + if discriminant.bits() <= MINIMAL_DISCRIMINANT_SIZE { + return Err(InvalidInput); + } + hash_to_group_with_custom_parameters( + seed, + discriminant, + DEFAULT_PRIME_FACTOR_SIZE_IN_BYTES, + DEFAULT_PRIME_FACTORS, + ) } } -fn get_default_k(discriminant_bits: usize) -> u16 { - // This is chosen to ensure that the range of the hash function is large (at least 2^256) but also that the - // performance is near optimal, based on benchmarks. - if discriminant_bits <= 2048 { - 16 - } else { - 32 +/// Generate a random quadratic form from a seed with the given discriminant and custom parameters. +/// +/// The output will be a uniformly random element from the set of points (a,b,c) where a = p_1 ... p_k +/// for some primes p_i < 2^lambda. +/// +/// If the discriminant is not a negative prime, an [InvalidInput] error may be returned. +/// +/// The parameters must be chosen carefully to ensure that the function is secure and for all +/// use cases, [hash_to_group] should be used. +fn hash_to_group_with_custom_parameters( + seed: &[u8], + discriminant: &Discriminant, + prime_factor_size_in_bytes: u64, + prime_factors: u64, +) -> FastCryptoResult { + // Ensure that the image is sufficiently large + debug_assert!( + prime_factors as f64 * n_bit_primes(prime_factor_size_in_bytes * 8) + >= 2.0 * SECURITY_PARAMETER_IN_BITS as f64 + ); + + // Ensure that the prime factors are so large that the corresponding quadratic form cannot be precomputed. + debug_assert!( + n_bit_primes(prime_factor_size_in_bytes * 8) >= SECURITY_PARAMETER_IN_BITS as f64 + ); + + // Ensure that the result will be reduced + debug_assert!( + discriminant.as_bigint().abs().sqrt().shr(1) + > BigInt::one().shl(prime_factors * prime_factor_size_in_bytes) + ); + + // Sample a and b such that a < sqrt(|discriminant|)/2 has exactly prime_factors prime factors and b is the square root of the discriminant modulo a. + let (a, mut b) = sample_modulus( + seed, + discriminant, + prime_factor_size_in_bytes, + prime_factors, + )?; + + // b must be odd but may be negative + if b.is_even() { + b -= &a; } -} -/// Increasing `k` reduces the range of the hash function for a given discriminant. This function returns a choice of -/// `k` such that the range is at least `2^256`, and chooses this it as large as possible. Consult the paper for -/// details. -fn largest_allowed_k(discriminant: &Discriminant) -> u16 { - let bits = discriminant.bits(); - let lambda = 256.0; - let log_b = bits as f64 / 2.0 - 1.0; - let numerator = log_b - lambda; - let denominator = (log_b * 2.0_f64.ln()).log2() + 1.0; - (numerator / denominator).floor() as u16 + QuadraticForm::from_a_b_and_discriminant(a, b, discriminant) } -/// Sample a product of `k` primes and return this along with the square root of the discriminant modulo `a`. If `k` is -/// larger than the largest allowed `k` (as computed in [largest_allowed_k]) for the given discriminant, an -/// [InvalidInput] error is returned. +/// Sample a product of `prime_factors` primes each of size `prime_factor_size_in_bytes` and return +/// this along with the square root of the discriminant modulo `a`. If the discriminant is not a +/// prime, an [InvalidInput] error may be returned. fn sample_modulus( - discriminant: &Discriminant, seed: &[u8], - k: u16, + discriminant: &Discriminant, + prime_factor_size_in_bytes: u64, + prime_factors: u64, ) -> FastCryptoResult<(BigInt, BigInt)> { - // This heuristic bound ensures that the range of the hash function has size at least 2^256. - if discriminant.bits() < 800 || k > largest_allowed_k(discriminant) { - return Err(InvalidInput); - } - - // If a is smaller than this bound and |b| < a, the form is guaranteed to be reduced. - let mut bound: BigInt = discriminant.as_bigint().abs().sqrt().shr(1); - if k > 1 { - bound = bound.nth_root(k as u32); - } - // Seed a rng with the hash of the seed let mut rng = ChaCha8Rng::from_seed(Sha256::digest(seed).digest); - let mut factors = Vec::with_capacity(k as usize); - let mut square_roots = Vec::with_capacity(k as usize); + let mut factors = Vec::with_capacity(prime_factors as usize); + let mut square_roots = Vec::with_capacity(prime_factors as usize); - for _ in 0..k { + for _ in 0..prime_factors { let mut factor; loop { - factor = sample_odd_number(&bound, &mut rng); + factor = sample_odd_number(prime_factor_size_in_bytes, &mut rng); if factors.contains(&factor) { continue; } - // The primality check does not try divisions with small primes, so we do it here. This speeds up the - // algorithm significantly. - if !trial_division(&factor, &PRIMES) { + // The primality check does not try divisions with small primes, so we do it here. This speeds up + // the algorithm significantly. + if PRIMES.iter().any(|p| factor.is_multiple_of(p)) { continue; } @@ -148,27 +160,34 @@ fn sample_modulus( Ok((result, square_root)) } -/// Sample a random odd number in [1, bound) -fn sample_odd_number(bound: &BigInt, rng: &mut R) -> BigInt { - let mut a = UniformBigInt::new(BigInt::from(1), bound.clone().shr(1)).sample(rng); - a.shl_assign(1); - a.add_assign(1); - a +/// Returns an approximation of the log2 of the number of primes smaller than 2^n. +fn n_bit_primes(n: u64) -> f64 { + // The Prime Number Theorem states that the number of primes smaller than n is close to n / ln(n), + // so the number of primes smaller than 2^n is approximately: + // + // log2(2^n / ln 2^n) = n - log2(ln 2^n) + // = n - log2(n ln 2) + // = n - log2(n) - log2(ln 2) + n as f64 - (n as f64).log2() - 2f64.ln().log2() } -/// The odd primes smaller than 100. -const PRIMES: [u64; 24] = [ - 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, -]; +/// Sample a random odd number smaller than 2^{8*size_in_bytes}. +fn sample_odd_number(size_in_bytes: u64, rng: &mut R) -> BigInt { + let mut bytes = vec![0u8; size_in_bytes as usize]; + rng.fill_bytes(&mut bytes); + bytes[0] |= 1; + BigInt::from_bytes_le(Sign::Plus, &bytes) +} -/// Perform trial division on `n` with the given primes. Returns true if neither of the divisors divide `n` -fn trial_division(n: &BigInt, divisors: &[u64]) -> bool { - for p in divisors { - if n.is_multiple_of(&BigInt::from(*p)) { - return false; - } - } - true +lazy_static! { + /// The odd primes smaller than 100. + pub static ref PRIMES: Vec = [ + 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, + 97, + ] + .into_iter() + .map(BigInt::from) + .collect(); } #[cfg(test)] @@ -179,6 +198,7 @@ mod tests { use rand::RngCore; use crate::class_group::discriminant::Discriminant; + use crate::class_group::hash::hash_to_group_with_custom_parameters; use crate::class_group::QuadraticForm; use crate::math::parameterized_group::ParameterizedGroupElement; @@ -188,14 +208,14 @@ mod tests { let discriminant = Discriminant::from_seed(&seed, 1024).unwrap(); for _ in 0..10 { - let qf = QuadraticForm::hash_to_group(&seed, &discriminant, 1).unwrap(); + let qf = hash_to_group_with_custom_parameters(&seed, &discriminant, 17, 2).unwrap(); assert!(qf.is_reduced_assuming_normal()); assert!(qf.is_in_group(&discriminant)); seed[0] += 1; } for _ in 0..10 { - let qf = QuadraticForm::hash_to_group(&seed, &discriminant, 4).unwrap(); + let qf = hash_to_group_with_custom_parameters(&seed, &discriminant, 17, 4).unwrap(); assert!(qf.is_reduced_assuming_normal()); assert!(qf.is_in_group(&discriminant)); seed[0] += 1; @@ -205,32 +225,39 @@ mod tests { #[test] fn qf_from_seed_sanity_tests() { let discriminant = Discriminant::from_seed(b"discriminant seed", 800).unwrap(); - let base_qf = QuadraticForm::hash_to_group(b"qf seed", &discriminant, 6).unwrap(); + let base_qf = + hash_to_group_with_custom_parameters(b"qf seed", &discriminant, 17, 3).unwrap(); assert!(base_qf.is_in_group(&discriminant)); // Same seed, same discriminant, same k - let other_qf = QuadraticForm::hash_to_group(b"qf seed", &discriminant, 6).unwrap(); + let other_qf = + hash_to_group_with_custom_parameters(b"qf seed", &discriminant, 17, 3).unwrap(); assert_eq!(base_qf, other_qf); // Smaller k - let other_qf = QuadraticForm::hash_to_group(b"qf seed", &discriminant, 5).unwrap(); + let other_qf = + hash_to_group_with_custom_parameters(b"qf seed", &discriminant, 17, 2).unwrap(); assert_ne!(base_qf, other_qf); // Larger k - let other_qf = QuadraticForm::hash_to_group(b"qf seed", &discriminant, 7).unwrap(); + let other_qf = + hash_to_group_with_custom_parameters(b"qf seed", &discriminant, 17, 4).unwrap(); assert_ne!(base_qf, other_qf); let mut seed = [0u8; 32]; for _ in 0..10 { // Different seed thread_rng().fill_bytes(&mut seed); - let other_qf = QuadraticForm::hash_to_group(&seed, &discriminant, 6).unwrap(); + let other_qf = + hash_to_group_with_custom_parameters(&seed, &discriminant, 17, 3).unwrap(); assert_ne!(base_qf, other_qf); } let other_discriminant = Discriminant::from_seed(b"other discriminant seed", 800).unwrap(); + // Same seed, same k, other discriminant - let other_qf = QuadraticForm::hash_to_group(b"qf seed", &other_discriminant, 6).unwrap(); + let other_qf = + hash_to_group_with_custom_parameters(b"qf seed", &other_discriminant, 17, 2).unwrap(); assert_ne!(base_qf, other_qf); } @@ -238,28 +265,27 @@ mod tests { fn qf_from_seed_regression_tests() { let discriminant = Discriminant::from_trusted_bigint(-BigInt::from_str_radix("c3811f4ad2f4a7bdf2ed89385866ad526c6dd3aa942e04c141d0562a8e7b014f08804f47b3c2ecbba0a5a0ad8f4d8e869a10cff13dbc522aea141f6d1c42913f2d3bff8d3e7656c72523a2e9d47f838234bd65f05ef3ca86c2f640bca6630ed8d1da21e30a67f83e25b89c32c2d0dc0bacb81bd971b0932a82d131b4a74bff36b60b66543105da2c3ecb1a4e8c2cb6d47c1e85942cce8f3fc50c27856e6dfbd15c0bd5017fea15ae0eb43dfb32b2d947c3131d1951f00bcc40352eeb65e364551e40d13768f443406760ee6b37a5b5819d3f630c034c7f42212ad49c803772aaafd4cd1f87697c68d5a6b0855f475b370b20058558993e76759caa38edbc82407b4e3559bade5f7479a860ebef62fed82d657765ebb8f7f375c2b78f73669760e4bd4932177087a49a0b68d7", 16).unwrap()); - let qf = QuadraticForm::hash_to_group(b"seed", &discriminant, 64).unwrap(); - assert_eq!(bcs::to_bytes(&qf).unwrap(), hex::decode("8b0104397d87d59220ec1bbbf79f471689ad0a48f67625abed478749b2f110d79990684b782160a7e00288c240160d10da0198298fd68f7e3fa0964975f1816d5bb38c978ea1bc9fb5aaefa62971435de9565801c80e545b497d00783c0d518722311c6fa7e924bff4f4765f6f3c6b3de8dcf1c314e7ea8df998de524af394e5cec7dfc867cf07f7eb501dfc279102ff304620732b3d44d3ceeadbd054e20eb953eed85ac684044b1192c1ccaeb9ba79695b28204e7148e8560e4b782c6b20ea20123bda9061eed1920d7ff1fd9741220ee1fac09f596524a12aa993734f2fa4ccf792d46c3bf8320073def0c938e6fb608b8866f70fc380f1a37f3fd9c52935837f5ff06ef6ab882599460e7b950ab17a75602a0b29523ab99c4d030923244a5a9e0431759c59a33a471641c013dadaebdc711baf3a05320330959f13b88c6619c64201bc10517c0bbc69524e6d3345eaeade453ea1ebe8b4ce41068e321399c41e8a90831f9713aa2df564423dfa2fe36e65ccf8157c9ebd24f4ac545482b1a609b7bce94316af8e53cbe191ba073b312a60831ea1f657a92ded17350710ed960309f9853536dd6c8dc45ed0069b1feb7e4acbc7adcf15252e96d5c35e37afbd5b6c413c8511e8225b0f938ae03225b5f2a856aed3551f424795b08807fdc0e38566acdebd699e4db85cf216e3467e9ca3d6c82cfaf77d8446e612de64b1fd3a5df8c5a982df1470daf56f3a15787b35439769c6003693c9b88bf14962b40995931baad12c0e00ac9456556deee599db40209dffe5ebf04f193776ba1dbf3c6fa1a81daafb80ec83e9ce0f8365b8f8fffedf13fe1c2d34d12c2bc5c3c223dd1ea6158645d229e65ccf774c04e4aa4715a67d20f2a20752553c30410651990bbb27d1be95c8b690c7a4edd6450ecbeef312e862944c3eeac7ad25541c14aa6c3da7c14bb4ab6119be67dda0ff244b18711c3da20570ecc1536c3c5cfe297bce254df07fe52d05f54d59272d1fe8c6b30c0eb60a6154b86c71e48379a109986a3632dea79fa0e77fe49931abae8a9188163dc388e772342c0f66d90791a3dd8e337211884aea2b7c2f7920862ade85b6e93d4b1e6afe44a0bf62ed509917cde6ef93a8f6dcd763831652e5c193b7b7ed7d9bb937d1ca1870").unwrap()); + let qf = hash_to_group_with_custom_parameters(b"seed", &discriminant, 34, 1).unwrap(); + assert_eq!(bcs::to_bytes(&qf).unwrap(), hex::decode("2272124e6ab4f8d7ba031217017485e79421d4e56fff43d5aa632a78bf4ffe68a6984922402d5f3fe5d21fd017b87a9409bda5f16fb6349a59bc0ba959f826c2f8f951ae89bf8a026db023918de8bc9b3a76b6572536c19e22ea0f870272dde155bca2f31da8d353ff782736a57a2218393e89e0be6cf6a97e144ef4e6c766a5f8afe506cea47083f70a49ad38dd95cab912f54729ab5ba1bee583ac4b642884df802d41492d13e4c898a63fe120c84ebae686cb1760895f0ffadf3cd46cbf54e4d3998cd0a68b40eb0ffa03df792f8f23b47499c143e6a72c5af9f2f6e626b362c85f7f045d351124dcd7cbdf210fd206c6ad05a502680b093579bbd29c5ef81bc92f90ac34c28292375dd6ed79d272530e22e201ce893304c551b85651a97185e5b8e0433e3bb4583c2bd74eecee64021d59b846b9a55e8dea1888a5d8560e5cc54b58a52e35bac5525e76f8257c2bcaa6").unwrap()); - let qf = QuadraticForm::hash_to_group(b"seed", &discriminant, 32).unwrap(); - assert_eq!(bcs::to_bytes(&qf).unwrap(), hex::decode("91010131e81a0ad42da693099a5c3756a494a32be2f80055634b6ffad271b03a1da3d4fd94d310d63ba16dcfaff8ec034215db89aac493573a399d3ecd0db3418234a96ad8cd92f93b3f9d5964e1e7b6d89c4ea7cecaf8a8b86d3ea039b5b47d76cba90539317efc131a8d25b14c2effe966ffdde5151babfe3f5604c1edbc82132c66a8941edd2fa3392b101770d3e0cb90c19702e4aa2da476751cc4ff0a848db4dfbe56ee3e9f09922b3f55c8a0374a2c296fc5a73fc259375d2a931c8e1515cb872005ed5a50ee85ee663b6130254d389c4092d945490e92deeaf27f91d684509ec1b9dd718f01a041d3ade398fac284c3b220950c8832d030d6b0236fa5e6626f63ec0be64f66d82cdcb45f70a169a2c0fff664d1c37f8fafc0153b9f6aeeff986bf056ec5953fc362fcb229a359053f1393a6cbdecc8a0b3e5853be996b0d0ba7a660c00ed6728f4762f01009c8b8ad12b493e8f3e3e9d58837e42372586101e585d40a1715271afe41fe435a57921bd9acd4fcbadfd4e4396812727c3c5fe100296e01d3baa8d9bbc37904080dfcb4860ba8476ac1a0af200244fc8028e71ff7b3a58a85341cb0cdf9e03009c53fa427eea51d6703ddba90c70752d84d76685cb64596f335f74445d15d6463516126d2d3fc32871d472192a555847da6dbccb08396013a444c2f900de32ae5df6bdd8bdc7e870eef02f5a953194d831baaa8f653fc59fb3513b0c3ec5206dd3c41c0ee72f70ddba4d3ae0245928ceb1b0d8f59f5133d0f7647187094652cf6773aab2d05fa0a0b161ba19ae4f954c2d80bfdacb0c51ee2d5ad1b25240e348b4472db239d2dbc6864af6e1425d88a94b3ce8a8f6d754799c59609ab095a469cda07869fff1ad558fe0517a6c35018d224ca52af18537e460345e38a579af48b1043392312d8ed9c868f72993d092843c939817102e89db737c3509eea800be399800de35570a0d255369b9c49013e208c598570a6c888424651ed5b371bedfc571c30e39d971d262bdf3a4b4d60b5f29ec7fac14b8fcb4c654d346c7313113c027605bce2c2464827ff44f1b839be19025014cf8d291455bc67aa4277edd4e3ded467778611d3f7da4e3002eef718a5110b000af428dc3be5e59e89ec798f56310b099464e7c765b8f1c84f1e67205feb6376338925be58657093046").unwrap()); + let qf = hash_to_group_with_custom_parameters(b"seed", &discriminant, 17, 2).unwrap(); + assert_eq!(bcs::to_bytes(&qf).unwrap(), hex::decode("2300a0f9131173334d92c14bbc1d83d411168de882cb1e387b48a5194006c58632e9a9c33269cc033517c7d6b299377c647ba53aded9e27341dd4b941716b9e5191144864791c162fd9e52c5572ff85beae15ebdd9a2ab8a024dbaa59598e97587ae8ecb848611552c21b4a7a32ee1a69dc968dbc37b67774712a9ca92d630113853952ec9d55c737738c59bfcd452ab7f45d1c8df8ce405f55de4392d85d96428a8f1b547b44a11a2b418f5b4ccbd5385723fd34e60a7e3a4b8ac812addf27ace931c3450f989eae8c382e1f9181914e96a35902e6ef5fe972b7d0a1562d7274a68256de34a228c5260df099baa42a13cc011713dd246f149cb085b5002701e95c1a9c7b61467aefab791d9793bfed8c3ebfb251fe0d8f578b165d79b2cb8109cd6b62f84405f659668b9580fffd6f7631f66079ec18846a9e9feb75c128e318914ff93fcb24152ba7c655131af3a75832b37a5024c8095a13faadd23723b90c586ec").unwrap()); - let qf = QuadraticForm::hash_to_group(b"seed", &discriminant, 16).unwrap(); - assert_eq!(bcs::to_bytes(&qf).unwrap(), hex::decode("9401031797d54ddb89c329b525b1aa6e3f1e193d93056b3c19d34b422c0f65212f9abacb807116fff67eeac9e73c8aa6e57a8eecea4e3fb78551d277831baf6e657afbfe99c063af48fd67a6f9b48174f9f4207caaba39eb90bbe09318597473fb281bc3e95ea6dc8ad773c826d4a97452253f7c7662593bee386d0d1d4a7596ea810661e0391c0ab005642dc1dcc33649340c408dc194022d85bd17b5e06fc59ab741554454d0450e12b4007c0aae9bb68ca4d9f1edac4fcd1577d8a4b23ea5d487f11acee384e71e4c6037b17cd60c496c099be926d21b52bfabccfe4e402abac837b9b0818ef0e4172039baf9d46a3c2864866870df86e8f1e3bd813a53b2d217d0234bfe67f245398aad77f8db7cde11c259f247ae96d5af982ddf8cf7dad2b0225eece2de9ee00c83fb8cb32ba7f77599033b4a2ad35712ab0cc6eb69d67cfde5b6647fca0ebb9b3a7db0092bd8a31c509dfea38d961fe24ad5fa68f73ae5bd5b42538cfe62874e8a8d0f72f52492524791ad51d70e433dcd988033ab4be061cdab0b9b7d960625cde8430dd16e02b2bb1ff510231f59262dd93a796ccf99825f3f1144e58667303509950300a78b3c507be066b2aa31ed2cbbc4de664d27561825164240eb639860a561c0bd8abe11790dc875f2a13c6171c9eda777a03f5a4258b99639ded20b938c5c494223aa72e9d612471ae0e54967af8730bd54a32e408511adcab4816a95b1c9924f56adaf60be01715c02fb80b35f531cf1298f661fe8e40cf1f800444a291e26303e79291db8900067069fe203e97376b88f6ada38ece7e04f87241fd1bb395076621c0a339cb283ca960a8252d95f4d4fe0c3435943285ca9de7df811fd1642862a9fdacb258ed05e27cbf7001b7804a0421f5ae0eca95dce9aa5c6d8b873ee0eb696db556d4e12c246eacf93c1e6f2feee2a73301540101cf2154c94cc2ef7a656e0d65aa78316756b875d27100d151b1cbf5dabb185429ed20693a7a395703f99e27e88c7b5b919fec492e59299b8bb1abcf451ac7f0ec4789dbf4a95835a5da0569f83440045a654e28d313212dd56b01627c6edf27f261dd75336bda675f698887771b9afd28ca8b3379cbbcffb373cb8803738e48fd5f286f77c40c1bc94e47eccefce38be9de1be9a22751634bf6cd2cf4a").unwrap()); + let qf = hash_to_group_with_custom_parameters(b"seed", &discriminant, 68, 1).unwrap(); + assert_eq!(bcs::to_bytes(&qf).unwrap(), hex::decode("445bb192c1106b9b7dd9789cb0882c652db9b2d32ee59feb059ffaa8ff392d38b5878e79503bbea893624e847ebe0da2c38606620fc157d00cbb911a634d6c510665b8edff4408b2d1f92ee84acd0d43fead1d7fe8cb353e47b280480e432a8d0327d3059d6f213c30cc87e79f22e1325136c9fbeb76347e9ad989925045f373675c9bb580b2daf03529e9010088751b17498f404f0fa45456e75f49240bdca7b5d587376406ac2c674c4be7a89ef96616e79a1275f980cb6f1622b44657dc26799cfa0eb50e755a04296701a5904251de540ec26246d6571f17b9bc6ecdecc40f66e99fd0a5cf088f73fae967cc985640d5d627a23997d2928c74e888a9aeae55a6e89932e534ffe1d0ba56817c7e0c20ae3379df01b055d8f03085cabbf5608309924bc754d23bd3141766d47c07cdcd93842fe4fb03ea15e23dfbeebc15393c41556d36bd1d3093701e8c7b91e10b7c70d39970091dd6bfefe034faacdb3a8158ce33711d5483d8b91793438d46b9dcd7eaf9a6").unwrap()); - let qf = QuadraticForm::hash_to_group(b"seed", &discriminant, 8).unwrap(); - assert_eq!(bcs::to_bytes(&qf).unwrap(), hex::decode("950166d2bf1d0ad57988b9b6a789fc2acab4ae89fa080022a9cc9566a5c0b67cf4f6d1a2a7ad0d4488ecea1c59cec64de1d424273065e2186a08a8ee37fc8f7a2cc34a167224133f78e47eceb3dc9781655289ed9c988f5267f5ba3fb1173d7f52071e9b9a3bf196b6db657c227245222b6871c04e2956d37543d8b3f422722c486b10e82bff46b35c15415e1dbbf5b0f84159dd961aef8502fed697e8c66401370be358a98d8648f0385bf2a72705767f8a37b8c3bd0a0c7824944b4ff1b109094d6fa19e063d5a3ec1a8475f9820bbc9ce10cb45095de0daeaa227277a87d6aefff2068c8cbd95358b54a4ed151a86858362b91f86b283707239c2d4661a847917508fe3ec8df2f928879b4a3ebea2373daa233314fd1c36f4ee264f1e1913c54bc388f6b911f9ba322bd33361db6988acf37589332459068175ede93967f8ea9442e77117e22d7d8c53a42b1a3279c357068df9584ac2b6024b952a9ba7011469a37cd470d9d8443bde67c696b2cee2cd55ad5da2d34c9b63f132bc2c4182f415d72c8343ab313ba4ad527ab886badec927fc0f1d829f894a3a34a32df40200d70e22e98c42fa7b109e6c3fcc6a36f423efee520d588e0fb4a78e2bb997f3c6162c3cec1363150406e3142b4716f8c148e91d0d4cc818cb330b0bbd14ecfe39145ee71b36018366f417774554181437d1787458cc8fd3f0c25a27696de5e285209fcfe2cad01be819c1c16027903033114e56a049e4a57f5afe8d87e6032c107a77caeec944aeb3e707af8a446e17b07aa2e6c551eb768037ad96ca1f28939cd8154cd7f98abed95ae96920f88a820d1cdc4ed8bff892bede47606bd4c6c3f4431256ecf3ff3aeecd668aa4a1da0c90a14562e172bf32c281a83f688cda5fcb756c9d353c9a665744ba94332212f87ab512ae36778cf0e760c35500158163accb440b24713a48b789c03da2e348b99234277055dce5d92a05b9587a4cd283739c7ae4c8552d4d7088946ce693de313f955eee31c1f5d2aa3087dd9d3629ab9c95ab0ee7659b1e0a49d4bb6a441f821b88b88d7cec5fd225f6dcd076608b1f80c6561c43b747bebdbc3e636bb29e7675474b50").unwrap()); + let qf = hash_to_group_with_custom_parameters(b"seed", &discriminant, 34, 2).unwrap(); + assert_eq!(bcs::to_bytes(&qf).unwrap(), hex::decode("44377b7cf8cb36c4bc0742ffeaf3816b6798bf915b9c8c584a77d65e30973863e43a5af5a252a7ff7615d2d889c026daf82a92833b5becd99ad2d250e5eb91b4ae1f98803d66fec045495392669db030e29e8c58c4bdbd98c27360e9f003ecfee16dfdacbc1c81805bb5a82aba9203483016dd141fd0c18abf1f88cc9116480d9444da2feecbfb0685051b844cfda19fa0d6967a2571ac626a2c1185ca83bc9c854a610595f665753f246cffe90100e184a2ed6c29954f1f43a0f97e961e8ff8d6965d32ad8f76171ba3e756de8795f97606445fa7d7ccaa542056e6216cc54c28396909e0fa6416e8ff2b104ca28e8d372e07834605ca99a394e6a6c19b310786157e7a0e9142edf919022303d6a1399d6bb1c181746be656b66bfded01ed4113cfd9df14ad97117c9700919d9e2aaa2fee589c414307bfefba619daaf654dfa418fb1c088b88574cc6abb344b0715f488782fbd64c6cccf7956b9e7ce9898325ee46fdd2f565609317dce1a74983343355d23f31dd28801e6322c01edcf41508fcf9c001f9702b6ef237d69f183af99436a9f86a07ee").unwrap()); - let qf = QuadraticForm::hash_to_group(b"seed", &discriminant, 4).unwrap(); - assert_eq!(bcs::to_bytes(&qf).unwrap(), hex::decode("960102d12a2199c0d002e25d9f3ab2972ca4a625d272801e86da11690b28ce005e83ac8f58d6ff97945d2e15a6fba11dd37b3ada8ef8cc2e8fe505fcc470dbd76562992c9ac14f02febcd05ee14dae7f611cce78676d1301dfc97c8c2c0d49ee00a5d6bd9ab50540a533518c7cf58f7756a74595ae10a759d0cd6e72f557193a1a7d7a68ec180bb985aef1f1f64ed10637041069d343de99e001f9e5bf7c4c79a58012dcbf3c8c062dd4971ab88176c6dfd1ce314d85f98c31ba67c1dd99ce3f7d2a04be56deaec618436e6cc5fc68d9417d955478f04dfc0af4e85726e3f1c0a7d9613d3b994035efbd1fcc90a2186895f43732b787b717211b882227496de79dd3cb6d3387ee8041a6d9a9dfa83af3fbbe57e89b408077241fe0aef8dd585982205c7d846921421ffcc84e455cd60fa9c15f13b31d5e1a96f4ed37506571baf9eb935f8b7aa184b94ea3662db78cda03164e34490c7cf2e74c4cc68793e855b0c0d1e3a4c7683102a114480629f5373bcac4ea28e6a0601a3baa02034e12ac78243002acf5441c693308133fbff6e1aa6e5ab5c904cf41f94febd3a2847b54e516c9ca42bbc08695cd3ab07f4d1ca8d41108bf552cdbdebdd3a3cfcb3d296245b86ec788c4315f8ce03565e5bc6cf27babc4585874ee1cc64dd487fc7c43a1c82ab47783d05c7a7347cd6efe0645a746ce3a131649a8047a832665232be81d006da67ed832691ba8d32e9374b2f38a40d127dd677d011f2d9840b27b4817bb3bd98083c7260dc8ec9ccc75ab19512a05a6e36cf27518415b2f65adc79fab3cbf71836b07a6395870c4b55d8d973266a0658e497effe0ecf23a2109b68a8d8b6c8d33d122122f9787a3d63b0c85b2698156d759cfb4d8a1fb656ca002d9c84c7ec74fddccbe097c73a36fc8a4f51b29374970e16c8da0ad99cc0d18e48323376757205a6efc").unwrap()); + let qf = hash_to_group_with_custom_parameters(b"seed", &discriminant, 17, 4).unwrap(); + assert_eq!(bcs::to_bytes(&qf).unwrap(), hex::decode("44658cdcc513982dd4e5446a7d41aebce6f8cbd523475b4d1a8547b8b43434fa9eca9b9032844356752b4f4032bfb6b102ee7e0c20b98041414870180baa248f3f596df2df6601c8abfbef53cc4c19cecb3476845f3ebecbb375b652fadf21092ab5324bb1d788285bf6387cc0465333cc303757ef041eb116af12e5df3def1a72d562f58416c566df63456539e57febed5929d96631b8c8ddda294009c5bea70870ed0546d0ea1a67c0e9ffe8017b36740e2ae3f722074cec6cb13f33c47c144dff7ee118dbb07bd3415c91c1295a123724f24fe2bdb5c0565dd90395901d6776407b25f5fe773c54b9e0cb30500718f790d62de3b04de64cbde739d9c2572d0d155971b49e9de123b5d6a3d9f9bcfaefe1954d62302780f800c0a28ae84f2ea717194d649dae838d49454735ef3198c467dc65a81cb39d7c85ae31587df9abb985519d87065267ba1dd93384f8ec27251c8f06bd973ae284bdbb4251fc47ff928a67ac1eb40dc9182c83d0deeb9f9f455311b3b95e6c40bc60be82aa82885db585200e0fc8f0142b426db1cf45fb95f3919279a78a").unwrap()); } #[test] fn qf_default_hash_test() { let discriminant = Discriminant::from_trusted_bigint(-BigInt::from_str_radix("c3811f4ad2f4a7bdf2ed89385866ad526c6dd3aa942e04c141d0562a8e7b014f08804f47b3c2ecbba0a5a0ad8f4d8e869a10cff13dbc522aea141f6d1c42913f2d3bff8d3e7656c72523a2e9d47f838234bd65f05ef3ca86c2f640bca6630ed8d1da21e30a67f83e25b89c32c2d0dc0bacb81bd971b0932a82d131b4a74bff36b60b66543105da2c3ecb1a4e8c2cb6d47c1e85942cce8f3fc50c27856e6dfbd15c0bd5017fea15ae0eb43dfb32b2d947c3131d1951f00bcc40352eeb65e364551e40d13768f443406760ee6b37a5b5819d3f630c034c7f42212ad49c803772aaafd4cd1f87697c68d5a6b0855f475b370b20058558993e76759caa38edbc82407b4e3559bade5f7479a860ebef62fed82d657765ebb8f7f375c2b78f73669760e4bd4932177087a49a0b68d7", 16).unwrap()); - let qf = - QuadraticForm::hash_to_group_with_default_parameters(b"seed", &discriminant).unwrap(); - assert_eq!(bcs::to_bytes(&qf).unwrap(), hex::decode("91010131e81a0ad42da693099a5c3756a494a32be2f80055634b6ffad271b03a1da3d4fd94d310d63ba16dcfaff8ec034215db89aac493573a399d3ecd0db3418234a96ad8cd92f93b3f9d5964e1e7b6d89c4ea7cecaf8a8b86d3ea039b5b47d76cba90539317efc131a8d25b14c2effe966ffdde5151babfe3f5604c1edbc82132c66a8941edd2fa3392b101770d3e0cb90c19702e4aa2da476751cc4ff0a848db4dfbe56ee3e9f09922b3f55c8a0374a2c296fc5a73fc259375d2a931c8e1515cb872005ed5a50ee85ee663b6130254d389c4092d945490e92deeaf27f91d684509ec1b9dd718f01a041d3ade398fac284c3b220950c8832d030d6b0236fa5e6626f63ec0be64f66d82cdcb45f70a169a2c0fff664d1c37f8fafc0153b9f6aeeff986bf056ec5953fc362fcb229a359053f1393a6cbdecc8a0b3e5853be996b0d0ba7a660c00ed6728f4762f01009c8b8ad12b493e8f3e3e9d58837e42372586101e585d40a1715271afe41fe435a57921bd9acd4fcbadfd4e4396812727c3c5fe100296e01d3baa8d9bbc37904080dfcb4860ba8476ac1a0af200244fc8028e71ff7b3a58a85341cb0cdf9e03009c53fa427eea51d6703ddba90c70752d84d76685cb64596f335f74445d15d6463516126d2d3fc32871d472192a555847da6dbccb08396013a444c2f900de32ae5df6bdd8bdc7e870eef02f5a953194d831baaa8f653fc59fb3513b0c3ec5206dd3c41c0ee72f70ddba4d3ae0245928ceb1b0d8f59f5133d0f7647187094652cf6773aab2d05fa0a0b161ba19ae4f954c2d80bfdacb0c51ee2d5ad1b25240e348b4472db239d2dbc6864af6e1425d88a94b3ce8a8f6d754799c59609ab095a469cda07869fff1ad558fe0517a6c35018d224ca52af18537e460345e38a579af48b1043392312d8ed9c868f72993d092843c939817102e89db737c3509eea800be399800de35570a0d255369b9c49013e208c598570a6c888424651ed5b371bedfc571c30e39d971d262bdf3a4b4d60b5f29ec7fac14b8fcb4c654d346c7313113c027605bce2c2464827ff44f1b839be19025014cf8d291455bc67aa4277edd4e3ded467778611d3f7da4e3002eef718a5110b000af428dc3be5e59e89ec798f56310b099464e7c765b8f1c84f1e67205feb6376338925be58657093046").unwrap()); + let qf = QuadraticForm::hash_to_group(b"seed", &discriminant).unwrap(); + assert_eq!(bcs::to_bytes(&qf).unwrap(), hex::decode("2300a0f9131173334d92c14bbc1d83d411168de882cb1e387b48a5194006c58632e9a9c33269cc033517c7d6b299377c647ba53aded9e27341dd4b941716b9e5191144864791c162fd9e52c5572ff85beae15ebdd9a2ab8a024dbaa59598e97587ae8ecb848611552c21b4a7a32ee1a69dc968dbc37b67774712a9ca92d630113853952ec9d55c737738c59bfcd452ab7f45d1c8df8ce405f55de4392d85d96428a8f1b547b44a11a2b418f5b4ccbd5385723fd34e60a7e3a4b8ac812addf27ace931c3450f989eae8c382e1f9181914e96a35902e6ef5fe972b7d0a1562d7274a68256de34a228c5260df099baa42a13cc011713dd246f149cb085b5002701e95c1a9c7b61467aefab791d9793bfed8c3ebfb251fe0d8f578b165d79b2cb8109cd6b62f84405f659668b9580fffd6f7631f66079ec18846a9e9feb75c128e318914ff93fcb24152ba7c655131af3a75832b37a5024c8095a13faadd23723b90c586ec").unwrap()); } } diff --git a/fastcrypto-vdf/src/class_group/tests.rs b/fastcrypto-vdf/src/class_group/tests.rs index d71efe9cc..f88d285f3 100644 --- a/fastcrypto-vdf/src/class_group/tests.rs +++ b/fastcrypto-vdf/src/class_group/tests.rs @@ -33,9 +33,7 @@ fn test_qf_to_from_bytes() { fn test_large_qf_to_from_bytes() { assert_eq!(DISCRIMINANT_3072.bits(), 3072); - let expected = - QuadraticForm::hash_to_group_with_default_parameters(&[1, 2, 3], &DISCRIMINANT_3072) - .unwrap(); + let expected = QuadraticForm::hash_to_group(&[1, 2, 3], &DISCRIMINANT_3072).unwrap(); let bytes = bcs::to_bytes(&expected).unwrap(); let actual = bcs::from_bytes(&bytes).unwrap(); assert_eq!(expected, actual); diff --git a/fastcrypto-vdf/src/vdf/wesolowski.rs b/fastcrypto-vdf/src/vdf/wesolowski.rs index 2f680f9b4..999dbf825 100644 --- a/fastcrypto-vdf/src/vdf/wesolowski.rs +++ b/fastcrypto-vdf/src/vdf/wesolowski.rs @@ -236,16 +236,12 @@ mod tests { ); // Compute the VDF input from the combined randomness - let input = QuadraticForm::hash_to_group_with_default_parameters( - &combined_randomness, - &DISCRIMINANT_3072, - ) - .unwrap(); - assert_eq!(bcs::to_bytes(&input).unwrap(), hex::decode("bc01009ed67199c633da0faa75a8ed0ff5c3ae7c278c79aad85953cdf86d57101b1ee941e5239b7d614e5b16eac269c460f16d57a12c75b52c48fac643a1c4918fab86805fe08fcd6b38093a17143cca7550fd018b8bc6871fb441b406bec7a7f3a61c3b2a5aa9daca5f9a6fa474b270688de643323de1acc8073a3418bc1681a614c1abb5fa56b61a7d6df4260547c9f613c5f0dbd7cb91a478ac94b1cce6b1f4784dc161ec3c85bf02cf99fd460b0b25a44d1990dacd1fe7a43b797611ea0210645fef3905f7e1accf97bd3b868a8a99d4a1a546e5a55e20f343fc2724829f1770591b50a73c93ec9b8c01ce1fa6b84eddd5a7ddd077110e21b8e058bf2fed2592a5449db177ec0e32595b20bda5779c2f346b01df8c0d277d9d3a7fe0a04e67b210be60334efdadb7abc5ac001b71509c2d487d9d26443527c1b8b02dfcffc50ef98020f569cdf6fffca5870b0e502493fceee35b79eed99e2c758a0aff4c86b2af0dd223e270ecf84eb7405fe35a9e37d6b080efa3c59806c2ceffa82f38502f9d37b6c298cf07534347cd9ee436406784bd7e0a57d380dd3923ddca13d86f3b2c83a135f125f9429a6802247a0e926b54144d74e4e8f66f0303cdc91843ce7e1fb9c6276c000512c0709c7fbfde2b80e66db77222447ef6b4da4a698e011c6de95ad88738aea465c158288a54223c7f7152577cc48691af57e2631e3224b7c94e2a4c5034db35bbf9e807753fa51da8798bf63b7e6ebd857ca4cf01fcab7a33e63fa89eb386e2ef98046c44491bdf8d62ede2af4ab79ccac88e404abb649b92f49c9f9abcf2216bb628e96400a75a66c12b6ff1c6dae498dd4183ad989921ebc6a1be73127741333671eb72cd25eabc69fecc3c50da06b4a3af155264d4e39e8c681b8c5555d4cab748ed15d119527820e01854fa203c2deba3a67620d47733919e8c71d659e60e86db69905ebdc4dbeda67f77291c2202b2116a05f227f963a97eb8c87104b2df349f01f251aa22bbd41541998ce755309b98d9597d7ee26b6acaef1869885c775e6ceb710c36c07e401e17a8ccb838e33f64e43e4db3491b5cef6e800c4e494610ab81a8b489263b86976160d7d0106cab79bf2a2fce5b01e8f9d1fb069a98e814c94f10d9917b7ea27209bc822b35741f56a9aeadb75a7eae6a8cbd7df08e079db64fd48655f42c24c14bb6c72e744206a3e15deee45cab74d589deb1055e0e69fe508a2ef356dc4e2caaaf89f44a520722490374eade8573429d0d6d16e3c681853f96759cc6e3ea3aaad55284282abd40686281ff944c6a507086143cf76d0f7f93b486d552fa4698656cff8a325fea84943333645b29ee11c99555b2076a09466f6e602db663e1bd45c523a12a7fcd2328d5139d14b25561b94f62f69d436c5d4c92b01ae3a91baa1b5781bd0bf2156e1d0042ab2cbc6e10f4389868fc41d05b19bfe3dfcaacb0478b3dce887da8435c9d49f457fd54e129133e5ce87c39acb9206213daec867fca35e6b612c523fb9fba959542a777ea74").unwrap()); + let input = QuadraticForm::hash_to_group(&combined_randomness, &DISCRIMINANT_3072).unwrap(); + assert_eq!(bcs::to_bytes(&input).unwrap(), hex::decode("2300b094d4facc4b552df23714f5d09a6ddfde4f0d06163b7fda1fc022ebafa5be196f4d33fc3bce80649d3e64cb6d1497bf65f6b40ffcf5ca3211889b994019cf4dfa8697b0f69a70c5ee14ef438cf0e50b2f93786f506fde02412ad75a441ab785dbe34ce00cb829962e4216f964fb8c53852cc86e0977428322ef7d505e10c37260a9ebeb0cc66ddb59901556bc4a6fa9bc0f9d8159c3319f3a2e1781912000917a12054126a728b46dc6849cda81648e0f34200824a050fd1e01382bf4cfa17019ae2f6f48cfbe6e4ef84e1b00361ed6a4892e4b5db94e8847e0c7050637d668c5cbef08fc60fde9b5d68a02af4c5ed7f7ba99f3b68eb59fa2ea8a282b705124ec5577f166130a0c043823ea1a3fd495643dfbe8d294a9f034d91f8c8e76689a676ebe1ded776bdf7fd1e4050a84b8cead2e6adcd0ae7d12a6e221cb6579eb54911d3ce9739048924f3451c07b203ab811a9506d4d134b335eab6e84c49983f405f3d5b2040c522922e501086c19db5a82a4c7134a7cad5738bc884b382e4b3cfca0521a0e7eacd0d053855dcbb6fa897f122cc2b49df60d4d3424d37a01764b77b65b5f5472365ae3b82a3cb7f9f7a13d4a6ca100c4").unwrap()); // Compute the output of the VDF let (output, proof) = vdf.evaluate(&input).unwrap(); - assert_eq!(bcs::to_bytes(&output).unwrap(), hex::decode("c001503be6eff558a40ba145da5aa9d1270367f32cde44c1601846cdd3d0911abce8ab6adb6b82682b45107545e9ae1efca44dd6f3ba8d95a687652b94f479f6b1a37156c44194d6bc5f266098b75251b12de6fa67de6aea14250c0481694db5f24db5e3c89da3354aafc10c4bd0371f9a175d1b5b193190c4c1089ed7a95dc07f1ce29021b55f3aaa7eb65725d61277f0996b783c005a919ba121d81f211f63d188ac525056235504fe4858765dc6498362d98e8540287a0ff78424c18de53abe46c0014f847bd49f599960fe3c3b7cfc571cd854c7d21b0e9984070f7e168c872a6e6480d8fd37d30602f57a237b83ae961e6a4acb94b78c32d04f06058bda037d6ad313c81f823db25c53c265b02a29008f727f95010c82b0cf8745e77a7f4000dac929ba83a4594482b4e6ff59c93a78df5c816f244914329c145e288fd3fd4800a1cc2df23f386112e569608e6de40ee65fe870960b4e3fee4bb188d8db0dd5df3c2384eb24a797eb20cf8524d563663ccde866a405e2713cfafdb760e50c77a797c10100a31fc5ca0a91aa788d5f5df17a1433f1a0e6e4da440ce935b1b48dc6868c8fc00d7ee725ce21797a6c4440af02570466081479e99eee1a5b509a3e1ac2e000ed386c35d9fadd130df2a292fa5f9aa2c195c48c9d11e58ac98c8dbd2169721ed2d2c9f5544de17deeaa9655360ed7baa46820f5e008af1e3f028d819dee3fee50ab55b266385dfc8f65f7f0c1b6149e5295bfefb83b14db3a30b2cefd1495ba4e5ae39d2b729f9644fc28764d03243fad3e61145ed83cbf2708b60c0b7cac7148").unwrap()); + assert_eq!(bcs::to_bytes(&output).unwrap(), hex::decode("c001532225cbc82be245b2571c83babcc61ab86234465a7e91e000b14b1a3426cef72a90e5db733523ba5593200c35281b77156eaa978b7ad1c5eac1336ca8e74b1341ae072b9fd620d24ff33590903668ac6d5f53fb6ac32d7c0cd380c790418f68e64505aeb82f40d6e9bcf3642850c440bc458c0465965ce384c7d6d11570d3499e265a38e4e52580e54580fccd28b1dbb9d32a7bca5e59dc9d083c6c6642df20a160da447c78f2695d424984531a1de5a35cd13ba496cf9c0adec749d31d2bbfc001f2d872ba990524a2756e74224f1162bcbceafb2222a2ca19255511f775ceb74a4bc6a36848377201b62b3bc12332781e20097612005d642033866bca926d9242bb2d0a6d305b0e46e9715340b64012271d3fe2c614ab9dca9d2f81a18ba8f49b5b9945fd4b3af743d4c7f2ac0906266ae4c26915bfcbe9ec6a1a17420c442e3cb00422efb70467188e124a56e171004521360f2da80323a2b9d327c43931327a59a711986116333010e743d9ff1c3de811281e5eba84e49c33a78d60e27b065fc101008af0c8fa3fe81a2bbdcdbc3040727f3797121254d48b182ca4a4cd698f0523057b4b223a94253a75842fe823085e8a55b2cb639e4799256f03252ded38eb93a544ca93b89f72c358098b0badedda13de0d3c99c8a33e3b6fa4d894b4031e5400872453086b36cb28d02497c3e2f1e4c6a0b4344b4dc94f4b39481cef8ea05d170f0159f06d7ffcbc99e214d62a1297153a58c41d11dacae5b409b5e6023159897bb773e0a146b7785dc772bc2c61a75aa9b30765027fc1a36bf31113799d2644").unwrap()); assert_eq!(bcs::to_bytes(&proof).unwrap(), hex::decode("0101010180032cf35709e1301d02b40a0dbe3dadfe6ec1eeba8fb8060a1decd0c7a126ea3f27fadcad81435601b0e0abca5c89173ef639e5a88043aa29801e6799e430b509e479b57af981f9ddd48d3a8d5919f99258081557a08270bb441233c78030a01e03ec199b5e3eef5ccc9b1a3d4841cbe4ff529c22a8cd1b1b0075338d864e3890942df6b007d2c3e3a8ef1ce7490c6bbec5372adfcbf8704a1ffc9a69db8d9cdc54762f019036e450e457325eef74b794f3f16ff327d68079a5b9de49163d7323937374f8a785a8f9afe84d6a71b336e4de00f239ee3af1d7604a3985e610e1603bd0e1a4998e19fa0c8920ffd8d61b0a87eeee50ac7c03ff7c4708a34f3bc92fd0103758c954ee34032cee2c78ad8cdc79a35dbc810196b7bf6833e1c45c83b09c0d1b78bc6f8753e10770e7045b08d50b4aa16a75b27a096d5ec1331f1fd0a44e95a8737c20240c90307b5497d3470393c2a00da0649e86d13e820591296c644fc1eef9e7c6ca4967c5e19df3153cd7fbd598c271e11c10397349ddc8cc8452ec").unwrap()); // Verify the output and proof @@ -254,7 +250,7 @@ mod tests { // Derive randomness from the output let randomness = Sha256::digest(bcs::to_bytes(&output).unwrap()); let expected = - hex::decode("f9ea418d988bbe5b13839bb5958aa78d43cc9f57b3dc9d84cebc7c1f5b1a338e") + hex::decode("edc12df54fdcb9ca51422c52125d617bdf6482f4c4d6d0d1d96063ee3f2a6746") .unwrap(); assert_eq!(randomness.to_vec(), expected); }