g2p-1.1.0/.cargo_vcs_info.json0000644000000001410000000000100115170ustar { "git": { "sha1": "c3a3a1578db31be1774f63f9f628e1fa2b8957a7" }, "path_in_vcs": "g2p" }g2p-1.1.0/.gitignore000064400000000000000000000000321046102023000122760ustar 00000000000000/target **/*.rs.bk .idea/ g2p-1.1.0/Cargo.toml0000644000000024420000000000100075230ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "g2p" version = "1.1.0" authors = ["WanzenBug "] description = """ A crate to create types that implement fast finite field arithmetic. """ documentation = "https://docs.rs/g2p" readme = "README.md" keywords = [ "finite-field", "galois", "macro", "newtype", ] categories = [ "no-std", "cryptography", "algorithms", ] license = "MIT/Apache-2.0" repository = "https://github.com/WanzenBug/g2p" [[bench]] name = "g2_8_bench" harness = false [dependencies.g2gen] version = "1.1" [dependencies.g2poly] version = "1.1" [dev-dependencies.criterion] version = "0.4" [dev-dependencies.galois_2p8] version = "0.1.2" [dev-dependencies.rand] version = "0.8" [dev-dependencies.reed-solomon-erasure] version = "6.0" [dev-dependencies.static_assertions] version = "1.1" g2p-1.1.0/Cargo.toml.orig000064400000000000000000000013361046102023000132050ustar 00000000000000[package] name = "g2p" version = "1.1.0" authors = ["WanzenBug "] edition = "2018" readme = "../README.md" license = "MIT/Apache-2.0" repository = "https://github.com/WanzenBug/g2p" documentation = "https://docs.rs/g2p" description = """ A crate to create types that implement fast finite field arithmetic. """ categories = [ "no-std", "cryptography", "algorithms" ] keywords = [ "finite-field", "galois", "macro", "newtype"] [dev-dependencies] static_assertions = "1.1" galois_2p8 = "0.1.2" reed-solomon-erasure = "6.0" criterion = "0.4" rand = "0.8" [dependencies] g2gen = { path = "../g2gen", version = "1.1" } g2poly = { path = "../g2poly", version = "1.1" } [[bench]] name = "g2_8_bench" harness = false g2p-1.1.0/README.md000064400000000000000000000071631046102023000116010ustar 00000000000000# g2p [Documentation](https://docs.rs/g2p) This crate can generate types that implement fast finite field arithmetic. Many error correcting codes rely on some form of finite field of the form GF(2^p), where p is relatively small. Similarly some cryptographic algorithms such as AES use finite field arithmetic. While addition and subtraction can be done quickly using just a simple XOR, multiplication is more involved. To speed things up, you can use a precomputed table. Typically this table is just copied into the source code directly. Using this crate, you can have the benefits in speed of precomputed table, without the need to create your own type with custom multiplication and division implementation. ## WARNING The types generated by this library are probably not suitable for cryptographic purposes, as multiplication is not guaranteed to be constant time. ## Note The implementation was tested for finite fields up to 2^17 in size, which compiles reasonably fast. The space requirements are linear to the field size for the inversion table and log^2(N) for the multiplication table. This means it is not feasible to use this to generate fields of size 2^32, which would 4*4GB memory. ## Examples ```ignore use g2p; g2p::g2p!(GF16, 4, modulus: 0b10011); let one: GF16 = 1.into(); let a: GF16 = 5.into(); let b: GF16 = 4.into(); let c: GF16 = 7.into(); assert_eq!(a + c, 2.into()); assert_eq!(a - c, 2.into()); assert_eq!(a * b, c); assert_eq!(a / c, one / b); assert_eq!(b / b, one); ``` ## Performance There is a benchmark suite comparing the result of this crate to [galois_2p8](https://crates.io/crates/galois_2p8) and [reed-solomon-erasure](https://crates.io/crates/reed-solomon-erasure) which both implement a finite field with 256 elements. ![multiplication](doc/mul.svg) ![division](doc/div.svg) Note that the competing libraries implement some special functionality to improve performance when one of the operands is fixed. Here are the results: ![const operand multiplication](doc/mul_const.svg) ![const operand division](doc/div_const.svg) ## Implementation details `g2p` generates a new type that implements all the common arithmetic operations. The calculations are performed on either u8, u16 or u32, depending on the field size. Addition and subtraction are implemented using regular `Xor`. For division, the divisor inverted using a precomputed inversion table, which is then multiplied using the multiplication outlined below ### Multiplication Multiplication uses a number of precomputed tables to determine the result. Because a full table would grow with the square of the field size, this approach was not deemed feasible. For example, using a full table for GF65536 = GF(2^16), one would need 2^32 entries, which would mean the program reserves 2*4GB just for these tables alone. Instead a number `n` is split into 8bit components `n = a + 256 * b + 65536 * c ...`. Using this representation we can multiply two numbers by cross-multiplying all the components and then adding them up again. So assuming 16bit numbers `n = n0 + 256 * n1` and `m = m0 + 256 * m1` we get `n*m = n0*m0 + 256*n0*m1 + 256*n1*m0 + 65536*n1*m1`. We can now create precomputed tables for multiplying the different components together. There is a table for first component times first component, first times second etc. The results then just have to be added together using the normal finite field addition. For our GF65536 example this means the multiplication tables use 4 * 256 * 256 entries á 2 byte which is ~0.5MB ## License Licensed under the Apache License, Version 2.0 [LICENSE-APACHE](LICENSE-APACHE) or the MIT license [LICENSE-MIT](LICENSE-MIT)>, at your option. g2p-1.1.0/benches/g2_8_bench.rs000064400000000000000000000346331046102023000141770ustar 00000000000000use criterion::{BatchSize, BenchmarkId, Criterion, criterion_group, criterion_main}; use galois_2p8; use galois_2p8::Field; use rand; use rand::{Rng, RngCore}; use reed_solomon_erasure; use g2p; g2p::g2p!(GF256, 8); fn g2p_addition(a: &[u8], b: &[u8], dest: &mut [u8]) { assert_eq!(a.len(), b.len()); assert_eq!(b.len(), dest.len()); for ((&l, &r), d) in Iterator::zip(Iterator::zip(a.into_iter(), b), dest) { *d = (GF256::from(l) + GF256::from(r)).into() } } fn galois_2p8_addition(field: &galois_2p8::PrimitivePolynomialField, a: &[u8], b: &[u8], dest: &mut [u8]) { assert_eq!(a.len(), b.len()); assert_eq!(b.len(), dest.len()); field.add_multiword(dest, a); field.add_multiword(dest, b); } fn reed_solomon_erasure_addition(a: &[u8], b: &[u8], dest: &mut [u8]) { assert_eq!(a.len(), b.len()); assert_eq!(b.len(), dest.len()); for ((&l, &r), d) in Iterator::zip(Iterator::zip(a.into_iter(), b), dest) { *d = reed_solomon_erasure::galois_8::add(l, r); } } fn g2p_multiplication(a: &[u8], b: &[u8], dest: &mut [u8]) { assert_eq!(a.len(), b.len()); assert_eq!(b.len(), dest.len()); for ((&l, &r), d) in Iterator::zip(Iterator::zip(a.into_iter(), b), dest) { *d = (GF256::from(l) * GF256::from(r)).into() } } fn galois_2p8_multiplication(field: &galois_2p8::PrimitivePolynomialField, a: &[u8], b: &[u8], dest: &mut [u8]) { assert_eq!(a.len(), b.len()); assert_eq!(b.len(), dest.len()); for ((&l, &r), d) in Iterator::zip(Iterator::zip(a.into_iter(), b), dest) { *d = field.mult(l, r) } } fn reed_solomon_erasure_multiplication(a: &[u8], b: &[u8], dest: &mut [u8]) { assert_eq!(a.len(), b.len()); assert_eq!(b.len(), dest.len()); for ((&l, &r), d) in Iterator::zip(Iterator::zip(a.into_iter(), b), dest) { *d = reed_solomon_erasure::galois_8::mul(l, r); } } fn g2p_multiplication_const(a: &[u8], b: u8, dest: &mut [u8]) { assert_eq!(a.len(), dest.len()); for (&l, d) in Iterator::zip(a.into_iter(), dest) { *d = (GF256::from(l) * GF256::from(b)).into() } } fn galois_2p8_multiplication_const(field: &galois_2p8::PrimitivePolynomialField, a: &[u8], b: u8, dest: &mut [u8]) { assert_eq!(a.len(), dest.len()); dest.copy_from_slice(a); field.mult_multiword(dest, b); } fn reed_solomon_erasure_multiplication_const(a: &[u8], b: u8, dest: &mut [u8]) { assert_eq!(a.len(), dest.len()); reed_solomon_erasure::galois_8::mul_slice(b, a, dest); } fn g2p_division(a: &[u8], b: &[u8], dest: &mut [u8]) { assert_eq!(a.len(), b.len()); assert_eq!(b.len(), dest.len()); for ((&l, &r), d) in Iterator::zip(Iterator::zip(a.into_iter(), b), dest) { *d = (GF256::from(l) / GF256::from(r)).into() } } fn galois_2p8_division(field: &galois_2p8::PrimitivePolynomialField, a: &[u8], b: &[u8], dest: &mut [u8]) { assert_eq!(a.len(), b.len()); assert_eq!(b.len(), dest.len()); for ((&l, &r), d) in Iterator::zip(Iterator::zip(a.into_iter(), b), dest) { *d = field.div(l, r) } } fn reed_solomon_erasure_division(a: &[u8], b: &[u8], dest: &mut [u8]) { assert_eq!(a.len(), b.len()); assert_eq!(b.len(), dest.len()); for ((&l, &r), d) in Iterator::zip(Iterator::zip(a.into_iter(), b), dest) { *d = reed_solomon_erasure::galois_8::div(l, r); } } fn g2p_division_const(a: &[u8], b: u8, dest: &mut [u8]) { assert_eq!(a.len(), dest.len()); for (&l, d) in Iterator::zip(a.into_iter(), dest) { *d = (GF256::from(l) / GF256::from(b)).into() } } fn galois_2p8_division_const(field: &galois_2p8::PrimitivePolynomialField, a: &[u8], b: u8, dest: &mut [u8]) { assert_eq!(a.len(), dest.len()); dest.copy_from_slice(a); field.div_multiword(dest, b); } fn reed_solomon_erasure_division_const(a: &[u8], b: u8, dest: &mut [u8]) { assert_eq!(a.len(), dest.len()); for (&l, d) in Iterator::zip(a.into_iter(), dest) { *d = reed_solomon_erasure::galois_8::div(l, b); } } fn g2p_inverse(a: &[u8], dest: &mut [u8]) { assert_eq!(a.len(), dest.len()); for (&inv, d) in Iterator::zip(a.into_iter(), dest) { *d = (GF256::from(1) / GF256::from(inv)).into() } } fn galois_2p8_inverse(field: &galois_2p8::PrimitivePolynomialField, a: &[u8], dest: &mut [u8]) { assert_eq!(a.len(), dest.len()); for (&inv, d) in Iterator::zip(a.into_iter(), dest) { *d = field.div(1, inv); } } fn reed_solomon_erasure_inverse(a: &[u8], dest: &mut [u8]) { assert_eq!(a.len(), dest.len()); for (&inv, d) in Iterator::zip(a.into_iter(), dest) { *d = reed_solomon_erasure::galois_8::div(1, inv); } } fn all_benches(c: &mut Criterion) { let mut rng = rand::thread_rng(); let galois_2p8_field = galois_2p8::PrimitivePolynomialField::new_might_panic(galois_2p8::IrreducablePolynomial::Poly84320); let input_sizes = [64, 1_024, 16_384]; let mut group = c.benchmark_group("addition"); for &i in input_sizes.iter() { let mut a = vec![0; i]; let mut b = vec![0; i]; let dest = vec![0; i]; rng.fill_bytes(&mut a[..]); rng.fill_bytes(&mut b[..]); group.bench_function( BenchmarkId::new("g2p", i), |bencher| { bencher.iter_batched( || (a.clone(), b.clone(), dest.clone()), |(a, b, mut dest)| { g2p_addition(&a, &b, &mut dest); dest }, BatchSize::SmallInput, ) }); group.bench_function( BenchmarkId::new("galois_2p8", i), |bencher| { bencher.iter_batched( || (a.clone(), b.clone(), dest.clone()), |(a, b, mut dest)| { galois_2p8_addition(&galois_2p8_field, &a, &b, &mut dest); dest }, BatchSize::SmallInput, ) }); group.bench_function( BenchmarkId::new("reed_solomon_erasure", i), |bencher| { bencher.iter_batched( || (a.clone(), b.clone(), dest.clone()), |(a, b, mut dest)| { reed_solomon_erasure_addition(&a, &b, &mut dest); dest }, BatchSize::SmallInput, ) }); } group.finish(); let mut group = c.benchmark_group("multiplication"); for &i in input_sizes.iter() { let mut a = vec![0; i]; let mut b = vec![0; i]; let dest = vec![0; i]; rng.fill_bytes(&mut a[..]); rng.fill_bytes(&mut b[..]); group.bench_function( BenchmarkId::new("g2p", i), |bencher| { bencher.iter_batched( || (a.clone(), b.clone(), dest.clone()), |(a, b, mut dest)| { g2p_multiplication(&a, &b, &mut dest); dest }, BatchSize::SmallInput, ) }); group.bench_function( BenchmarkId::new("galois_2p8", i), |bencher| { bencher.iter_batched( || (a.clone(), b.clone(), dest.clone()), |(a, b, mut dest)| { galois_2p8_multiplication(&galois_2p8_field, &a, &b, &mut dest); dest }, BatchSize::SmallInput, ) }); group.bench_function( BenchmarkId::new("reed_solomon_erasure", i), |bencher| { bencher.iter_batched( || (a.clone(), b.clone(), dest.clone()), |(a, b, mut dest)| { reed_solomon_erasure_multiplication(&a, &b, &mut dest); dest }, BatchSize::SmallInput, ) }); } group.finish(); let mut group = c.benchmark_group("multiplication_const"); for &i in input_sizes.iter() { let mut a = vec![0; i]; let b = rng.gen(); let dest = vec![0; i]; rng.fill_bytes(&mut a[..]); group.bench_function( BenchmarkId::new("g2p", i), |bencher| { bencher.iter_batched( || (a.clone(), dest.clone()), |(a, mut dest)| { g2p_multiplication_const(&a, b, &mut dest); dest }, BatchSize::SmallInput, ) }); group.bench_function( BenchmarkId::new("galois_2p8", i), |bencher| { bencher.iter_batched( || (a.clone(), dest.clone()), |(a, mut dest)| { galois_2p8_multiplication_const(&galois_2p8_field, &a, b, &mut dest); dest }, BatchSize::SmallInput, ) }); group.bench_function( BenchmarkId::new("reed_solomon_erasure", i), |bencher| { bencher.iter_batched( || (a.clone(), dest.clone()), |(a, mut dest)| { reed_solomon_erasure_multiplication_const(&a, b, &mut dest); dest }, BatchSize::SmallInput, ) }); } group.finish(); let mut group = c.benchmark_group("inverse"); for &i in input_sizes.iter() { let mut a = vec![0; i]; let dest = vec![0; i]; rng.fill_bytes(&mut a[..]); for divisor in &mut a { while *divisor == 0 { *divisor = rng.gen(); } } group.bench_function( BenchmarkId::new("g2p", i), |bencher| { bencher.iter_batched( || (a.clone(), dest.clone()), |(a, mut dest)| { g2p_inverse(&a, &mut dest); dest }, BatchSize::SmallInput, ) }); group.bench_function( BenchmarkId::new("galois_2p8", i), |bencher| { bencher.iter_batched( || (a.clone(), dest.clone()), |(a, mut dest)| { galois_2p8_inverse(&galois_2p8_field, &a, &mut dest); dest }, BatchSize::SmallInput, ) }); group.bench_function( BenchmarkId::new("reed_solomon_erasure", i), |bencher| { bencher.iter_batched( || (a.clone(), dest.clone()), |(a, mut dest)| { reed_solomon_erasure_inverse(&a, &mut dest); dest }, BatchSize::SmallInput, ) }); } group.finish(); let mut group = c.benchmark_group("division"); for &i in input_sizes.iter() { let mut a = vec![0; i]; let mut b = vec![0; i]; let dest = vec![0; i]; rng.fill_bytes(&mut a[..]); rng.fill_bytes(&mut b[..]); for divisor in &mut b { while *divisor == 0 { *divisor = rng.gen(); } } group.bench_function( BenchmarkId::new("g2p", i), |bencher| { bencher.iter_batched( || (a.clone(), b.clone(), dest.clone()), |(a, b, mut dest)| { g2p_division(&a, &b, &mut dest); dest }, BatchSize::SmallInput, ) }); group.bench_function( BenchmarkId::new("galois_2p8", i), |bencher| { bencher.iter_batched( || (a.clone(), b.clone(), dest.clone()), |(a, b, mut dest)| { galois_2p8_division(&galois_2p8_field, &a, &b, &mut dest); dest }, BatchSize::SmallInput, ) }); group.bench_function( BenchmarkId::new("reed_solomon_erasure", i), |bencher| { bencher.iter_batched( || (a.clone(), b.clone(), dest.clone()), |(a, b, mut dest)| { reed_solomon_erasure_division(&a, &b, &mut dest); dest }, BatchSize::SmallInput, ) }); } group.finish(); let mut group = c.benchmark_group("division_const"); for &i in input_sizes.iter() { let mut a = vec![0; i]; let b = rng.gen_range(1..=255); let dest = vec![0; i]; rng.fill_bytes(&mut a[..]); group.bench_function( BenchmarkId::new("g2p", i), |bencher| { bencher.iter_batched( || (a.clone(), dest.clone()), |(a, mut dest)| { g2p_division_const(&a, b, &mut dest); dest }, BatchSize::SmallInput, ) }); group.bench_function( BenchmarkId::new("galois_2p8", i), |bencher| { bencher.iter_batched( || (a.clone(), dest.clone()), |(a, mut dest)| { galois_2p8_division_const(&galois_2p8_field, &a, b, &mut dest); dest }, BatchSize::SmallInput, ) }); group.bench_function( BenchmarkId::new("reed_solomon_erasure", i), |bencher| { bencher.iter_batched( || (a.clone(), dest.clone()), |(a, mut dest)| { reed_solomon_erasure_division_const(&a, b, &mut dest); dest }, BatchSize::SmallInput, ) }); } group.finish(); } criterion_group!(benches, all_benches); criterion_main!(benches); g2p-1.1.0/src/lib.rs000064400000000000000000000133221046102023000122170ustar 00000000000000// Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! This crate can generate types that implement fast finite field arithmetic. //! //! Many error correcting codes rely on some form of finite field of the form GF(2^p), where //! p is relatively small. Similarly some cryptographic algorithms such as AES use finite field //! arithmetic. //! //! While addition and subtraction can be done quickly using just a simple XOR, multiplication is //! more involved. To speed things up, you can use a precomputed table. Typically this table is just //! copied into the source code directly. //! //! Using this crate, you can have the benefits in speed of precomputed table, without the need //! to create your own type with custom multiplication and division implementation. //! //! # WARNING //! The types generated by this library are probably not suitable for cryptographic purposes, as //! multiplication is not guaranteed to be constant time. //! //! # Note //! The implementation was tested for finite fields up to 2^17 in size, which compiles reasonably //! fast. The space requirements are linear to the field size for the inversion table and log^2(N) //! for the multiplication table. This means it is not feasible to use this to generate fields of //! size 2^32, which would 4*4GB memory. //! //! # Examples //! //! ```rust //! g2p::g2p!(GF16, 4, modulus: 0b10011); //! # fn main() { //! let one: GF16 = 1.into(); //! let a: GF16 = 5.into(); //! let b: GF16 = 4.into(); //! let c: GF16 = 7.into(); //! assert_eq!(a + c, 2.into()); //! assert_eq!(a - c, 2.into()); //! assert_eq!(a * b, c); //! assert_eq!(a / c, one / b); //! assert_eq!(b / b, one); //! # } //! ``` //! //! # Implementation details //! `g2p` generates a new type that implements all the common arithmetic operations. The //! calculations are performed on either u8, u16 or u32, depending on the field size. //! //! Addition and subtraction are implemented using regular `Xor`. For division, the divisor inverted //! using a precomputed inversion table, which is then multiplied using the multiplication outlined //! below //! //! ## Multiplication //! Multiplication uses a number of precomputed tables to determine the result. Because a full table //! would grow with the square of the field size, this approach was not deemed feasible. For //! example, using a full table for GF65536 = GF(2^16), one would need 2^32 entries, which would //! mean the program reserves 2*4GB just for these tables alone. //! //! Instead a number `n` is split into 8bit components `n = a + 256 * b + 65536 * c ...`. Using this //! representation we can multiply two numbers by cross-multiplying all the components //! and then adding them up again. So assuming 16bit numbers `n = n0 + 256 * n1` and //! `m = m0 + 256 * m1` we get `n*m = n0*m0 + 256*n0*m1 + 256*n1*m0 + 65536*n1*m1`. //! //! We can now create precomputed tables for multiplying the different components together. There is //! a table for first component times first component, first times second etc. The results then just //! have to be added together using the normal finite field addition. For our GF65536 example this //! means the multiplication tables use 4 * 256 * 256 entries á 2 byte which is ~0.5MB use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; /// Procedural macro to generate binary galois fields pub use g2gen::g2p; /// Polynomial representation of values pub use g2poly::G2Poly; /// Common trait for finite fields /// /// All types generated by `g2p!` implement this trait. /// The trait ensures that all the expected operations of a finite field are implemented. /// /// In addition, some often used constants like `ONE` and `ZERO` are exported, as well as the more /// esoteric `GENERATOR`. pub trait GaloisField: Add + AddAssign + Sub + SubAssign + Mul + MulAssign + Div + DivAssign + Copy + PartialEq + Eq { /// Number of elements in the field const SIZE: usize; /// The value 0 as a finite field constant const ZERO: Self; /// The value 1 as a finite field constant const ONE: Self; /// A generator of the multiplicative group of a finite field /// /// The powers of this element will generate all non-zero elements of the finite field /// /// ```rust /// use g2p::{GaloisField, g2p}; /// /// g2p!(GF4, 2); /// # fn main() { /// let g = GF4::GENERATOR; /// assert_ne!(g, GF4::ONE); /// assert_ne!(g * g, GF4::ONE); /// assert_eq!(g * g * g, GF4::ONE); /// # } /// ``` const GENERATOR: Self; /// Polynomial representation of the modulus used to generate the field const MODULUS: G2Poly; /// Calculate the p-th power of a value /// /// Calculate the value of x to the power p in finite field arithmethic /// /// # Example /// ```rust /// use g2p::{GaloisField, g2p}; /// /// g2p!(GF16, 4); /// # fn main() { /// let g: GF16 = 2.into(); /// assert_eq!(g.pow(0), GF16::ONE); /// assert_eq!(g.pow(1), g); /// assert_eq!(g.pow(2), 4.into()); /// assert_eq!(g.pow(3), 8.into()); /// assert_eq!(g.pow(4), 3.into()); /// # } /// ``` fn pow(self, p: usize) -> Self { let mut val = Self::ONE; let mut pow_pos = 1 << (::std::mem::size_of::() * 8 - 1); assert_eq!(pow_pos << 1, 0); while pow_pos > 0 { val *= val; if (pow_pos & p) > 0 { val *= self; } pow_pos >>= 1; } val } } g2p-1.1.0/tests/impls.rs000064400000000000000000000016601046102023000131520ustar 00000000000000use g2p::{g2p, GaloisField}; use core::ops::{ Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign, }; use core::fmt::{ Debug, Display, }; use core::marker::{ Sync, Send, Sized, Copy, }; use core::clone::Clone; use core::convert::{ From, Into, }; g2p!(GF4, 2); #[test] fn test_impls() { static_assertions::assert_impl_all!(GF4: Clone, Copy, Send, Sync, Sized, Debug, Display, Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign, Eq, PartialEq, Into, From, ); } #[test] fn test_div_impl() { let z = GF4::ZERO; let a = GF4::from(3); assert_eq!(z, z / a); } #[test] #[should_panic] fn test_div_panic() { let z = GF4::ZERO; let a = GF4::from(3); let _ = a / z; } g2p-1.1.0/tests/rijndael.rs000064400000000000000000000014431046102023000136150ustar 00000000000000// Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use g2p::g2p; g2p!( GF256, 8, modulus: 0b_1_0001_1011, ); #[test] fn test_rijndael() { let a = GF256::from(0); let b = GF256::from(1); let c = GF256::from(0x53); let d = GF256::from(0xca); assert_eq!(GF256::MASK, 0b1111_1111); assert_eq!(b + a, b); assert_eq!(a + b, b); assert_eq!(a * b, a); assert_eq!(b * a, a); assert_eq!(c * d, b); assert_eq!(d * c, b); assert_eq!(b / c, d); assert_eq!(b / d, c); assert_eq!(c / b, c); } g2p-1.1.0/tests/test_doc_examples.rs000064400000000000000000000030601046102023000155240ustar 00000000000000// Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use g2p::{GaloisField, g2p}; g2p!(GF4, 2); g2p!(GF16, 4, modulus: 0b10011); g2p!(GF1024, 10, modulus: 0b100_0000_1001); #[test] fn test_g16() { let one: GF16 = 1.into(); let a: GF16 = 5.into(); let b: GF16 = 4.into(); let c: GF16 = 7.into(); assert_eq!(a + c, 2.into()); assert_eq!(a - c, 2.into()); assert_eq!(a * b, c); assert_eq!(a / c, one / b); assert_eq!(b / b, one); } #[test] fn test_gf1024() { eprintln!("1"); let a: GF1024 = 555.into(); eprintln!("2"); let b: GF1024 = 444.into(); eprintln!("3"); let c = a + b; eprintln!("4"); let d = a * b; assert_eq!(765, u16::from(d)); eprintln!("5"); assert_eq!(c + a, b); eprintln!("6"); assert_eq!(c + b, a); eprintln!("7"); assert_eq!(d / b, a); eprintln!("8"); assert_eq!(d / a, b); eprintln!("9"); assert_eq!(u16::from(d / b), 555_u16); eprintln!("10"); } #[test] fn test_g4() { let g = GF4::GENERATOR; assert_ne!(g * g, GF4::ONE); assert_eq!(g * g * g, GF4::ONE); } #[test] fn test_pow() { let g: GF16 = 2.into(); assert_eq!(g.pow(0), GF16::ONE); assert_eq!(g.pow(1), g); assert_eq!(g.pow(2), 4.into()); assert_eq!(g.pow(3), 8.into()); assert_eq!(g.pow(4), 3.into()); } g2p-1.1.0/tests/test_gf131072.rs000064400000000000000000000011551046102023000141360ustar 00000000000000// Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use g2p::g2p; g2p!(GF131072, 17); #[test] fn test_gf131072() { let z: GF131072 = 0.into(); let e: GF131072 = 1.into(); let a: GF131072 = 131071.into(); let b: GF131072 = 30000.into(); assert_eq!(z, a + a); assert_eq!(z, a - a); assert_eq!(e, a * (e / a)); assert_eq!(a * b, b * a); } g2p-1.1.0/tests/test_gf65536.rs000064400000000000000000000011461046102023000140710ustar 00000000000000// Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use g2p::g2p; g2p!(GF65536, 16); #[test] fn test_gf65536() { let z: GF65536 = 0.into(); let e: GF65536 = 1.into(); let a: GF65536 = 65535.into(); let b: GF65536 = 30000.into(); assert_eq!(z, a + a); assert_eq!(z, a - a); assert_eq!(e, a * (e / a)); assert_eq!(a * b, b * a); } g2p-1.1.0/tests/test_precomputed_tables.rs000064400000000000000000000240701046102023000167460ustar 00000000000000// Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use g2p::{g2p, GaloisField}; g2p!(GF16, 4, modulus: 0b1_0011); g2p!(GF256, 8, modulus: 0b1_0001_1101); #[test] fn test_gf16() { // Test against QR code defined tables for (i, check) in GF16_EXP.iter().enumerate() { let a = GF16::GENERATOR.pow(i); assert_eq!(a.0, *check); assert_eq!(GF16_LOG[a.0 as usize] % 15, i as u8 % 15); } } #[test] fn test_gf256() { // Test against QR code defined tables for (i, check) in GF256_EXP.iter().enumerate() { let a = GF256::GENERATOR.pow(i); assert_eq!(a.0, *check); assert_eq!(GF256_LOG[a.0 as usize] % 255, i as u8 % 255); } } const GF16_EXP: [u8; 16] = [ 0x1_u8, 0x2_u8, 0x4_u8, 0x8_u8, 0x3_u8, 0x6_u8, 0xc_u8, 0xb_u8, 0x5_u8, 0xa_u8, 0x7_u8, 0xe_u8, 0xf_u8, 0xd_u8, 0x9_u8, 0x1_u8, ]; const GF16_LOG: [u8; 16] = [ 0_u8, 0xf_u8, 0x1_u8, 0x4_u8, 0x2_u8, 0x8_u8, 0x5_u8, 0xa_u8, 0x3_u8, 0xe_u8, 0x9_u8, 0x7_u8, 0x6_u8, 0xd_u8, 0xb_u8, 0xc_u8, ]; const GF256_LOG: [u8; 256] = { [ 0_u8, 0xff_u8, 0x1_u8, 0x19_u8, 0x2_u8, 0x32_u8, 0x1a_u8, 0xc6_u8, 0x3_u8, 0xdf_u8, 0x33_u8, 0xee_u8, 0x1b_u8, 0x68_u8, 0xc7_u8, 0x4b_u8, 0x4_u8, 0x64_u8, 0xe0_u8, 0xe_u8, 0x34_u8, 0x8d_u8, 0xef_u8, 0x81_u8, 0x1c_u8, 0xc1_u8, 0x69_u8, 0xf8_u8, 0xc8_u8, 0x8_u8, 0x4c_u8, 0x71_u8, 0x5_u8, 0x8a_u8, 0x65_u8, 0x2f_u8, 0xe1_u8, 0x24_u8, 0xf_u8, 0x21_u8, 0x35_u8, 0x93_u8, 0x8e_u8, 0xda_u8, 0xf0_u8, 0x12_u8, 0x82_u8, 0x45_u8, 0x1d_u8, 0xb5_u8, 0xc2_u8, 0x7d_u8, 0x6a_u8, 0x27_u8, 0xf9_u8, 0xb9_u8, 0xc9_u8, 0x9a_u8, 0x9_u8, 0x78_u8, 0x4d_u8, 0xe4_u8, 0x72_u8, 0xa6_u8, 0x6_u8, 0xbf_u8, 0x8b_u8, 0x62_u8, 0x66_u8, 0xdd_u8, 0x30_u8, 0xfd_u8, 0xe2_u8, 0x98_u8, 0x25_u8, 0xb3_u8, 0x10_u8, 0x91_u8, 0x22_u8, 0x88_u8, 0x36_u8, 0xd0_u8, 0x94_u8, 0xce_u8, 0x8f_u8, 0x96_u8, 0xdb_u8, 0xbd_u8, 0xf1_u8, 0xd2_u8, 0x13_u8, 0x5c_u8, 0x83_u8, 0x38_u8, 0x46_u8, 0x40_u8, 0x1e_u8, 0x42_u8, 0xb6_u8, 0xa3_u8, 0xc3_u8, 0x48_u8, 0x7e_u8, 0x6e_u8, 0x6b_u8, 0x3a_u8, 0x28_u8, 0x54_u8, 0xfa_u8, 0x85_u8, 0xba_u8, 0x3d_u8, 0xca_u8, 0x5e_u8, 0x9b_u8, 0x9f_u8, 0xa_u8, 0x15_u8, 0x79_u8, 0x2b_u8, 0x4e_u8, 0xd4_u8, 0xe5_u8, 0xac_u8, 0x73_u8, 0xf3_u8, 0xa7_u8, 0x57_u8, 0x7_u8, 0x70_u8, 0xc0_u8, 0xf7_u8, 0x8c_u8, 0x80_u8, 0x63_u8, 0xd_u8, 0x67_u8, 0x4a_u8, 0xde_u8, 0xed_u8, 0x31_u8, 0xc5_u8, 0xfe_u8, 0x18_u8, 0xe3_u8, 0xa5_u8, 0x99_u8, 0x77_u8, 0x26_u8, 0xb8_u8, 0xb4_u8, 0x7c_u8, 0x11_u8, 0x44_u8, 0x92_u8, 0xd9_u8, 0x23_u8, 0x20_u8, 0x89_u8, 0x2e_u8, 0x37_u8, 0x3f_u8, 0xd1_u8, 0x5b_u8, 0x95_u8, 0xbc_u8, 0xcf_u8, 0xcd_u8, 0x90_u8, 0x87_u8, 0x97_u8, 0xb2_u8, 0xdc_u8, 0xfc_u8, 0xbe_u8, 0x61_u8, 0xf2_u8, 0x56_u8, 0xd3_u8, 0xab_u8, 0x14_u8, 0x2a_u8, 0x5d_u8, 0x9e_u8, 0x84_u8, 0x3c_u8, 0x39_u8, 0x53_u8, 0x47_u8, 0x6d_u8, 0x41_u8, 0xa2_u8, 0x1f_u8, 0x2d_u8, 0x43_u8, 0xd8_u8, 0xb7_u8, 0x7b_u8, 0xa4_u8, 0x76_u8, 0xc4_u8, 0x17_u8, 0x49_u8, 0xec_u8, 0x7f_u8, 0xc_u8, 0x6f_u8, 0xf6_u8, 0x6c_u8, 0xa1_u8, 0x3b_u8, 0x52_u8, 0x29_u8, 0x9d_u8, 0x55_u8, 0xaa_u8, 0xfb_u8, 0x60_u8, 0x86_u8, 0xb1_u8, 0xbb_u8, 0xcc_u8, 0x3e_u8, 0x5a_u8, 0xcb_u8, 0x59_u8, 0x5f_u8, 0xb0_u8, 0x9c_u8, 0xa9_u8, 0xa0_u8, 0x51_u8, 0xb_u8, 0xf5_u8, 0x16_u8, 0xeb_u8, 0x7a_u8, 0x75_u8, 0x2c_u8, 0xd7_u8, 0x4f_u8, 0xae_u8, 0xd5_u8, 0xe9_u8, 0xe6_u8, 0xe7_u8, 0xad_u8, 0xe8_u8, 0x74_u8, 0xd6_u8, 0xf4_u8, 0xea_u8, 0xa8_u8, 0x50_u8, 0x58_u8, 0xaf_u8, ] }; const GF256_EXP: [u8; 256] = { [ 0x1_u8, 0x2_u8, 0x4_u8, 0x8_u8, 0x10_u8, 0x20_u8, 0x40_u8, 0x80_u8, 0x1d_u8, 0x3a_u8, 0x74_u8, 0xe8_u8, 0xcd_u8, 0x87_u8, 0x13_u8, 0x26_u8, 0x4c_u8, 0x98_u8, 0x2d_u8, 0x5a_u8, 0xb4_u8, 0x75_u8, 0xea_u8, 0xc9_u8, 0x8f_u8, 0x3_u8, 0x6_u8, 0xc_u8, 0x18_u8, 0x30_u8, 0x60_u8, 0xc0_u8, 0x9d_u8, 0x27_u8, 0x4e_u8, 0x9c_u8, 0x25_u8, 0x4a_u8, 0x94_u8, 0x35_u8, 0x6a_u8, 0xd4_u8, 0xb5_u8, 0x77_u8, 0xee_u8, 0xc1_u8, 0x9f_u8, 0x23_u8, 0x46_u8, 0x8c_u8, 0x5_u8, 0xa_u8, 0x14_u8, 0x28_u8, 0x50_u8, 0xa0_u8, 0x5d_u8, 0xba_u8, 0x69_u8, 0xd2_u8, 0xb9_u8, 0x6f_u8, 0xde_u8, 0xa1_u8, 0x5f_u8, 0xbe_u8, 0x61_u8, 0xc2_u8, 0x99_u8, 0x2f_u8, 0x5e_u8, 0xbc_u8, 0x65_u8, 0xca_u8, 0x89_u8, 0xf_u8, 0x1e_u8, 0x3c_u8, 0x78_u8, 0xf0_u8, 0xfd_u8, 0xe7_u8, 0xd3_u8, 0xbb_u8, 0x6b_u8, 0xd6_u8, 0xb1_u8, 0x7f_u8, 0xfe_u8, 0xe1_u8, 0xdf_u8, 0xa3_u8, 0x5b_u8, 0xb6_u8, 0x71_u8, 0xe2_u8, 0xd9_u8, 0xaf_u8, 0x43_u8, 0x86_u8, 0x11_u8, 0x22_u8, 0x44_u8, 0x88_u8, 0xd_u8, 0x1a_u8, 0x34_u8, 0x68_u8, 0xd0_u8, 0xbd_u8, 0x67_u8, 0xce_u8, 0x81_u8, 0x1f_u8, 0x3e_u8, 0x7c_u8, 0xf8_u8, 0xed_u8, 0xc7_u8, 0x93_u8, 0x3b_u8, 0x76_u8, 0xec_u8, 0xc5_u8, 0x97_u8, 0x33_u8, 0x66_u8, 0xcc_u8, 0x85_u8, 0x17_u8, 0x2e_u8, 0x5c_u8, 0xb8_u8, 0x6d_u8, 0xda_u8, 0xa9_u8, 0x4f_u8, 0x9e_u8, 0x21_u8, 0x42_u8, 0x84_u8, 0x15_u8, 0x2a_u8, 0x54_u8, 0xa8_u8, 0x4d_u8, 0x9a_u8, 0x29_u8, 0x52_u8, 0xa4_u8, 0x55_u8, 0xaa_u8, 0x49_u8, 0x92_u8, 0x39_u8, 0x72_u8, 0xe4_u8, 0xd5_u8, 0xb7_u8, 0x73_u8, 0xe6_u8, 0xd1_u8, 0xbf_u8, 0x63_u8, 0xc6_u8, 0x91_u8, 0x3f_u8, 0x7e_u8, 0xfc_u8, 0xe5_u8, 0xd7_u8, 0xb3_u8, 0x7b_u8, 0xf6_u8, 0xf1_u8, 0xff_u8, 0xe3_u8, 0xdb_u8, 0xab_u8, 0x4b_u8, 0x96_u8, 0x31_u8, 0x62_u8, 0xc4_u8, 0x95_u8, 0x37_u8, 0x6e_u8, 0xdc_u8, 0xa5_u8, 0x57_u8, 0xae_u8, 0x41_u8, 0x82_u8, 0x19_u8, 0x32_u8, 0x64_u8, 0xc8_u8, 0x8d_u8, 0x7_u8, 0xe_u8, 0x1c_u8, 0x38_u8, 0x70_u8, 0xe0_u8, 0xdd_u8, 0xa7_u8, 0x53_u8, 0xa6_u8, 0x51_u8, 0xa2_u8, 0x59_u8, 0xb2_u8, 0x79_u8, 0xf2_u8, 0xf9_u8, 0xef_u8, 0xc3_u8, 0x9b_u8, 0x2b_u8, 0x56_u8, 0xac_u8, 0x45_u8, 0x8a_u8, 0x9_u8, 0x12_u8, 0x24_u8, 0x48_u8, 0x90_u8, 0x3d_u8, 0x7a_u8, 0xf4_u8, 0xf5_u8, 0xf7_u8, 0xf3_u8, 0xfb_u8, 0xeb_u8, 0xcb_u8, 0x8b_u8, 0xb_u8, 0x16_u8, 0x2c_u8, 0x58_u8, 0xb0_u8, 0x7d_u8, 0xfa_u8, 0xe9_u8, 0xcf_u8, 0x83_u8, 0x1b_u8, 0x36_u8, 0x6c_u8, 0xd8_u8, 0xad_u8, 0x47_u8, 0x8e_u8, 0x1_u8, ] }; g2p-1.1.0/tests/test_trait_impl.rs000064400000000000000000000005201046102023000152230ustar 00000000000000use g2p::{GaloisField, G2Poly, g2p}; g2p!(GF256, 8, modulus: 0b1_0001_1011); #[test] fn test_build() { static_assertions::assert_impl_all!(GF256: GaloisField); assert_eq!(GF256::SIZE, 256); assert_eq!(GF256::MODULUS, G2Poly(0b1_0001_1011)); assert_eq!(GF256(0), GF256::ZERO); assert_eq!(GF256(1), GF256::ONE); }