ModularArithmetic 1.1.4

There is a newer version of this package available.
See the version list below for details.
dotnet add package ModularArithmetic --version 1.1.4
                    
NuGet\Install-Package ModularArithmetic -Version 1.1.4
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ModularArithmetic" Version="1.1.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ModularArithmetic" Version="1.1.4" />
                    
Directory.Packages.props
<PackageReference Include="ModularArithmetic" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ModularArithmetic --version 1.1.4
                    
#r "nuget: ModularArithmetic, 1.1.4"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ModularArithmetic@1.1.4
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ModularArithmetic&version=1.1.4
                    
Install as a Cake Addin
#tool nuget:?package=ModularArithmetic&version=1.1.4
                    
Install as a Cake Tool

Modular Arithmetic Library

under construction

Intro

This is a library written in C# aimed to work with Modular Arithmetic. Is is capable of working with Residual Number System (RNS) and performing basic arithmetical with Residue Numbers (RN). Apart from that, it implements Montgomery Arithmetic and performs Number Theoretic Transform (NTT) both on regular polynomials and those ones that use RNS for coefficient/evaluation representations.

Installation

To install the library, easiest way is to get it directly from NuGet via dotnet add package ModularArithmetic. This commans can be also executed directly from the IDE - here are the instructors for Visual Studio and here for Rider.

Alternatively, one can also download the files manually and add them to a project.

Usage

In this section we will through the basic usage of the library and its functions.

Representation of the Residue Number

Representation of the Residue Number can be done via 2 classes: SimpleResidueNumber for basic representation and NttResidueNumber which is also NTT friendly, hence the moduli must be prime numbers and not only coprime integers. For both representations, all modulu need to be odd numbers due to Montgomery arithmetic. Both classes support generic types, so you can also have SimpleResidueNumber<int> and SimpleResidueNumber<UInt128>, for example. To <> you can put any unmanaged IBinaryInteger. BigInteger is not supported.

Please note that that moduli are sorted (and residues are accordingly adjusted) before object is created, unless unsafe options are used.

First way of creating the object is via the residues and moduli array. First residue corresponds to first modulus and so on:

using ModularArithmetic;    // for SimpleResidueNumber
using ModularArithmetic.NTT;    // for NttResidueNumber

// residues and moduli array
// residues: [1, 2, 3], moduli: [3, 7, 11]
var a = new SimpleResidueNumber<int>([1, 2, 3], [3, 7, 11]);
// same as a because moduli are sorted
var alsoA = new SimpleResidueNumber<int>([3, 2, 1], [11, 7, 3]);

It is also possible to create the object from a single value and an array of moduli. Then a residue for each modulus will be counted. The single numeric value is always a BigInteger whilst the array has the type specified in <>.

using ModularArithmetic.NTT;    // to show NttResidueNumber

// residues = [13 % 3 = 1, 13 % 7 = 6, 13 % 11 = 2]
// moduli = [3, 7, 11]
var b = new NttResidueNumber<int>(13, [3, 7, 11]);

By using these methods, modulis are checked whether they are correct (no common divisors, respectively primality). These processes can be slow, hence there is an option to create the object without doing these checks. Moduli are still sorted, though.

using ModularArithmetic;

var notCheckedA = SimpleResidueNumber<int>.SkipModuliCheck([1, 2, 3], [3, 7, 11]);
var notCheckedB = NttResidueNumber<int>.SkipModuliCheck(13, [3, 7, 11]);

Last way of creating the object is via FromRawValues. Here, no sorting and checks are made. Object is simply created by feeding parameters into respective fields with no additional touches. If this method is desired, ImmutableAeeay<T> must be passed as that it the internal representation of the Residue Number.

using System.Collections.Immutable;     // for Immutable arrays 
using ModularArithmetic; 

ImmutableArray<int> aResidues = [1, 2, 3];
ImmutableArray<int> aModuli = [3, 7, 11];
var aFromRawValues = SimpleResidueNumber<int>.FromRawValues(aResidues, aModuli);

All of these methods are supported both on SimpleResidueNumber and NttResidueNumber.

Operations on Residue Numbers

All implementations (SimpleResidueNumber and NttResidueNumber) of the Residue Number support basic operations. Here is an enumeration of them.

Conversion to integer

