Skip to content

Commit e7bae86

Browse files
authored
From Hex for PrimeField Elements (#484)
* from hex * fix text * fix text * fix test
1 parent 304d36e commit e7bae86

File tree

6 files changed

+107
-21
lines changed

6 files changed

+107
-21
lines changed

math/src/field/element.rs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,14 @@ impl<F: IsPrimeField> FieldElement<F> {
411411
pub fn legendre_symbol(&self) -> LegendreSymbol {
412412
F::legendre_symbol(&self.value)
413413
}
414+
415+
/// Creates a `FieldElement` from a hexstring. It can contain `0x` or not.
416+
/// Returns an `CreationError::InvalidHexString`if the value is not a hexstring
417+
pub fn from_hex(hex_string: &str) -> Result<Self, CreationError> {
418+
Ok(Self {
419+
value: F::from_hex(hex_string)?,
420+
})
421+
}
414422
}
415423

416424
impl<M, const NUM_LIMBS: usize> fmt::Display
@@ -442,21 +450,6 @@ where
442450
),
443451
}
444452
}
445-
446-
/// Creates a `FieldElement` from a hexstring. It can contain `0x` or not.
447-
/// Returns an `CreationError::InvalidHexString`if the value is not a hexstring
448-
pub fn from_hex(hex: &str) -> Result<Self, CreationError> {
449-
let integer = UnsignedInteger::<NUM_LIMBS>::from_hex(hex)?;
450-
451-
Ok(Self {
452-
value: MontgomeryAlgorithms::cios(
453-
&integer,
454-
&MontgomeryBackendPrimeField::<M, NUM_LIMBS>::R2,
455-
&M::MODULUS,
456-
&MontgomeryBackendPrimeField::<M, NUM_LIMBS>::MU,
457-
),
458-
})
459-
}
460453
}
461454

462455
#[cfg(test)]
@@ -590,6 +583,13 @@ mod tests {
590583
assert!(sqrt.is_none());
591584
}
592585

586+
#[test]
587+
fn from_hex_1a_is_26_for_stark252_prime_field_element() {
588+
type F = Stark252PrimeField;
589+
type FE = FieldElement<F>;
590+
assert_eq!(FE::from_hex("1a").unwrap(), FE::from(26))
591+
}
592+
593593
prop_compose! {
594594
fn field_element()(num in any::<u64>().prop_filter("Avoid null coefficients", |x| x != &0)) -> FieldElement::<Stark252PrimeField> {
595595
FieldElement::<Stark252PrimeField>::from(num)

math/src/field/fields/montgomery_backed_prime_fields.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,16 @@ where
270270

271271
evaluated_bit + 1
272272
}
273+
274+
fn from_hex(hex_string: &str) -> Result<Self::BaseType, crate::errors::CreationError> {
275+
let integer = Self::BaseType::from_hex(hex_string)?;
276+
Ok(MontgomeryAlgorithms::cios(
277+
&integer,
278+
&MontgomeryBackendPrimeField::<M, NUM_LIMBS>::R2,
279+
&M::MODULUS,
280+
&MontgomeryBackendPrimeField::<M, NUM_LIMBS>::MU,
281+
))
282+
}
273283
}
274284

275285
impl<M, const NUM_LIMBS: usize> FieldElement<MontgomeryBackendPrimeField<M, NUM_LIMBS>> where

math/src/field/fields/u64_prime_field.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::cyclic_group::IsGroup;
22
#[cfg(feature = "std")]
33
use crate::errors::ByteConversionError::{FromBEBytesError, FromLEBytesError};
4+
use crate::errors::CreationError;
45
#[cfg(feature = "std")]
56
use crate::errors::DeserializationError;
67
use crate::field::element::FieldElement;
@@ -84,6 +85,20 @@ impl<const MODULUS: u64> IsPrimeField for U64PrimeField<MODULUS> {
8485
fn field_bit_size() -> usize {
8586
((MODULUS - 1).ilog2() + 1) as usize
8687
}
88+
89+
fn from_hex(hex_string: &str) -> Result<Self::BaseType, CreationError> {
90+
let mut hex_string = hex_string;
91+
// Remove 0x if it's on the string
92+
let mut char_iterator = hex_string.chars();
93+
if hex_string.len() > 2
94+
&& char_iterator.next().unwrap() == '0'
95+
&& char_iterator.next().unwrap() == 'x'
96+
{
97+
hex_string = &hex_string[2..];
98+
}
99+
100+
u64::from_str_radix(hex_string, 16).map_err(|_| CreationError::InvalidHexString)
101+
}
87102
}
88103

