From 40ec9891848e4c49a27aa696812ed216c0cde320 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Sun, 30 Jul 2017 00:11:34 -0600 Subject: [PATCH] Add (not particularly efficient) from_str to PrimeField. --- src/bls12_381/fq.rs | 1 + src/bls12_381/fr.rs | 1 + src/lib.rs | 40 ++++++++++++++++++++++++++++++++++++++++ src/tests/field.rs | 36 +++++++++++++++++++++++++++++++++++- 4 files changed, 77 insertions(+), 1 deletion(-) diff --git a/src/bls12_381/fq.rs b/src/bls12_381/fq.rs index ea69d0e..cf81975 100644 --- a/src/bls12_381/fq.rs +++ b/src/bls12_381/fq.rs @@ -1766,6 +1766,7 @@ fn fq_field_tests() { ::tests::field::random_field_tests::(); ::tests::field::random_sqrt_tests::(); ::tests::field::random_frobenius_tests::(Fq::char(), 13); + ::tests::field::from_str_tests::(); } #[test] diff --git a/src/bls12_381/fr.rs b/src/bls12_381/fr.rs index 6d6c9ef..dcfc11b 100644 --- a/src/bls12_381/fr.rs +++ b/src/bls12_381/fr.rs @@ -1478,6 +1478,7 @@ fn fr_field_tests() { ::tests::field::random_field_tests::(); ::tests::field::random_sqrt_tests::(); ::tests::field::random_frobenius_tests::(Fr::char(), 13); + ::tests::field::from_str_tests::(); } #[test] diff --git a/src/lib.rs b/src/lib.rs index a8d72ce..96ea04b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -477,6 +477,46 @@ pub trait PrimeField: Field /// representation. type Repr: PrimeFieldRepr + From; + /// Interpret a string of numbers as a (congruent) prime field element. + /// Does not accept unnecessary leading zeroes or a blank string. + fn from_str(s: &str) -> Option { + if s.len() == 0 { + return None; + } + + if s == "0" { + return Some(Self::zero()); + } + + let mut res = Self::zero(); + + let ten = Self::from_repr(Self::Repr::from(10)).unwrap(); + + let mut first_digit = true; + + for c in s.chars() { + match c.to_digit(10) { + Some(c) => { + if first_digit { + if c == 0 { + return None; + } + + first_digit = false; + } + + res.mul_assign(&ten); + res.add_assign(&Self::from_repr(Self::Repr::from(c as u64)).unwrap()); + }, + None => { + return None; + } + } + } + + Some(res) + } + /// Convert this prime field element into a biginteger representation. fn from_repr(Self::Repr) -> Result; diff --git a/src/tests/field.rs b/src/tests/field.rs index dbc9f8c..5f99992 100644 --- a/src/tests/field.rs +++ b/src/tests/field.rs @@ -1,5 +1,5 @@ use rand::{Rng, SeedableRng, XorShiftRng}; -use ::{SqrtField, Field}; +use ::{SqrtField, Field, PrimeField}; pub fn random_frobenius_tests>(characteristic: C, maxpower: usize) { let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); @@ -87,6 +87,40 @@ pub fn random_field_tests() { } } +pub fn from_str_tests() { + { + let a = "84395729384759238745923745892374598234705297301958723458712394587103249587213984572934750213947582345792304758273458972349582734958273495872304598234"; + let b = "38495729084572938457298347502349857029384609283450692834058293405982304598230458230495820394850293845098234059823049582309485203948502938452093482039"; + let c = "3248875134290623212325429203829831876024364170316860259933542844758450336418538569901990710701240661702808867062612075657861768196242274635305077449545396068598317421057721935408562373834079015873933065667961469731886739181625866970316226171512545167081793907058686908697431878454091011239990119126"; + + let mut a = F::from_str(a).unwrap(); + let b = F::from_str(b).unwrap(); + let c = F::from_str(c).unwrap(); + + a.mul_assign(&b); + + assert_eq!(a, c); + } + + { + let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + + for _ in 0..1000 { + let n: u64 = rng.gen(); + + let a = F::from_str(&format!("{}", n)).unwrap(); + let b = F::from_repr(n.into()).unwrap(); + + assert_eq!(a, b); + } + } + + assert!(F::from_str("").is_none()); + assert!(F::from_str("0").unwrap().is_zero()); + assert!(F::from_str("00").is_none()); + assert!(F::from_str("00000000000").is_none()); +} + fn random_multiplication_tests(rng: &mut R) { for _ in 0..10000 { let a = F::rand(rng);