1
- use crate :: errors:: CreationError ;
1
+ use crate :: errors:: { ByteConversionError , CreationError } ;
2
2
use crate :: field:: errors:: FieldError ;
3
3
use crate :: field:: traits:: IsField ;
4
- #[ cfg( feature = "lambdaworks-serde-binary" ) ]
5
4
use crate :: traits:: ByteConversion ;
6
5
use crate :: unsigned_integer:: element:: UnsignedInteger ;
7
6
use crate :: unsigned_integer:: montgomery:: MontgomeryAlgorithms ;
8
7
use crate :: unsigned_integer:: traits:: IsUnsignedInteger ;
8
+ #[ cfg( feature = "alloc" ) ]
9
+ use alloc:: {
10
+ format,
11
+ string:: { String , ToString } ,
12
+ } ;
9
13
use core:: fmt;
10
14
use core:: fmt:: Debug ;
11
15
use core:: iter:: Sum ;
@@ -15,6 +19,8 @@ use core::iter::Sum;
15
19
) ) ]
16
20
use core:: marker:: PhantomData ;
17
21
use core:: ops:: { Add , AddAssign , Div , Mul , MulAssign , Neg , Sub } ;
22
+ use num_bigint:: BigUint ;
23
+ use num_traits:: Num ;
18
24
#[ cfg( any(
19
25
feature = "lambdaworks-serde-binary" ,
20
26
feature = "lambdaworks-serde-string"
@@ -104,6 +110,21 @@ where
104
110
}
105
111
}
106
112
113
+ #[ cfg( feature = "alloc" ) ]
114
+ /// From overloading for BigUint.
115
+ /// Creates a field element from a BigUint that is smaller than the modulus.
116
+ /// Returns error if the BigUint value is bigger than the modulus.
117
+ impl < F > TryFrom < BigUint > for FieldElement < F >
118
+ where
119
+ Self : ByteConversion ,
120
+ F : IsPrimeField ,
121
+ {
122
+ type Error = ByteConversionError ;
123
+ fn try_from ( value : BigUint ) -> Result < Self , ByteConversionError > {
124
+ FieldElement :: < F > :: from_reduced_big_uint ( & value)
125
+ }
126
+ }
127
+
107
128
impl < F > FieldElement < F >
108
129
where
109
130
F :: BaseType : Clone ,
@@ -491,6 +512,77 @@ where
491
512
value : <F as IsSubFieldOf < L > >:: embed ( self . value ) ,
492
513
}
493
514
}
515
+
516
+ #[ cfg( feature = "alloc" ) ]
517
+ /// Creates a field element from a BigUint that is smaller than the modulus.
518
+ /// Returns error if the value is bigger than the modulus.
519
+ pub fn from_reduced_big_uint ( value : & BigUint ) -> Result < Self , ByteConversionError >
520
+ where
521
+ Self : ByteConversion ,
522
+ F : IsPrimeField ,
523
+ {
524
+ let mod_minus_one = F :: modulus_minus_one ( ) . to_string ( ) ;
525
+
526
+ // We check if `mod_minus_one` is a hex string or a decimal string.
527
+ // In case it is a hex we remove the prefix `0x`.
528
+ let ( digits, radix) = if let Some ( hex) = mod_minus_one
529
+ . strip_prefix ( "0x" )
530
+ . or_else ( || mod_minus_one. strip_prefix ( "0X" ) )
531
+ {
532
+ ( hex, 16 )
533
+ } else {
534
+ ( mod_minus_one. as_str ( ) , 10 )
535
+ } ;
536
+
537
+ let modulus =
538
+ BigUint :: from_str_radix ( digits, radix) . expect ( "invalid modulus representation" ) + 1u32 ;
539
+
540
+ if value >= & modulus {
541
+ Err ( ByteConversionError :: ValueNotReduced )
542
+ } else {
543
+ let mut bytes = value. to_bytes_le ( ) ;
544
+ // We pad the bytes to the size of the base type to be able to apply `from_bytes_le`.
545
+ bytes. resize ( core:: mem:: size_of :: < F :: BaseType > ( ) , 0 ) ;
546
+ Self :: from_bytes_le ( & bytes)
547
+ }
548
+ }
549
+
550
+ #[ cfg( feature = "alloc" ) ]
551
+ /// Converts a field element into a BigUint.
552
+ pub fn to_big_uint ( & self ) -> BigUint
553
+ where
554
+ Self : ByteConversion ,
555
+ {
556
+ BigUint :: from_bytes_be ( & self . to_bytes_be ( ) )
557
+ }
558
+
559
+ #[ cfg( feature = "alloc" ) ]
560
+ /// Converts a hex string into a field element.
561
+ /// It returns error if the hex value is larger than the modulus.
562
+ pub fn from_hex_str ( hex : & str ) -> Result < Self , CreationError >
563
+ where
564
+ Self : ByteConversion ,
565
+ F : IsPrimeField ,
566
+ {
567
+ let hex_str = hex. strip_prefix ( "0x" ) . unwrap_or ( hex) ;
568
+ if hex_str. is_empty ( ) {
569
+ return Err ( CreationError :: EmptyString ) ;
570
+ }
571
+
572
+ let value =
573
+ BigUint :: from_str_radix ( hex_str, 16 ) . map_err ( |_| CreationError :: InvalidHexString ) ?;
574
+
575
+ Self :: from_reduced_big_uint ( & value) . map_err ( |_| CreationError :: InvalidHexString )
576
+ }
577
+
578
+ #[ cfg( feature = "alloc" ) ]
579
+ /// Converts a field element into a hex string.
580
+ pub fn to_hex_str ( & self ) -> String
581
+ where
582
+ Self : ByteConversion ,
583
+ {
584
+ format ! ( "0x{:02X}" , self . to_big_uint( ) )
585
+ }
494
586
}
495
587
496
588
impl < F : IsPrimeField > FieldElement < F > {
@@ -514,8 +606,8 @@ impl<F: IsPrimeField> FieldElement<F> {
514
606
/// Creates a `FieldElement` from a hexstring. It can contain `0x` or not.
515
607
/// Returns an `CreationError::InvalidHexString`if the value is not a hexstring.
516
608
/// Returns a `CreationError::EmptyString` if the input string is empty.
517
- /// Returns a `CreationError::HexStringIsTooBig` if the the input hex string is bigger
518
- /// than the maximum amount of characters for this element.
609
+ /// Returns a `CreationError::HexStringIsTooBig` if the the input hex string is bigger than the
610
+ /// maximum amount of characters for this element.
519
611
pub fn from_hex ( hex_string : & str ) -> Result < Self , CreationError > {
520
612
if hex_string. is_empty ( ) {
521
613
return Err ( CreationError :: EmptyString ) ;
@@ -728,14 +820,20 @@ where
728
820
729
821
#[ cfg( test) ]
730
822
mod tests {
731
- use crate :: field:: element:: FieldElement ;
732
- use crate :: field:: fields:: fft_friendly:: stark_252_prime_field:: Stark252PrimeField ;
823
+ use super :: * ;
824
+ use crate :: elliptic_curve:: short_weierstrass:: curves:: bn_254:: field_extension:: BN254PrimeField ;
825
+ use crate :: field:: fields:: fft_friendly:: {
826
+ babybear_u32:: Babybear31PrimeField , stark_252_prime_field:: Stark252PrimeField ,
827
+ } ;
828
+ use crate :: field:: fields:: montgomery_backed_prime_fields:: U384PrimeField ;
733
829
use crate :: field:: fields:: u64_prime_field:: U64PrimeField ;
734
830
use crate :: field:: test_fields:: u64_test_field:: U64TestField ;
735
831
#[ cfg( feature = "alloc" ) ]
736
832
use crate :: unsigned_integer:: element:: UnsignedInteger ;
833
+ use crate :: unsigned_integer:: element:: U384 ;
737
834
#[ cfg( feature = "alloc" ) ]
738
835
use alloc:: vec:: Vec ;
836
+ use num_bigint:: BigUint ;
739
837
#[ cfg( feature = "alloc" ) ]
740
838
use proptest:: collection;
741
839
use proptest:: { prelude:: * , prop_compose, proptest, strategy:: Strategy } ;
@@ -910,4 +1008,124 @@ mod tests {
910
1008
}
911
1009
}
912
1010
}
1011
+
1012
+ // Tests for BigUint conversion.
1013
+ // We define different fields to test the conversion.
1014
+
1015
+ // Prime field with modulus 17 and base type u64.
1016
+ type U64F17 = U64PrimeField < 17 > ;
1017
+ type U64F17Element = FieldElement < U64F17 > ;
1018
+
1019
+ // Baby Bear Prime field with u32 montgomery backend.
1020
+ type BabyBear = Babybear31PrimeField ;
1021
+ type BabyBearElement = FieldElement < BabyBear > ;
1022
+
1023
+ // Prime field with modulus 23, using u64 montgomery backend of 6 limbs.
1024
+ #[ derive( Clone , Debug ) ]
1025
+ struct U384Modulus23 ;
1026
+ impl IsModulus < U384 > for U384Modulus23 {
1027
+ const MODULUS : U384 = UnsignedInteger :: from_u64 ( 23 ) ;
1028
+ }
1029
+ type U384F23 = U384PrimeField < U384Modulus23 > ;
1030
+ type U384F23Element = FieldElement < U384F23 > ;
1031
+
1032
+ #[ test]
1033
+ fn test_reduced_biguint_conversion_u64_field ( ) {
1034
+ let value = BigUint :: from ( 10u32 ) ;
1035
+ let fe = U64F17Element :: try_from ( value. clone ( ) ) . unwrap ( ) ;
1036
+ let back_to_biguint = fe. to_big_uint ( ) ;
1037
+ assert_eq ! ( value, back_to_biguint) ;
1038
+ }
1039
+
1040
+ #[ test]
1041
+ fn test_reduced_biguint_conversion_baby_bear ( ) {
1042
+ let value = BigUint :: from ( 1000u32 ) ;
1043
+ let fe = BabyBearElement :: from_reduced_big_uint ( & value) . unwrap ( ) ;
1044
+ assert_eq ! ( fe, BabyBearElement :: from( 1000 ) ) ;
1045
+ let back_to_biguint = fe. to_big_uint ( ) ;
1046
+ assert_eq ! ( value, back_to_biguint) ;
1047
+ }
1048
+
1049
+ #[ test]
1050
+ fn test_reduced_biguint_conversion_u384_field ( ) {
1051
+ let value = BigUint :: from ( 22u32 ) ;
1052
+ let fe = U384F23Element :: from_reduced_big_uint ( & value) . unwrap ( ) ;
1053
+ let back_to_biguint = fe. to_big_uint ( ) ;
1054
+ assert_eq ! ( value, back_to_biguint) ;
1055
+ }
1056
+ #[ test]
1057
+ fn test_bn254_field_biguint_conversion ( ) {
1058
+ type BN254Element = FieldElement < BN254PrimeField > ;
1059
+ let value = BigUint :: from ( 1001u32 ) ;
1060
+ let fe = BN254Element :: from_reduced_big_uint ( & value) . unwrap ( ) ;
1061
+ let back_to_biguint = fe. to_big_uint ( ) ;
1062
+ assert_eq ! ( value, back_to_biguint) ;
1063
+ }
1064
+
1065
+ #[ test]
1066
+ fn non_reduced_biguint_value_conversion_errors_u64_field ( ) {
1067
+ let value = BigUint :: from ( 17u32 ) ;
1068
+ let result = U64F17Element :: from_reduced_big_uint ( & value) ;
1069
+ assert_eq ! ( result, Err ( ByteConversionError :: ValueNotReduced ) ) ;
1070
+ }
1071
+
1072
+ #[ test]
1073
+ fn non_reduced_biguint_value_conversion_errors_baby_bear ( ) {
1074
+ let value = BigUint :: from ( 2013265921u32 ) ;
1075
+ let result = BabyBearElement :: try_from ( value) ;
1076
+ assert_eq ! ( result, Err ( ByteConversionError :: ValueNotReduced ) ) ;
1077
+ }
1078
+
1079
+ #[ test]
1080
+ fn non_reduced_biguint_value_conversion_errors_u384_field ( ) {
1081
+ let value = BigUint :: from ( 30u32 ) ;
1082
+ let result = U384F23Element :: try_from ( value) ;
1083
+ assert_eq ! ( result, Err ( ByteConversionError :: ValueNotReduced ) ) ;
1084
+ }
1085
+
1086
+ #[ test]
1087
+ fn test_hex_string_conversion_u64_field ( ) {
1088
+ let hex_str = "0x0a" ;
1089
+ let fe = U64F17Element :: from_hex_str ( hex_str) . unwrap ( ) ;
1090
+ assert_eq ! ( fe, U64F17Element :: from( 10 ) ) ;
1091
+ assert_eq ! ( fe. to_hex_str( ) , "0x0A" ) ;
1092
+ }
1093
+
1094
+ #[ test]
1095
+ fn test_hex_string_conversion_baby_bear ( ) {
1096
+ let hex_str = "0x77FFFFFF" ; // 2013265919
1097
+ let fe = BabyBearElement :: from_hex_str ( hex_str) . unwrap ( ) ;
1098
+ assert_eq ! ( fe, BabyBearElement :: from( 2013265919 ) ) ;
1099
+ assert_eq ! ( fe. to_hex_str( ) , "0x77FFFFFF" ) ;
1100
+ }
1101
+
1102
+ #[ test]
1103
+ fn test_hex_string_conversion_u384_field ( ) {
1104
+ let hex_str = "0x14" ; // 20
1105
+ let fe = U384F23Element :: from_hex_str ( hex_str) . unwrap ( ) ;
1106
+ assert_eq ! ( fe, U384F23Element :: from( 20 ) ) ;
1107
+ assert_eq ! ( fe. to_hex_str( ) , "0x14" ) ;
1108
+ }
1109
+
1110
+ #[ test]
1111
+ fn test_invalid_hex_string_u64_field ( ) {
1112
+ let hex_str = "0xzz" ;
1113
+ let result = U64F17Element :: from_hex_str ( hex_str) ;
1114
+ assert ! ( result. is_err( ) ) ;
1115
+ }
1116
+
1117
+ #[ test]
1118
+ fn test_invalid_hex_string_baby_bear ( ) {
1119
+ // modulus = 0x78000001
1120
+ let hex_str = "0x78000001" ;
1121
+ let result = BabyBearElement :: from_hex_str ( hex_str) ;
1122
+ assert ! ( result. is_err( ) ) ;
1123
+ }
1124
+
1125
+ #[ test]
1126
+ fn test_empty_hex_string ( ) {
1127
+ let hex_str = "" ;
1128
+ let result = U64F17Element :: from_hex_str ( hex_str) ;
1129
+ assert ! ( result. is_err( ) ) ;
1130
+ }
913
1131
}
0 commit comments