It is possible to convert a ResidueNumber to integer. This can be done either by ToInteger or ToIntegerGarner method. Both of these return BigInteger type as the maximum possible number represented by Residual Number System grows really quickly (it's the sum of the moduli).

using System.Numerics;
using ModularArithmetic;

var a = new SimpleResidueNumber<int>([1, 2, 3], [3, 7, 11]);
BigInteger aInteger = a.ToInteger();
BigInteger aIntegerGarner = a.ToIntegerGarner();
Comparison

Since Residue Number is still a numeric representation, it is possible to compare the instances of both implementations. One can either use overloaded operators such as <, == and so on or directly call Equals or CompareTo methods.

using ModularArithmetic;

var a = new SimpleResidueNumber<int>([1, 2, 3], [3, 7, 11]);
var b = new SimpleResidueNumber<int>([0, 1, 9], [3, 7, 11]);

if (a > b)  // overloading the operators
{
    Console.WriteLine("a is greater than b");
}

if (a < b)
{
    Console.WriteLine("a is less than b");
}

if (a.Equals(b))    // directly calling the method
{
    Console.WriteLine("a is equal to b");
}  

Please note that checking for equality is fast. We just run through the residues and moduli and check whether they are the same. However, the comparison (greater than, smaller than, etc.) is slower due to the need for reconsruction to BigInteger as there is no way to deduce it from the moduli itself.

Montgomery Arithmetic

Whilst many internal operations depend directly on Montgomery Arithmetic, these functions are made open, so users can also take benefits from them.

Montgomery Space

Montgomery arithmetic is strictly defined within a modular space. This space is determined by a chosen modulus, and all operations are performed modulo that modulus. Chosen modulus is always an odd number (that's also why we don't allow even moduli in the Residue Number representation). Below is an example on how to create such space. Importing ModularArithmetic.MathHelpers is required.

using ModularArithmetic;
using ModularArithmetic.MathHelpers;

// Montgomery space where all operations are performed modulo 13
UInt128 modulus = 13;
MontgomerySpace mySpace = new MontgomerySpace(13modulus);

Is is possible to test individual MontgomerySpace objects for equality and the parameter in the constructor is of UInt128 type.

Montgomery Number

To represent a number inside given MontgomerySpace, MontgomeryNumber struct is used. Within the space, a number is represented by a numeric value that typically differs from its value in ordinary arithmetic. Creating an instance of MontgomeryNumber can be done in 2 ways:

  • via the constructor: here the Montgomery space and the value inside that space are provided
  • via Transform method: transforms any regular integer to its representation inside selected Montgomery space
using ModularArithmetic.MathHelpers;

// creating the space
MontgomerySpace mySpace = new MontgomerySpace(13);

// transforming regular 11 to mySpace
MontgomeryNumber a = mySpace.Transform(11);

// creating a number that has value 11 inside mySpace
MontgomeryNumber b = new MontgomeryNumber(11, mySpace);	// a != b

Notice that Transform method accepts any numeric type that satsifies IBinaryIntegeer but the method via constructor requires and UInt128 number to be passed. Internal representation then happens through usnigned 128-bit integers. Additionally, one can test these numbers for equality but the information about number's size is lost.

Additionally, by using ToRegular method, a number can be transformed from Montgomery space back to regular representation. Method returns UInt128

using ModularArithmetic.MathHelpers;

// creating the space
MontgomerySpace mySpace = new MontgomerySpace(13);

// transforming regular 11 to mySpace
MontgomeryNumber a = mySpace.Transform(11);

UInt128 regular = a.ToRegular;
Operations within Montgomery Space

Basic arithemtic operations (add, subtract and multiply) can be done between the numbers within the same Montgomery space. Objects are also made in a way, so they support overloaded operators. Moreover, because the internal representation uses a custom UInt256 for intermediate calculations, operations with large numbers near UInt128.MaxValue work correctly. Without Montgomery arithmetic, intermediate results could overflow, leading to incorrect outcomes.

using ModularArithmetic.MathHelpers;

// creating the space with a modulus of 13
UInt128 modulus = 13;
var montSpace = new MontgomerySpace(modulus);

// transforming regular 11 to mySpace
MontgomeryNumber a = montSpace.Transform(11);

// creating a number that has value 11 inside mySpace
MontgomeryNumber b = new MontgomeryNumber(11, montSpace);	// a != b

MontgomeryNumber sum = a + b;
MontgomeryNumber product = a * b;

MontgomeryNumber alsoProduct = montSpace.Multiply(a, b); 
Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net9.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.1.9 205 10/9/2025
1.1.8 135 9/27/2025
1.1.7 129 9/27/2025
1.1.6 143 9/26/2025
1.1.5 141 9/26/2025
1.1.4 196 9/23/2025
1.1.3 202 9/22/2025
1.1.2 200 9/22/2025
1.1.1 199 9/22/2025
1.1.0 324 9/16/2025
1.0.1 253 9/15/2025
1.0.0 189 9/9/2025
0.0.1 194 6/24/2025