@@ -6,13 +6,15 @@ use std::borrow::Cow;
66use num_bigint:: { BigInt , Sign } ;
77use serde:: { Deserialize , Serialize } ;
88
9+ use super :: MAX_BIGINT_SIZE ;
10+
911/// Wrapper for serializing big ints to match filecoin spec. Serializes as bytes.
1012#[ derive( Serialize ) ]
1113#[ serde( transparent) ]
1214pub struct BigIntSer < ' a > ( #[ serde( with = "self" ) ] pub & ' a BigInt ) ;
1315
1416/// Wrapper for deserializing as BigInt from bytes.
15- #[ derive( Deserialize , Serialize , Clone , Default , PartialEq ) ]
17+ #[ derive( Deserialize , Serialize , Clone , Default , PartialEq , Debug ) ]
1618#[ serde( transparent) ]
1719pub struct BigIntDe ( #[ serde( with = "self" ) ] pub BigInt ) ;
1820
3032 Sign :: NoSign => bz = Vec :: new ( ) ,
3133 }
3234
35+ if bz. len ( ) > MAX_BIGINT_SIZE {
36+ return Err ( <S :: Error as serde:: ser:: Error >:: custom ( "BigInt too large" ) ) ;
37+ }
38+
3339 // Serialize as bytes
3440 serde_bytes:: Serialize :: serialize ( & bz, serializer)
3541}
5359 ) ) ;
5460 }
5561 } ;
62+
63+ if bz. len ( ) > MAX_BIGINT_SIZE {
64+ return Err ( <D :: Error as serde:: de:: Error >:: custom ( "BigInt too large" ) ) ;
65+ }
66+
5667 Ok ( BigInt :: from_bytes_be ( sign, & bz[ 1 ..] ) )
5768}
69+
70+ #[ cfg( test) ]
71+ mod tests {
72+ use fvm_ipld_encoding:: { from_slice, to_vec} ;
73+
74+ use super :: * ;
75+
76+ #[ test]
77+ fn test_bigiint_max ( ) {
78+ let max_limbs = MAX_BIGINT_SIZE / 4 ; // 32bit limbs to bytes
79+ let good = BigInt :: new ( Sign :: Plus , vec ! [ u32 :: MAX ; max_limbs - 1 ] ) ;
80+ let good_neg = BigInt :: new ( Sign :: Minus , vec ! [ u32 :: MAX ; max_limbs - 1 ] ) ;
81+
82+ let good_bytes = to_vec ( & BigIntSer ( & good) ) . expect ( "should be good" ) ;
83+ let good_back: BigIntDe = from_slice ( & good_bytes) . unwrap ( ) ;
84+ assert_eq ! ( good_back. 0 , good) ;
85+
86+ let good_neg_bytes = to_vec ( & BigIntSer ( & good_neg) ) . expect ( "should be good" ) ;
87+ let good_neg_back: BigIntDe = from_slice ( & good_neg_bytes) . unwrap ( ) ;
88+ assert_eq ! ( good_neg_back. 0 , good_neg) ;
89+
90+ // max limbs will fail as the sign is prepended
91+ let bad1 = BigInt :: new ( Sign :: Plus , vec ! [ u32 :: MAX ; max_limbs] ) ;
92+ let bad1_neg = BigInt :: new ( Sign :: Minus , vec ! [ u32 :: MAX ; max_limbs] ) ;
93+ let bad2 = BigInt :: new ( Sign :: Plus , vec ! [ u32 :: MAX ; max_limbs + 1 ] ) ;
94+ let bad2_neg = BigInt :: new ( Sign :: Minus , vec ! [ u32 :: MAX ; max_limbs + 1 ] ) ;
95+
96+ assert ! ( to_vec( & BigIntSer ( & bad1) ) . is_err( ) ) ;
97+ assert ! ( to_vec( & BigIntSer ( & bad1_neg) ) . is_err( ) ) ;
98+ assert ! ( to_vec( & BigIntSer ( & bad2) ) . is_err( ) ) ;
99+ assert ! ( to_vec( & BigIntSer ( & bad2_neg) ) . is_err( ) ) ;
100+
101+ let bad_bytes = {
102+ let ( sign, mut source) = bad1. to_bytes_be ( ) ;
103+ match sign {
104+ Sign :: Minus => source. insert ( 0 , 0 ) ,
105+ _ => source. insert ( 0 , 1 ) ,
106+ }
107+ to_vec ( & serde_bytes:: Bytes :: new ( & source) ) . unwrap ( )
108+ } ;
109+
110+ let res: Result < BigIntDe , _ > = from_slice ( & bad_bytes) ;
111+ assert ! ( res. is_err( ) ) ;
112+ assert_eq ! (
113+ res. unwrap_err( ) . to_string( ) ,
114+ "Serialization error for Cbor protocol: BigInt too large"
115+ ) ;
116+ }
117+ }
0 commit comments