@@ -6,13 +6,15 @@ use std::borrow::Cow;
6
6
use num_bigint:: { BigInt , Sign } ;
7
7
use serde:: { Deserialize , Serialize } ;
8
8
9
+ use super :: MAX_BIGINT_SIZE ;
10
+
9
11
/// Wrapper for serializing big ints to match filecoin spec. Serializes as bytes.
10
12
#[ derive( Serialize ) ]
11
13
#[ serde( transparent) ]
12
14
pub struct BigIntSer < ' a > ( #[ serde( with = "self" ) ] pub & ' a BigInt ) ;
13
15
14
16
/// Wrapper for deserializing as BigInt from bytes.
15
- #[ derive( Deserialize , Serialize , Clone , Default , PartialEq ) ]
17
+ #[ derive( Deserialize , Serialize , Clone , Default , PartialEq , Debug ) ]
16
18
#[ serde( transparent) ]
17
19
pub struct BigIntDe ( #[ serde( with = "self" ) ] pub BigInt ) ;
18
20
30
32
Sign :: NoSign => bz = Vec :: new ( ) ,
31
33
}
32
34
35
+ if bz. len ( ) > MAX_BIGINT_SIZE {
36
+ return Err ( <S :: Error as serde:: ser:: Error >:: custom ( "BigInt too large" ) ) ;
37
+ }
38
+
33
39
// Serialize as bytes
34
40
serde_bytes:: Serialize :: serialize ( & bz, serializer)
35
41
}
53
59
) ) ;
54
60
}
55
61
} ;
62
+
63
+ if bz. len ( ) > MAX_BIGINT_SIZE {
64
+ return Err ( <D :: Error as serde:: de:: Error >:: custom ( "BigInt too large" ) ) ;
65
+ }
66
+
56
67
Ok ( BigInt :: from_bytes_be ( sign, & bz[ 1 ..] ) )
57
68
}
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