From a084199c394fac283ebd51295b34da171827c2f1 Mon Sep 17 00:00:00 2001 From: "Inseon Yu(Merlyn)" Date: Wed, 4 Oct 2023 10:17:54 +0900 Subject: [PATCH] chore(math): add comments to math base files --- tachyon/math/base/big_int.h | 58 ++++++++++++++++++++++++++++++++++ tachyon/math/base/field.h | 9 ++++++ tachyon/math/base/groups.h | 24 +++++++++++++- tachyon/math/base/rings.h | 12 +++++++ tachyon/math/base/semigroups.h | 19 +++++++++++ 5 files changed, 121 insertions(+), 1 deletion(-) diff --git a/tachyon/math/base/big_int.h b/tachyon/math/base/big_int.h index 572a07002..b5881b582 100644 --- a/tachyon/math/base/big_int.h +++ b/tachyon/math/base/big_int.h @@ -33,6 +33,8 @@ constexpr size_t LimbsAlignment(size_t x) { } // namespace internal +// BigInt is a fixed size array of uint64_t, capable of holding up to |N| limbs, +// designed to support a wide range of big integer arithmetic operations. template struct ALIGNAS(internal::LimbsAlignment(N)) BigInt { uint64_t limbs[N] = { @@ -78,6 +80,7 @@ struct ALIGNAS(internal::LimbsAlignment(N)) BigInt { constexpr static BigInt One() { return BigInt(1); } + // Returns the maximum representable value for BigInt. constexpr static BigInt Max() { BigInt ret; for (uint64_t& limb : ret.limbs) { @@ -86,6 +89,7 @@ struct ALIGNAS(internal::LimbsAlignment(N)) BigInt { return ret; } + // Generate a random BigInt between [0, |max|). constexpr static BigInt Random(const BigInt& max = Max()) { BigInt ret; for (size_t i = 0; i < N; ++i) { @@ -98,18 +102,22 @@ struct ALIGNAS(internal::LimbsAlignment(N)) BigInt { return ret; } + // Convert a decimal string to a BigInt. constexpr static BigInt FromDecString(std::string_view str) { BigInt ret; CHECK(internal::StringToLimbs(str, ret.limbs, N)); return ret; } + // Convert a hexadecimal string to a BigInt. constexpr static BigInt FromHexString(std::string_view str) { BigInt ret; CHECK(internal::HexStringToLimbs(str, ret.limbs, N)); return ret; } + // Constructs a BigInt value from a given array of bits in little-endian + // order. template constexpr static BigInt FromBitsLE(const std::bitset& bits) { static_assert(BitNums <= kBitNums); @@ -136,6 +144,7 @@ struct ALIGNAS(internal::LimbsAlignment(N)) BigInt { return ret; } + // Constructs a BigInt value from a given array of bits in big-endian order. template constexpr static BigInt FromBitsBE(const std::bitset& bits) { static_assert(BitNums <= kBitNums); @@ -162,6 +171,8 @@ struct ALIGNAS(internal::LimbsAlignment(N)) BigInt { return ret; } + // Constructs a BigInt value from a given array of bytes in little-endian + // order. constexpr static BigInt FromBytesLE(const std::vector& bytes) { BigInt ret; size_t byte_idx = 0; @@ -184,6 +195,7 @@ struct ALIGNAS(internal::LimbsAlignment(N)) BigInt { return ret; } + // Constructs a BigInt value from a given array of bytes in big-endian order. constexpr static BigInt FromBytesBE(const std::vector& bytes) { BigInt ret; size_t byte_idx = 0; @@ -218,6 +230,7 @@ struct ALIGNAS(internal::LimbsAlignment(N)) BigInt { return FromMontgomery(value, modulus, inverse); } + // Extend the current |N| size BigInt to a larger |N2| size. template constexpr BigInt Extend() const { static_assert(N2 > N); @@ -228,6 +241,7 @@ struct ALIGNAS(internal::LimbsAlignment(N)) BigInt { return ret; } + // Shrink the current |N| size BigInt to a smaller |N2| size. template constexpr BigInt Shrink() const { static_assert(N2 < N); @@ -238,6 +252,10 @@ struct ALIGNAS(internal::LimbsAlignment(N)) BigInt { return ret; } + // Clamp the BigInt value with respect to a modulus. + // If the value is larger than or equal to the modulus, then the modulus is + // subtracted from the value. The function considers a spare bit in the + // modulus based on the template parameter. template constexpr static void Clamp(const BigInt& modulus, BigInt* value, [[maybe_unused]] bool carry = false) { @@ -283,20 +301,26 @@ struct ALIGNAS(internal::LimbsAlignment(N)) BigInt { constexpr bool IsEven() const { return limbs[kSmallestLimbIdx] % 2 == 0; } constexpr bool IsOdd() const { return limbs[kSmallestLimbIdx] % 2 == 1; } + // Return the largest (most significant) limb of the BigInt. constexpr uint64_t& biggest_limb() { return limbs[kBiggestLimbIdx]; } constexpr const uint64_t& biggest_limb() const { return limbs[kBiggestLimbIdx]; } + // Return the smallest (least significant) limb of the BigInt. constexpr uint64_t& smallest_limb() { return limbs[kSmallestLimbIdx]; } constexpr const uint64_t& smallest_limb() const { return limbs[kSmallestLimbIdx]; } + // Extracts a specified number of bits starting from a given bit offset and + // returns them as a uint64_t. constexpr uint64_t ExtractBits64(size_t bit_offset, size_t bit_count) const { return ExtractBits(bit_offset, bit_count); } + // Extracts a specified number of bits starting from a given bit offset and + // returns them as a uint32_t. constexpr uint32_t ExtractBits32(size_t bit_offset, size_t bit_count) const { return ExtractBits(bit_offset, bit_count); } @@ -627,6 +651,7 @@ struct ALIGNAS(internal::LimbsAlignment(N)) BigInt { return internal::LimbsToHexString(limbs, N); } + // Converts the BigInt to a bit array in little-endian. template std::bitset ToBitsLE() const { std::bitset ret; @@ -641,6 +666,7 @@ struct ALIGNAS(internal::LimbsAlignment(N)) BigInt { return ret; } + // Converts the BigInt to a bit array in big-endian. template std::bitset ToBitsBE() const { std::bitset ret; @@ -655,6 +681,7 @@ struct ALIGNAS(internal::LimbsAlignment(N)) BigInt { return ret; } + // Converts the BigInt to a byte array in little-endian. std::vector ToBytesLE() const { std::vector ret; ret.reserve(kByteNums); @@ -667,6 +694,7 @@ struct ALIGNAS(internal::LimbsAlignment(N)) BigInt { return ret; } + // Converts the BigInt to a byte array in big-endian. std::vector ToBytesBE() const { std::vector ret; ret.reserve(kByteNums); @@ -781,6 +809,14 @@ struct ALIGNAS(internal::LimbsAlignment(N)) BigInt { return ret & mask; } + // Montgomery arithmetic is a technique that allows modular arithmetic to be + // done more efficiently, by avoiding the need for explicit divisions. + // See https://en.wikipedia.org/wiki/Montgomery_modular_multiplication + + // Converts a BigInt value from the Montgomery domain back to the standard + // domain. |FromMontgomery()| performs the Montgomery reduction algorithm to + // transform a value from the Montgomery domain back to its standard + // representation. template constexpr static BigInt FromMontgomery(const BigInt& value, const BigInt& modulus, T inverse) { @@ -810,6 +846,28 @@ struct ALIGNAS(internal::LimbsAlignment(N)) BigInt { return r; } + // Performs Montgomery reduction on a doubled-sized BigInt, and populates + // |out| with the result. + + // Inputs: + // - r: A BigInt representing a value (typically A x B) in Montgomery form. + // - modulus: The modulus M against which we're performing arithmetic. + // - inverse: The multiplicative inverse of the radix w.r.t. the modulus. + + // Operation: + // 1. For each limb of r: + // - Compute a tmp = r(current limb) * inverse. + // This value aids in eliminating the lowest limb of r when multiplied by + // the modulus. + // - Incrementally add tmp * (modulus to r), effectively canceling out its + // current lowest limb. + // + // 2. After iterating over all limbs, the higher half of r is the + // Montgomery-reduced result of the original operation (like A x B). This + // result remains in the Montgomery domain. + // + // 3. Apply a final correction (if necessary) to ensure the result is less + // than |modulus|. template constexpr static void MontgomeryReduce(BigInt<2 * N>& r, const BigInt& modulus, T inverse, diff --git a/tachyon/math/base/field.h b/tachyon/math/base/field.h index d9970e29b..733455c60 100644 --- a/tachyon/math/base/field.h +++ b/tachyon/math/base/field.h @@ -5,9 +5,18 @@ namespace tachyon::math { +// Field is any set of elements that satisfies the field axioms for both +// addition and multiplication and is commutative division algebra +// Simply put, a field is a ring in which multiplicative commutativity exists, +// and every non-zero element has a multiplicative inverse. +// See https://mathworld.wolfram.com/Field.html + +// The Field supports SumOfProducts, inheriting the properties of both +// AdditiveGroup and MultiplicativeGroup. template class Field : public AdditiveGroup, public MultiplicativeGroup { public: + // Sum of products: a₁ * b₁ + a₂ * b₂ + ... + aₙ * bₙ template < typename InputIterator, std::enable_if_t>>* = diff --git a/tachyon/math/base/groups.h b/tachyon/math/base/groups.h index 388fd0437..7b7db9de5 100644 --- a/tachyon/math/base/groups.h +++ b/tachyon/math/base/groups.h @@ -12,9 +12,20 @@ SUPPORTS_BINARY_OPERATOR(Mod); } // namespace internal +// Group 'G' is a set of elements together with a binary operation (called the +// group operation) that together satisfy the four fundamental properties of +// closure, associative, the identity property, and the inverse property. +// See https://mathworld.wolfram.com/Group.html + +// MultiplicativeGroup is a group with the group operation '*'. +// MultiplicativeGroup supports division and inversion, inheriting the +// properties of MultiplicativeSemigroup. template class MultiplicativeGroup : public MultiplicativeSemigroup { public: + // Division: + // 1) a / b if division is supported. + // 2) a * b⁻¹ otherwise template < typename G2, std::enable_if_t::value || @@ -33,6 +44,7 @@ class MultiplicativeGroup : public MultiplicativeSemigroup { } } + // Division in place: a /= b template < typename G2, std::enable_if_t::value>* = nullptr> @@ -41,6 +53,7 @@ class MultiplicativeGroup : public MultiplicativeSemigroup { return g->DivInPlace(other); } + // Division in place: a *= b⁻¹ template < typename G2, std::enable_if_t::value && @@ -50,15 +63,21 @@ class MultiplicativeGroup : public MultiplicativeSemigroup { return g->MulInPlace(other.Inverse()); } + // Inverse: a⁻¹ [[nodiscard]] constexpr auto Inverse() const { G ret = *static_cast(this); return ret.InverseInPlace(); } }; - +// AdditiveGroup is a group with the group operation '+'. +// AdditiveGroup supports subtraction and negation, inheriting the +// properties of AdditiveSemigroup. template class AdditiveGroup : public AdditiveSemigroup { public: + // Subtraction: + // 1) a - b if subtraction is supported. + // 2) a + (-b) otherwise template < typename G2, std::enable_if_t::value || @@ -77,6 +96,7 @@ class AdditiveGroup : public AdditiveSemigroup { } } + // Subtraction in place: a -= b template < typename G2, std::enable_if_t::value>* = nullptr> @@ -85,6 +105,7 @@ class AdditiveGroup : public AdditiveSemigroup { return g->SubInPlace(other); } + // Subtraction in place: a += (-b) template < typename G2, std::enable_if_t::value && @@ -94,6 +115,7 @@ class AdditiveGroup : public AdditiveSemigroup { return g->AddInPlace(other.Negative()); } + // Negation: -a constexpr auto operator-() const { return Negative(); } [[nodiscard]] constexpr auto Negative() const { diff --git a/tachyon/math/base/rings.h b/tachyon/math/base/rings.h index e6ac59eb3..2da7b01ce 100644 --- a/tachyon/math/base/rings.h +++ b/tachyon/math/base/rings.h @@ -8,9 +8,21 @@ namespace tachyon::math { +// Ring is a set S with operations + and * that satisfies the followings: +// 1. Additive associativity: (a + b) + c = a + (b + c) +// 2. Additive commutativity: a + b = b + a +// 3. Additive identity: a + 0 = 0 + a = a +// 4. Additive inverse: a + (-a) = (-a) + a = 0 +// 5. Distributivity: a * (b + c) = (a * b) + (a * c) +// 6. Multiplicative associativity: (a * b) * c = a * (b * c) +// See https://mathworld.wolfram.com/Ring.html + +// The Ring supports SumOfProducts, inheriting the properties of both +// AdditiveGroup and MultiplicativeSemigroup. template class Ring : public AdditiveGroup, public MultiplicativeSemigroup { public: + // Sum of products: a₁ * b₁ + a₂ * b₂ + ... + aₙ * bₙ template < typename InputIterator, std::enable_if_t>>* = diff --git a/tachyon/math/base/semigroups.h b/tachyon/math/base/semigroups.h index d088a8d8d..7fcedfb44 100644 --- a/tachyon/math/base/semigroups.h +++ b/tachyon/math/base/semigroups.h @@ -54,6 +54,12 @@ struct AdditiveSemigroupTraits { } // namespace internal +// Semigroup is a mathematical object defined for a set 'S' and a binary +// operator '○' in which the operation is associative. +// Associativity: (a ○ b) ○ c = a ○ (b ○ c) +// See https://mathworld.wolfram.com/Semigroup.html + +// MultiplicativeSemigroup is a semigroup with a multiplicative operator. template class MultiplicativeSemigroup { public: @@ -61,6 +67,8 @@ class MultiplicativeSemigroup { typename G2, std::enable_if_t::value || internal::SupportsMulInPlace::value>* = nullptr> + + // Multiplication: a * b constexpr auto operator*(const G2& other) const { if constexpr (internal::SupportsMul::value) { const G* g = static_cast(this); @@ -71,6 +79,7 @@ class MultiplicativeSemigroup { } } + // Multiplication in place: a *= b template < typename G2, std::enable_if_t::value>* = nullptr> @@ -79,6 +88,7 @@ class MultiplicativeSemigroup { return g->MulInPlace(other); } + // a.Square(): a² [[nodiscard]] constexpr auto Square() const { if constexpr (internal::SupportsSquareInPlace::value) { G g = *static_cast(this); @@ -88,6 +98,9 @@ class MultiplicativeSemigroup { } } + // a.Pow(e): aᵉ + // Square it as much as possible and multiply the remainder. + // ex) a¹³ = (((a)² * a)²)² * a template ::ReturnTy> @@ -114,6 +127,8 @@ class MultiplicativeSemigroup { return ret; } + // Computes the power of a base element using a pre-computed table of powers + // of two, instead of performing repeated multiplications. template ::ReturnTy> @@ -134,9 +149,11 @@ class MultiplicativeSemigroup { } }; +// AdditiveSemigroup is a semigroup with an additive operator. template class AdditiveSemigroup { public: + // Addition: a + b template < typename G2, std::enable_if_t::value || @@ -151,6 +168,7 @@ class AdditiveSemigroup { } } + // Addition in place: a += b template < typename G2, std::enable_if_t::value>* = nullptr> @@ -159,6 +177,7 @@ class AdditiveSemigroup { return g->AddInPlace(other); } + // a.Double(): 2a [[nodiscard]] constexpr auto Double() const { if constexpr (internal::SupportsDoubleInPlace::value) { G g = *static_cast(this);