boolean_function/
lib.rs

1//! # Boolean Function analysis library
2
3#![doc = include_str!("../README.md")]
4#![forbid(unsafe_code, unused_must_use)]
5#![forbid(
6    missing_docs,
7    unreachable_pub,
8    unused_import_braces,
9    unused_extern_crates
10)]
11
12pub mod affine_equivalence_classes;
13mod anf_polynom;
14mod big_boolean_function;
15mod boolean_function_error;
16mod iterator;
17mod small_boolean_function;
18mod utils;
19
20pub use crate::anf_polynom::AnfPolynomial;
21use crate::boolean_function_error::{AND_DIFFERENT_VAR_COUNT_PANIC_MSG, XOR_DIFFERENT_VAR_COUNT_PANIC_MSG};
22pub use crate::iterator::BooleanFunctionIterator;
23use crate::BooleanFunctionError::{
24    StringHexParseError, UnexpectedError, WrongStringHexTruthTableLength,
25};
26pub use big_boolean_function::BigBooleanFunction;
27pub use boolean_function_error::BooleanFunctionError;
28use enum_dispatch::enum_dispatch;
29use gen_combinations::CombinationIterator;
30use num_bigint::BigUint;
31use num_traits::{Num, ToPrimitive};
32pub use small_boolean_function::SmallBooleanFunction;
33use std::collections::{HashMap, HashSet};
34use std::fmt::Debug;
35use std::ops::{Add, AddAssign, BitAnd, BitAndAssign, BitXor, BitXorAssign, Mul, MulAssign, Not};
36use hackfn::hackfn;
37use crate::iterator::CloseBalancedFunctionIterator;
38
39/// Internal representation of Boolean function
40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
41pub enum BooleanFunctionType {
42    /// Small boolean function with 6 or fewer variables, the truth table is stored in an u64
43    Small,
44    /// Big boolean function with more than 6 variables, the truth table is stored in a BigUint
45    Big,
46}
47
48/// Trait for Boolean function implementations.
49/// This trait is implemented by [SmallBooleanFunction] and [BigBooleanFunction].
50///
51/// You could use this trait via the [BooleanFunction] type, which encapsulates the [BooleanFunctionImpl] trait.
52#[enum_dispatch]
53pub trait BooleanFunctionImpl: Debug {
54    /// Variable count of the Boolean function.
55    fn variables_count(&self) -> usize;
56
57    /// Internal type of the Boolean function abstraction:
58    ///
59    /// - [BooleanFunctionType::Big] for [BigBooleanFunction]
60    ///
61    /// - [BooleanFunctionType::Small] for [SmallBooleanFunction]
62    fn get_boolean_function_type(&self) -> BooleanFunctionType;
63
64    /// Maximum input value for the Boolean function, as unsigned 32-bit integer.
65    ///
66    /// This is equal to $2^n - 1$, where $n$ is the number of variables.
67    fn get_max_input_value(&self) -> u32 {
68        (1 << self.variables_count()) - 1
69    }
70
71    /// Returns `true` if the Boolean function is balanced, ie it has an equal number of 0 and 1 outputs.
72    fn is_balanced(&self) -> bool;
73
74    /// Computes the value of the Boolean function for a given input, as a 32-bit unsigned integer.
75    ///
76    /// This is equivalent of calling directly your Boolean function object as a function.
77    ///
78    /// # Parameters
79    /// - `input_bits`: The input value for which to compute the Boolean function value, the least significant bit being the first variable.
80    ///
81    /// # Returns
82    /// The value of the Boolean function for the given input bits.
83    ///
84    /// # Panics
85    /// If the input value is greater than the maximum input value, and the `unsafe_disable_safety_checks` feature is not enabled.
86    ///
87    /// # Example
88    /// ```rust
89    /// use boolean_function::BooleanFunction;
90    /// use boolean_function::BooleanFunctionImpl;
91    ///
92    /// let boolean_function = BooleanFunction::from_hex_string_truth_table("abce1234").unwrap();
93    /// assert_eq!(boolean_function.compute_cellular_automata_rule(8), false);
94    /// assert_eq!(boolean_function(8), false); // directly as a function
95    /// ```
96    fn compute_cellular_automata_rule(&self, input_bits: u32) -> bool;
97
98    /// Computes the Walsh-Hadamard transform of the Boolean function for a given point.
99    ///
100    /// The Walsh-Hadamard transform of a Boolean function $f$, for a given point $\omega$, is defined as:
101    ///
102    /// $$W_f(\omega) = \sum_{x=0}^{2^n-1} (-1)^{f(x) \oplus \omega \cdot x}$$
103    ///
104    /// Where $\oplus$ is the XOR operation, $\cdot$ is the AND operand product, and $2^n - 1$ is the maximum input value.
105    ///
106    /// # Parameters
107    /// - `w`: The point $\omega$ for which to compute the Walsh-Hadamard transform.
108    ///
109    /// # Returns
110    /// The value of the Walsh-Hadamard transform for the given point.
111    ///
112    /// # Panics
113    /// If the point is greater than the maximum input value, and the `unsafe_disable_safety_checks` feature is not enabled.
114    fn walsh_hadamard_transform(&self, w: u32) -> i32 {
115        let max_input_value = self.get_max_input_value();
116        #[cfg(not(feature = "unsafe_disable_safety_checks"))]
117        if w > max_input_value {
118            panic!(
119                "Too big Walsh parameter point, must be <= {}",
120                max_input_value
121            );
122        }
123        (0..=max_input_value)
124            .map(|x| {
125                if (self.compute_cellular_automata_rule(x) as u32
126                    + utils::fast_binary_dot_product(w, x))
127                    & 1
128                    == 0
129                {
130                    // % modulo 2
131                    1
132                } else {
133                    -1
134                }
135            })
136            .sum()
137    }
138
139    /// Computes the Walsh-Hadamard values for all points.
140    ///
141    /// # Returns
142    /// A vector containing the Walsh-Hadamard values for all points.
143    fn walsh_hadamard_values(&self) -> Vec<i32> {
144        (0..=self.get_max_input_value())
145            .map(|w| self.walsh_hadamard_transform(w))
146            .collect()
147    }
148
149    /// Computes the absolute Walsh-Hadamard spectrum of the Boolean function.
150    ///
151    /// The absolute Walsh-Hadamard spectrum is the number of occurrences of each absolute value of the Walsh-Hadamard transform.
152    ///
153    /// # Returns
154    /// A hashmap containing the absolute Walsh-Hadamard values as keys, and the number of occurrences as values.
155    fn absolute_walsh_hadamard_spectrum(&self) -> HashMap<u32, usize> {
156        let mut absolute_walsh_value_count_map: HashMap<u32, usize> = HashMap::new();
157        (0..=self.get_max_input_value()).for_each(|w| {
158            let absolute_walsh_value = self.walsh_hadamard_transform(w).unsigned_abs();
159            if !absolute_walsh_value_count_map.contains_key(&absolute_walsh_value) {
160                absolute_walsh_value_count_map.insert(absolute_walsh_value, 1);
161            } else {
162                let count = absolute_walsh_value_count_map
163                    .get_mut(&absolute_walsh_value)
164                    .unwrap();
165                *count += 1;
166            }
167        });
168        absolute_walsh_value_count_map
169    }
170
171    /// Computes the Walsh-Fourier transform of the Boolean function for a given point.
172    ///
173    /// The Walsh-Fourier transform of a Boolean function $f$, for a given point $\omega$, is defined as:
174    ///
175    /// $$F_f(\omega) = \sum_{x=0}^{2^n-1} f(x) \cdot (-1)^{\omega \cdot x}$$
176    ///
177    /// Where $\cdot$ is the AND operand product, and $2^n - 1$ is the maximum input value.
178    ///
179    /// # Parameters
180    /// - `w`: The point $\omega$ for which to compute the Walsh-Fourier transform.
181    ///
182    /// # Returns
183    /// The value of the Walsh-Fourier transform for the given point.
184    ///
185    /// # Panics
186    /// If the point is greater than the maximum input value, and the `unsafe_disable_safety_checks` feature is not enabled.
187    fn walsh_fourier_transform(&self, w: u32) -> i32 {
188        let max_input_value = self.get_max_input_value();
189        #[cfg(not(feature = "unsafe_disable_safety_checks"))]
190        if w > max_input_value {
191            panic!(
192                "Too big Walsh parameter point, must be <= {}",
193                max_input_value
194            );
195        }
196        (0..=max_input_value)
197            .map(|x| {
198                if !self.compute_cellular_automata_rule(x) {
199                    0
200                } else {
201                    if utils::fast_binary_dot_product(w, x) & 1 == 0 {
202                        1
203                    } else {
204                        -1
205                    }
206                }
207            })
208            .sum()
209    }
210
211    /// Computes the Walsh-Fourier values for all points.
212    ///
213    /// # Returns
214    /// A vector containing the Walsh-Fourier values for all points.
215    fn walsh_fourier_values(&self) -> Vec<i32> {
216        (0..=self.get_max_input_value())
217            .map(|w| self.walsh_fourier_transform(w))
218            .collect()
219    }
220
221    /// Computes the autocorrelation transform of the Boolean function for a given point.
222    /// The autocorrelation transform of a Boolean function $f$, for a given point $\omega$, is defined as:
223    ///
224    /// $$\Delta_f(\omega) = \sum_{x=0}^{2^n-1} (-1)^{f(x) \oplus f(x \oplus \omega)}$$
225    ///
226    /// Where $\oplus$ is the XOR operation, and $2^n - 1$ is the maximum input value.
227    ///
228    /// # Parameters
229    /// - `w`: The point $\omega$ for which to compute the autocorrelation transform.
230    ///
231    /// # Returns
232    /// The value of the autocorrelation transform for the given point.
233    ///
234    /// # Panics
235    /// If the point is greater than the maximum input value, and the `unsafe_disable_safety_checks` feature is not enabled.
236    fn auto_correlation_transform(&self, w: u32) -> i32 {
237        let max_input_value = self.get_max_input_value();
238        #[cfg(not(feature = "unsafe_disable_safety_checks"))]
239        if w > max_input_value {
240            panic!(
241                "Too big auto-correlation parameter point, must be <= {}",
242                max_input_value
243            );
244        }
245        (0..=max_input_value)
246            .map(|x| {
247                if self.compute_cellular_automata_rule(x)
248                    ^ self.compute_cellular_automata_rule(x ^ w)
249                {
250                    -1
251                } else {
252                    1
253                }
254            })
255            .sum()
256    }
257
258    /// Computes the absolute autocorrelation spectrum of the Boolean function.
259    ///
260    /// The absolute autocorrelation spectrum is the number of occurrences of each absolute value of the autocorrelation transform.
261    ///
262    /// # Returns
263    /// A hashmap containing the absolute autocorrelation values as keys, and the number of occurrences as values.
264    fn absolute_autocorrelation(&self) -> HashMap<u32, usize> {
265        let mut absolute_autocorrelation_value_count_map: HashMap<u32, usize> = HashMap::new();
266        (0..=self.get_max_input_value()).for_each(|w| {
267            let absolute_autocorrelation_value = self.auto_correlation_transform(w).unsigned_abs();
268            if !absolute_autocorrelation_value_count_map
269                .contains_key(&absolute_autocorrelation_value)
270            {
271                absolute_autocorrelation_value_count_map.insert(absolute_autocorrelation_value, 1);
272            } else {
273                let count = absolute_autocorrelation_value_count_map
274                    .get_mut(&absolute_autocorrelation_value)
275                    .unwrap();
276                *count += 1;
277            }
278        });
279        absolute_autocorrelation_value_count_map
280    }
281
282    /// Returns the absolute indicator of the Boolean function.
283    ///
284    /// As defined [here](https://www.researchgate.net/publication/322383819_Distribution_of_the_absolute_indicator_of_random_Boolean_functions),
285    /// the absolute indicator is the maximal absolute value of the auto-correlation transform for all points starting from 1 to the maximum input value $2^n - 1$,
286    /// $n$ being the number of variables.
287    fn absolute_indicator(&self) -> u32 {
288        (1..=self.get_max_input_value())
289            .map(|w| self.auto_correlation_transform(w).unsigned_abs())
290            .max()
291            .unwrap_or(0)
292    }
293
294    /// Computes the derivative of the Boolean function for a given direction.
295    ///
296    /// The derivative of a Boolean function $f$ in the direction $u$ is defined as:
297    ///
298    /// $$\nabla_u f(x) = f(x) \oplus f(x \oplus u)$$
299    ///
300    /// Where $\oplus$ is the XOR operation.
301    ///
302    /// # Parameters
303    /// - `direction`: The direction $u$ for which to compute the derivative.
304    ///
305    /// # Returns
306    /// The derivative of the Boolean function in the given direction, or an error if the direction is greater than the maximum input value and the `unsafe_disable_safety_checks` feature is not enabled.
307    fn derivative(&self, direction: u32) -> Result<BooleanFunction, BooleanFunctionError>;
308
309    /// Returns `true` if the Boolean function is linear, ie its algebraic degree is 0 or 1.
310    fn is_linear(&self) -> bool;
311
312    /// Reverse the Boolean function, ie swap 0 and 1 outputs.
313    ///
314    /// This is equivalent to the NOT operation, like `!boolean_function`.
315    ///
316    /// # Returns
317    /// The reversed Boolean function.
318    fn reverse(&self) -> BooleanFunction;
319
320    /// Returns the Algebraic Normal Form of the Boolean function, in the form of an [AnfPolynomial].
321    ///
322    /// We use the Bakoev's algorithm to compute the ANF polynomial <http://www.math.bas.bg/moiuser/OCRT2017/a3.pdf>.
323    ///
324    /// # Returns
325    /// The Algebraic Normal Form of the Boolean function.
326    ///
327    /// # Example
328    /// ```rust
329    /// // Wolfram's rule 30
330    /// use boolean_function::BooleanFunctionImpl;
331    /// use boolean_function::BooleanFunction;
332    /// let boolean_function = BooleanFunction::from_u64_truth_table(30, 3).unwrap();
333    /// let anf_polynomial = boolean_function.algebraic_normal_form();
334    /// // `*` denotes the AND operation, and `+` denotes the XOR operation
335    /// assert_eq!(anf_polynomial.to_string(), "x0*x1 + x0 + x1 + x2");
336    /// ```
337    fn algebraic_normal_form(&self) -> AnfPolynomial;
338
339    /// Returns the algebraic degree of the Boolean function.
340    ///
341    /// The algebraic degree of a Boolean function is the maximum degree of the AND monomials in its Algebraic Normal Form.
342    ///
343    /// The degree of a monomial is the number of variables in the monomial.
344    ///
345    /// # Returns
346    /// The algebraic degree of the Boolean function.
347    fn algebraic_degree(&self) -> usize {
348        self.algebraic_normal_form().get_degree()
349    }
350
351    /// Returns `true` if the Boolean function is symmetric.
352    ///
353    /// A Boolean function is symmetric if for all inputs $x$, the value of the function is the same as the value of the function for the bitwise reversed input.
354    ///
355    /// It means that the output depends only on the Hamming weight of the input.
356    fn is_symmetric(&self) -> bool {
357        let variables_count = self.variables_count() as u32;
358        let precomputed_hamming_weights = (0..(variables_count + 1))
359            .map(|i| self.compute_cellular_automata_rule(u32::MAX.checked_shr(32 - i).unwrap_or(0)))
360            .collect::<Vec<bool>>();
361
362        (0u32..(1 << variables_count)).all(|i| {
363            precomputed_hamming_weights[i.count_ones() as usize]
364                == self.compute_cellular_automata_rule(i)
365        })
366    }
367
368    /// Returns the nonlinearity of the Boolean function.
369    ///
370    /// Nonlinearity is a measure of how far the Boolean function is from being linear.
371    /// It's defined as the Hamming distance between the Boolean function and the closest linear function, or the minimum number of output bits that must be changed to make the function linear.
372    ///
373    /// # Returns
374    /// The nonlinearity of the Boolean function, as an unsigned 32-bit integer.
375    fn nonlinearity(&self) -> u32 {
376        ((1 << self.variables_count())
377            - (0..=self.get_max_input_value())
378                .map(|x| self.walsh_hadamard_transform(x).unsigned_abs())
379                .max()
380                .unwrap_or(0))
381            >> 1
382    }
383
384    /// Returns `true` if the Boolean function is bent, meaning maximally nonlinear, or perfectly nonlinear.
385    ///
386    /// Only functions with an even number of variables can be bent.
387    ///
388    /// The maximum possible nonlinearity for a Boolean function with $n$ variables is $\frac{2^n - 2^{\frac{n}{2}}}{2}$.
389    ///
390    /// A bent function has all its derivative balanced.
391    ///
392    /// The Rothaus theorem states that if an $n$-variable Boolean function $f$ is bent, then $deg(f) <= \frac{n}{2}$.
393    ///
394    /// A bent function cannot be balanced.
395    fn is_bent(&self) -> bool {
396        if self.variables_count() & 1 != 0 {
397            return false;
398        }
399        self.nonlinearity()
400            == ((1 << self.variables_count()) - (1 << (self.variables_count() >> 1))) >> 1
401    }
402
403    /// Returns `true` if the Boolean function is near-bent.
404    ///
405    /// A $n$-variable Boolean function is said to be *near-bent* if $n$ is odd,
406    /// and its [Walsh-Hamamard](#method.walsh_hadamard_values) spectrum contains all and only the 3 values $\\{0, \pm 2^{\frac{n+1}{2}}\\}$.
407    fn is_near_bent(&self) -> bool {
408        if self.variables_count() & 1 == 0 {
409            return false;
410        }
411        let absolute_walsh_allowed_value = 1 << ((self.variables_count() + 1) >> 1);
412        let walsh_hadamard_spectrum = (0..=self.get_max_input_value())
413            .map(|x| self.walsh_hadamard_transform(x))
414            .collect::<HashSet<_>>();
415
416        walsh_hadamard_spectrum.len() == 3 && walsh_hadamard_spectrum.iter().all(|w| {
417            *w == 0 || *w == absolute_walsh_allowed_value || *w == -absolute_walsh_allowed_value
418        })
419    }
420
421    /// Returns, if it exists, an annihilator function, its degree and the dimension of annihilator vector space.
422    ///
423    /// The annihilator of a Boolean function $f$ is a non-null Boolean function $g$ such that:
424    ///
425    /// $$f(x).g(x) = 0 \ \ \forall x \in \mathbb{F}_2^n$$
426    ///
427    /// **Special case**: annihilator of zero function is constant one function, by convention.
428    ///
429    /// # Parameters
430    /// - `max_degree`: An optional maximum degree of the annihilator to search for. If set to `None`, the value is set to the variable count.
431    ///
432    /// # Returns
433    /// - `None` if no annihilator is found (this is the case for constant one function).
434    /// - `Some((annihilator, degree, dimension))` if an annihilator is found:
435    ///    - `annihilator`: The annihilator function.
436    ///    - `degree`: The degree of the returned annihilator function.
437    ///    - `dimension`: The dimension of the annihilator vector space.
438    fn annihilator(&self, max_degree: Option<usize>) -> Option<(BooleanFunction, usize, usize)>;
439
440    /// Returns the algebraic immunity of the Boolean function.
441    ///
442    /// The algebraic immunity of a Boolean function is defined as the minimum degree of an annihilator of the function.
443    ///
444    /// # Returns
445    /// The algebraic immunity of the Boolean function, or 0 if the function has no annihilator.
446    fn algebraic_immunity(&self) -> usize {
447        match self.annihilator(Some(self.variables_count())) {
448            None => 0,
449            Some(annihilator) => annihilator.1,
450        }
451    }
452
453    /// Returns `true` if the Boolean function is plateaued.
454    ///
455    /// A Boolean function is plateaued if its Walsh-Hadamard spectrum has at most three values: 0, $\lambda$ and $-\lambda$, where $\lambda \in \mathbb{N}^*$.
456    fn is_plateaued(&self) -> bool {
457        let absolute_walsh_hadamard_spectrum = self.absolute_walsh_hadamard_spectrum();
458        absolute_walsh_hadamard_spectrum.len() == 1
459            || (absolute_walsh_hadamard_spectrum.len() == 2
460                && absolute_walsh_hadamard_spectrum.contains_key(&0))
461    }
462
463    /// Returns the sum of the square of the indicator of the Boolean function.
464    ///
465    /// The sum of the square of the indicator for a $n$-variable Boolean function $f$ is defined as:
466    ///
467    /// $$\sum_{w=0}^{2^n-1} \Delta_f(w)^2$$
468    ///
469    /// Where $\Delta_f(w)$ is the [autocorrelation transform](Self::auto_correlation_transform) of the function for a given point $w$.
470    ///
471    /// # Returns
472    /// The sum of the square of the indicator of the Boolean function.
473    fn sum_of_square_indicator(&self) -> usize {
474        (0..=self.get_max_input_value())
475            .map(|w| self.auto_correlation_transform(w))
476            .map(|value| (value as i64 * value as i64) as usize)
477            .sum()
478    }
479
480    /// Returns `true` if the Boolean function has a linear structure.
481    ///
482    /// A $n$-variable boolean function has a linear structure if $\exists a \in \mathbb{F}_2^n$ such that
483    /// $x \longmapsto f(x) \oplus f(x \oplus a)$ is a constant function.
484    ///
485    /// <https://www.sciencedirect.com/topics/mathematics/linear-structure>
486    fn has_linear_structure(&self) -> bool {
487        (1..=self.get_max_input_value()).any(|x| {
488            self.auto_correlation_transform(x).unsigned_abs() == 1 << self.variables_count()
489        })
490    }
491
492    /// Checks if the parameter is a linear structure of the Boolean function.
493    ///
494    /// A vector $a \in \mathbb{F}_2^n$ is a linear structure of a $n$-variable Boolean function $f$ if the function
495    /// $x \longmapsto f(x) \oplus f(x \oplus a)$ is a constant function.
496    ///
497    /// # Parameters
498    /// - `value`: The value to check if it is a linear structure.
499    ///
500    /// # Returns
501    /// `true` if the value is a linear structure of the Boolean function, `false` otherwise.
502    ///
503    /// # Panics
504    /// The function panics if the value is greater than the function maximum input value and the `unsafe_disable_safety_checks` feature is not enabled.
505    fn is_linear_structure(&self, value: u32) -> bool {
506        #[cfg(not(feature = "unsafe_disable_safety_checks"))]
507        {
508            let max_input_value = self.get_max_input_value();
509            if value > max_input_value {
510                panic!("Too big value parameter, must be <= {}", max_input_value);
511            }
512        }
513        self.auto_correlation_transform(value).unsigned_abs() == 1 << self.variables_count()
514    }
515
516    /// List of all linear structures of the Boolean function.
517    ///
518    /// A vector $a \in \mathbb{F}_2^n$ is a linear structure of a $n$-variable Boolean function $f$ if the function
519    /// $x \longmapsto f(x) \oplus f(x \oplus a)$ is a constant function.
520    ///
521    /// # Returns
522    /// A vector containing all linear structures of the Boolean function.
523    fn linear_structures(&self) -> Vec<u32> {
524        (0..=self.get_max_input_value())
525            .filter(|x| {
526                self.auto_correlation_transform(*x).unsigned_abs() == 1 << self.variables_count()
527            })
528            .collect()
529    }
530
531    /// Returns the correlation immunity order of the Boolean function (calculated using Xiao Massey theorem).
532    ///
533    /// A Boolean function is said to be correlation immune of order $k$ if the output of the function is statistically independent of any subset of maximum $k$ input bits.
534    ///
535    /// As shown by Siegenthaler, a $n$-variable Boolean function  which is correlation immune of order $k$ has a degree $d \leq n - m$.
536    /// <https://iacr.org/archive/asiacrypt2002/25010483/25010483.pdf>
537    ///
538    /// # Returns
539    /// The correlation immunity order of the Boolean function.
540    fn correlation_immunity(&self) -> usize {
541        (1..=self.get_max_input_value())
542            .filter(|x| self.walsh_hadamard_transform(*x) != 0)
543            .map(|x| x.count_ones() as usize)
544            .min()
545            .unwrap_or(self.variables_count() + 1)
546            - 1
547    }
548
549    /// Returns the resiliency order of the Boolean function.
550    ///
551    /// A boolean function is said to be resilient of order $k$ if it is balanced and correlation immune of order $k$.
552    ///
553    /// # Returns
554    /// The resiliency order of the Boolean function, or `None` if the function is not balanced.
555    fn resiliency_order(&self) -> Option<usize> {
556        if !self.is_balanced() {
557            return None;
558        }
559        Some(self.correlation_immunity())
560    }
561
562    /// Returns the support of the Boolean function.
563    ///
564    /// The support of a $n$-variable Boolean function is the set of all inputs $x \in \mathbb{F}_2^n$ such that $f(x) = 1$.
565    ///
566    /// # Returns
567    /// The support of the Boolean function, as a set of unsigned 32-bit integers.
568    fn support(&self) -> HashSet<u32> {
569        (0..=self.get_max_input_value())
570            .filter(|x| self.compute_cellular_automata_rule(*x))
571            .collect()
572    }
573
574    /// Returns the maximum propagation criterion of the Boolean function.
575    ///
576    /// A $n$-variable Boolean function $f$ satisfies propagation criterion at order $k$ if its output changes with a probability
577    /// of $\frac{1}{2}$ when changing the value of any subset of $i$ variables, $\forall i \in \llbracket 1, k \rrbracket$
578    ///
579    /// # Returns
580    /// The maximum propagation criterion of the Boolean function.
581    fn propagation_criterion(&self) -> usize {
582        let num_variables = self.variables_count();
583        let max_input_value = self.get_max_input_value();
584        let possible_reversable_bit_position =
585            (0..num_variables).into_iter().collect::<Vec<usize>>();
586        (1..=num_variables)
587            .into_iter()
588            .take_while(|criterion_degree| {
589                CombinationIterator::new(&possible_reversable_bit_position, *criterion_degree).all(
590                    |combination| {
591                        let mut bit_mask = 0;
592                        for &bit_position in combination {
593                            bit_mask |= (1 << bit_position) as u32;
594                        }
595                        let function_equal_mask_count = (0..=max_input_value)
596                            .into_iter()
597                            .filter(|&x| {
598                                let x_prime = x ^ bit_mask;
599                                self.compute_cellular_automata_rule(x)
600                                    == self.compute_cellular_automata_rule(x_prime)
601                            })
602                            .count();
603                        function_equal_mask_count == (1 << (num_variables - 1))
604                    },
605                )
606            })
607            .count()
608    }
609
610    /// Returns a 1-local neighbor of the Boolean function, at a specific position
611    ///
612    /// A 1-local neighbor of a Boolean function $f$ at position $i$ is a Boolean function $f_i$ such that:
613    ///
614    /// $$f_i(x) = \begin{cases}
615    /// f(x) &\text{if } x \neq i \\\\
616    ///    f(x) \oplus 1 &\text{if } x = i
617    /// \end{cases}$$
618    ///
619    /// $f_i$ is said to be *connected* to $f$.
620    ///
621    /// # Parameters
622    /// - `position`: The position $i$ at which to compute the 1-local neighbor.
623    ///
624    /// # Returns
625    /// The 1-local neighbor of the Boolean function at the given position.
626    ///
627    /// # Panics
628    /// If the position is greater than the maximum input value, and the `unsafe_disable_safety_checks` feature is not enabled.
629    fn get_1_local_neighbor(&self, position: u32) -> BooleanFunction;
630
631    /// Returns an iterator over the values of the Boolean function.
632    ///
633    /// # Returns
634    /// An iterator over the values of the Boolean function.
635    ///
636    /// # Example
637    /// ```rust
638    /// // Wolfram's rule 30
639    /// use boolean_function::BooleanFunctionImpl;
640    /// use boolean_function::BooleanFunction;
641    /// let boolean_function = BooleanFunction::from_u64_truth_table(30, 3).unwrap();
642    /// let mut iterator = boolean_function.iter();
643    /// assert_eq!(iterator.next(), Some(false));
644    /// assert_eq!(iterator.next(), Some(true));
645    /// ```
646    fn iter(&self) -> BooleanFunctionIterator;
647
648    /// Returns the truth table of the Boolean function as a hexadecimal string.
649    ///
650    /// # Returns
651    /// The truth table of the Boolean function as a hexadecimal string.
652    ///
653    /// # Example
654    /// ```rust
655    /// // Wolfram's rule 30
656    /// use boolean_function::BooleanFunctionImpl;
657    /// use boolean_function::BooleanFunction;
658    /// let boolean_function = BooleanFunction::from_u64_truth_table(30, 3).unwrap();
659    /// assert_eq!(boolean_function.printable_hex_truth_table(), "1e");
660    /// ```
661    fn printable_hex_truth_table(&self) -> String;
662
663    /// Returns the truth table of the Boolean function as a BigUint.
664    ///
665    /// # Returns
666    /// The truth table of the Boolean function as a BigUint.
667    fn biguint_truth_table(&self) -> BigUint;
668
669    /// Returns the truth table of the Boolean function as an unsigned 64-bit integer, if it fits (meaning the Boolean function has 6 or less input variables).
670    ///
671    /// # Returns
672    /// The truth table of the Boolean function as an unsigned 64-bit integer, or `None` if the truth table is too big to fit in an u64.
673    fn try_u64_truth_table(&self) -> Option<u64> {
674        self.biguint_truth_table().to_u64()
675    }
676
677    /// Returns an iterator over the closest possible balanced Boolean functions.
678    ///
679    /// "closest" means the minimum possible Hamming distance over the truth table.
680    ///
681    /// This is particularly useful if you want to extract a set of balanced functions from a bent function.
682    /// So that you can generate highly nonlinear balanced functions.
683    ///
684    /// # Returns
685    ///
686    /// An iterator over close balanced Boolean functions, or an error if the function is already balanced.
687    ///
688    /// # Note
689    /// It is assumed that the function truth table is correctly sanitized, so be careful if you generated it with `unsafe_disable_safety_checks` feature activated.
690    ///
691    /// # Example
692    /// ```rust
693    /// use boolean_function::BooleanFunction;
694    ///  use crate::boolean_function::BooleanFunctionImpl;
695    ///
696    /// let bent_function = BooleanFunction::from_hex_string_truth_table(
697    ///             "80329780469d0b85cd2ad63e1a6ba42adbd83c9a0c55e4e8c99f227b0ffc1418"
698    ///         ).unwrap();
699    /// let close_balanced_iterator = bent_function.close_balanced_functions_iterator();
700    /// assert!(close_balanced_iterator.is_ok());
701    /// let mut close_balanced_iterator = close_balanced_iterator.unwrap();
702    /// let highly_nonlinear_balanced_function = close_balanced_iterator.next().unwrap();
703    /// assert!(highly_nonlinear_balanced_function.is_balanced());
704    /// assert_eq!(highly_nonlinear_balanced_function.nonlinearity(), 112);
705    /// ```
706    fn close_balanced_functions_iterator(&self) -> Result<CloseBalancedFunctionIterator, BooleanFunctionError>;
707}
708
709/// This type is used to store a boolean function with any number of variables.
710///
711/// It abstracts The [SmallBooleanFunction] and [BigBooleanFunction] types, by encapsulating the [BooleanFunctionImpl] trait.
712///
713/// Please refer to the [BooleanFunctionImpl] trait for more information.
714#[enum_dispatch(BooleanFunctionImpl)]
715#[derive(Debug, Clone, PartialEq, Eq)]
716pub enum BooleanFunction {
717    /// Struct representing a boolean function with a small truth table.
718    Small(pub SmallBooleanFunction),
719    /// Struct representing a boolean function with a big truth table.
720    Big(pub BigBooleanFunction),
721}
722
723/// In-place XOR operator for Boolean functions truth tables.
724///
725/// # Panics
726/// If the Boolean functions have different number of variables, and the `unsafe_disable_safety_checks` feature is not enabled.
727impl BitXorAssign for BooleanFunction {
728    fn bitxor_assign(&mut self, rhs: Self) {
729        let self_num_variables = self.variables_count();
730        let rhs_num_variables = rhs.variables_count();
731        if self_num_variables != rhs_num_variables {
732            panic!("{}", XOR_DIFFERENT_VAR_COUNT_PANIC_MSG);
733        }
734        match (
735            self,
736            rhs,
737        ) {
738            (BooleanFunction::Small(self_small_boolean_function), BooleanFunction::Small(rhs_small_boolean_function)) => {
739                *self_small_boolean_function ^= rhs_small_boolean_function;
740            },
741            (BooleanFunction::Small(self_small_boolean_function), BooleanFunction::Big(rhs_big_boolean_function)) => {
742                let rhs_small_boolean_function = SmallBooleanFunction::from_truth_table(
743                rhs_big_boolean_function
744                        .biguint_truth_table()
745                        .to_u64()
746                        .unwrap(),
747                    self_num_variables,
748                )
749                .unwrap();
750                *self_small_boolean_function ^= rhs_small_boolean_function;
751            },
752            (BooleanFunction::Big(self_big_boolean_function), BooleanFunction::Small(rhs_small_boolean_function)) => {
753                let rhs_big_boolean_function = BigBooleanFunction::from_truth_table(
754                    rhs_small_boolean_function.biguint_truth_table(),
755                    rhs_num_variables,
756                );
757                *self_big_boolean_function ^= rhs_big_boolean_function;
758            },
759            (BooleanFunction::Big(self_big_boolean_function), BooleanFunction::Big(rhs_big_boolean_function)) => {
760                *self_big_boolean_function ^= rhs_big_boolean_function;
761            }
762        }
763    }
764}
765
766/// XOR operator for Boolean functions truth tables.
767///
768/// # Panics
769/// If the Boolean functions have different number of variables, and the `unsafe_disable_safety_checks` feature is not enabled.
770impl BitXor for BooleanFunction {
771    type Output = Self;
772
773    fn bitxor(mut self, rhs: Self) -> Self::Output {
774        self ^= rhs;
775        self
776    }
777}
778
779/// ADD operator for Boolean functions truth tables.
780///
781/// It is equivalent to [crate::BooleanFunction::bitxor] operator.
782///
783/// # Panics
784/// If the Boolean functions have different number of variables, and the `unsafe_disable_safety_checks` feature is not enabled.
785impl Add for BooleanFunction {
786    type Output = Self;
787
788    fn add(self, rhs: Self) -> Self::Output {
789        self ^ rhs
790    }
791}
792
793/// In-place ADD operator for Boolean functions truth tables.
794///
795/// It is equivalent to [crate::BooleanFunction::bitxor_assign] operator.
796///
797/// # Panics
798/// If the Boolean functions have different number of variables, and the `unsafe_disable_safety_checks` feature is not enabled.
799impl AddAssign for BooleanFunction {
800    fn add_assign(&mut self, rhs: Self) {
801        *self ^= rhs;
802    }
803}
804
805/// In-place AND operator for Boolean functions truth tables.
806///
807/// # Panics
808/// If the Boolean functions have different number of variables, and the `unsafe_disable_safety_checks` feature is not enabled.
809impl BitAndAssign for BooleanFunction {
810    fn bitand_assign(&mut self, rhs: Self) {
811        let self_num_variables = self.variables_count();
812        let rhs_num_variables = rhs.variables_count();
813        if self_num_variables != rhs_num_variables {
814            panic!("{}", AND_DIFFERENT_VAR_COUNT_PANIC_MSG);
815        }
816        match (
817            self,
818            rhs,
819        ) {
820            (BooleanFunction::Small(self_small_boolean_function), BooleanFunction::Small(rhs_small_boolean_function)) => {
821                *self_small_boolean_function &= rhs_small_boolean_function;
822            },
823            (BooleanFunction::Small(self_small_boolean_function), BooleanFunction::Big(rhs_big_boolean_function)) => {
824                let rhs_small_boolean_function = SmallBooleanFunction::from_truth_table(
825                    rhs_big_boolean_function
826                        .biguint_truth_table()
827                        .to_u64()
828                        .unwrap(),
829                    self_num_variables,
830                )
831                    .unwrap();
832                *self_small_boolean_function &= rhs_small_boolean_function;
833            },
834            (BooleanFunction::Big(self_big_boolean_function), BooleanFunction::Small(rhs_small_boolean_function)) => {
835                let rhs_big_boolean_function = BigBooleanFunction::from_truth_table(
836                    rhs_small_boolean_function.biguint_truth_table(),
837                    rhs_num_variables,
838                );
839                *self_big_boolean_function &= rhs_big_boolean_function;
840            },
841            (BooleanFunction::Big(self_big_boolean_function), BooleanFunction::Big(rhs_big_boolean_function)) => {
842                *self_big_boolean_function &= rhs_big_boolean_function;
843            }
844        }
845    }
846}
847
848/// AND operator for Boolean functions truth tables.
849///
850/// # Panics
851/// If the Boolean functions have different number of variables, and the `unsafe_disable_safety_checks` feature is not enabled.
852impl BitAnd for BooleanFunction {
853    type Output = Self;
854
855    fn bitand(mut self, rhs: Self) -> Self::Output {
856        self &= rhs;
857        self
858    }
859}
860
861/// MUL operator for Boolean functions truth tables.
862///
863/// It is equivalent to [crate::BooleanFunction::bitand] operator.
864///
865/// # Panics
866/// If the Boolean functions have different number of variables, and the `unsafe_disable_safety_checks` feature is not enabled.
867impl Mul for BooleanFunction {
868    type Output = Self;
869    fn mul(self, rhs: Self) -> Self::Output {
870        self & rhs
871    }
872}
873
874/// In-place MUL operator for Boolean functions truth tables.
875///
876/// It is equivalent to [crate::BooleanFunction::bitand_assign] operator.
877///
878/// # Panics
879/// If the Boolean functions have different number of variables, and the `unsafe_disable_safety_checks` feature is not enabled.
880impl MulAssign for BooleanFunction {
881    fn mul_assign(&mut self, rhs: Self) {
882        *self &= rhs;
883    }
884}
885
886/// NOT operator for Boolean functions.
887///
888/// This is equivalent to the [BooleanFunctionImpl::reverse] operation: it reverses each output of the Boolean function.
889impl Not for BooleanFunction {
890    type Output = Self;
891
892    fn not(self) -> Self::Output {
893        self.reverse()
894    }
895}
896
897/// Create Boolean Function from hex string truth table representation
898impl TryFrom<&str> for BooleanFunction {
899    type Error = BooleanFunctionError;
900
901    fn try_from(value: &str) -> Result<Self, Self::Error> {
902        Self::from_hex_string_truth_table(value)
903    }
904}
905
906#[hackfn]
907impl BooleanFunction {
908    fn call(&self, input_bits: u32) -> bool {
909        self.compute_cellular_automata_rule(input_bits)
910    }
911}
912
913impl BooleanFunction {
914    /// Creates a new BooleanFunction from a hexadecimal string representing the truth table.
915    ///
916    /// The hexadecimal string must have a length of $\frac{2^n}{4}$ where $n$ is the number of variables of the Boolean function
917    /// (meaning this function only accepts Boolean function with 2 or more input variables).
918    ///
919    /// # Parameters
920    /// - `hex_truth_table`: The hexadecimal string representing the truth table of the Boolean function.
921    ///
922    /// # Returns
923    /// The Boolean function created from the hexadecimal string, or an error if the string cannot be parsed as a hexadecimal truth table of a Boolean function.
924    ///
925    /// # Example
926    /// ```rust
927    /// use boolean_function::BooleanFunction;
928    /// let boolean_function = BooleanFunction::from_hex_string_truth_table("0969817CC5893BA6")
929    ///     .unwrap();
930    /// ```
931    pub fn from_hex_string_truth_table(
932        hex_truth_table: &str,
933    ) -> Result<Self, BooleanFunctionError> {
934        if hex_truth_table.len().count_ones() != 1 {
935            return Err(WrongStringHexTruthTableLength);
936        }
937        let num_variables = (hex_truth_table.len() << 2).trailing_zeros() as usize;
938        if num_variables <= 6 {
939            Ok(SmallBooleanFunction::from_truth_table(
940                u64::from_str_radix(hex_truth_table, 16).map_err(|_| StringHexParseError)?,
941                num_variables,
942            )
943                .map_err(|_| UnexpectedError)?
944                .into())
945        } else {
946            Ok(BigBooleanFunction::from_truth_table(
947                BigUint::from_str_radix(hex_truth_table, 16).map_err(|_| StringHexParseError)?,
948                num_variables,
949            )
950                .into())
951        }
952    }
953
954    /// Creates a new BooleanFunction from a list of integers representing the [Walsh-Hadamard transform](BooleanFunctionImpl::walsh_hadamard_values), by applying a reverse Walsh-Hadamard transform.
955    ///
956    /// The Walsh-Hadamard values list for an $n$-variable Boolean function must have a length of $2^n$.
957    /// The function returns a [SmallBooleanFunction] if the given Walsh-Hadamard values list has a length of 64 or less, and a [BigBooleanFunction] otherwise.
958    /// It won't check that the values are consistent, if not the function will return the closest Boolean function possible.
959    ///
960    /// # Parameters
961    /// - `walsh_hadamard_values`: The list of integers representing the Walsh-Hadamard transform of the Boolean function.
962    ///
963    /// # Returns
964    /// The Boolean function created from the Walsh-Hadamard values list, or an error if the list length is less than 4, or not a power of 2.
965    pub fn from_reverse_walsh_hadamard_transform(
966        walsh_hadamard_values: &[i32],
967    ) -> Result<Self, BooleanFunctionError> {
968        const MAX_WALSH_VALUES_SMALL: usize = 64; // (2^6)
969        if walsh_hadamard_values.len() > MAX_WALSH_VALUES_SMALL {
970            return Ok(BigBooleanFunction::from_walsh_hadamard_values(walsh_hadamard_values)?.into());
971            // Error is handled in BigBooleanFunction constructor
972        }
973        Ok(SmallBooleanFunction::from_walsh_hadamard_values(walsh_hadamard_values)?.into())
974    }
975
976    /// Creates a new BooleanFunction from a list of integers representing the [Walsh-Fourier transform](BooleanFunctionImpl::walsh_fourier_values), by applying a reverse Walsh-Fourier transform.
977    ///
978    /// The Walsh-Fourier values list for an $n$-variable Boolean function must have a length of $2^n$.
979    /// The function returns a [SmallBooleanFunction] if the given Walsh-Fourier values list has a length of 64 or less, and a [BigBooleanFunction] otherwise.
980    /// It won't check that the values are consistent, if not the function will return the closest Boolean function possible.
981    ///
982    /// # Parameters
983    /// - `walsh_fourier_values`: The list of integers representing the Walsh-Fourier transform of the Boolean function.
984    ///
985    /// # Returns
986    /// The Boolean function created from the Walsh-Fourier values list, or an error if the list length is less than 4, or not a power of 2.
987    pub fn from_reverse_walsh_fourier_transform(
988        walsh_fourier_values: &[i32],
989    ) -> Result<Self, BooleanFunctionError> {
990        const MAX_WALSH_VALUES_SMALL: usize = 64; // (2^6)
991        if walsh_fourier_values.len() > MAX_WALSH_VALUES_SMALL {
992            return Ok(BigBooleanFunction::from_walsh_fourier_values(walsh_fourier_values)?.into());
993            // Error is handled in BigBooleanFunction constructor
994        }
995        Ok(SmallBooleanFunction::from_walsh_fourier_values(walsh_fourier_values)?.into())
996    }
997
998    /// Creates a new BooleanFunction from an u64 representing the truth table (meaning the Boolean function has 6 or less input variables).
999    ///
1000    /// The wrapped Boolean function is a [SmallBooleanFunction].
1001    ///
1002    /// # Parameters
1003    /// - `truth_table`: The u64 truth table of the Boolean function, where the lower bit represents the output of the Boolean function for the input 0.
1004    /// - `num_variables`: The number of input variables of the Boolean function.
1005    ///
1006    /// # Returns
1007    /// The Boolean function created from the u64 truth table.
1008    ///
1009    /// Returns an error if:
1010    /// - The given input variables count is greater than 6.
1011    /// - The given truth table is too big for the given input variables count and the `unsafe_disable_safety_checks` feature is not enabled.
1012    pub fn from_u64_truth_table(
1013        truth_table: u64,
1014        num_variables: usize,
1015    ) -> Result<Self, BooleanFunctionError> {
1016        Ok(SmallBooleanFunction::from_truth_table(truth_table, num_variables)?.into())
1017    }
1018
1019    /// Creates a new BooleanFunction from a BigUint representing the truth table.
1020    ///
1021    /// The wrapped Boolean function is a [BigBooleanFunction] if the variables count is greater than 6, and a [SmallBooleanFunction] otherwise.
1022    ///
1023    /// # Parameters
1024    /// - `truth_table`: The BigUint truth table of the Boolean function, where the lower bit represents the output of the Boolean function for the input 0.
1025    /// - `num_variables`: The number of input variables of the Boolean function.
1026    ///
1027    /// # Returns
1028    /// The Boolean function created from the BigUint truth table.
1029    ///
1030    /// Returns an error if:
1031    /// - The given input variables count is greater than 31, and the `unsafe_disable_safety_checks` feature is not enabled.
1032    /// - The given truth table is too big for the given input variables count and the `unsafe_disable_safety_checks` feature is not enabled.
1033    pub fn from_biguint_truth_table(
1034        truth_table: &BigUint,
1035        num_variables: usize,
1036    ) -> Result<Self, BooleanFunctionError> {
1037        #[cfg(not(feature = "unsafe_disable_safety_checks"))]
1038        if truth_table.bits() > (1 << num_variables) {
1039            return Err(BooleanFunctionError::TooBigTruthTableForVarCount);
1040        }
1041        #[cfg(not(feature = "unsafe_disable_safety_checks"))]
1042        if num_variables > 31 {
1043            return Err(BooleanFunctionError::TooBigVariableCount(31));
1044        }
1045        if num_variables <= 6 {
1046            return Ok(SmallBooleanFunction::from_truth_table(
1047                truth_table.to_u64().unwrap(),
1048                num_variables,
1049            )?
1050                .into());
1051        }
1052        Ok(BigBooleanFunction::from_truth_table(truth_table.clone(), num_variables).into())
1053    }
1054
1055    /// Computes Boolean Function from string ANF representation
1056    ///
1057    /// The ANF string representation must be in exact form "`x0*x2*x3 + x2*x3 + x1 + 1`".
1058    ///
1059    /// X's index starts at 0, meaning the maximum index is variable count - 1.
1060    ///
1061    /// # Parameters:
1062    /// - `anf_polynomial`: The string representation of the ANF form
1063    /// - `num_variables`: Variable count of the polynomial
1064    /// 
1065    /// # Returns
1066    /// The BooleanFunction corresponding to the ANF string representation, or an error if the input string doesn't respect the format and `unsafe_disable_safety_checks` feature is not activated.
1067    ///
1068    /// # Example
1069    /// ```rust
1070    /// use boolean_function::{BooleanFunction, BooleanFunctionImpl};
1071    ///
1072    /// let rule_30 = BooleanFunction::from_anf_polynomial_str("x0*x1 + x0 + x1 + x2", 3).unwrap();
1073    /// assert_eq!(rule_30.printable_hex_truth_table(), "1e");
1074    /// ```
1075    pub fn from_anf_polynomial_str(anf_polynomial: &str, num_variables: usize) -> Result<Self, BooleanFunctionError> {
1076        Ok(AnfPolynomial::from_str(anf_polynomial, num_variables)?.to_boolean_function())
1077    }
1078
1079    /// Computes Boolean Function from ANF polynomial
1080    ///
1081    /// # Parameters:
1082    /// - `anf_polynomial`: The polynomial in Algebraic Normal Form
1083    ///
1084    /// # Returns
1085    /// The BooleanFunction corresponding to the ANF polynomial
1086    pub fn from_anf_polynomial(anf_polynomial: &AnfPolynomial) -> Self {
1087        anf_polynomial.to_boolean_function()
1088    }
1089}
1090
1091#[cfg(test)]
1092mod tests {
1093    use crate::BooleanFunctionError::InvalidWalshValuesCount;
1094    use crate::{AnfPolynomial, BooleanFunction, BooleanFunctionImpl, BooleanFunctionType};
1095    use num_bigint::BigUint;
1096    use num_traits::Num;
1097    use std::collections::HashMap;
1098
1099    #[test]
1100    fn test_boolean_function_from_hex_string_truth_table() {
1101        let boolean_function =
1102            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD");
1103        assert!(boolean_function.is_err());
1104
1105        let boolean_function = BooleanFunction::from_hex_string_truth_table("");
1106        assert!(boolean_function.is_err());
1107
1108        let boolean_function = BooleanFunction::from_hex_string_truth_table("fe1z");
1109        assert!(boolean_function.is_err());
1110
1111        let boolean_function = BooleanFunction::from_hex_string_truth_table("fe12").unwrap();
1112        assert_eq!(boolean_function.variables_count(), 4);
1113
1114        let boolean_function =
1115            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD0")
1116                .unwrap();
1117        assert_eq!(boolean_function.variables_count(), 7);
1118    }
1119
1120    #[test]
1121    fn test_variables_count() {
1122        let boolean_function =
1123            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD0")
1124                .unwrap();
1125        assert_eq!(boolean_function.variables_count(), 7);
1126
1127        let boolean_function = BooleanFunction::from_hex_string_truth_table("fe12").unwrap();
1128        assert_eq!(boolean_function.variables_count(), 4);
1129    }
1130
1131    #[test]
1132    fn test_get_boolean_function_type() {
1133        let boolean_function =
1134            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD0")
1135                .unwrap();
1136        assert_eq!(
1137            boolean_function.get_boolean_function_type(),
1138            BooleanFunctionType::Big
1139        );
1140
1141        let boolean_function =
1142            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6").unwrap();
1143        assert_eq!(
1144            boolean_function.get_boolean_function_type(),
1145            BooleanFunctionType::Small
1146        );
1147    }
1148
1149    #[test]
1150    fn test_get_max_input_value() {
1151        let boolean_function =
1152            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD0")
1153                .unwrap();
1154        assert_eq!(boolean_function.get_max_input_value(), 127);
1155
1156        let boolean_function = BooleanFunction::from_hex_string_truth_table("fe12").unwrap();
1157        assert_eq!(boolean_function.get_max_input_value(), 15);
1158    }
1159
1160    #[test]
1161    fn test_is_balanced() {
1162        let boolean_function =
1163            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD0")
1164                .unwrap();
1165        assert!(boolean_function.is_balanced());
1166
1167        let boolean_function =
1168            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD1")
1169                .unwrap();
1170        assert!(!boolean_function.is_balanced());
1171
1172        let boolean_function =
1173            BooleanFunction::from_hex_string_truth_table("aa55aa55").unwrap();
1174        assert!(boolean_function.is_balanced());
1175
1176        let boolean_function =
1177            BooleanFunction::from_hex_string_truth_table("abce1234").unwrap();
1178        assert!(!boolean_function.is_balanced());
1179    }
1180
1181    #[test]
1182    fn test_compute_cellular_automata_rule() {
1183        let boolean_function =
1184            BooleanFunction::from_hex_string_truth_table("abce1234").unwrap();
1185        assert_eq!(boolean_function.compute_cellular_automata_rule(0), false);
1186        assert_eq!(boolean_function.compute_cellular_automata_rule(1), false);
1187        assert_eq!(boolean_function.compute_cellular_automata_rule(4), true);
1188        assert_eq!(boolean_function.compute_cellular_automata_rule(8), false);
1189        assert_eq!(boolean_function.compute_cellular_automata_rule(23), true);
1190
1191        assert_eq!(boolean_function(0), false);
1192        assert_eq!(boolean_function(1), false);
1193        assert_eq!(boolean_function(4), true);
1194        assert_eq!(boolean_function(8), false);
1195        assert_eq!(boolean_function(23), true);
1196
1197        let boolean_function =
1198            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD0")
1199                .unwrap();
1200        assert_eq!(boolean_function.compute_cellular_automata_rule(13), false);
1201        assert_eq!(boolean_function.compute_cellular_automata_rule(62), false);
1202        assert_eq!(boolean_function.compute_cellular_automata_rule(64), false);
1203        assert_eq!(boolean_function.compute_cellular_automata_rule(80), true);
1204        assert_eq!(boolean_function.compute_cellular_automata_rule(100), true);
1205
1206        assert_eq!(boolean_function(13), false);
1207        assert_eq!(boolean_function(62), false);
1208        assert_eq!(boolean_function(64), false);
1209        assert_eq!(boolean_function(80), true);
1210        assert_eq!(boolean_function(100), true);
1211    }
1212
1213    #[test]
1214    fn test_walsh_hadamard_transform() {
1215        let boolean_function =
1216            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD0")
1217                .unwrap();
1218        assert_eq!(boolean_function.walsh_hadamard_transform(0), 0);
1219        assert_eq!(boolean_function.walsh_hadamard_transform(1), 0);
1220        assert_eq!(boolean_function.walsh_hadamard_transform(7), -16);
1221        assert_eq!(boolean_function.walsh_hadamard_transform(15), 16);
1222        assert_eq!(boolean_function.walsh_hadamard_transform(126), 16);
1223        assert_eq!(boolean_function.walsh_hadamard_transform(127), -16);
1224
1225        let boolean_function =
1226            BooleanFunction::from_hex_string_truth_table("aa55aa55").unwrap();
1227        assert_eq!(boolean_function.walsh_hadamard_transform(0), 0);
1228        assert_eq!(boolean_function.walsh_hadamard_transform(1), 0);
1229        assert_eq!(boolean_function.walsh_hadamard_transform(9), -32);
1230        assert_eq!(boolean_function.walsh_hadamard_transform(31), 0);
1231
1232        let boolean_function =
1233            BooleanFunction::from_hex_string_truth_table("abce1234").unwrap();
1234        assert_eq!(boolean_function.walsh_hadamard_transform(0), 2);
1235        assert_eq!(boolean_function.walsh_hadamard_transform(1), 6);
1236        assert_eq!(boolean_function.walsh_hadamard_transform(2), -2);
1237        assert_eq!(boolean_function.walsh_hadamard_transform(31), -6);
1238    }
1239
1240    #[test]
1241    fn test_absolute_walsh_hadamard_spectrum() {
1242        let boolean_function =
1243            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD0")
1244                .unwrap();
1245        assert_eq!(
1246            boolean_function.absolute_walsh_hadamard_spectrum(),
1247            HashMap::from([(0, 64), (16, 64)])
1248        );
1249
1250        let boolean_function =
1251            BooleanFunction::from_hex_string_truth_table("abce1234").unwrap();
1252        assert_eq!(
1253            boolean_function.absolute_walsh_hadamard_spectrum(),
1254            HashMap::from([(6, 10), (10, 6), (2, 16)])
1255        );
1256    }
1257
1258    #[test]
1259    fn test_auto_correlation_transform() {
1260        let boolean_function =
1261            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD0")
1262                .unwrap();
1263        assert_eq!(boolean_function.auto_correlation_transform(0), 128);
1264        assert_eq!(boolean_function.auto_correlation_transform(1), -24);
1265        assert_eq!(boolean_function.auto_correlation_transform(126), -8);
1266        assert_eq!(boolean_function.auto_correlation_transform(127), -32);
1267
1268        let boolean_function = BooleanFunction::from_hex_string_truth_table("03").unwrap();
1269        assert_eq!(boolean_function.auto_correlation_transform(0), 8);
1270        assert_eq!(boolean_function.auto_correlation_transform(1), 8);
1271        assert_eq!(boolean_function.auto_correlation_transform(2), 0);
1272        assert_eq!(boolean_function.auto_correlation_transform(3), 0);
1273        assert_eq!(boolean_function.auto_correlation_transform(4), 0);
1274        assert_eq!(boolean_function.auto_correlation_transform(5), 0);
1275        assert_eq!(boolean_function.auto_correlation_transform(6), 0);
1276        assert_eq!(boolean_function.auto_correlation_transform(7), 0);
1277    }
1278
1279    #[test]
1280    fn test_absolute_autocorrelation_spectrum() {
1281        let boolean_function =
1282            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD0")
1283                .unwrap();
1284        assert_eq!(
1285            boolean_function.absolute_autocorrelation(),
1286            HashMap::from([(0, 33), (8, 58), (16, 28), (24, 6), (32, 2), (128, 1)])
1287        );
1288
1289        let boolean_function =
1290            BooleanFunction::from_hex_string_truth_table("abce1234").unwrap();
1291        assert_eq!(
1292            boolean_function.absolute_autocorrelation(),
1293            HashMap::from([(4, 25), (12, 6), (32, 1)])
1294        );
1295    }
1296
1297    #[test]
1298    fn test_derivative() {
1299        let boolean_function =
1300            BooleanFunction::from_hex_string_truth_table("aa55aa55").unwrap();
1301        let derivative = boolean_function.derivative(1).unwrap();
1302        assert_eq!(derivative.variables_count(), 5);
1303        assert_eq!(derivative.printable_hex_truth_table(), "ffffffff");
1304
1305        let boolean_function =
1306            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD0")
1307                .unwrap();
1308        let derivative = boolean_function.derivative(1).unwrap();
1309        assert_eq!(derivative.variables_count(), 7);
1310        assert_eq!(
1311            derivative.printable_hex_truth_table(),
1312            "cfffc3c00fcf0cfff003f3ccf3f0ff30"
1313        );
1314    }
1315
1316    #[test]
1317    fn test_algebraic_normal_form() {
1318        let boolean_function =
1319            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD0")
1320                .unwrap();
1321        assert_eq!(boolean_function.algebraic_normal_form().to_string(), "x0*x1*x2*x3 + x0*x1*x2*x4 + x0*x1*x3*x4 + x1*x2*x3*x4 + x0*x1*x2*x5 + x0*x2*x3*x5 + x1*x2*x3*x5 + x0*x2*x4*x5 + x1*x2*x4*x5 + x1*x3*x4*x5 + x2*x3*x4*x5 + x0*x1*x2*x6 + x0*x1*x3*x6 + x0*x2*x3*x6 + x1*x2*x3*x6 + x0*x2*x4*x6 + x1*x2*x4*x6 + x0*x3*x4*x6 + x2*x3*x4*x6 + x0*x1*x5*x6 + x0*x2*x5*x6 + x1*x2*x5*x6 + x1*x3*x5*x6 + x2*x3*x5*x6 + x3*x4*x5*x6 + x0*x1*x2 + x0*x2*x3 + x1*x2*x4 + x1*x3*x4 + x2*x3*x4 + x0*x1*x5 + x0*x2*x5 + x1*x2*x5 + x1*x3*x5 + x2*x3*x5 + x0*x4*x5 + x2*x4*x5 + x3*x4*x5 + x0*x2*x6 + x1*x2*x6 + x3*x4*x6 + x0*x5*x6 + x2*x5*x6 + x3*x5*x6 + x0*x2 + x0*x3 + x2*x4 + x3*x5 + x0*x6 + x1*x6 + x2*x6 + x3*x6 + x5*x6 + x2 + x4 + x5");
1322
1323        let boolean_function =
1324            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD1")
1325                .unwrap();
1326        assert_eq!(boolean_function.algebraic_normal_form().to_string(), "x0*x1*x2*x3*x4*x5*x6 + x0*x1*x2*x3*x4*x5 + x0*x1*x2*x3*x4*x6 + x0*x1*x2*x3*x5*x6 + x0*x1*x2*x4*x5*x6 + x0*x1*x3*x4*x5*x6 + x0*x2*x3*x4*x5*x6 + x1*x2*x3*x4*x5*x6 + x0*x1*x2*x3*x4 + x0*x1*x2*x3*x5 + x0*x1*x2*x4*x5 + x0*x1*x3*x4*x5 + x0*x2*x3*x4*x5 + x1*x2*x3*x4*x5 + x0*x1*x2*x3*x6 + x0*x1*x2*x4*x6 + x0*x1*x3*x4*x6 + x0*x2*x3*x4*x6 + x1*x2*x3*x4*x6 + x0*x1*x2*x5*x6 + x0*x1*x3*x5*x6 + x0*x2*x3*x5*x6 + x1*x2*x3*x5*x6 + x0*x1*x4*x5*x6 + x0*x2*x4*x5*x6 + x1*x2*x4*x5*x6 + x0*x3*x4*x5*x6 + x1*x3*x4*x5*x6 + x2*x3*x4*x5*x6 + x0*x2*x3*x4 + x0*x1*x3*x5 + x0*x1*x4*x5 + x0*x3*x4*x5 + x0*x1*x4*x6 + x1*x3*x4*x6 + x0*x3*x5*x6 + x0*x4*x5*x6 + x1*x4*x5*x6 + x2*x4*x5*x6 + x0*x1*x3 + x1*x2*x3 + x0*x1*x4 + x0*x2*x4 + x0*x3*x4 + x0*x3*x5 + x1*x4*x5 + x0*x1*x6 + x0*x3*x6 + x1*x3*x6 + x2*x3*x6 + x0*x4*x6 + x1*x4*x6 + x2*x4*x6 + x1*x5*x6 + x4*x5*x6 + x0*x1 + x1*x2 + x1*x3 + x2*x3 + x0*x4 + x1*x4 + x3*x4 + x0*x5 + x1*x5 + x2*x5 + x4*x5 + x4*x6 + x0 + x1 + x3 + x6 + 1");
1327
1328        let boolean_function = BooleanFunction::from_hex_string_truth_table("1e").unwrap();
1329        assert_eq!(
1330            boolean_function.algebraic_normal_form().to_string(),
1331            "x0*x1 + x0 + x1 + x2"
1332        );
1333
1334        let boolean_function = BooleanFunction::from_hex_string_truth_table("00").unwrap();
1335        assert_eq!(boolean_function.algebraic_normal_form().to_string(), "0");
1336
1337        let boolean_function = BooleanFunction::from_hex_string_truth_table("ff").unwrap();
1338        assert_eq!(boolean_function.algebraic_normal_form().to_string(), "1");
1339
1340        let boolean_function = BooleanFunction::from_hex_string_truth_table("6e").unwrap();
1341        assert_eq!(
1342            boolean_function.algebraic_normal_form().to_string(),
1343            "x0*x1*x2 + x0*x1 + x0 + x1"
1344        );
1345
1346        let boolean_function = BooleanFunction::from_hex_string_truth_table("7b").unwrap();
1347        assert_eq!(
1348            boolean_function.algebraic_normal_form().to_string(),
1349            "x0*x1 + x1*x2 + x1 + 1"
1350        );
1351    }
1352
1353    #[test]
1354    fn test_algebraic_degree() {
1355        let boolean_function =
1356            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD0")
1357                .unwrap();
1358        assert_eq!(boolean_function.algebraic_degree(), 4);
1359
1360        let boolean_function =
1361            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD1")
1362                .unwrap();
1363        assert_eq!(boolean_function.algebraic_degree(), 7);
1364
1365        let boolean_function =
1366            BooleanFunction::from_hex_string_truth_table("00000000000000000000000000000000")
1367                .unwrap();
1368        assert_eq!(boolean_function.algebraic_degree(), 0);
1369
1370        let boolean_function =
1371            BooleanFunction::from_hex_string_truth_table("ffffffffffffffffffffffffffffffff")
1372                .unwrap();
1373        assert_eq!(boolean_function.algebraic_degree(), 0);
1374
1375        let boolean_function = BooleanFunction::from_hex_string_truth_table("1e").unwrap();
1376        assert_eq!(boolean_function.algebraic_degree(), 2);
1377
1378        let boolean_function = BooleanFunction::from_hex_string_truth_table("00").unwrap();
1379        assert_eq!(boolean_function.algebraic_degree(), 0);
1380
1381        let boolean_function = BooleanFunction::from_hex_string_truth_table("0f").unwrap();
1382        assert_eq!(boolean_function.algebraic_degree(), 1);
1383
1384        let boolean_function = BooleanFunction::from_hex_string_truth_table("ff").unwrap();
1385        assert_eq!(boolean_function.algebraic_degree(), 0);
1386
1387        let boolean_function = BooleanFunction::from_hex_string_truth_table("6e").unwrap();
1388        assert_eq!(boolean_function.algebraic_degree(), 3);
1389
1390        let boolean_function = BooleanFunction::from_hex_string_truth_table("7b").unwrap();
1391        assert_eq!(boolean_function.algebraic_degree(), 2);
1392    }
1393
1394    #[test]
1395    fn test_printable_hex_truth_table() {
1396        let boolean_function =
1397            BooleanFunction::from_hex_string_truth_table("0069817CC5893BA6AC326E47619F5AD0")
1398                .unwrap();
1399        assert_eq!(
1400            boolean_function.printable_hex_truth_table(),
1401            "0069817cc5893ba6ac326e47619f5ad0"
1402        );
1403
1404        let boolean_function = BooleanFunction::from_hex_string_truth_table("fe12").unwrap();
1405        assert_eq!(boolean_function.printable_hex_truth_table(), "fe12");
1406    }
1407
1408    #[test]
1409    fn test_clone() {
1410        let boolean_function =
1411            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD0")
1412                .unwrap();
1413        let cloned_boolean_function = boolean_function.clone();
1414        assert_eq!(&boolean_function, &cloned_boolean_function);
1415
1416        let boolean_function = BooleanFunction::from_hex_string_truth_table("fe12").unwrap();
1417        let cloned_boolean_function = boolean_function.clone();
1418        assert_eq!(&boolean_function, &cloned_boolean_function);
1419    }
1420
1421    #[test]
1422    fn test_eq() {
1423        let boolean_function =
1424            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD0")
1425                .unwrap();
1426        assert_eq!(&boolean_function, &boolean_function);
1427
1428        let boolean_function2 =
1429            BooleanFunction::from_hex_string_truth_table("fe12").unwrap();
1430        assert_eq!(&boolean_function2, &boolean_function2);
1431
1432        assert_ne!(&boolean_function2, &boolean_function);
1433
1434        let boolean_function3 =
1435            BooleanFunction::from_hex_string_truth_table("0000fe12").unwrap();
1436        assert_ne!(&boolean_function3, &boolean_function2);
1437
1438        let boolean_function4 =
1439            BooleanFunction::from_hex_string_truth_table("0969817CC5893BA6AC326E47619F5AD0")
1440                .unwrap();
1441        assert_ne!(&boolean_function, &boolean_function4);
1442    }
1443
1444    #[test]
1445    fn test_reverse() {
1446        let boolean_function =
1447            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD0")
1448                .unwrap();
1449        let reversed_boolean_function = boolean_function.reverse();
1450        assert_eq!(reversed_boolean_function.variables_count(), 7);
1451        assert_eq!(
1452            reversed_boolean_function.printable_hex_truth_table(),
1453            "86967e833a76c45953cd91b89e60a52f"
1454        );
1455
1456        let reversed_boolean_function = !boolean_function;
1457        assert_eq!(reversed_boolean_function.variables_count(), 7);
1458        assert_eq!(
1459            reversed_boolean_function.printable_hex_truth_table(),
1460            "86967e833a76c45953cd91b89e60a52f"
1461        );
1462
1463        let boolean_function = BooleanFunction::from_hex_string_truth_table("fe12").unwrap();
1464        let reversed_boolean_function = boolean_function.reverse();
1465        assert_eq!(reversed_boolean_function.variables_count(), 4);
1466        assert_eq!(
1467            reversed_boolean_function.printable_hex_truth_table(),
1468            "01ed"
1469        );
1470
1471        let reversed_boolean_function = !boolean_function;
1472        assert_eq!(reversed_boolean_function.variables_count(), 4);
1473        assert_eq!(
1474            reversed_boolean_function.printable_hex_truth_table(),
1475            "01ed"
1476        );
1477    }
1478
1479    #[test]
1480    fn test_is_linear() {
1481        let boolean_function =
1482            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD0")
1483                .unwrap();
1484        assert!(!boolean_function.is_linear());
1485
1486        let boolean_function =
1487            BooleanFunction::from_hex_string_truth_table("0000000000000000ffffffffffffffff")
1488                .unwrap();
1489        assert!(boolean_function.is_linear());
1490
1491        let boolean_function =
1492            BooleanFunction::from_hex_string_truth_table("abcdef0123456789").unwrap();
1493        assert!(!boolean_function.is_linear());
1494
1495        let boolean_function =
1496            BooleanFunction::from_hex_string_truth_table("00000000ffffffff").unwrap();
1497        assert!(boolean_function.is_linear());
1498    }
1499
1500    #[test]
1501    fn test_is_symmetric() {
1502        let boolean_function = BooleanFunction::from_hex_string_truth_table("00").unwrap();
1503        assert!(boolean_function.is_symmetric());
1504
1505        let boolean_function = BooleanFunction::from_hex_string_truth_table("ff").unwrap();
1506        assert!(boolean_function.is_symmetric());
1507
1508        let boolean_function = BooleanFunction::from_hex_string_truth_table("80").unwrap();
1509        assert!(boolean_function.is_symmetric());
1510
1511        let boolean_function = BooleanFunction::from_hex_string_truth_table("1e").unwrap();
1512        assert!(!boolean_function.is_symmetric());
1513
1514        let boolean_function =
1515            BooleanFunction::from_hex_string_truth_table("00000008").unwrap();
1516        assert!(!boolean_function.is_symmetric());
1517
1518        let boolean_function =
1519            BooleanFunction::from_hex_string_truth_table("ffffffffffffffffffffffffffffffff")
1520                .unwrap();
1521        assert!(boolean_function.is_symmetric());
1522    }
1523
1524    #[test]
1525    fn test_nonlinearity() {
1526        let boolean_function =
1527            BooleanFunction::from_hex_string_truth_table("00000000").unwrap();
1528        assert_eq!(boolean_function.nonlinearity(), 0);
1529
1530        let boolean_function =
1531            BooleanFunction::from_hex_string_truth_table("ffffffff").unwrap();
1532        assert_eq!(boolean_function.nonlinearity(), 0);
1533
1534        let boolean_function =
1535            BooleanFunction::from_hex_string_truth_table("0000000a").unwrap();
1536        assert_eq!(boolean_function.nonlinearity(), 2);
1537
1538        let boolean_function =
1539            BooleanFunction::from_hex_string_truth_table("0113077C165E76A8").unwrap();
1540        assert_eq!(boolean_function.nonlinearity(), 28);
1541    }
1542
1543    #[test]
1544    fn test_is_bent() {
1545        let boolean_function =
1546            BooleanFunction::try_from("00000000").unwrap();
1547        assert!(!boolean_function.is_bent());
1548
1549        let boolean_function =
1550            BooleanFunction::from_hex_string_truth_table("0113077C165E76A8").unwrap();
1551        assert!(boolean_function.is_bent());
1552
1553        let boolean_function =
1554            BooleanFunction::from_hex_string_truth_table("00000000ffffffff").unwrap();
1555        assert!(!boolean_function.is_bent());
1556    }
1557
1558    #[test]
1559    fn test_is_near_bent() {
1560        let boolean_function = BooleanFunction::from_hex_string_truth_table("f9")
1561            .unwrap();
1562        assert!(boolean_function.is_near_bent());
1563
1564        let boolean_function = BooleanFunction::from_hex_string_truth_table("ff")
1565            .unwrap();
1566        assert!(!boolean_function.is_near_bent());
1567
1568        // even variable count -> cannot be near-bent
1569        let boolean_function = BooleanFunction::from_hex_string_truth_table("f9f9")
1570            .unwrap();
1571        assert!(!boolean_function.is_near_bent());
1572    }
1573
1574    #[test]
1575    fn test_annihilator() {
1576        let boolean_function =
1577            BooleanFunction::from_hex_string_truth_table("00000000").unwrap();
1578        let annihilator = boolean_function.annihilator(Some(0)).unwrap();
1579        assert_eq!(annihilator.0.printable_hex_truth_table(), "ffffffff");
1580        assert_eq!(annihilator.1, 0);
1581        assert_eq!(annihilator.2, 1);
1582
1583        let boolean_function =
1584            BooleanFunction::from_hex_string_truth_table("abcdef0123456789").unwrap();
1585        let annihilator = boolean_function.annihilator(Some(4)).unwrap();
1586        assert_eq!(
1587            annihilator.0.printable_hex_truth_table(),
1588            "1010101010101010"
1589        );
1590        assert_eq!(annihilator.1, 3);
1591        assert_eq!(annihilator.2, 25);
1592
1593        let boolean_function = BooleanFunction::from_hex_string_truth_table(
1594            "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
1595        )
1596        .unwrap();
1597        let annihilator = boolean_function.annihilator(Some(4));
1598        assert!(annihilator.is_none());
1599
1600        let boolean_function = BooleanFunction::from_hex_string_truth_table(
1601            "0000000000000000000000000000000000000000000000000000000000000000",
1602        )
1603        .unwrap();
1604        let annihilator = boolean_function.annihilator(Some(4)).unwrap();
1605        assert_eq!(
1606            annihilator.0.printable_hex_truth_table(),
1607            "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
1608        );
1609        assert_eq!(annihilator.1, 0);
1610        assert_eq!(annihilator.2, 163);
1611
1612        let boolean_function = BooleanFunction::from_hex_string_truth_table(
1613            "80921c010276c44224422441188118822442244118811880400810a80e200425",
1614        )
1615        .unwrap();
1616        let annihilator = boolean_function.annihilator(Some(1));
1617        assert!(annihilator.is_none());
1618        let annihilator = boolean_function.annihilator(Some(5)).unwrap();
1619        assert_eq!(
1620            annihilator.0.printable_hex_truth_table(),
1621            "2244224411881188d2b4d2b4e178e178d2b4d2b4e178e1782244224411881188"
1622        );
1623        assert_eq!(annihilator.1, 2);
1624        assert_eq!(annihilator.2, 155);
1625    }
1626
1627    #[test]
1628    fn test_algebraic_immunity() {
1629        let boolean_function = BooleanFunction::from_hex_string_truth_table(
1630            "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
1631        )
1632        .unwrap();
1633        assert_eq!(boolean_function.algebraic_immunity(), 0);
1634
1635        let boolean_function = BooleanFunction::from_hex_string_truth_table(
1636            "0000000000000000000000000000000000000000000000000000000000000000",
1637        )
1638        .unwrap();
1639        assert_eq!(boolean_function.algebraic_immunity(), 0);
1640
1641        let boolean_function = BooleanFunction::from_hex_string_truth_table("ffff").unwrap();
1642        assert_eq!(boolean_function.algebraic_immunity(), 0);
1643
1644        let boolean_function = BooleanFunction::from_hex_string_truth_table("0000").unwrap();
1645        assert_eq!(boolean_function.algebraic_immunity(), 0);
1646
1647        let boolean_function = BooleanFunction::from_hex_string_truth_table(
1648            "80921c010276c44224422441188118822442244118811880400810a80e200425",
1649        )
1650        .unwrap();
1651        assert_eq!(boolean_function.algebraic_immunity(), 2);
1652
1653        let boolean_function = BooleanFunction::from_hex_string_truth_table(
1654            "2244224411881188d2b4d2b4e178e178d2b4d2b4e178e1782244224411881188",
1655        )
1656        .unwrap();
1657        assert_eq!(boolean_function.algebraic_immunity(), 2);
1658
1659        let boolean_function =
1660            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD0")
1661                .unwrap();
1662        assert_eq!(boolean_function.algebraic_immunity(), 3);
1663
1664        let boolean_function =
1665            BooleanFunction::from_hex_string_truth_table("0113077C165E76A8").unwrap();
1666        assert_eq!(boolean_function.algebraic_immunity(), 2);
1667
1668        let boolean_function = BooleanFunction::from_hex_string_truth_table("1e").unwrap();
1669        assert_eq!(boolean_function.algebraic_immunity(), 2);
1670    }
1671
1672    #[test]
1673    fn test_is_plateaued() {
1674        let boolean_function = BooleanFunction::from_hex_string_truth_table(
1675            "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
1676        )
1677        .unwrap();
1678        assert!(boolean_function.is_plateaued());
1679
1680        let boolean_function = BooleanFunction::from_hex_string_truth_table("8778").unwrap();
1681        assert!(boolean_function.is_plateaued());
1682
1683        let boolean_function = BooleanFunction::from_hex_string_truth_table("1e").unwrap();
1684        assert!(boolean_function.is_plateaued());
1685
1686        let boolean_function =
1687            BooleanFunction::from_hex_string_truth_table("abcdef1234567890").unwrap();
1688        assert!(!boolean_function.is_plateaued());
1689    }
1690
1691    #[test]
1692    fn test_sum_of_square_indicator() {
1693        let boolean_function =
1694            BooleanFunction::from_hex_string_truth_table("ffffffff").unwrap();
1695        assert_eq!(boolean_function.sum_of_square_indicator(), 32768);
1696
1697        let boolean_function = BooleanFunction::from_hex_string_truth_table("0000").unwrap();
1698        assert_eq!(boolean_function.sum_of_square_indicator(), 4096);
1699
1700        let boolean_function =
1701            BooleanFunction::from_hex_string_truth_table("abcdef1234567890abcdef1234567890")
1702                .unwrap();
1703        assert_eq!(boolean_function.sum_of_square_indicator(), 84992);
1704
1705        let boolean_function =
1706            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD0")
1707                .unwrap();
1708        assert_eq!(boolean_function.sum_of_square_indicator(), 32768);
1709    }
1710
1711    #[test]
1712    fn test_absolute_indicator() {
1713        let boolean_function = BooleanFunction::from_hex_string_truth_table("1e").unwrap();
1714        assert_eq!(boolean_function.absolute_indicator(), 8);
1715
1716        let boolean_function =
1717            BooleanFunction::from_hex_string_truth_table("ffffffff").unwrap();
1718        assert_eq!(boolean_function.absolute_indicator(), 32);
1719
1720        let boolean_function = BooleanFunction::from_hex_string_truth_table("0000").unwrap();
1721        assert_eq!(boolean_function.absolute_indicator(), 16);
1722
1723        let boolean_function =
1724            BooleanFunction::from_hex_string_truth_table("abcdef1234567890abcdef1234567890")
1725                .unwrap();
1726        assert_eq!(boolean_function.absolute_indicator(), 128);
1727
1728        let boolean_function =
1729            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD0")
1730                .unwrap();
1731        assert_eq!(boolean_function.absolute_indicator(), 32);
1732
1733        let boolean_function =
1734            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD0")
1735                .unwrap();
1736        assert_eq!(boolean_function.absolute_indicator(), 32);
1737    }
1738
1739    #[test]
1740    fn test_linear_structures() {
1741        let boolean_function = BooleanFunction::from_hex_string_truth_table("1e").unwrap();
1742        assert_eq!(boolean_function.linear_structures(), [0, 4]);
1743
1744        let boolean_function =
1745            BooleanFunction::from_hex_string_truth_table("abcdef1234567890abcdef1234567890")
1746                .unwrap();
1747        assert_eq!(boolean_function.linear_structures(), [0, 64]);
1748
1749        let boolean_function =
1750            BooleanFunction::from_hex_string_truth_table("0113077C165E76A8").unwrap();
1751        assert_eq!(boolean_function.linear_structures(), [0]);
1752
1753        let boolean_function =
1754            BooleanFunction::from_hex_string_truth_table("00000000ffffffff").unwrap();
1755        assert_eq!(
1756            boolean_function.linear_structures(),
1757            [
1758                0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
1759                23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
1760                44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63
1761            ]
1762        );
1763
1764        let boolean_function =
1765            BooleanFunction::from_hex_string_truth_table("00000000").unwrap();
1766        assert_eq!(
1767            boolean_function.linear_structures(),
1768            [
1769                0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
1770                23, 24, 25, 26, 27, 28, 29, 30, 31
1771            ]
1772        );
1773
1774        let boolean_function =
1775            BooleanFunction::from_hex_string_truth_table("ffffffff").unwrap();
1776        assert_eq!(
1777            boolean_function.linear_structures(),
1778            [
1779                0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
1780                23, 24, 25, 26, 27, 28, 29, 30, 31
1781            ]
1782        );
1783    }
1784
1785    #[test]
1786    fn test_has_linear_structure() {
1787        let boolean_function = BooleanFunction::from_hex_string_truth_table("659a").unwrap();
1788        assert!(boolean_function.has_linear_structure());
1789
1790        let boolean_function = BooleanFunction::from_hex_string_truth_table("dd0e").unwrap();
1791        assert!(!boolean_function.has_linear_structure());
1792
1793        let boolean_function =
1794            BooleanFunction::from_hex_string_truth_table("00000000").unwrap();
1795        assert!(boolean_function.has_linear_structure());
1796
1797        let boolean_function =
1798            BooleanFunction::from_hex_string_truth_table("ffffffff").unwrap();
1799        assert!(boolean_function.has_linear_structure());
1800
1801        let boolean_function =
1802            BooleanFunction::from_hex_string_truth_table("0113077C165E76A8").unwrap();
1803        assert!(!boolean_function.has_linear_structure());
1804    }
1805
1806    #[test]
1807    fn test_is_linear_structure() {
1808        let boolean_function = BooleanFunction::from_hex_string_truth_table("659a").unwrap();
1809        assert!(boolean_function.is_linear_structure(1));
1810        assert!(!boolean_function.is_linear_structure(7));
1811        assert!(boolean_function.is_linear_structure(9));
1812    }
1813
1814    #[test]
1815    fn test_walsh_hadamard_values() {
1816        let boolean_function = BooleanFunction::from_hex_string_truth_table("dd0e").unwrap();
1817        assert_eq!(
1818            boolean_function.walsh_hadamard_values(),
1819            [-2, -2, 6, -2, -6, 2, 2, 2, 6, 6, -2, 6, -6, 2, 2, 2]
1820        );
1821
1822        let boolean_function = BooleanFunction::from_hex_string_truth_table("0000").unwrap();
1823        assert_eq!(
1824            boolean_function.walsh_hadamard_values(),
1825            [16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
1826        );
1827
1828        let boolean_function = BooleanFunction::from_hex_string_truth_table("ffff").unwrap();
1829        assert_eq!(
1830            boolean_function.walsh_hadamard_values(),
1831            [-16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
1832        );
1833    }
1834
1835    #[test]
1836    fn test_boolean_function_from_reverse_walsh_transform() {
1837        let boolean_function = BooleanFunction::from_reverse_walsh_hadamard_transform(&[
1838            -2, -2, 6, -2, -6, 2, 2, 2, 6, 6, -2, 6, -6, 2, 2, 2,
1839        ])
1840        .unwrap();
1841        assert_eq!(boolean_function.printable_hex_truth_table(), "dd0e");
1842        assert_eq!(
1843            boolean_function.get_boolean_function_type(),
1844            BooleanFunctionType::Small
1845        );
1846
1847        let boolean_function = BooleanFunction::from_reverse_walsh_hadamard_transform(&[
1848            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1849            0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1850            0, 0, 0, 0, 0, 0,
1851        ])
1852        .unwrap();
1853        assert_eq!(
1854            boolean_function.printable_hex_truth_table(),
1855            "ffffffff00000000"
1856        );
1857        assert_eq!(
1858            boolean_function.get_boolean_function_type(),
1859            BooleanFunctionType::Small
1860        );
1861
1862        let boolean_function = BooleanFunction::from_reverse_walsh_hadamard_transform(&[
1863            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1864            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1865            0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1866            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1867            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1868        ])
1869        .unwrap();
1870        assert_eq!(
1871            boolean_function.printable_hex_truth_table(),
1872            "ffffffffffffffff0000000000000000"
1873        );
1874        assert_eq!(
1875            boolean_function.get_boolean_function_type(),
1876            BooleanFunctionType::Big
1877        );
1878
1879        let boolean_function = BooleanFunction::from_reverse_walsh_hadamard_transform(&[
1880            16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1881        ])
1882        .unwrap();
1883        assert_eq!(boolean_function.printable_hex_truth_table(), "0000");
1884
1885        let boolean_function = BooleanFunction::from_reverse_walsh_hadamard_transform(&[
1886            128, 0, 8, 8, 0, 0, 8, 8, -8, 8, -16, 0, 8, -8, -64, -16, 0, -16, 8, -8, 0, -16, 8, -8,
1887            8, 8, 0, 0, -8, -8, -16, -16, -8, 8, 0, -16, -8, 8, 0, 16, 0, 0, -8, 24, 16, -48, 8, 8,
1888            8, 8, 16, 16, 8, 8, -16, 16, 0, 16, -8, 8, -16, 32, 8, 24, 8, 8, 0, 0, -8, -8, 16, -16,
1889            0, 16, 8, -8, 0, -16, 8, -8, -8, 8, -16, 0, 8, -8, 0, 16, -32, 0, 8, 8, 0, 0, 8, 8, 0,
1890            0, -8, -8, -16, -16, 8, 8, 8, -8, -16, 0, 8, -8, -16, 0, 0, -16, -8, 8, -16, 0, 8, -8,
1891            -8, -8, 0, 0, -8, -8, 0, 0, 12, 4, 4, -4, -4, -12, 20, -20, 4, 12, 12, -12, 4, -20, 12,
1892            -12, -4, 4, -12, -4, 12, -12, 4, 12, -28, -4, 12, 4, 4, -4, 12, 4, 4, -4, -4, -12, -12,
1893            -20, 12, 4, 12, -12, -12, -4, 12, -12, -12, -4, 4, -20, -4, 4, -12, -4, 12, -12, -4,
1894            -12, 4, -4, -4, -12, 4, -4, -4, 4, 4, 12, -4, 4, 4, 12, -12, 12, -20, 4, 4, -4, 60,
1895            -12, -4, -12, 4, -4, -4, -12, 4, -4, 4, 12, -4, 4, -12, -4, -20, -12, -12, -20, -4, 84,
1896            -12, -20, -4, -12, -4, -28, -12, -4, 12, 52, 4, -20, 4, -20, 12, -12, 4, -20, -20, -12,
1897            -4, -12, -12, -20, -20, 4, 4, -4,
1898        ])
1899        .unwrap();
1900        assert_eq!(
1901            boolean_function.printable_hex_truth_table(),
1902            "80921c010276c44224422441188118822442244118811880400810a80e200425"
1903        );
1904        assert_eq!(
1905            boolean_function.get_boolean_function_type(),
1906            BooleanFunctionType::Big
1907        );
1908
1909        let boolean_function = BooleanFunction::from_reverse_walsh_hadamard_transform(&[
1910            128, 0, 8, 8, 0, 0, 8, 8, -8, 8, -16, 0, 8, -8, -64, -16, 0, -16, 8, -8, 0, -16, 8, -8,
1911            8, 8, 0, 0, -8, -8, -16, -16, -8, 8, 0, -16, -8, 8, 0, 16, 0, 0, -8, 24, 16, -48, 8, 8,
1912            8, 8, 16, 16, 8, 8, -16, 16, 0, 16, -8, 8, -16, 32, 8, 24, 8, 8, 0, 0, -8, -8, 16, -16,
1913            0, 16, 8, -8, 0, -16, 8, -8, -8, 8, -16, 0, 8, -8, 0, 16, -32, 0, 8, 8, 0, 0, 8, 8, 0,
1914            0, -8, -8, -16, -16, 8, 8, 8, -8, -16, 0, 8, -8, -16, 0, 0, -16, -8, 8, -16, 0, 8, -8,
1915            -8, -8, 0, 0, -8, -8, 0, 0, 12, 4, 4, -4, -4, -12, 20, -20, 4, 12, 12, -12, 4, -20, 12,
1916            -12, -4, 4, -12, -4, 12, -12, 4, 12, -28, -4, 12, 4, 4, -4, 12, 4, 4, -4, -4, -12, -12,
1917            -20, 12, 4, 12, -12, -12, -4, 12, -12, -12, -4, 4, -20, -4, 4, -12, -4, 12, -12, -4,
1918            -12, 4, -4, -4, -12, 4, -4, -4, 4, 4, 12, -4, 4, 4, 12, -12, 12, -20, 4, 4, -4, 60,
1919            -12, -4, -12, 4, -4, -4, -12, 4, -4, 4, 12, -4, 4, -12, -4, -20, -12, -12, -20, -4, 84,
1920            -12, -20, -4, -12, -4, -28, -12, -4, 12, 52, 4, -20, 4, -20, 12, -12, 4, -20, -20, -12,
1921            -4, -12, -12, -20, -20, 4, 4,
1922        ]);
1923        assert!(boolean_function.is_err());
1924        assert_eq!(boolean_function.unwrap_err(), InvalidWalshValuesCount(255));
1925
1926        let boolean_function =
1927            BooleanFunction::from_reverse_walsh_hadamard_transform(&[128]);
1928        assert!(boolean_function.is_err());
1929        assert_eq!(boolean_function.unwrap_err(), InvalidWalshValuesCount(1));
1930    }
1931
1932    #[test]
1933    fn test_correlation_immunity() {
1934        let boolean_function = BooleanFunction::from_hex_string_truth_table("dd0e").unwrap();
1935        assert_eq!(boolean_function.correlation_immunity(), 0);
1936
1937        let boolean_function =
1938            BooleanFunction::from_hex_string_truth_table("55C3AAC3").unwrap();
1939        assert_eq!(boolean_function.correlation_immunity(), 1);
1940
1941        let boolean_function = BooleanFunction::from_hex_string_truth_table("1f").unwrap();
1942        assert_eq!(boolean_function.correlation_immunity(), 0);
1943
1944        let boolean_function = BooleanFunction::from_hex_string_truth_table("ffff").unwrap();
1945        assert_eq!(boolean_function.correlation_immunity(), 4);
1946
1947        let boolean_function =
1948            BooleanFunction::from_hex_string_truth_table("00000000000000000000000000000000")
1949                .unwrap();
1950        assert_eq!(boolean_function.correlation_immunity(), 7);
1951
1952        let boolean_function =
1953            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD0")
1954                .unwrap();
1955        assert_eq!(boolean_function.correlation_immunity(), 2);
1956    }
1957
1958    #[test]
1959    fn test_resiliency_order() {
1960        let boolean_function = BooleanFunction::from_hex_string_truth_table("dd0e").unwrap();
1961        assert_eq!(boolean_function.resiliency_order(), None);
1962
1963        let boolean_function =
1964            BooleanFunction::from_hex_string_truth_table("55C3AAC3").unwrap();
1965        assert_eq!(boolean_function.resiliency_order(), Some(1));
1966
1967        let boolean_function = BooleanFunction::from_hex_string_truth_table("1f").unwrap();
1968        assert_eq!(boolean_function.resiliency_order(), None);
1969
1970        let boolean_function = BooleanFunction::from_hex_string_truth_table("ffff").unwrap();
1971        assert_eq!(boolean_function.resiliency_order(), None);
1972
1973        let boolean_function =
1974            BooleanFunction::from_hex_string_truth_table("00000000000000000000000000000000")
1975                .unwrap();
1976        assert_eq!(boolean_function.resiliency_order(), None);
1977
1978        let boolean_function =
1979            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD0")
1980                .unwrap();
1981        assert_eq!(boolean_function.resiliency_order(), Some(2));
1982    }
1983
1984    #[test]
1985    fn test_biguint_truth_table() {
1986        let boolean_function =
1987            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD0")
1988                .unwrap();
1989        assert_eq!(
1990            boolean_function.biguint_truth_table().to_str_radix(16),
1991            "7969817cc5893ba6ac326e47619f5ad0"
1992        );
1993
1994        let boolean_function = BooleanFunction::from_hex_string_truth_table("1e").unwrap();
1995        assert_eq!(
1996            boolean_function.biguint_truth_table().to_str_radix(16),
1997            "1e"
1998        );
1999    }
2000
2001    #[test]
2002    fn test_try_u64_truth_table() {
2003        let boolean_function =
2004            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD0")
2005                .unwrap();
2006        assert_eq!(boolean_function.try_u64_truth_table(), None);
2007
2008        let boolean_function = BooleanFunction::from_hex_string_truth_table("1e").unwrap();
2009        assert_eq!(boolean_function.try_u64_truth_table(), Some(30));
2010    }
2011
2012    #[test]
2013    fn test_xor() {
2014        let mut boolean_function =
2015            BooleanFunction::from_hex_string_truth_table("80921c010276c440400810a80e200425")
2016                .unwrap();
2017        let boolean_function2 =
2018            BooleanFunction::from_hex_string_truth_table("22442244118811882244224411881188")
2019                .unwrap();
2020        let boolean_function3 = boolean_function.clone() ^ boolean_function2.clone();
2021        boolean_function ^= boolean_function2.clone();
2022        assert_eq!(&boolean_function, &boolean_function3);
2023        assert_eq!(
2024            boolean_function.printable_hex_truth_table(),
2025            "a2d63e4513fed5c8624c32ec1fa815ad"
2026        );
2027        assert_eq!(boolean_function.variables_count(), 7);
2028        assert_eq!(
2029            boolean_function.get_boolean_function_type(),
2030            BooleanFunctionType::Big
2031        );
2032        assert_eq!(
2033            boolean_function3.get_boolean_function_type(),
2034            BooleanFunctionType::Big
2035        );
2036
2037        let mut boolean_function =
2038            BooleanFunction::from_hex_string_truth_table("1e").unwrap();
2039        let boolean_function2 = BooleanFunction::from_hex_string_truth_table("ab").unwrap();
2040        let boolean_function3 = boolean_function.clone() ^ boolean_function2.clone();
2041        boolean_function ^= boolean_function2.clone();
2042        assert_eq!(&boolean_function, &boolean_function3);
2043        assert_eq!(boolean_function.printable_hex_truth_table(), "b5");
2044        assert_eq!(boolean_function.variables_count(), 3);
2045        assert_eq!(
2046            boolean_function.get_boolean_function_type(),
2047            BooleanFunctionType::Small
2048        );
2049        assert_eq!(
2050            boolean_function3.get_boolean_function_type(),
2051            BooleanFunctionType::Small
2052        );
2053
2054        let mut boolean_function =
2055            BooleanFunction::from_hex_string_truth_table("1e").unwrap();
2056        let boolean_function2: BooleanFunction = super::BigBooleanFunction::from_truth_table(
2057            BigUint::from_str_radix("ab", 16).unwrap(),
2058            3,
2059        ).into();
2060        let boolean_function3 = boolean_function.clone() ^ boolean_function2.clone();
2061        boolean_function ^= boolean_function2.clone();
2062        assert_eq!(&boolean_function, &boolean_function3);
2063        assert_eq!(boolean_function.printable_hex_truth_table(), "b5");
2064        assert_eq!(boolean_function.variables_count(), 3);
2065        assert_eq!(
2066            boolean_function.get_boolean_function_type(),
2067            BooleanFunctionType::Small
2068        );
2069        assert_eq!(
2070            boolean_function2.get_boolean_function_type(),
2071            BooleanFunctionType::Big
2072        );
2073        assert_eq!(
2074            boolean_function3.get_boolean_function_type(),
2075            BooleanFunctionType::Small
2076        );
2077
2078        let mut boolean_function: BooleanFunction = super::BigBooleanFunction::from_truth_table(
2079            BigUint::from_str_radix("ab", 16).unwrap(),
2080            3,
2081        ).into();
2082        let boolean_function2 = BooleanFunction::from_hex_string_truth_table("1e").unwrap();
2083        let boolean_function3 = boolean_function.clone() ^ boolean_function2.clone();
2084        boolean_function ^= boolean_function2.clone();
2085        assert_eq!(&boolean_function, &boolean_function3);
2086        assert_eq!(boolean_function.printable_hex_truth_table(), "b5");
2087        assert_eq!(boolean_function.variables_count(), 3);
2088        assert_eq!(
2089            boolean_function.get_boolean_function_type(),
2090            BooleanFunctionType::Big
2091        );
2092        assert_eq!(
2093            boolean_function2.get_boolean_function_type(),
2094            BooleanFunctionType::Small
2095        );
2096        assert_eq!(
2097            boolean_function3.get_boolean_function_type(),
2098            BooleanFunctionType::Big
2099        );
2100    }
2101
2102    #[test]
2103    fn test_add() {
2104        let mut boolean_function =
2105            BooleanFunction::from_hex_string_truth_table("80921c010276c440400810a80e200425")
2106                .unwrap();
2107        let boolean_function2 =
2108            BooleanFunction::from_hex_string_truth_table("22442244118811882244224411881188")
2109                .unwrap();
2110        let boolean_function3 = boolean_function.clone() + boolean_function2.clone();
2111        boolean_function += boolean_function2.clone();
2112        assert_eq!(&boolean_function, &boolean_function3);
2113        assert_eq!(
2114            boolean_function.printable_hex_truth_table(),
2115            "a2d63e4513fed5c8624c32ec1fa815ad"
2116        );
2117        assert_eq!(boolean_function.variables_count(), 7);
2118        assert_eq!(
2119            boolean_function.get_boolean_function_type(),
2120            BooleanFunctionType::Big
2121        );
2122        assert_eq!(
2123            boolean_function3.get_boolean_function_type(),
2124            BooleanFunctionType::Big
2125        );
2126
2127        let mut boolean_function =
2128            BooleanFunction::from_hex_string_truth_table("1e").unwrap();
2129        let boolean_function2 = BooleanFunction::from_hex_string_truth_table("ab").unwrap();
2130        let boolean_function3 = boolean_function.clone() + boolean_function2.clone();
2131        boolean_function += boolean_function2.clone();
2132        assert_eq!(&boolean_function, &boolean_function3);
2133        assert_eq!(boolean_function.printable_hex_truth_table(), "b5");
2134        assert_eq!(boolean_function.variables_count(), 3);
2135        assert_eq!(
2136            boolean_function.get_boolean_function_type(),
2137            BooleanFunctionType::Small
2138        );
2139        assert_eq!(
2140            boolean_function3.get_boolean_function_type(),
2141            BooleanFunctionType::Small
2142        );
2143
2144        let mut boolean_function =
2145            BooleanFunction::from_hex_string_truth_table("1e").unwrap();
2146        let boolean_function2: BooleanFunction = super::BigBooleanFunction::from_truth_table(
2147            BigUint::from_str_radix("ab", 16).unwrap(),
2148            3,
2149        ).into();
2150        let boolean_function3 = boolean_function.clone() + boolean_function2.clone();
2151        boolean_function += boolean_function2.clone();
2152        assert_eq!(&boolean_function, &boolean_function3);
2153        assert_eq!(boolean_function.printable_hex_truth_table(), "b5");
2154        assert_eq!(boolean_function.variables_count(), 3);
2155        assert_eq!(
2156            boolean_function.get_boolean_function_type(),
2157            BooleanFunctionType::Small
2158        );
2159        assert_eq!(
2160            boolean_function2.get_boolean_function_type(),
2161            BooleanFunctionType::Big
2162        );
2163        assert_eq!(
2164            boolean_function3.get_boolean_function_type(),
2165            BooleanFunctionType::Small
2166        );
2167
2168        let mut boolean_function: BooleanFunction = super::BigBooleanFunction::from_truth_table(
2169            BigUint::from_str_radix("ab", 16).unwrap(),
2170            3,
2171        ).into();
2172        let boolean_function2 = BooleanFunction::from_hex_string_truth_table("1e").unwrap();
2173        let boolean_function3 = boolean_function.clone() + boolean_function2.clone();
2174        boolean_function += boolean_function2.clone();
2175        assert_eq!(&boolean_function, &boolean_function3);
2176        assert_eq!(boolean_function.printable_hex_truth_table(), "b5");
2177        assert_eq!(boolean_function.variables_count(), 3);
2178        assert_eq!(
2179            boolean_function.get_boolean_function_type(),
2180            BooleanFunctionType::Big
2181        );
2182        assert_eq!(
2183            boolean_function2.get_boolean_function_type(),
2184            BooleanFunctionType::Small
2185        );
2186        assert_eq!(
2187            boolean_function3.get_boolean_function_type(),
2188            BooleanFunctionType::Big
2189        );
2190    }
2191
2192    #[test]
2193    fn test_and() {
2194        let mut boolean_function =
2195            BooleanFunction::from_hex_string_truth_table("4f1ead396f247a0410bdb210c006eab568ab4bfa8acb7a13b14ede67096c6eed")
2196                .unwrap();
2197        let boolean_function2 =
2198            BooleanFunction::from_hex_string_truth_table("c870974094ead8a96a450b2ef33486b4e61a4c5e97816f7a7bae007d4c53fc7d")
2199                .unwrap();
2200        let boolean_function3 = boolean_function.clone() & boolean_function2.clone();
2201        boolean_function &= boolean_function2.clone();
2202        assert_eq!(&boolean_function, &boolean_function3);
2203        assert_eq!(
2204            boolean_function.printable_hex_truth_table(),
2205            "481085000420580000050200c00482b4600a485a82816a12310e006508406c6d"
2206        );
2207        assert_eq!(boolean_function.variables_count(), 8);
2208        assert_eq!(
2209            boolean_function.get_boolean_function_type(),
2210            BooleanFunctionType::Big
2211        );
2212        assert_eq!(
2213            boolean_function3.get_boolean_function_type(),
2214            BooleanFunctionType::Big
2215        );
2216
2217        let mut boolean_function =
2218            BooleanFunction::from_hex_string_truth_table("1e").unwrap();
2219        let boolean_function2 = BooleanFunction::from_hex_string_truth_table("ab").unwrap();
2220        let boolean_function3 = boolean_function.clone() & boolean_function2.clone();
2221        boolean_function &= boolean_function2.clone();
2222        assert_eq!(&boolean_function, &boolean_function3);
2223        assert_eq!(boolean_function.printable_hex_truth_table(), "0a");
2224        assert_eq!(boolean_function.variables_count(), 3);
2225        assert_eq!(
2226            boolean_function.get_boolean_function_type(),
2227            BooleanFunctionType::Small
2228        );
2229        assert_eq!(
2230            boolean_function3.get_boolean_function_type(),
2231            BooleanFunctionType::Small
2232        );
2233
2234        let mut boolean_function =
2235            BooleanFunction::from_hex_string_truth_table("1e").unwrap();
2236        let boolean_function2: BooleanFunction = super::BigBooleanFunction::from_truth_table(
2237            BigUint::from_str_radix("ab", 16).unwrap(),
2238            3,
2239        ).into();
2240        let boolean_function3 = boolean_function.clone() & boolean_function2.clone();
2241        boolean_function &= boolean_function2.clone();
2242        assert_eq!(&boolean_function, &boolean_function3);
2243        assert_eq!(boolean_function.printable_hex_truth_table(), "0a");
2244        assert_eq!(boolean_function.variables_count(), 3);
2245        assert_eq!(
2246            boolean_function.get_boolean_function_type(),
2247            BooleanFunctionType::Small
2248        );
2249        assert_eq!(
2250            boolean_function2.get_boolean_function_type(),
2251            BooleanFunctionType::Big
2252        );
2253        assert_eq!(
2254            boolean_function3.get_boolean_function_type(),
2255            BooleanFunctionType::Small
2256        );
2257
2258        let mut boolean_function: BooleanFunction = super::BigBooleanFunction::from_truth_table(
2259            BigUint::from_str_radix("ab", 16).unwrap(),
2260            3,
2261        ).into();
2262        let boolean_function2 = BooleanFunction::from_hex_string_truth_table("1e").unwrap();
2263        let boolean_function3 = boolean_function.clone() & boolean_function2.clone();
2264        boolean_function &= boolean_function2.clone();
2265        assert_eq!(&boolean_function, &boolean_function3);
2266        assert_eq!(boolean_function.printable_hex_truth_table(), "0a");
2267        assert_eq!(boolean_function.variables_count(), 3);
2268        assert_eq!(
2269            boolean_function.get_boolean_function_type(),
2270            BooleanFunctionType::Big
2271        );
2272        assert_eq!(
2273            boolean_function2.get_boolean_function_type(),
2274            BooleanFunctionType::Small
2275        );
2276        assert_eq!(
2277            boolean_function3.get_boolean_function_type(),
2278            BooleanFunctionType::Big
2279        );
2280    }
2281
2282    #[test]
2283    fn test_mul() {
2284        let mut boolean_function =
2285            BooleanFunction::from_hex_string_truth_table("4f1ead396f247a0410bdb210c006eab568ab4bfa8acb7a13b14ede67096c6eed")
2286                .unwrap();
2287        let boolean_function2 =
2288            BooleanFunction::from_hex_string_truth_table("c870974094ead8a96a450b2ef33486b4e61a4c5e97816f7a7bae007d4c53fc7d")
2289                .unwrap();
2290        let boolean_function3 = boolean_function.clone() & boolean_function2.clone();
2291        boolean_function &= boolean_function2.clone();
2292        assert_eq!(&boolean_function, &boolean_function3);
2293        assert_eq!(
2294            boolean_function.printable_hex_truth_table(),
2295            "481085000420580000050200c00482b4600a485a82816a12310e006508406c6d"
2296        );
2297        assert_eq!(boolean_function.variables_count(), 8);
2298        assert_eq!(
2299            boolean_function.get_boolean_function_type(),
2300            BooleanFunctionType::Big
2301        );
2302        assert_eq!(
2303            boolean_function3.get_boolean_function_type(),
2304            BooleanFunctionType::Big
2305        );
2306
2307        let mut boolean_function =
2308            BooleanFunction::from_hex_string_truth_table("1e").unwrap();
2309        let boolean_function2 = BooleanFunction::from_hex_string_truth_table("ab").unwrap();
2310        let boolean_function3 = boolean_function.clone() * boolean_function2.clone();
2311        boolean_function *= boolean_function2.clone();
2312        assert_eq!(&boolean_function, &boolean_function3);
2313        assert_eq!(boolean_function.printable_hex_truth_table(), "0a");
2314        assert_eq!(boolean_function.variables_count(), 3);
2315        assert_eq!(
2316            boolean_function.get_boolean_function_type(),
2317            BooleanFunctionType::Small
2318        );
2319        assert_eq!(
2320            boolean_function3.get_boolean_function_type(),
2321            BooleanFunctionType::Small
2322        );
2323
2324        let mut boolean_function =
2325            BooleanFunction::from_hex_string_truth_table("1e").unwrap();
2326        let boolean_function2: BooleanFunction = super::BigBooleanFunction::from_truth_table(
2327            BigUint::from_str_radix("ab", 16).unwrap(),
2328            3,
2329        ).into();
2330        let boolean_function3 = boolean_function.clone() * boolean_function2.clone();
2331        boolean_function *= boolean_function2.clone();
2332        assert_eq!(&boolean_function, &boolean_function3);
2333        assert_eq!(boolean_function.printable_hex_truth_table(), "0a");
2334        assert_eq!(boolean_function.variables_count(), 3);
2335        assert_eq!(
2336            boolean_function.get_boolean_function_type(),
2337            BooleanFunctionType::Small
2338        );
2339        assert_eq!(
2340            boolean_function2.get_boolean_function_type(),
2341            BooleanFunctionType::Big
2342        );
2343        assert_eq!(
2344            boolean_function3.get_boolean_function_type(),
2345            BooleanFunctionType::Small
2346        );
2347
2348        let mut boolean_function: BooleanFunction = super::BigBooleanFunction::from_truth_table(
2349            BigUint::from_str_radix("ab", 16).unwrap(),
2350            3,
2351        ).into();
2352        let boolean_function2 = BooleanFunction::from_hex_string_truth_table("1e").unwrap();
2353        let boolean_function3 = boolean_function.clone() * boolean_function2.clone();
2354        boolean_function *= boolean_function2.clone();
2355        assert_eq!(&boolean_function, &boolean_function3);
2356        assert_eq!(boolean_function.printable_hex_truth_table(), "0a");
2357        assert_eq!(boolean_function.variables_count(), 3);
2358        assert_eq!(
2359            boolean_function.get_boolean_function_type(),
2360            BooleanFunctionType::Big
2361        );
2362        assert_eq!(
2363            boolean_function2.get_boolean_function_type(),
2364            BooleanFunctionType::Small
2365        );
2366        assert_eq!(
2367            boolean_function3.get_boolean_function_type(),
2368            BooleanFunctionType::Big
2369        );
2370    }
2371
2372    #[test]
2373    fn test_walsh_fourier_values() {
2374        let boolean_function = BooleanFunction::from_hex_string_truth_table("ff").unwrap();
2375        assert_eq!(
2376            boolean_function.walsh_fourier_values(),
2377            [8, 0, 0, 0, 0, 0, 0, 0]
2378        );
2379
2380        let boolean_function = BooleanFunction::from_hex_string_truth_table("00").unwrap();
2381        assert_eq!(
2382            boolean_function.walsh_fourier_values(),
2383            [0, 0, 0, 0, 0, 0, 0, 0]
2384        );
2385
2386        let boolean_function = BooleanFunction::from_hex_string_truth_table("0f").unwrap();
2387        assert_eq!(
2388            boolean_function.walsh_fourier_values(),
2389            [4, 0, 0, 0, 4, 0, 0, 0]
2390        );
2391
2392        let boolean_function = BooleanFunction::from_hex_string_truth_table("55").unwrap();
2393        assert_eq!(
2394            boolean_function.walsh_fourier_values(),
2395            [4, 4, 0, 0, 0, 0, 0, 0]
2396        );
2397
2398        let boolean_function = BooleanFunction::from_hex_string_truth_table("aa").unwrap();
2399        assert_eq!(
2400            boolean_function.walsh_fourier_values(),
2401            [4, -4, 0, 0, 0, 0, 0, 0]
2402        );
2403
2404        let boolean_function = BooleanFunction::from_hex_string_truth_table("8001").unwrap();
2405        assert_eq!(
2406            boolean_function.walsh_fourier_values(),
2407            [2, 0, 0, 2, 0, 2, 2, 0, 0, 2, 2, 0, 2, 0, 0, 2]
2408        );
2409    }
2410
2411    #[test]
2412    fn test_boolean_function_from_reverse_walsh_fourier_transform() {
2413        let boolean_function =
2414            BooleanFunction::from_reverse_walsh_fourier_transform(&[8, 0, 0, 0, 0, 0, 0, 0])
2415                .unwrap();
2416        assert_eq!(boolean_function.printable_hex_truth_table(), "ff");
2417
2418        let boolean_function =
2419            BooleanFunction::from_reverse_walsh_fourier_transform(&[0, 0, 0, 0, 0, 0, 0, 0])
2420                .unwrap();
2421        assert_eq!(boolean_function.printable_hex_truth_table(), "00");
2422
2423        let boolean_function = BooleanFunction::from_reverse_walsh_fourier_transform(&[
2424            2, 0, 0, 2, 0, 2, 2, 0, 0, 2, 2, 0, 2, 0, 0, 2,
2425        ])
2426        .unwrap();
2427        assert_eq!(boolean_function.printable_hex_truth_table(), "8001");
2428        assert_eq!(
2429            boolean_function.get_boolean_function_type(),
2430            BooleanFunctionType::Small
2431        );
2432
2433        let boolean_function = BooleanFunction::from_hex_string_truth_table(
2434            "80921c010276c44224422441188118822442244118811880400810a80e200425",
2435        )
2436        .unwrap();
2437        let walsh_fourier_values = boolean_function.walsh_fourier_values();
2438        let boolean_function2 =
2439            BooleanFunction::from_reverse_walsh_fourier_transform(&walsh_fourier_values)
2440                .unwrap();
2441        assert_eq!(
2442            boolean_function2.printable_hex_truth_table(),
2443            "80921c010276c44224422441188118822442244118811880400810a80e200425"
2444        );
2445
2446        let boolean_function = BooleanFunction::from_hex_string_truth_table("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap();
2447        let walsh_fourier_values = boolean_function.walsh_fourier_values();
2448        let boolean_function2 =
2449            BooleanFunction::from_reverse_walsh_fourier_transform(&walsh_fourier_values)
2450                .unwrap();
2451        assert_eq!(boolean_function2.printable_hex_truth_table(), "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
2452        assert_eq!(
2453            boolean_function2.get_boolean_function_type(),
2454            BooleanFunctionType::Big
2455        );
2456        assert_eq!(boolean_function2.variables_count(), 9);
2457    }
2458
2459    #[test]
2460    fn test_support() {
2461        let boolean_function = BooleanFunction::from_hex_string_truth_table("00").unwrap();
2462        assert_eq!(boolean_function.support().len(), 0);
2463
2464        let boolean_function = BooleanFunction::from_hex_string_truth_table("ff").unwrap();
2465        assert_eq!(boolean_function.support().len(), 8);
2466
2467        let boolean_function = BooleanFunction::from_hex_string_truth_table("1e").unwrap();
2468        assert_eq!(boolean_function.support().len(), 4);
2469    }
2470
2471    #[test]
2472    fn test_propagation_criterion() {
2473        let boolean_function = BooleanFunction::from_hex_string_truth_table("00").unwrap();
2474        assert_eq!(boolean_function.propagation_criterion(), 0);
2475
2476        let boolean_function = BooleanFunction::from_hex_string_truth_table("ff").unwrap();
2477        assert_eq!(boolean_function.propagation_criterion(), 0);
2478
2479        let boolean_function =
2480            BooleanFunction::from_hex_string_truth_table("288d1b41").unwrap();
2481        assert_eq!(boolean_function.propagation_criterion(), 3);
2482    }
2483
2484    #[test]
2485    fn test_iter() {
2486        let boolean_function = BooleanFunction::from_hex_string_truth_table("1e").unwrap();
2487        let mut iter = boolean_function.iter();
2488        assert_eq!(iter.next().unwrap(), false);
2489        assert_eq!(iter.next().unwrap(), true);
2490        assert_eq!(iter.next().unwrap(), true);
2491        assert_eq!(iter.next().unwrap(), true);
2492        assert_eq!(iter.next().unwrap(), true);
2493        assert_eq!(iter.next().unwrap(), false);
2494        assert_eq!(iter.next().unwrap(), false);
2495        assert_eq!(iter.next().unwrap(), false);
2496        assert!(iter.next().is_none());
2497
2498        let iter = boolean_function.iter();
2499        assert_eq!(iter.count(), 8);
2500
2501        let boolean_function =
2502            BooleanFunction::from_hex_string_truth_table("7969817CC5893BA6AC326E47619F5AD0")
2503                .unwrap();
2504        let mut iter = boolean_function.iter();
2505        assert_eq!(iter.next(), Some(false));
2506        assert_eq!(iter.next(), Some(false));
2507        assert_eq!(iter.next(), Some(false));
2508        assert_eq!(iter.next(), Some(false));
2509        assert_eq!(iter.next(), Some(true));
2510
2511        let iter = boolean_function.iter();
2512        assert_eq!(iter.count(), 128);
2513    }
2514
2515    #[test]
2516    fn test_boolean_function_from_u64_truth_table() {
2517        let boolean_function = BooleanFunction::from_u64_truth_table(30, 3).unwrap();
2518        assert_eq!(boolean_function.printable_hex_truth_table(), "1e");
2519        assert_eq!(boolean_function.variables_count(), 3);
2520        assert_eq!(
2521            boolean_function.get_boolean_function_type(),
2522            BooleanFunctionType::Small
2523        );
2524
2525        let boolean_function = BooleanFunction::from_u64_truth_table(30, 7);
2526        assert!(boolean_function.is_err());
2527
2528        let boolean_function = BooleanFunction::from_u64_truth_table(300, 3);
2529        assert!(boolean_function.is_err());
2530    }
2531
2532    #[test]
2533    fn test_boolean_function_from_biguint_truth_table() {
2534        let boolean_function =
2535            BooleanFunction::from_biguint_truth_table(&BigUint::from(30u32), 3).unwrap();
2536        assert_eq!(boolean_function.printable_hex_truth_table(), "1e");
2537        assert_eq!(boolean_function.variables_count(), 3);
2538        assert_eq!(
2539            boolean_function.get_boolean_function_type(),
2540            BooleanFunctionType::Small
2541        );
2542
2543        let boolean_function =
2544            BooleanFunction::from_biguint_truth_table(&BigUint::from(30u32), 7).unwrap();
2545        assert_eq!(
2546            boolean_function.printable_hex_truth_table(),
2547            "0000000000000000000000000000001e"
2548        );
2549        assert_eq!(boolean_function.variables_count(), 7);
2550        assert_eq!(
2551            boolean_function.get_boolean_function_type(),
2552            BooleanFunctionType::Big
2553        );
2554
2555        let boolean_function = BooleanFunction::from_u64_truth_table(300, 3);
2556        assert!(boolean_function.is_err());
2557
2558        let boolean_function = BooleanFunction::from_u64_truth_table(300, 32);
2559        assert!(boolean_function.is_err());
2560    }
2561
2562    #[test]
2563    fn test_get_1_local_neighbor() {
2564        let boolean_function = BooleanFunction::from_hex_string_truth_table("1e").unwrap();
2565        let neighbor = boolean_function.get_1_local_neighbor(1);
2566        assert_eq!(neighbor.printable_hex_truth_table(), "1c");
2567
2568        let boolean_function = BooleanFunction::from_hex_string_truth_table("80921c010276c440400810a80e200425").unwrap();
2569        let neighbor = boolean_function.get_1_local_neighbor(0);
2570        assert_eq!(neighbor.printable_hex_truth_table(), "80921c010276c440400810a80e200424");
2571    }
2572
2573    #[test]
2574    fn test_close_balanced_functions_iterator() {
2575        let balanced_function = BooleanFunction::from_hex_string_truth_table("aaaa").unwrap();
2576        assert!(balanced_function.close_balanced_functions_iterator().is_err());
2577
2578        let bent_function = BooleanFunction::from_hex_string_truth_table("ac90").unwrap();
2579        let close_balanced_iterator = bent_function.close_balanced_functions_iterator();
2580        assert!(close_balanced_iterator.is_ok());
2581        let close_balanced_iterator = close_balanced_iterator.unwrap();
2582        assert_eq!(close_balanced_iterator.into_iter().count(), 45); // 10 choose 2
2583
2584        let mut close_balanced_iterator = bent_function.close_balanced_functions_iterator().unwrap();
2585        assert!(close_balanced_iterator.all(|f| f.is_balanced()));
2586
2587
2588        let balanced_function = BooleanFunction::from_hex_string_truth_table(
2589            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
2590        ).unwrap();
2591        assert!(balanced_function.close_balanced_functions_iterator().is_err());
2592
2593        let bent_function = BooleanFunction::from_hex_string_truth_table(
2594            "80329780469d0b85cd2ad63e1a6ba42adbd83c9a0c55e4e8c99f227b0ffc1418"
2595        ).unwrap();
2596        let close_balanced_iterator = bent_function.close_balanced_functions_iterator();
2597        assert!(close_balanced_iterator.is_ok());
2598        let mut close_balanced_iterator = close_balanced_iterator.unwrap();
2599        for _ in 0..10 {
2600            assert!(close_balanced_iterator.next().unwrap().is_balanced());
2601        }
2602    }
2603
2604    #[test]
2605    fn test_from_anf_polynomial_str() {
2606        let rule_30_anf_str = "x0*x1 + x0 + x1 + x2";
2607        let rule_30_function = BooleanFunction::from_anf_polynomial_str(rule_30_anf_str, 3).unwrap();
2608        assert_eq!(rule_30_function.printable_hex_truth_table(), "1e");
2609
2610        let anf_str = "x0*x1*x2*x3*x4*x5*x6 + x7";
2611        let boolean_function = BooleanFunction::from_anf_polynomial_str(anf_str, 8).unwrap();
2612        assert_eq!(boolean_function.printable_hex_truth_table(), "7fffffffffffffffffffffffffffffff80000000000000000000000000000000");
2613    }
2614
2615    #[test]
2616    fn test_from_anf_polynomial() {
2617        let rule_30_anf = AnfPolynomial::from_str("x0*x1 + x0 + x1 + x2", 3).unwrap();
2618        let rule_30_function = BooleanFunction::from_anf_polynomial(&rule_30_anf);
2619        assert_eq!(rule_30_function.printable_hex_truth_table(), "1e");
2620
2621        let anf = AnfPolynomial::from_str("x0*x1*x2*x3*x4*x5*x6 + x7", 8).unwrap();
2622        let boolean_function = BooleanFunction::from_anf_polynomial(&anf);
2623        assert_eq!(boolean_function.printable_hex_truth_table(), "7fffffffffffffffffffffffffffffff80000000000000000000000000000000");
2624    }
2625}