Skip to content

Commit 69882ee

Browse files
TAdev0enitrat
andauthored
Core Lib Documentation: Math module (#6782)
Co-authored-by: enitrat <[email protected]>
1 parent b8ace7b commit 69882ee

File tree

1 file changed

+70
-13
lines changed

1 file changed

+70
-13
lines changed

corelib/src/math.cairo

Lines changed: 70 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
//! Mathematical operations and utilities.
2+
//!
3+
//! Provides extended GCD, modular inverse, and modular arithmetic operations.
4+
15
#[allow(unused_imports)]
26
use crate::zeroable::{IsZeroResult, NonZeroIntoImpl, Zeroable};
37
#[allow(unused_imports)]
@@ -10,12 +14,24 @@ use crate::RangeCheck;
1014
// TODO(yuval): use signed integers once supported.
1115
// TODO(yuval): use a single impl of a trait with associated impls, once associated impls are
1216
// supported.
13-
/// Extended GCD: finds (g, s, t, sub_direction) such that
14-
/// `g = gcd(a, b) = s * a - t * b` if `sub_direction` is true, or
15-
/// `g = gcd(a, b) = t * b - s * a` if `sub_direction` is false.
16-
/// `(s, -t)` or `(-s, t)` are the Bezout coefficients (according to `sub_direction`).
17+
/// Computes the extended GCD and Bezout coefficients for two numbers.
18+
///
19+
/// Uses the Extended Euclidean algorithm to find (g, s, t, sub_direction) where `g = gcd(a, b)`.
20+
/// The relationship between inputs and outputs is:
21+
/// * If `sub_direction` is true: `g = s * a - t * b`
22+
/// * If `sub_direction` is false: `g = t * b - s * a`
23+
///
24+
/// Returns a tuple (g, s, t, sub_direction) where g is the GCD and `(s, -t)` or `(-s, t)` are the
25+
/// Bezout coefficients (according to `sub_direction`).
1726
///
18-
/// Uses the Extended Euclidean algorithm.
27+
/// # Examples
28+
///
29+
/// ```
30+
/// use core::math::egcd;
31+
///
32+
/// let (g, s, t, dir) = egcd::<u32>(12, 8);
33+
/// assert!(g == 4);
34+
/// ```
1935
pub fn egcd<
2036
T,
2137
+Copy<T>,
@@ -47,9 +63,19 @@ pub fn egcd<
4763
}
4864

4965
// TODO(yuval): use signed integers once supported.
50-
/// Returns `s` the inverse of `a` modulo `n` such that `as`≡ 1 modulo `n`, or None if `gcd(a, n)
51-
/// > 1`.
52-
/// `s` is guaranteed to be between `1` and `n - 1` (inclusive).
66+
/// Computes the modular multiplicative inverse of `a` modulo `n`.
67+
///
68+
/// Returns `s` such that `a*s ≡ 1 (mod n)` where `s` is between `1` and `n-1` inclusive, or
69+
/// `Option::None` if `gcd(a,n) > 1` (inverse doesn't exist).
70+
///
71+
/// # Examples
72+
///
73+
/// ```
74+
/// use core::math::inv_mod;
75+
///
76+
/// let inv = inv_mod::<u32>(3, 7);
77+
/// assert!(inv == Option::Some(5));
78+
/// ```
5379
pub fn inv_mod<
5480
T,
5581
+Copy<T>,
@@ -85,7 +111,8 @@ pub fn inv_mod<
85111
}
86112
}
87113

88-
/// Returns `1 / b (mod n)`, or None if `b` is not invertible modulo `n`.
114+
/// Returns `1 / b (mod n)`, or `None` if `b` is not invertible modulo `n`.
115+
///
89116
/// All `b`s will be considered not invertible for `n == 1`.
90117
/// Additionally returns several `U128MulGuarantee`s that are required for validating the
91118
/// calculation.
@@ -106,8 +133,18 @@ extern fn u256_guarantee_inv_mod_n(
106133
(U128MulGuarantee, U128MulGuarantee),
107134
> implicits(RangeCheck) nopanic;
108135

109-
/// Returns the inverse of `a` modulo `n`, or None if `a` is not invertible modulo `n`.
136+
/// Returns the inverse of `a` modulo `n`, or `None` if `a` is not invertible modulo `n`.
137+
///
110138
/// All `a`s will be considered not invertible for `n == 1`.
139+
///
140+
/// # Examples
141+
///
142+
/// ```
143+
/// use core::math::u256_inv_mod;
144+
///
145+
/// let inv = u256_inv_mod(3, 17);
146+
/// assert!(inv == Option::Some(6));
147+
/// ```
111148
#[inline]
112149
pub fn u256_inv_mod(a: u256, n: NonZero<u256>) -> Option<NonZero<u256>> {
113150
match u256_guarantee_inv_mod_n(a, n) {
@@ -116,26 +153,45 @@ pub fn u256_inv_mod(a: u256, n: NonZero<u256>) -> Option<NonZero<u256>> {
116153
}
117154
}
118155

119-
/// Returns `a / b (mod n)`, or None if `b` is not invertible modulo `n`.
156+
/// Returns `a / b (mod n)`, or `None` if `b` is not invertible modulo `n`.
157+
///
158+
/// # Examples
159+
///
160+
/// ```
161+
/// use core::math::u256_inv_mod;
162+
///
163+
/// let result = u256_div_mod_n(17, 7, 29);
164+
/// assert!(result == Option::Some(19));
165+
/// ```
120166
pub fn u256_div_mod_n(a: u256, b: u256, n: NonZero<u256>) -> Option<u256> {
121167
Option::Some(u256_mul_mod_n(a, u256_inv_mod(b, n)?.into(), n))
122168
}
123169

124170
/// Returns `a * b (mod n)`.
171+
///
172+
/// # Examples
173+
///
174+
/// ```
175+
/// use core::math::u256_mul_mod_n;
176+
///
177+
/// let result = u256_mul_mod_n(17, 23, 29);
178+
/// assert!(result == 14);
179+
/// ```
125180
pub fn u256_mul_mod_n(a: u256, b: u256, n: NonZero<u256>) -> u256 {
126181
let (_, r) = u512_safe_div_rem_by_u256(u256_wide_mul(a, b), n);
127182
r
128183
}
129184

130-
// === Oneable ===
131185
/// A trait for types that have a multiplicative identity element.
132186
trait Oneable<T> {
133187
/// Returns the multiplicative identity element of Self, 1.
134188
#[must_use]
135189
fn one() -> T;
190+
136191
/// Returns whether self is equal to 1, the multiplicative identity element.
137192
#[must_use]
138193
fn is_one(self: T) -> bool;
194+
139195
/// Returns whether self is not equal to 1, the multiplicative identity element.
140196
#[must_use]
141197
fn is_non_one(self: T) -> bool;
@@ -148,18 +204,19 @@ pub(crate) mod one_based {
148204
fn one() -> T {
149205
OneImpl::one()
150206
}
207+
151208
#[inline]
152209
fn is_one(self: T) -> bool {
153210
OneImpl::is_one(@self)
154211
}
212+
155213
#[inline]
156214
fn is_non_one(self: T) -> bool {
157215
OneImpl::is_non_one(@self)
158216
}
159217
}
160218
}
161219

162-
// Oneable impls
163220
impl U8Oneable = one_based::OneableImpl<u8>;
164221
impl U16Oneable = one_based::OneableImpl<u16>;
165222
impl U32Oneable = one_based::OneableImpl<u32>;

0 commit comments

Comments
 (0)