89104
/// Represents an element in Fp. (E.g: 0, 1, 2 are the elements of F3)
@@ -145,7 +160,18 @@ impl<const MODULUS: u64> Deserializable for FieldElement<U64PrimeField<MODULUS>>
145160
mod tests {
146161
use super::*;
147162
const MODULUS: u64 = 13;
148-
type FE = FieldElement<U64PrimeField<MODULUS>>;
163+
type F = U64PrimeField<MODULUS>;
164+
type FE = FieldElement<F>;
165+
166+
#[test]
167+
fn from_hex_for_b_is_11() {
168+
assert_eq!(F::from_hex("B").unwrap(), 11);
169+
}
170+
171+
#[test]
172+
fn from_hex_for_0x1_a_is_26() {
173+
assert_eq!(F::from_hex("0x1a").unwrap(), 26);
174+
}
149175

150176
#[test]
151177
fn bit_size_of_mod_13_field_is_4() {

math/src/field/test_fields/u32_test_field.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use crate::field::traits::{IsFFTField, IsField, IsPrimeField};
1+
use crate::{
2+
errors::CreationError,
3+
field::traits::{IsFFTField, IsField, IsPrimeField},
4+
};
25

36
#[derive(Debug, Clone, PartialEq, Eq)]
47

@@ -65,6 +68,21 @@ impl<const MODULUS: u32> IsPrimeField for U32Field<MODULUS> {
6568
fn field_bit_size() -> usize {
6669
((MODULUS - 1).ilog2() + 1) as usize
6770
}
71+
72+
/// Unimplemented for test fields
73+
fn from_hex(hex_string: &str) -> Result<Self::BaseType, crate::errors::CreationError> {
74+
let mut hex_string = hex_string;
75+
// Remove 0x if it's on the string
76+
let mut char_iterator = hex_string.chars();
77+
if hex_string.len() > 2
78+
&& char_iterator.next().unwrap() == '0'
79+
&& char_iterator.next().unwrap() == 'x'
80+
{
81+
hex_string = &hex_string[2..];
82+
}
83+
84+
u32::from_str_radix(hex_string, 16).map_err(|_| CreationError::InvalidHexString)
85+
}
6886
}
6987

7088
// 15 * 2^27 + 1;
@@ -78,7 +96,12 @@ impl IsFFTField for U32TestField {
7896

7997
#[cfg(test)]
8098
mod tests_u32_test_field {
81-
use crate::field::test_fields::u32_test_field::U32TestField;
99+
use crate::field::{test_fields::u32_test_field::U32TestField, traits::IsPrimeField};
100+
101+
#[test]
102+
fn from_hex_for_b_is_11() {
103+
assert_eq!(U32TestField::from_hex("B").unwrap(), 11);
104+
}
82105

83106
#[test]
84107
fn bit_size_of_test_field_is_31() {

math/src/field/test_fields/u64_test_field.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use crate::field::traits::{IsFFTField, IsField, IsPrimeField};
1+
use crate::{
2+
errors::CreationError,
3+
field::traits::{IsFFTField, IsField, IsPrimeField},
4+
};
25

36
#[derive(Debug, Clone, PartialEq, Eq)]
47
pub struct U64Field<const MODULUS: u64>;
@@ -64,6 +67,20 @@ impl<const MODULUS: u64> IsPrimeField for U64Field<MODULUS> {
6467
fn field_bit_size() -> usize {
6568
((MODULUS - 1).ilog2() + 1) as usize
6669
}
70+
71+
fn from_hex(hex_string: &str) -> Result<Self::BaseType, crate::errors::CreationError> {
72+
let mut hex_string = hex_string;
73+
// Remove 0x if it's on the string
74+
let mut char_iterator = hex_string.chars();
75+
if hex_string.len() > 2
76+
&& char_iterator.next().unwrap() == '0'
77+
&& char_iterator.next().unwrap() == 'x'
78+
{
79+
hex_string = &hex_string[2..];
80+
}
81+
82+
u64::from_str_radix(hex_string, 16).map_err(|_| CreationError::InvalidHexString)
83+
}
6784
}
6885

6986
pub type U64TestField = U64Field<18446744069414584321>;
@@ -76,7 +93,12 @@ impl IsFFTField for U64TestField {
7693

7794
#[cfg(test)]
7895
mod tests_u64_test_field {
79-
use crate::field::test_fields::u64_test_field::U64TestField;
96+
use crate::field::{test_fields::u64_test_field::U64TestField, traits::IsPrimeField};
97+
98+
#[test]
99+
fn from_hex_for_b_is_11() {
100+
assert_eq!(U64TestField::from_hex("B").unwrap(), 11);
101+
}
80102

81103
#[test]
82104
fn bit_size_of_test_field_is_64() {

math/src/field/traits.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::{element::FieldElement, errors::FieldError};
2-
use crate::unsigned_integer::traits::IsUnsignedInteger;
2+
use crate::{errors::CreationError, unsigned_integer::traits::IsUnsignedInteger};
33
use core::fmt::Debug;
44

55
/// Represents different configurations that powers of roots of unity can be in. Some of these may
@@ -149,6 +149,11 @@ pub trait IsPrimeField: IsField {
149149
Self::representative(&Self::neg(&Self::one()))
150150
}
151151

152+
/// Creates a BaseType from a Hex String
153+
/// 0x is optional
154+
/// Returns an `CreationError::InvalidHexString`if the value is not a hexstring
155+
fn from_hex(hex_string: &str) -> Result<Self::BaseType, CreationError>;
156+
152157
/// Returns the number of bits of the max element of the field, as per field documentation, not internal representation.
153158
/// This is `log2(max FE)` rounded up
154159
fn field_bit_size() -> usize;

0 commit comments

Comments
 (0)