LibTomMath Documentation
repository·develop·Indexed 21 days ago
https://github.com/libtom/libtommathA portable, open-source multiple-precision integer (MPI) library written in C for number theoretic computations. It provides high-performance integer arithmetic, including basic operations, Montgomery reduction for modular exponentiation, primality testing, and binary export/import compatible with GMP.
What's inside LibTomMath
- LibTomMath is a free, open-source, portable multiple-precision integer (MPI) library written entirely in C. It is designed for number theoretic applications and provides high-performance integer arithmetic.
Build LibTomMath using Make
developThe project can be built using
make. Standard targets include:make: Build the library.make clean: Remove build artifacts.make install: Install the library to the system.
Note: For detailed GNU Linux building instructions, refer to the "Building LibTomMath" section in the
doc/bn.pdfdocumentation.Run LibTomMath tests
developTests are located in the
demo/directory and can be run in two different modes:- Standalone Tests: Run
make testto create a standalone test binary that executes several internal test routines. - Opponent Testing (
mtest): This mode verifies LibTomMath against test vectors generated by an alternative MPI library.- Build
mtestusingmake mtest. - Build the opponent binary using
make mtest_opponent. - Execute the test pipeline using:
./mtest/mtest | ./mtest_opponent.
- Build
# Standalone tests make test # mtest opponent testing make mtest make mtest_opponent ./mtest/mtest | ./mtest_opponent- Standalone Tests: Run
Build LibTomMath using CMake
developThe project supports the CMake build system. To build the library, create a build directory, run
cmake, and thenmake. By default, it builds static libraries. To build shared libraries instead, pass the-DBUILD_SHARED_LIBS=Onflag to thecmakecommand.git clone https://github.com/libtom/libtommath.git mkdir -p libtommath/build cd libtommath/build cmake .. make -j$(nproc) # To build shared libraries: cmake -DBUILD_SHARED_LIBS=On .. make -j$(nproc)Include LibTomMath in your project
developTo use LibTomMath, include the header file
tommath.hin your C/C++ source code.#include <tommath.h>Generate performance graphs using ltmtest and gnuplot
developTo generate visual performance graphs for libtommath, you must first build and run the
ltmtestutility from the root directory of the package. This process generates timing data in.logfiles within thelogs/directory. Once the logs are generated, you can usegnuplotto convert them into PNG images and view them viaindex.html.# 1. Build and run the timing tests (takes ~10 minutes) make timing ; ltmtest # 2. Generate PNG graphs from the logs gnuplot graphs.dem # 3. Open logs/index.html in your browser to view resultsAccess LibTomMath documentation
developDocumentation is primarily available in two forms:
- PDF: Detailed documentation is generated from the LaTeX file
doc/bn.texand is available as a PDF for each release. - Header Comments: Limited documentation is provided directly within
tommath.h.
- PDF: Detailed documentation is generated from the LaTeX file
Handle errors in LibTomMath
developMost functions return an
mp_errtype. To understand what went wrong, usemp_error_to_string(mp_err code)to get a human-readable ASCII message describing the error code.Common error codes mentioned in documentation include:
MP_OVF: Overflow (e.g., result too large formp_int).MP_VAL: Invalid value (e.g., negative exponent or invalid radix).MP_MEM: Memory allocation failure.MP_ERR: Error reading/writing to a file or stream.MP_BUF: Buffer is too small.
Example: Check if an integer is a perfect power
developThis example demonstrates using a mix of Libtommath functions to determine if a number $n$ is a perfect power ($n = root^{exponent}$). It uses
mp_prime_next_primeto iterate through possible prime exponents andmp_expt_nfor exponentiation.static mp_err mp_is_perfect_power(const mp_int *n, bool *result, mp_int *rootout, mp_int *exponent) { mp_int root, power, prime, max; int highbit, lowbit, p; mp_err err = MP_OKAY; *result = false; if (mp_cmp_d(n, 4) == MP_LT) { err = MP_VAL; goto LTM_OUT; } highbit = mp_count_bits(n) - 1; if (MP_IS_POWER_OF_TWO(n)) { *result = true; if (exponent != NULL) { if ((err = mp_set_l(exponent, (long)highbit)) != MP_OKAY) return err; } if (rootout != NULL) { if ((err = mp_set_l(rootout, 2l)) != MP_OKAY) return err; } return err; } if ((err = mp_init_multi(&root, &power, &prime, &max, NULL)) != MP_OKAY) return err; if ((err = mp_set_l(&max, (long)highbit)) != MP_OKAY) goto LTM_ERR; mp_set(&prime, 2u); while (mp_cmp(&prime, &max) != MP_GT) { if ((err = mp_prime_next_prime(&prime, -1, false)) != MP_OKAY) goto LTM_ERR; p = (int)mp_get_l(&prime); if ((err = mp_root_n(n, p, &root)) != MP_OKAY) goto LTM_ERR; if ((err = mp_expt_n(&root, p, &power)) != MP_OKAY) goto LTM_ERR; if (mp_cmp(n, &power) == MP_EQ) { *result = true; if (rootout != NULL) mp_exch(&root, rootout); if (exponent != NULL) { if ((e = mp_set_l(exponent, (long)p)) != MP_OKAY) goto LTM_ERR; } } } LTM_OUT: if (rootout != NULL) mp_set(rootout, 0u); if (exponent != NULL) mp_set(exponent, 0u); LTM_ERR: mp_clear_multi(&root, &power, &prime, NULL); return err; }Use Montgomery reduction for fast modular exponentiation
developFor high-performance modular arithmetic, use Montgomery reduction. This requires a pre-computation step.
- Setup: Use
mp_montgomery_setup(const mp_int *a, mp_digit *mp)to compute the pre-computation valuempfor an odd modulusa. - Normalization: Use
mp_montgomery_calc_normalization(&R, b)to compute $R = r^n$. - Reduction: Use
mp_montgomery_reduce(mp_int *a, const mp_int *m, mp_digit mp)to reduceain place modulomusing the pre-computedmp.
Example workflow for computing $a^3 ext{ mod } b$:
/* ... initialization and setup ... */ /* normalize 'a' so now a is equal to aR */ mp_mulmod(&a, &R, &b, &a); /* square a to get c = a^2R^2 */ mp_sqr(&a, &c); /* reduce 'c' back down to c = a^2R^2 * R^-1 == a^2R */ mp_montgomery_reduce(&c, &b, mp); /* multiply a to get c = a^3R^2 */ mp_mul(&a, &c, &c); /* reduce 'c' back down to c = a^3R^2 * R^-1 == a^3R */ mp_montgomery_reduce(&c, &b, mp); /* reduce 'c' again to get c = a^3R * R^-1 == a^3 */ mp_montgomery_reduce(&c, &b, mp); /* c now equals a^3 mod b */int main(void) { mp_int a, b, c, R; mp_digit mp; mp_err result; /* initialize a,b to desired values, * mp_init R, c and set c to 1.... */ /* get normalization */ if ((result = mp_montgomery_calc_normalization(&R, b)) != MP_OKAY) { printf("Error getting norm. %s", mp_error_to_string(result)); return EXIT_FAILURE; } /* get mp value */ if ((result = mp_montgomery_setup(&c, &mp)) != MP_OKAY) { printf("Error setting up montgomery. %s", mp_error_to_string(result)); return EXIT_FAILURE; } /* normalize `a' so now a is equal to aR */ if ((result = mp_mulmod(&a, &R, &b, &a)) != MP_OKAY) { printf("Error computing aR. %s", mp_error_to_string(result)); return EXIT_FAILURE; } /* square a to get c = a^2R^2 */ if ((result = mp_sqr(&a, &c)) != MP_OKAY) { printf("Error squaring. %s", mp_error_to_string(result)); return EXIT_FAILURE; } /* now reduce `c' back down to c = a^2R^2 * R^-1 == a^2R */ if ((result = mp_montgomery_reduce(&c, &b, mp)) != MP_OKAY) { printf("Error reducing. %s", mp_error_to_string(result)); return EXIT_FAILURE; } /* multiply a to get c = a^3R^2 */ if ((result = mp_mul(&a, &c, &c)) != MP_OKAY) { printf("Error reducing. %s", mp_error_to_string(result)); return EXIT_FAILURE; } /* now reduce `c' back down to c = a^3R^2 * R^-1 == a^3R */ if ((result = mp_montgomery_reduce(&c, &b, mp)) != MP_OKAY) { printf("Error reducing. %s", mp_error_to_string(result)); return EXIT_FAILURE; } /* now reduce (again) `c' back down to c = a^3R * R^-1 == a^3 */ if ((result = mp_montgomery_reduce(&c, &b, mp)) != MP_OKAY) { printf("Error reducing. %s", mp_error_to_string(result)); return EXIT_FAILURE; } /* c now equals a^3 mod b */ return EXIT_SUCCESS; }- Setup: Use
Calculate required bytes for unsigned big integer with mp_ubin_size
developUse
mp_ubin_sizeto determine the number of bytes (octets) required to store the unsigned representation of a big integera.size_t mp_ubin_size(const mp_int *a)Convert mp_int to standard integer types
developUse the
mp_get_*family of functions to extract values from a big integer into standard C types. Note that these functions are truncating if the big integer is larger than the target type.mp_get_i32(const mp_int *a): Returns a signed 32-bit integer.mp_get_i64(const mp_int *a): Returns a signed 64-bit integer.mp_get_l(const mp_int *a): Returns a signedlong.mp_get_u32(const mp_int *a): Returns an unsigned 32-bit integer.mp_get_u64(const mp_int *a): Returns an unsigned 64-bit integer.mp_get_mag_u32(const mp_int *a): Returns the absolute value (magnitude) as an unsigned 32-bit integer.mp_get_double(const mp_int *a): Returns adouble(binary64). This may overflow if the integer is too large.