#ruint2

ruint2

Unsigned integer type with cont-generic bit length

2 stable releases

1.9.0 Jun 13, 2023
1.8.0 Jun 13, 2023

#237 in Math

Download history 76/week @ 2023-11-04 58/week @ 2023-11-11 81/week @ 2023-11-18 117/week @ 2023-11-25 84/week @ 2023-12-02 123/week @ 2023-12-09 163/week @ 2023-12-16 76/week @ 2023-12-23 78/week @ 2023-12-30 105/week @ 2024-01-06 122/week @ 2024-01-13 62/week @ 2024-01-20 50/week @ 2024-01-27 46/week @ 2024-02-03 99/week @ 2024-02-10 155/week @ 2024-02-17

355 downloads per month

MIT license

425KB
9K SLoC

Rust uint crate using const-generics

crates.io docs.rs MIT License dependency status codecov CI

Implements [Uint<BITS, LIMBS>], the ring of numbers modulo $2^{\mathsf{BITS}}$. It requires two generic arguments: the number of bits and the number of 64-bit 'limbs' required to store those bits.

# use ruint2::Uint;
let answer: Uint<256, 4> = Uint::from(42);

You can compute LIMBS yourself using $\mathsf{LIMBS} = \left\lceil{\mathsf{BITS} / 64}\right\rceil$, i.e.LIMBS equals BITS divided by $64$ rounded up. Uint will panic! if you try to construct it with incorrect arguments. Ideally this would be a compile time error, but that is blocked by Rust issue #60551.

A more convenient method on stable is to use the uint! macro, which constructs the right Uint for you.

# use ruint2::{Uint, uint};
let answer = uint!(42_U256);

You can also use one of the pre-computed type aliases:

# use ruint2::Uint;
use ruint2::aliases::*;

let answer: U256 = Uint::from(42);

You can of course also create your own type alias if you need a funny size:

# use ruint2::Uint;
type U1337 = Uint<1337, 21>;

let answer: U1337 = Uint::from(42);

Rust nightly

If you are on nightly, you can use Uint<BITS> which will compute the number of limbs for you. Unfortunately this can not be made stable without generic_const_exprs support (Rust issue #76560).

# #[cfg(has_generic_const_exprs)] {
use ruint2::nightly::Uint;

let answer: Uint<256> = Uint::<256>::from(42);
# }

Even on nightly, the ergonomics of Rust are limited. In the example above Rust requires explicit type annotation for Uint::from, where it did not require it in the stable version. There are a few more subtle issues that make this less ideal than it appears. It also looks like it may take some time before these nightly features are stabilized.

Examples

use ruint2::Uint;

let a: Uint<256, 4> = Uint::from(0xf00f_u64);
let b: Uint<256, 4> = Uint::from(42_u64);
let c  = a + b;
assert_eq!(c, Uint::from(0xf039_u64));

There is a convenient macro uint! to create constants for you. It allows for arbitrary length constants using standard Rust integer syntax. The size of the Uint or Bits is specified with a U or B suffix followed by the number of bits. The standard Rust syntax of decimal, hexadecimal and even binary and octal is supported using their prefixes 0x, 0b and 0o. Literals can have underscores _ added for readability.

# use ruint2::uint;
let cow = uint!(0xc85ef7d79691fe79573b1a7064c19c1a9819ebdbd1faaab1a8ec92344438aaf4_U256);

In fact, this macro recurses down the parse tree, so you can apply it to entire source files:

# use ruint2::uint;
uint!{

let a = 42_U256;
let b = 0xf00f_1337_c0d3_U256;
let c = a + b;
assert_eq!(c, 263947537596669_U256);

}

Note that since B is a valid hexadecimal digit there can be ambiguity. To lessen the impact an underscore separator _B is required in this case.

Feature flags

There is support for a number of crates. These are enabled by setting the identically named feature flag.

Building and testing

Format, lint, build and test everything (I recommend creating a shell alias for this):

cargo fmt &&\
cargo clippy --all-features --all-targets &&\
cargo test --workspace --all-features --doc -- --nocapture &&\
cargo test --workspace --all-features --all-targets -- --nocapture &&\
cargo doc --workspace --all-features --no-deps

Run benchmarks with the provided .cargo/config.toml alias

cargo criterion

Check documentation coverage

RUSTDOCFLAGS="-Z unstable-options --show-coverage"  cargo doc --workspace --all-features --no-deps

Features

  • All the quality of life features one could want.
  • Compatible with std u64, etc types. See Rust's integer methods.
  • Adhere to Rust API Guidelines
  • Montgomery REDC and other algo's for implementing prime fields.

To do

  • Builds no-std and wasm.
  • Fast platform agnostic generic algorithms.
  • Target specific assembly optimizations (where available).
  • Optional num-traits, etc, support.
  • Run-time sized type with compatible interface.

lines of code GitHub contributors GitHub issues GitHub pull requests GitHub Repo stars crates.io

Dependencies

~1–19MB
~257K SLoC