primitives.rs 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235
  1. // SPDX-License-Identifier: Apache-2.0
  2. use crate::build_solidity;
  3. use crate::build_solidity_with_overflow_check;
  4. use ethabi::ethereum_types::U256;
  5. use num_bigint::{BigInt, BigUint, RandBigInt, Sign};
  6. use rand::seq::SliceRandom;
  7. use rand::Rng;
  8. use std::ops::Add;
  9. use std::ops::BitAnd;
  10. use std::ops::Div;
  11. use std::ops::Mul;
  12. use std::ops::Rem;
  13. use std::ops::Shl;
  14. use std::ops::Shr;
  15. use std::ops::Sub;
  16. #[test]
  17. #[should_panic]
  18. fn assert_false() {
  19. // without a working assert, this is not going to work
  20. let mut vm = build_solidity(
  21. r#"
  22. contract foo {
  23. function assert_fails() public {
  24. require(false, "humpty-dumpty");
  25. }
  26. }"#,
  27. );
  28. vm.constructor("foo", &[]);
  29. vm.function("assert_fails", &[], &[], None);
  30. }
  31. #[test]
  32. fn assert_true() {
  33. // without a working assert, this is not going to work
  34. let mut vm = build_solidity(
  35. r#"
  36. contract foo {
  37. function assert_fails() public {
  38. require(true, "humpty-dumpty");
  39. }
  40. }"#,
  41. );
  42. vm.constructor("foo", &[]);
  43. vm.function("assert_fails", &[], &[], None);
  44. }
  45. #[test]
  46. fn boolean() {
  47. // we need to test: literals
  48. // passing address around
  49. // abi encoding/decoding address
  50. // comparing address to another
  51. let mut vm = build_solidity(
  52. r#"
  53. contract foo {
  54. function return_true() public returns (bool) {
  55. return true;
  56. }
  57. function return_false() public returns (bool) {
  58. return false;
  59. }
  60. function true_arg(bool b) public {
  61. assert(b);
  62. }
  63. function false_arg(bool b) public {
  64. assert(!b);
  65. }
  66. }"#,
  67. );
  68. vm.constructor("foo", &[]);
  69. let returns = vm.function("return_true", &[], &[], None);
  70. assert_eq!(returns, vec![ethabi::Token::Bool(true),]);
  71. let returns = vm.function("return_false", &[], &[], None);
  72. assert_eq!(returns, vec![ethabi::Token::Bool(false),]);
  73. vm.function("true_arg", &[ethabi::Token::Bool(true)], &[], None);
  74. vm.function("false_arg", &[ethabi::Token::Bool(false)], &[], None);
  75. }
  76. #[test]
  77. fn address() {
  78. // we need to test: literals
  79. // passing address around
  80. // abi encoding/decoding address
  81. // comparing address to another
  82. let mut vm = build_solidity(
  83. r#"
  84. contract foo {
  85. function return_address() public returns (address) {
  86. return address'CXQw5tfeRKKzV4hk6PcdyKyANSvFxoZCKwHkVXAhAYSJ';
  87. }
  88. function address_arg(address a) public {
  89. assert(a == address'66Eh1STPJgabub73TP8YbN7VNCwjaVTEJGHRxCLeBJ4A');
  90. }
  91. }"#,
  92. );
  93. vm.constructor("foo", &[]);
  94. let returns = vm.function("return_address", &[], &[], None);
  95. assert_eq!(
  96. returns,
  97. vec![ethabi::Token::FixedBytes(vec![
  98. 171, 59, 10, 127, 211, 122, 217, 123, 53, 213, 159, 40, 54, 36, 50, 52, 196, 144, 17,
  99. 226, 97, 168, 69, 213, 79, 14, 6, 232, 165, 44, 58, 31
  100. ]),]
  101. );
  102. vm.function(
  103. "address_arg",
  104. &[ethabi::Token::FixedBytes(vec![
  105. 75, 161, 209, 89, 47, 84, 50, 13, 23, 127, 94, 21, 50, 249, 250, 185, 117, 49, 186,
  106. 134, 82, 130, 112, 97, 218, 24, 157, 198, 40, 105, 118, 27,
  107. ])],
  108. &[],
  109. None,
  110. );
  111. }
  112. #[test]
  113. fn test_enum() {
  114. // we need to test enum literals
  115. // abi encoding/decode literals
  116. // comparing enums
  117. let mut vm = build_solidity(
  118. r#"
  119. contract foo {
  120. enum bar { bar0, bar1, bar2, bar3, bar4, bar5, bar6, bar7, bar8, bar9, bar10 }
  121. function return_enum() public returns (bar) {
  122. return bar.bar9;
  123. }
  124. function enum_arg(bar a) public {
  125. assert(a == bar.bar6);
  126. }
  127. }"#,
  128. );
  129. vm.constructor("foo", &[]);
  130. let returns = vm.function("return_enum", &[], &[], None);
  131. assert_eq!(returns, vec![ethabi::Token::Uint(U256::from(9))]);
  132. vm.function("enum_arg", &[ethabi::Token::Uint(U256::from(6))], &[], None);
  133. }
  134. #[test]
  135. fn bytes() {
  136. let mut rng = rand::thread_rng();
  137. for width in 1..32 {
  138. let src = r#"
  139. contract test {
  140. function return_literal() public returns (bytes7) {
  141. return hex"01020304050607";
  142. }
  143. function return_arg(bytes7 x) public returns (bytes7) {
  144. return x;
  145. }
  146. function or(bytesN a, bytesN b) public returns (bytesN) {
  147. return a | b;
  148. }
  149. function and(bytesN a, bytesN b) public returns (bytesN) {
  150. return a & b;
  151. }
  152. function xor(bytesN a, bytesN b) public returns (bytesN) {
  153. return a ^ b;
  154. }
  155. function shift_left(bytesN a, uint32 r) public returns (bytesN) {
  156. return a << r;
  157. }
  158. function shift_right(bytesN a, uint32 r) public returns (bytesN) {
  159. return a >> r;
  160. }
  161. }"#
  162. .replace("bytesN", &format!("bytes{}", width));
  163. let mut vm = build_solidity(&src);
  164. vm.constructor("test", &[]);
  165. let returns = vm.function("return_literal", &[], &[], None);
  166. assert_eq!(
  167. returns,
  168. vec![ethabi::Token::FixedBytes(vec![1, 2, 3, 4, 5, 6, 7]),]
  169. );
  170. let returns = vm.function(
  171. "return_arg",
  172. &[ethabi::Token::FixedBytes(vec![1, 2, 3, 4, 5, 6, 7])],
  173. &[],
  174. None,
  175. );
  176. assert_eq!(
  177. returns,
  178. vec![ethabi::Token::FixedBytes(vec![1, 2, 3, 4, 5, 6, 7])]
  179. );
  180. for _ in 0..10 {
  181. let mut a = Vec::new();
  182. let mut b = Vec::new();
  183. a.resize(width, 0);
  184. b.resize(width, 0);
  185. rng.fill(&mut a[..]);
  186. rng.fill(&mut b[..]);
  187. let or = vm.function(
  188. "or",
  189. &[
  190. ethabi::Token::FixedBytes(a.to_vec()),
  191. ethabi::Token::FixedBytes(b.to_vec()),
  192. ],
  193. &[],
  194. None,
  195. );
  196. let res: Vec<u8> = a.iter().zip(b.iter()).map(|(a, b)| a | b).collect();
  197. println!(
  198. "{} | {} = {}",
  199. hex::encode(&a),
  200. hex::encode(&b),
  201. hex::encode(&res)
  202. );
  203. assert_eq!(or, vec![ethabi::Token::FixedBytes(res)]);
  204. let and = vm.function(
  205. "and",
  206. &[
  207. ethabi::Token::FixedBytes(a.to_vec()),
  208. ethabi::Token::FixedBytes(b.to_vec()),
  209. ],
  210. &[],
  211. None,
  212. );
  213. let res: Vec<u8> = a.iter().zip(b.iter()).map(|(a, b)| a & b).collect();
  214. assert_eq!(and, vec![ethabi::Token::FixedBytes(res)]);
  215. let xor = vm.function(
  216. "xor",
  217. &[
  218. ethabi::Token::FixedBytes(a.to_vec()),
  219. ethabi::Token::FixedBytes(b.to_vec()),
  220. ],
  221. &[],
  222. None,
  223. );
  224. let res: Vec<u8> = a.iter().zip(b.iter()).map(|(a, b)| a ^ b).collect();
  225. assert_eq!(xor, vec![ethabi::Token::FixedBytes(res)]);
  226. let r = rng.gen::<u32>() % (width as u32 * 8);
  227. println!("w = {} r = {}", width, r);
  228. let shl = vm.function(
  229. "shift_left",
  230. &[
  231. ethabi::Token::FixedBytes(a.to_vec()),
  232. ethabi::Token::Uint(U256::from(r)),
  233. ],
  234. &[],
  235. None,
  236. );
  237. let mut res = (BigUint::from_bytes_be(&a) << r).to_bytes_be();
  238. while res.len() > width {
  239. res.remove(0);
  240. }
  241. while res.len() < width {
  242. res.insert(0, 0);
  243. }
  244. assert_eq!(shl, vec![ethabi::Token::FixedBytes(res)]);
  245. let shr = vm.function(
  246. "shift_right",
  247. &[
  248. ethabi::Token::FixedBytes(a.to_vec()),
  249. ethabi::Token::Uint(U256::from(r)),
  250. ],
  251. &[],
  252. None,
  253. );
  254. let mut res = (BigUint::from_bytes_be(&a) >> r).to_bytes_be();
  255. while res.len() < width {
  256. res.insert(0, 0);
  257. }
  258. assert_eq!(shr, vec![ethabi::Token::FixedBytes(res)]);
  259. }
  260. }
  261. }
  262. #[test]
  263. fn uint() {
  264. let mut rng = rand::thread_rng();
  265. for width in (8..=256).step_by(8) {
  266. let src = r#"
  267. contract test {
  268. function pass(uintN a) public returns (uintN) {
  269. print("x:{:x}".format(uint64(a)));
  270. return 0x7f;
  271. }
  272. function add(uintN a, uintN b) public returns (uintN) {
  273. return a + b;
  274. }
  275. function sub(uintN a, uintN b) public returns (uintN) {
  276. return a - b;
  277. }
  278. function mul(uintN a, uintN b) public returns (uintN) {
  279. unchecked {
  280. return a * b;
  281. }
  282. }
  283. function div(uintN a, uintN b) public returns (uintN) {
  284. return a / b;
  285. }
  286. function mod(uintN a, uintN b) public returns (uintN) {
  287. return a % b;
  288. }
  289. function pow(uintN a, uintN b) public returns (uintN) {
  290. unchecked {
  291. return a ** b;
  292. }
  293. }
  294. function or(uintN a, uintN b) public returns (uintN) {
  295. return a | b;
  296. }
  297. function and(uintN a, uintN b) public returns (uintN) {
  298. return a & b;
  299. }
  300. function xor(uintN a, uintN b) public returns (uintN) {
  301. return a ^ b;
  302. }
  303. function shift_left(uintN a, uint32 r) public returns (uintN) {
  304. return a << r;
  305. }
  306. function shift_right(uintN a, uint32 r) public returns (uintN) {
  307. return a >> r;
  308. }
  309. }"#
  310. .replace("uintN", &format!("uint{}", width));
  311. let mut vm = build_solidity(&src);
  312. vm.constructor("test", &[]);
  313. println!("width:{}", width);
  314. for _ in 0..10 {
  315. let mut a = Vec::new();
  316. let mut b = Vec::new();
  317. a.resize(width / 8, 0);
  318. b.resize(width / 8, 0);
  319. rng.fill(&mut a[..]);
  320. rng.fill(&mut b[..]);
  321. let mut a = U256::from_big_endian(&a);
  322. let mut b = U256::from_big_endian(&b);
  323. rng.fill(&mut a.0[..]);
  324. rng.fill(&mut b.0[..]);
  325. truncate_uint(&mut a, width);
  326. truncate_uint(&mut b, width);
  327. let res = vm.function("pass", &[ethabi::Token::Uint(a)], &[], None);
  328. println!("{:x} = {:?} o", a, res);
  329. let add = vm.function(
  330. "add",
  331. &[ethabi::Token::Uint(a), ethabi::Token::Uint(b)],
  332. &[],
  333. None,
  334. );
  335. let (mut res, _) = a.overflowing_add(b);
  336. truncate_uint(&mut res, width);
  337. println!("{:x} + {:x} = {:?} or {:x}", a, b, add, res);
  338. assert_eq!(add, vec![ethabi::Token::Uint(res)]);
  339. let sub = vm.function(
  340. "sub",
  341. &[ethabi::Token::Uint(a), ethabi::Token::Uint(b)],
  342. &[],
  343. None,
  344. );
  345. let (mut res, _) = a.overflowing_sub(b);
  346. truncate_uint(&mut res, width);
  347. assert_eq!(sub, vec![ethabi::Token::Uint(res)]);
  348. let mul = vm.function(
  349. "mul",
  350. &[ethabi::Token::Uint(a), ethabi::Token::Uint(b)],
  351. &[],
  352. None,
  353. );
  354. let (mut res, _) = a.overflowing_mul(b);
  355. truncate_uint(&mut res, width);
  356. assert_eq!(mul, vec![ethabi::Token::Uint(res)]);
  357. let pow = vm.function(
  358. "pow",
  359. &[ethabi::Token::Uint(a), ethabi::Token::Uint(b)],
  360. &[],
  361. None,
  362. );
  363. let (mut res, _) = a.overflowing_pow(b);
  364. truncate_uint(&mut res, width);
  365. assert_eq!(pow, vec![ethabi::Token::Uint(res)]);
  366. if b != U256::zero() {
  367. let div = vm.function(
  368. "div",
  369. &[ethabi::Token::Uint(a), ethabi::Token::Uint(b)],
  370. &[],
  371. None,
  372. );
  373. let mut res = a.div(b);
  374. truncate_uint(&mut res, width);
  375. assert_eq!(div, vec![ethabi::Token::Uint(res)]);
  376. let add = vm.function(
  377. "mod",
  378. &[ethabi::Token::Uint(a), ethabi::Token::Uint(b)],
  379. &[],
  380. None,
  381. );
  382. let mut res = a.rem(b);
  383. truncate_uint(&mut res, width);
  384. assert_eq!(add, vec![ethabi::Token::Uint(res)]);
  385. }
  386. let or = vm.function(
  387. "or",
  388. &[ethabi::Token::Uint(a), ethabi::Token::Uint(b)],
  389. &[],
  390. None,
  391. );
  392. let mut res = U256([
  393. a.0[0] | b.0[0],
  394. a.0[1] | b.0[1],
  395. a.0[2] | b.0[2],
  396. a.0[3] | b.0[3],
  397. ]);
  398. truncate_uint(&mut res, width);
  399. assert_eq!(or, vec![ethabi::Token::Uint(res)]);
  400. let and = vm.function(
  401. "and",
  402. &[ethabi::Token::Uint(a), ethabi::Token::Uint(b)],
  403. &[],
  404. None,
  405. );
  406. let mut res = U256([
  407. a.0[0] & b.0[0],
  408. a.0[1] & b.0[1],
  409. a.0[2] & b.0[2],
  410. a.0[3] & b.0[3],
  411. ]);
  412. truncate_uint(&mut res, width);
  413. assert_eq!(and, vec![ethabi::Token::Uint(res)]);
  414. let xor = vm.function(
  415. "xor",
  416. &[ethabi::Token::Uint(a), ethabi::Token::Uint(b)],
  417. &[],
  418. None,
  419. );
  420. let mut res = U256([
  421. a.0[0] ^ b.0[0],
  422. a.0[1] ^ b.0[1],
  423. a.0[2] ^ b.0[2],
  424. a.0[3] ^ b.0[3],
  425. ]);
  426. truncate_uint(&mut res, width);
  427. assert_eq!(xor, vec![ethabi::Token::Uint(res)]);
  428. let r = rng.gen::<u32>() % (width as u32);
  429. let shl = vm.function(
  430. "shift_left",
  431. &[ethabi::Token::Uint(a), ethabi::Token::Uint(U256::from(r))],
  432. &[],
  433. None,
  434. );
  435. let mut res = a.shl(r);
  436. truncate_uint(&mut res, width);
  437. assert_eq!(shl, vec![ethabi::Token::Uint(res)]);
  438. let shr = vm.function(
  439. "shift_right",
  440. &[ethabi::Token::Uint(a), ethabi::Token::Uint(U256::from(r))],
  441. &[],
  442. None,
  443. );
  444. let mut res = a.shr(r);
  445. truncate_uint(&mut res, width);
  446. assert_eq!(shr, vec![ethabi::Token::Uint(res)]);
  447. }
  448. }
  449. }
  450. fn truncate_uint(n: &mut U256, width: usize) {
  451. let mut bits = 256 - width;
  452. let mut offset = 3;
  453. while bits > 64 {
  454. n.0[offset] = 0;
  455. offset -= 1;
  456. bits -= 64;
  457. }
  458. if bits > 0 {
  459. n.0[offset] &= (1 << (64 - bits)) - 1;
  460. }
  461. }
  462. #[test]
  463. fn test_power_overflow_boundaries() {
  464. for width in (8..=256).step_by(8) {
  465. let src = r#"
  466. contract test {
  467. function pow(uintN a, uintN b) public returns (uintN) {
  468. return a ** b;
  469. }
  470. }"#
  471. .replace("intN", &format!("int{}", width));
  472. let mut contract = build_solidity_with_overflow_check(&src, true);
  473. contract.constructor("test", &[]);
  474. let return_value = contract.function(
  475. "pow",
  476. &[
  477. ethabi::Token::Uint(U256::from(2)),
  478. ethabi::Token::Uint(U256::from(width - 1)),
  479. ],
  480. &[],
  481. None,
  482. );
  483. let res = BigUint::from(2_u32).pow((width - 1) as u32);
  484. assert_eq!(
  485. return_value,
  486. vec![ethabi::Token::Uint(U256::from_big_endian(
  487. &res.to_bytes_be()
  488. ))]
  489. );
  490. let sesa = contract.function_must_fail(
  491. "pow",
  492. &[
  493. ethabi::Token::Uint(U256::from(2)),
  494. ethabi::Token::Uint(U256::from(width + 1)),
  495. ],
  496. &[],
  497. None,
  498. );
  499. assert_ne!(sesa, Ok(0));
  500. }
  501. }
  502. #[test]
  503. fn test_overflow_boundaries() {
  504. for width in (8..=256).step_by(8) {
  505. let src = r#"
  506. contract test {
  507. function mul(intN a, intN b) public returns (intN) {
  508. return a * b;
  509. }
  510. }"#
  511. .replace("intN", &format!("int{}", width));
  512. let mut contract = build_solidity_with_overflow_check(&src, true);
  513. // The range of values that can be held in signed N bits is [-2^(N-1), 2^(N-1)-1]. We generate these boundaries:
  514. let upper_boundary = BigInt::from(2_u32).pow(width - 1).sub(1);
  515. let lower_boundary = BigInt::from(2_u32).pow(width - 1).mul(-1);
  516. let second_op = BigInt::from(1_u32);
  517. // Multiply the boundaries by 1.
  518. contract.constructor("test", &[]);
  519. let return_value = contract.function(
  520. "mul",
  521. &[
  522. ethabi::Token::Int(bigint_to_eth(&upper_boundary, width.try_into().unwrap())),
  523. ethabi::Token::Int(bigint_to_eth(&second_op, width.try_into().unwrap())),
  524. ],
  525. &[],
  526. None,
  527. );
  528. assert_eq!(
  529. return_value,
  530. vec![ethabi::Token::Int(bigint_to_eth(
  531. &upper_boundary,
  532. width.try_into().unwrap(),
  533. ))]
  534. );
  535. let return_value = contract.function(
  536. "mul",
  537. &[
  538. ethabi::Token::Int(bigint_to_eth(&lower_boundary, width.try_into().unwrap())),
  539. ethabi::Token::Int(bigint_to_eth(&second_op, width.try_into().unwrap())),
  540. ],
  541. &[],
  542. None,
  543. );
  544. assert_eq!(
  545. return_value,
  546. vec![ethabi::Token::Int(bigint_to_eth(
  547. &lower_boundary,
  548. width.try_into().unwrap(),
  549. ))]
  550. );
  551. let upper_boundary_plus_one = BigInt::from(2_u32).pow(width - 1);
  552. // We subtract 2 instead of one to make the number even, so that no rounding occurs when we divide by 2 later on.
  553. let lower_boundary_minus_two = BigInt::from(2_u32).pow(width - 1).mul(-1_i32).sub(2_i32);
  554. let upper_second_op = upper_boundary_plus_one.div(2);
  555. let lower_second_op = lower_boundary_minus_two.div(2);
  556. let res = contract.function_must_fail(
  557. "mul",
  558. &[
  559. ethabi::Token::Int(bigint_to_eth(&upper_second_op, width.try_into().unwrap())),
  560. ethabi::Token::Int(bigint_to_eth(&BigInt::from(2), width.try_into().unwrap())),
  561. ],
  562. &[],
  563. None,
  564. );
  565. assert_ne!(res, Ok(0));
  566. let res = contract.function_must_fail(
  567. "mul",
  568. &[
  569. ethabi::Token::Int(bigint_to_eth(&lower_second_op, width.try_into().unwrap())),
  570. ethabi::Token::Int(bigint_to_eth(&BigInt::from(2), width.try_into().unwrap())),
  571. ],
  572. &[],
  573. None,
  574. );
  575. assert_ne!(res, Ok(0));
  576. let res = contract.function_must_fail(
  577. "mul",
  578. &[
  579. ethabi::Token::Int(bigint_to_eth(&upper_boundary, width.try_into().unwrap())),
  580. ethabi::Token::Int(bigint_to_eth(&upper_boundary, width.try_into().unwrap())),
  581. ],
  582. &[],
  583. None,
  584. );
  585. assert_ne!(res, Ok(0));
  586. let res = contract.function_must_fail(
  587. "mul",
  588. &[
  589. ethabi::Token::Int(bigint_to_eth(&lower_boundary, width.try_into().unwrap())),
  590. ethabi::Token::Int(bigint_to_eth(&lower_boundary, width.try_into().unwrap())),
  591. ],
  592. &[],
  593. None,
  594. );
  595. assert_ne!(res, Ok(0));
  596. let res = contract.function_must_fail(
  597. "mul",
  598. &[
  599. ethabi::Token::Int(bigint_to_eth(&upper_boundary, width.try_into().unwrap())),
  600. ethabi::Token::Int(bigint_to_eth(&lower_boundary, width.try_into().unwrap())),
  601. ],
  602. &[],
  603. None,
  604. );
  605. assert_ne!(res, Ok(0));
  606. }
  607. }
  608. #[test]
  609. fn test_mul_within_range_signed() {
  610. let mut rng = rand::thread_rng();
  611. for width in (8..=256).step_by(8) {
  612. let src = r#"
  613. contract test {
  614. function mul(intN a, intN b) public returns (intN) {
  615. return a * b;
  616. }
  617. }"#
  618. .replace("intN", &format!("int{}", width));
  619. let mut contract = build_solidity(&src);
  620. // The range of values that can be held in signed N bits is [-2^(N-1), 2^(N-1)-1]. Here we generate a random number within this range and multiply it by -1, 1 or 0.
  621. let first_operand_rand = rng.gen_bigint(width - 1).sub(1_u32);
  622. println!("First op : {:?}", first_operand_rand);
  623. let side = vec![-1, 0, 1];
  624. // -1, 1 or 0
  625. let second_op = BigInt::from(*side.choose(&mut rng).unwrap() as i32);
  626. println!("second op : {:?}", second_op);
  627. contract.constructor("test", &[]);
  628. let return_value = contract.function(
  629. "mul",
  630. &[
  631. ethabi::Token::Int(bigint_to_eth(
  632. &first_operand_rand,
  633. width.try_into().unwrap(),
  634. )),
  635. ethabi::Token::Int(bigint_to_eth(&second_op, width.try_into().unwrap())),
  636. ],
  637. &[],
  638. None,
  639. );
  640. let res = first_operand_rand.mul(second_op);
  641. assert_eq!(
  642. return_value,
  643. vec![ethabi::Token::Int(bigint_to_eth(
  644. &res,
  645. width.try_into().unwrap(),
  646. ))]
  647. );
  648. }
  649. }
  650. #[test]
  651. fn test_mul_within_range() {
  652. let mut rng = rand::thread_rng();
  653. for width in (8..=256).step_by(8) {
  654. let src = r#"
  655. contract test {
  656. function mul(uintN a, uintN b) public returns (uintN) {
  657. return a * b;
  658. }
  659. }"#
  660. .replace("intN", &format!("int{}", width));
  661. let mut contract = build_solidity_with_overflow_check(&src, true);
  662. contract.constructor("test", &[]);
  663. for _ in 0..10 {
  664. // Max number to fit unsigned N bits is (2^N)-1
  665. let limit = BigUint::from(2_u32).pow(width).sub(1_u32);
  666. // Generate a random number within the the range [0, 2^N -1]
  667. let first_operand_rand = rng.gen_biguint(width.into()).add(1_u32);
  668. // Calculate a number that when multiplied by first_operand_rand, the result will not overflow N bits (the result of this division will cast the float result to int result, therefore lowering it. The result of multiplication will never overflow).
  669. let second_operand_rand = limit.div(&first_operand_rand);
  670. let return_value = contract.function(
  671. "mul",
  672. &[
  673. ethabi::Token::Uint(U256::from_big_endian(&first_operand_rand.to_bytes_be())),
  674. ethabi::Token::Uint(U256::from_big_endian(&second_operand_rand.to_bytes_be())),
  675. ],
  676. &[],
  677. None,
  678. );
  679. let res = first_operand_rand * second_operand_rand;
  680. assert_eq!(
  681. return_value,
  682. vec![ethabi::Token::Uint(U256::from_big_endian(
  683. &res.to_bytes_be()
  684. ))]
  685. );
  686. }
  687. }
  688. }
  689. #[test]
  690. fn test_overflow_detect_signed() {
  691. let mut rng = rand::thread_rng();
  692. for width in (8..=256).step_by(8) {
  693. let src = r#"
  694. contract test {
  695. function mul(intN a, intN b) public returns (intN) {
  696. return a * b;
  697. }
  698. }"#
  699. .replace("intN", &format!("int{}", width));
  700. let mut contract = build_solidity_with_overflow_check(&src, true);
  701. contract.constructor("test", &[]);
  702. // The range of values that can be held in signed N bits is [-2^(N-1), 2^(N-1)-1] .Generate a value that will overflow this range:
  703. let limit = BigInt::from(2_u32).pow(width - 1).add(1_u32);
  704. // Divide Limit by a random number
  705. let first_operand_rand = rng.gen_bigint((width - 1).into()).sub(1_u32);
  706. // Calculate a number that when multiplied by first_operand_rand, the result will overflow N bits
  707. let mut second_operand_rand = limit / &first_operand_rand;
  708. if let Sign::Minus = second_operand_rand.sign() {
  709. // Decrease by 1 if negative, this is to make sure the result will overflow
  710. second_operand_rand = second_operand_rand.sub(1);
  711. } else {
  712. // Increase by 1 if psotive
  713. second_operand_rand = second_operand_rand.add(1);
  714. }
  715. let res = contract.function_must_fail(
  716. "mul",
  717. &[
  718. ethabi::Token::Int(bigint_to_eth(
  719. &first_operand_rand,
  720. width.try_into().unwrap(),
  721. )),
  722. ethabi::Token::Int(bigint_to_eth(
  723. &second_operand_rand,
  724. width.try_into().unwrap(),
  725. )),
  726. ],
  727. &[],
  728. None,
  729. );
  730. assert_ne!(res, Ok(0));
  731. }
  732. }
  733. #[test]
  734. fn test_overflow_detect_unsigned() {
  735. let mut rng = rand::thread_rng();
  736. for width in (8..=256).step_by(8) {
  737. let src = r#"
  738. contract test {
  739. function mul(uintN a, uintN b) public returns (uintN) {
  740. return a * b;
  741. }
  742. }"#
  743. .replace("intN", &format!("int{}", width));
  744. let mut contract = build_solidity_with_overflow_check(&src, true);
  745. contract.constructor("test", &[]);
  746. for _ in 0..10 {
  747. // N bits can hold the range [0, (2^N)-1]. Generate a value that overflows N bits
  748. let limit = BigUint::from(2_u32).pow(width);
  749. // Generate a random number within the the range [0, 2^N -1]
  750. let first_operand_rand = rng.gen_biguint(width.into()).add(1_u32);
  751. // Calculate a number that when multiplied by first_operand_rand, the result will overflow N bits
  752. let second_operand_rand = limit.div(&first_operand_rand).add(1_usize);
  753. let res = contract.function_must_fail(
  754. "mul",
  755. &[
  756. ethabi::Token::Uint(U256::from_big_endian(&first_operand_rand.to_bytes_be())),
  757. ethabi::Token::Uint(U256::from_big_endian(&second_operand_rand.to_bytes_be())),
  758. ],
  759. &[],
  760. None,
  761. );
  762. assert_ne!(res, Ok(0));
  763. }
  764. }
  765. }
  766. #[test]
  767. fn int() {
  768. let mut rng = rand::thread_rng();
  769. for width in (8..=256).step_by(8) {
  770. let src = r#"
  771. contract test {
  772. function add(intN a, intN b) public returns (intN) {
  773. return a + b;
  774. }
  775. function sub(intN a, intN b) public returns (intN) {
  776. return a - b;
  777. }
  778. function mul(intN a, intN b) public returns (intN) {
  779. unchecked {
  780. return a * b;
  781. }
  782. }
  783. function div(intN a, intN b) public returns (intN) {
  784. return a / b;
  785. }
  786. function mod(intN a, intN b) public returns (intN) {
  787. return a % b;
  788. }
  789. function or(intN a, intN b) public returns (intN) {
  790. return a | b;
  791. }
  792. function and(intN a, intN b) public returns (intN) {
  793. return a & b;
  794. }
  795. function xor(intN a, intN b) public returns (intN) {
  796. return a ^ b;
  797. }
  798. function shift_left(intN a, uint32 r) public returns (intN) {
  799. return a << r;
  800. }
  801. function shift_right(intN a, uint32 r) public returns (intN) {
  802. return a >> r;
  803. }
  804. }"#
  805. .replace("intN", &format!("int{}", width));
  806. let mut vm = build_solidity(&src);
  807. vm.constructor("test", &[]);
  808. for _ in 0..10 {
  809. let mut a_bs = Vec::new();
  810. let mut b_bs = Vec::new();
  811. a_bs.resize(width / 8, 0);
  812. b_bs.resize(width / 8, 0);
  813. rng.fill(&mut a_bs[..]);
  814. rng.fill(&mut b_bs[..]);
  815. let mut a = U256::from_big_endian(&a_bs);
  816. let mut b = U256::from_big_endian(&b_bs);
  817. truncate_int(&mut a, width);
  818. truncate_int(&mut b, width);
  819. let big_a = eth_to_bigint(&a, width);
  820. let big_b = eth_to_bigint(&b, width);
  821. let add = vm.function(
  822. "add",
  823. &[ethabi::Token::Int(a), ethabi::Token::Int(b)],
  824. &[],
  825. None,
  826. );
  827. let res = big_a.clone().add(&big_b);
  828. let res = bigint_to_eth(&res, width);
  829. assert_eq!(add, vec![ethabi::Token::Int(res)]);
  830. let sub = vm.function(
  831. "sub",
  832. &[ethabi::Token::Int(a), ethabi::Token::Int(b)],
  833. &[],
  834. None,
  835. );
  836. let res = bigint_to_eth(&big_a.clone().sub(&big_b), width);
  837. assert_eq!(sub, vec![ethabi::Token::Int(res)]);
  838. let mul = vm.function(
  839. "mul",
  840. &[ethabi::Token::Int(a), ethabi::Token::Int(b)],
  841. &[],
  842. None,
  843. );
  844. let res = bigint_to_eth(&big_a.clone().mul(&big_b), width);
  845. assert_eq!(mul, vec![ethabi::Token::Int(res)]);
  846. if b != U256::zero() {
  847. let div = vm.function(
  848. "div",
  849. &[ethabi::Token::Int(a), ethabi::Token::Int(b)],
  850. &[],
  851. None,
  852. );
  853. let res = bigint_to_eth(&big_a.clone().div(&big_b), width);
  854. assert_eq!(div, vec![ethabi::Token::Int(res)]);
  855. let add = vm.function(
  856. "mod",
  857. &[ethabi::Token::Int(a), ethabi::Token::Int(b)],
  858. &[],
  859. None,
  860. );
  861. let res = big_a.clone().rem(&big_b);
  862. let res = bigint_to_eth(&res, width);
  863. assert_eq!(add, vec![ethabi::Token::Int(res)]);
  864. }
  865. let or = vm.function(
  866. "or",
  867. &[ethabi::Token::Int(a), ethabi::Token::Int(b)],
  868. &[],
  869. None,
  870. );
  871. let mut res = U256([
  872. a.0[0] | b.0[0],
  873. a.0[1] | b.0[1],
  874. a.0[2] | b.0[2],
  875. a.0[3] | b.0[3],
  876. ]);
  877. truncate_int(&mut res, width);
  878. assert_eq!(or, vec![ethabi::Token::Int(res)]);
  879. let and = vm.function(
  880. "and",
  881. &[ethabi::Token::Int(a), ethabi::Token::Int(b)],
  882. &[],
  883. None,
  884. );
  885. let mut res = U256([
  886. a.0[0] & b.0[0],
  887. a.0[1] & b.0[1],
  888. a.0[2] & b.0[2],
  889. a.0[3] & b.0[3],
  890. ]);
  891. truncate_int(&mut res, width);
  892. assert_eq!(and, vec![ethabi::Token::Int(res)]);
  893. let xor = vm.function(
  894. "xor",
  895. &[ethabi::Token::Int(a), ethabi::Token::Int(b)],
  896. &[],
  897. None,
  898. );
  899. let mut res = U256([
  900. a.0[0] ^ b.0[0],
  901. a.0[1] ^ b.0[1],
  902. a.0[2] ^ b.0[2],
  903. a.0[3] ^ b.0[3],
  904. ]);
  905. truncate_int(&mut res, width);
  906. assert_eq!(xor, vec![ethabi::Token::Int(res)]);
  907. let r = rng.gen::<u32>() % (width as u32);
  908. let shl = vm.function(
  909. "shift_left",
  910. &[ethabi::Token::Int(a), ethabi::Token::Uint(U256::from(r))],
  911. &[],
  912. None,
  913. );
  914. let mut res = a.shl(r);
  915. truncate_int(&mut res, width);
  916. assert_eq!(shl, vec![ethabi::Token::Int(res)]);
  917. let shr = vm.function(
  918. "shift_right",
  919. &[ethabi::Token::Int(a), ethabi::Token::Uint(U256::from(r))],
  920. &[],
  921. None,
  922. );
  923. let res = bigint_to_eth(&big_a.clone().shr(r), width);
  924. assert_eq!(shr, vec![ethabi::Token::Int(res)]);
  925. }
  926. }
  927. }
  928. fn truncate_int(n: &mut U256, width: usize) {
  929. let sign = n.bitand(U256::from(1) << (width - 1)) != U256::zero();
  930. let mut bits = 256 - width;
  931. let mut offset = 3;
  932. while bits > 64 {
  933. n.0[offset] = if sign { u64::MAX } else { 0 };
  934. offset -= 1;
  935. bits -= 64;
  936. }
  937. if bits > 0 {
  938. if sign {
  939. n.0[offset] |= !((1 << (64 - bits)) - 1);
  940. } else {
  941. n.0[offset] &= (1 << (64 - bits)) - 1;
  942. }
  943. }
  944. }
  945. fn bigint_to_eth(v: &BigInt, width: usize) -> U256 {
  946. let mut buf = v.to_signed_bytes_be();
  947. let width = width / 8;
  948. while buf.len() > width {
  949. buf.remove(0);
  950. }
  951. let sign = if (buf[0] & 128) != 0 { 0xff } else { 0 };
  952. while buf.len() < 32 {
  953. buf.insert(0, sign);
  954. }
  955. U256::from_big_endian(&buf)
  956. }
  957. fn eth_to_bigint(v: &U256, width: usize) -> BigInt {
  958. let mut buf = Vec::new();
  959. buf.resize(32, 0);
  960. v.to_big_endian(&mut buf);
  961. let width = width / 8;
  962. while buf.len() > width {
  963. buf.remove(0);
  964. }
  965. BigInt::from_signed_bytes_be(&buf)
  966. }