rings_core/algebra/module.rs
1#[cfg(test)]
2use std::fmt::Debug;
3use std::ops::Mul;
4
5#[cfg(test)]
6use super::assert_abelian_group_laws;
7use super::AbelianGroup;
8use super::CommutativeRing;
9
10/// Right scalar action of a commutative ring on an abelian group.
11///
12/// `Module<Scalar>` is parameterized by the scalar carrier. The element carrier
13/// is `Self`, and the scalar action is expressed by `Self: Mul<Scalar>`. In this
14/// crate that matches elliptic-curve notation as `point * scalar`.
15///
16/// A left action would be a different Rust operation shape,
17/// `Scalar: Mul<Self>`. Do not implement this trait for a left-only action by
18/// swapping argument meaning in the implementation.
19///
20/// Law: `a * (s + t) == a * s + a * t`.
21///
22/// Law: `(a + b) * s == a * s + b * s`.
23///
24/// Law: `a * (s * t) == (a * s) * t`.
25///
26/// Law: `a * Scalar::one() == a`.
27pub trait Module<Scalar>: AbelianGroup + Mul<Scalar, Output = Self>
28where Scalar: CommutativeRing
29{
30}
31
32/// Assert right scalar-action laws for representative samples.
33///
34/// This helper assumes the caller has already checked the scalar carrier laws.
35/// It still checks the element abelian-group laws because module elements carry
36/// their own additive group structure. Use it when a test has already run a
37/// stricter scalar law helper, such as [`assert_field_laws`], and only needs the
38/// module action witness afterward.
39#[cfg(test)]
40pub fn assert_module_action_laws<Scalar, Element>(scalars: &[Scalar], elements: &[Element])
41where
42 Scalar: CommutativeRing + Clone + Eq + Debug,
43 Element: Module<Scalar> + Clone + Eq + Debug,
44{
45 assert_abelian_group_laws(elements);
46
47 for s in scalars {
48 for t in scalars {
49 for a in elements {
50 let lhs = a.clone() * (s.clone() + t.clone());
51 let rhs = (a.clone() * s.clone()) + (a.clone() * t.clone());
52 assert_eq!(lhs, rhs);
53
54 let lhs = a.clone() * (s.clone() * t.clone());
55 let rhs = (a.clone() * s.clone()) * t.clone();
56 assert_eq!(lhs, rhs);
57
58 for b in elements {
59 let lhs = (a.clone() + b.clone()) * s.clone();
60 let rhs = (a.clone() * s.clone()) + (b.clone() * s.clone());
61 assert_eq!(lhs, rhs);
62 }
63 }
64 }
65
66 for a in elements {
67 assert_eq!(a.clone() * Scalar::one(), *a);
68 }
69 }
70}