referrerpolicy=no-referrer-when-downgrade

biguint/
biguint.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! # Running
19//! Running this fuzzer can be done with `cargo hfuzz run biguint`. `honggfuzz` CLI options can
20//! be used by setting `HFUZZ_RUN_ARGS`, such as `-n 4` to use 4 threads.
21//!
22//! # Debugging a panic
23//! Once a panic is found, it can be debugged with
24//! `cargo hfuzz run-debug biguint hfuzz_workspace/biguint/*.fuzz`.
25//!
26//! # More information
27//! More information about `honggfuzz` can be found
28//! [here](https://docs.rs/honggfuzz/).
29
30use honggfuzz::fuzz;
31use sp_arithmetic::biguint::{BigUint, Single};
32
33fn main() {
34	loop {
35		fuzz!(|data: (Vec<Single>, Vec<Single>, bool)| {
36			let (mut digits_u, mut digits_v, return_remainder) = data;
37
38			let mut u = BigUint::from_limbs(&digits_u);
39			let mut v = BigUint::from_limbs(&digits_v);
40
41			u.lstrip();
42			v.lstrip();
43
44			let ue = u128::try_from(u.clone());
45			let ve = u128::try_from(v.clone());
46
47			digits_u.reverse();
48			digits_v.reverse();
49
50			let num_u = num_bigint::BigUint::new(digits_u);
51			let num_v = num_bigint::BigUint::new(digits_v);
52
53			if check_digit_lengths(&u, &v, 4) {
54				assert_eq!(u.cmp(&v), ue.cmp(&ve));
55				assert_eq!(u.eq(&v), ue.eq(&ve));
56			}
57
58			if check_digit_lengths(&u, &v, 3) {
59				let expected = ue.unwrap() + ve.unwrap();
60				let t = u.clone().add(&v);
61				assert_eq!(
62					u128::try_from(t.clone()).unwrap(),
63					expected,
64					"{:?} + {:?} ===> {:?} != {:?}",
65					u,
66					v,
67					t,
68					expected,
69				);
70			}
71
72			if check_digit_lengths(&u, &v, 4) {
73				let expected = ue.unwrap().checked_sub(ve.unwrap());
74				let t = u.clone().sub(&v);
75				if expected.is_none() {
76					assert!(t.is_err())
77				} else {
78					let t = t.unwrap();
79					let expected = expected.unwrap();
80					assert_eq!(
81						u128::try_from(t.clone()).unwrap(),
82						expected,
83						"{:?} - {:?} ===> {:?} != {:?}",
84						u,
85						v,
86						t,
87						expected,
88					);
89				}
90			}
91
92			if check_digit_lengths(&u, &v, 2) {
93				let expected = ue.unwrap() * ve.unwrap();
94				let t = u.clone().mul(&v);
95				assert_eq!(
96					u128::try_from(t.clone()).unwrap(),
97					expected,
98					"{:?} * {:?} ===> {:?} != {:?}",
99					u,
100					v,
101					t,
102					expected,
103				);
104			}
105
106			if check_digit_lengths(&u, &v, 4) {
107				let (ue, ve) = (ue.unwrap(), ve.unwrap());
108				if ve == 0 {
109					return
110				}
111				let (q, r) = (ue / ve, ue % ve);
112				if let Some((qq, rr)) = u.clone().div(&v, true) {
113					assert_eq!(
114						u128::try_from(qq.clone()).unwrap(),
115						q,
116						"{:?} / {:?} ===> {:?} != {:?}",
117						u,
118						v,
119						qq,
120						q,
121					);
122					assert_eq!(
123						u128::try_from(rr.clone()).unwrap(),
124						r,
125						"{:?} % {:?} ===> {:?} != {:?}",
126						u,
127						v,
128						rr,
129						r,
130					);
131				} else if v.len() == 1 {
132					let qq = u.clone().div_unit(ve as Single);
133					assert_eq!(
134						u128::try_from(qq.clone()).unwrap(),
135						q,
136						"[single] {:?} / {:?} ===> {:?} != {:?}",
137						u,
138						v,
139						qq,
140						q,
141					);
142				} else if v.msb() != 0 && u.msb() != 0 && u.len() > v.len() {
143					panic!("div returned none for an unexpected reason");
144				}
145			}
146
147			// Test against num_bigint
148
149			// Equality
150
151			assert_eq!(u.cmp(&v), num_u.cmp(&num_v));
152
153			// Addition
154
155			let w = u.clone().add(&v);
156			let num_w = num_u.clone() + &num_v;
157
158			assert_biguints_eq(&w, &num_w);
159
160			// Subtraction
161
162			if let Ok(w) = u.clone().sub(&v) {
163				let num_w = num_u.clone() - &num_v;
164
165				assert_biguints_eq(&w, &num_w);
166			}
167
168			// Multiplication
169
170			let w = u.clone().mul(&v);
171			let num_w = num_u.clone() * &num_v;
172
173			assert_biguints_eq(&w, &num_w);
174
175			// Division
176
177			if v.len() == 1 && v.get(0) != 0 {
178				let w = u.div_unit(v.get(0));
179				let num_w = num_u / &num_v;
180				assert_biguints_eq(&w, &num_w);
181			} else if u.len() > v.len() && v.len() > 1 {
182				let num_remainder = num_u.clone() % num_v.clone();
183
184				let (w, remainder) = u.div(&v, return_remainder).unwrap();
185				let num_w = num_u / &num_v;
186
187				assert_biguints_eq(&w, &num_w);
188
189				if return_remainder {
190					assert_biguints_eq(&remainder, &num_remainder);
191				}
192			}
193		});
194	}
195}
196
197fn check_digit_lengths(u: &BigUint, v: &BigUint, max_limbs: usize) -> bool {
198	1 <= u.len() && u.len() <= max_limbs && 1 <= v.len() && v.len() <= max_limbs
199}
200
201fn assert_biguints_eq(a: &BigUint, b: &num_bigint::BigUint) {
202	let mut a = a.clone();
203	a.lstrip();
204
205	// `num_bigint::BigUint` doesn't expose it's internals, so we need to convert into that to
206	// compare.
207	let limbs = (0..a.len()).map(|i| a.get(i)).collect();
208	let num_a = num_bigint::BigUint::new(limbs);
209
210	assert!(&num_a == b, "\narithmetic: {:?}\nnum-bigint: {:?}", a, b);
211}