Skip to main content

Uint256

zisklib 256-bit unsigned integer routines. Every value is a [u64; 4] array in little-endian limb order. Each operation has the familiar checked_ / wrapping_ / overflowing_ / saturating_ variants modulo 2^256, plus full division, exponentiation, and modular arithmetic.

Overview

Fixed-width 256-bit unsigned integer operations. Each value is [u64; 4] little-endian (limb 0 = LSB), matching EVM word layout and the arith256 / arith256_mod precompiles. Each arithmetic operation comes in up to four mode variants mirroring Rust's standard library: checked_* returns None on overflow / division-by-zero, overflowing_* returns the wrapped result plus an overflow flag, wrapping_* discards overflow, and saturating_* clamps to MAX_256 or ZERO_256. For arbitrary-precision work see the lower-level bigint module; uint256 is the fixed-width, application-facing API with explicit overflow semantics.

Sections at a glance:

SectionProvidesDepends on
Addition and subtraction*_add256, *_sub256, *_neg256 in checked / overflowing / wrapping / saturating variants.
Multiplication and inversion*_mul256, *_square256, inv256 (multiplicative inverse mod 2²⁵⁶).
Division and remainderchecked_div256 / checked_rem256, div_rem256, div_ceil256, wrapping_div256 / wrapping_rem256.
Modular arithmeticreduce_mod256, add_mod256, mul_mod256, square_mod256, inv_mod256.Multiplication, division
Exponentiationchecked_/overflowing_/wrapping_/saturating_pow256, pow_mod256.Multiplication, modular
note

Modular helpers (reduce_mod256, add_mod256, mul_mod256, square_mod256, pow_mod256) silently return zero when modulus is zero. Division by zero panics in the wrapping_ and div_rem forms; use checked_div256 / checked_rem256 to avoid that.


Addition and subtraction

Linear 256-bit arithmetic: addition, subtraction, and negation (equivalent to subtraction from zero). All three are available in checked_, overflowing_, wrapping_, and saturating_ forms. Overflow occurs when the true sum exceeds 2^256 - 1; underflow occurs when a < b. Negation is exact only for a == 0 — every other input wraps in two's-complement and is reported as overflow.

Computes a + b modulo 2^256. Returns None on overflow.

pub fn checked_add256(a: &[u64; 4], b: &[u64; 4]) -> Option<[u64; 4]>

Parameters

NameTypeDescription
a&[u64; 4]First addend.
b&[u64; 4]Second addend.

Returns

TypeDescription
Option<[u64; 4]>Some(a + b) if no overflow, None otherwise.

Example

let sum = zisklib::checked_add256(&a, &b).expect("overflow");

Multiplication and inversion

Nonlinear 256-bit arithmetic: multiplication, squaring, and the multiplicative inverse modulo 2^256. Multiplication and squaring expose the full mode matrix (checked_, overflowing_, wrapping_, saturating_); overflow means the full 512-bit product has non-zero high limbs. \1 returns Some(x) such that a · x ≡ 1 (mod 2^256), which exists if and only if a is odd — even inputs (including zero) yield None.

Computes a · b modulo 2^256. Returns None if the full 512-bit product does not fit in 256 bits.

pub fn checked_mul256(a: &[u64; 4], b: &[u64; 4]) -> Option<[u64; 4]>

Parameters

NameTypeDescription
a&[u64; 4]First factor.
b&[u64; 4]Second factor.

Returns

TypeDescription
Option<[u64; 4]>Some(a · b) if no overflow, None otherwise.

Example

let prod = zisklib::checked_mul256(&a, &b).expect("overflow");

Division and remainder

Euclidean division of 256-bit values: quotient, remainder, the combined div_rem256 form, and a ceiling variant. The quotient and remainder are hinted out of circuit and Euclid's lemma (a = q·b + r, r < b) is verified in-circuit. Division by zero behavior depends on the variant: checked_div256 and checked_rem256 return None, while wrapping_div256, wrapping_rem256, div_rem256, and div_ceil256 panic.

Computes a / b. Returns None when b == 0.

pub fn checked_div256(a: &[u64; 4], b: &[u64; 4]) -> Option<[u64; 4]>

Parameters

NameTypeDescription
a&[u64; 4]Dividend.
b&[u64; 4]Divisor.

Returns

TypeDescription
Option<[u64; 4]>Some(a / b) if b != 0, None otherwise.

Example

let q = zisklib::checked_div256(&a, &b).expect("div by zero");

Modular arithmetic

Arithmetic over Z / modulusZ for a 256-bit modulus, dispatched through the arith256_mod syscall: reduction, modular add, multiply, square, and inversion. The modular add/mul/square/reduce helpers silently return ZERO_256 when modulus == 0 rather than panicking; \1 returns None when gcd(a, modulus) != 1 (no inverse exists). These are the building blocks for ad-hoc prime-field arithmetic at the 256-bit width.

Reduces a modulo modulus. Returns ZERO_256 when modulus == 0.

pub fn reduce_mod256(a: &[u64; 4], modulus: &[u64; 4]) -> [u64; 4]

Parameters

NameTypeDescription
a&[u64; 4]Value to reduce.
modulus&[u64; 4]Modulus.

Returns

TypeDescription
[u64; 4]a mod modulus, or 0 when modulus == 0.

Example

let r = zisklib::reduce_mod256(&a, &p);

Exponentiation

Repeated multiplication via left-to-right square-and-multiply over a hinted binary decomposition of the exponent. The non-modular forms (checked_pow256, overflowing_pow256, wrapping_pow256, saturating_pow256) work modulo 2^256 with the usual overflow semantics; \1 takes a squaring-only fast path when exp is a power of two. \1 is the modular variant and returns ZERO_256 when modulus == 0.

Computes base^exp modulo 2^256. Returns None on overflow.

pub fn checked_pow256(
base: &[u64; 4],
exp: &[u64; 4],
) -> Option<[u64; 4]>

Parameters

NameTypeDescription
base&[u64; 4]Base.
exp&[u64; 4]Exponent.

Returns

TypeDescription
Option<[u64; 4]>Some(base^exp) if no overflow, None otherwise.

Example

let p = zisklib::checked_pow256(&base, &exp).expect("overflow");