ADDED .fossil-settings/crlf-glob
Index: .fossil-settings/crlf-glob
==================================================================
--- /dev/null
+++ .fossil-settings/crlf-glob
@@ -0,0 +1,17 @@
+compat/zlib/contrib/dotzlib/DotZLib/UnitTests.cs
+compat/zlib/contrib/vstudio/readme.txt
+compat/zlib/contrib/vstudio/*/zlib.rc
+compat/zlib/win32/*.txt
+compat/zlib/win64/*.txt
+libtommath/*.dsp
+libtommath/*.sln
+libtommath/*.vcproj
+tools/tcl.hpj.in
+tools/tcl.wse.in
+win/buildall.vc.bat
+win/coffbase.txt
+win/makefile.vc
+win/rules.vc
+win/tcl.dsp
+win/tcl.dsw
+win/tcl.hpj.in
ADDED .fossil-settings/ignore-glob
Index: .fossil-settings/ignore-glob
==================================================================
--- /dev/null
+++ .fossil-settings/ignore-glob
@@ -0,0 +1,56 @@
+*.a
+*.dll
+*.dylib
+*.exe
+*.exp
+*.la
+*.lib
+*.lo
+*.o
+*.obj
+*.pdb
+*.res
+*.sl
+*.so
+*/Makefile
+*/config.cache
+*/config.log
+*/config.status
+*/tclConfig.sh
+*/tclsh*
+*/tcltest*
+*/versions.vc
+*/version.vc
+*/libtcl.vfs
+*/libtcl_*.zip
+html
+libtommath/bn.ilg
+libtommath/bn.ind
+libtommath/doc
+libtommath/pretty.build
+libtommath/tommath.src
+libtommath/*.log
+libtommath/*.pdf
+libtommath/gen.pl
+libtommath/*.sh
+libtommath/doc/*
+libtommath/tombc/*
+libtommath/pre_gen/*
+libtommath/pics/*
+libtommath/mtest/*
+libtommath/logs/*
+libtommath/etc/*
+libtommath/demo/*
+libtommath/*.out
+libtommath/*.tex
+unix/autoMkindex.tcl
+unix/dltest.marker
+unix/tcl.pc
+unix/tclIndex
+unix/pkgs/*
+win/Debug*
+win/Release*
+win/pkgs/*
+win/coffbase.txt
+win/tcl.hpj
+win/nmhlp-out.txt
ADDED .gitattributes
Index: .gitattributes
==================================================================
--- /dev/null
+++ .gitattributes
@@ -0,0 +1,39 @@
+# Set the default behavior, in case people don't have core.autocrlf set.
+* eol=lf
+* text=auto
+
+# Explicitly declare text files you want to always be normalized and converted
+# to native line endings on checkout.
+*.3 text
+*.c text
+*.css text
+*.enc text
+*.h text
+*.htm text
+*.html text
+*.java text
+*.js text
+*.json text
+*.n text
+*.svg text
+*.ts text
+*.tcl text
+*.test text
+
+# Declare files that will always have CRLF line endings on checkout.
+*.bat eol=crlf
+*.sln eol=crlf
+*.vc eol=crlf
+
+# Denote all files that are truly binary and should not be modified.
+*.a binary
+*.dll binary
+*.exe binary
+*.gif binary
+*.gz binary
+*.jpg binary
+*.lib binary
+*.pdf binary
+*.png binary
+*.xlsx binary
+*.zip binary
ADDED .gitignore
Index: .gitignore
==================================================================
--- /dev/null
+++ .gitignore
@@ -0,0 +1,54 @@
+*.a
+*.dll
+*.dylib
+*.exe
+*.exp
+*.lib
+*.o
+*.obj
+*.pdb
+*.res
+*.sl
+*.so
+*/Makefile
+*/config.cache
+*/config.log
+*/config.status
+*/tclConfig.sh
+*/tclsh*
+*/tcltest*
+*/versions.vc
+*/version.vc
+*/libtcl.vfs
+*/libtcl_*.zip
+html
+libtommath/bn.ilg
+libtommath/bn.ind
+libtommath/pretty.build
+libtommath/tommath.src
+libtommath/*.log
+libtommath/*.pdf
+libtommath/*.pl
+libtommath/*.sh
+libtommath/doc/*
+libtommath/tombc/*
+libtommath/pre_gen/*
+libtommath/pics/*
+libtommath/mtest/*
+libtommath/logs/*
+libtommath/etc/*
+libtommath/demo/*
+libtommath/*.out
+libtommath/*.tex
+unix/autoMkindex.tcl
+unix/dltest.marker
+unix/tcl.pc
+unix/tclIndex
+unix/pkgs/*
+win/Debug*
+win/Release*
+win/*.manifest
+win/pkgs/*
+win/coffbase.txt
+win/tcl.hpj
+win/nmhlp-out.txt
ADDED libtommath/LICENSE
Index: libtommath/LICENSE
==================================================================
--- /dev/null
+++ libtommath/LICENSE
@@ -0,0 +1,26 @@
+ The LibTom license
+
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to
ADDED libtommath/README.md
Index: libtommath/README.md
==================================================================
--- /dev/null
+++ libtommath/README.md
@@ -0,0 +1,44 @@
+# libtommath
+
+This is the git repository for [LibTomMath](http://www.libtom.net/LibTomMath/), a free open source portable number theoretic multiple-precision integer (MPI) library written entirely in C.
+
+## Build Status
+
+### Travis CI
+
+master: [![Build Status](https://api.travis-ci.org/libtom/libtommath.png?branch=master)](https://travis-ci.org/libtom/libtommath)
+
+develop: [![Build Status](https://api.travis-ci.org/libtom/libtommath.png?branch=develop)](https://travis-ci.org/libtom/libtommath)
+
+### AppVeyor
+
+master: [![Build status](https://ci.appveyor.com/api/projects/status/b80lpolw3i8m6hsh/branch/master?svg=true)](https://ci.appveyor.com/project/libtom/libtommath/branch/master)
+
+develop: [![Build status](https://ci.appveyor.com/api/projects/status/b80lpolw3i8m6hsh/branch/develop?svg=true)](https://ci.appveyor.com/project/libtom/libtommath/branch/develop)
+
+### ABI Laboratory
+
+API/ABI changes: [check here](https://abi-laboratory.pro/tracker/timeline/libtommath/)
+
+## Summary
+
+The `develop` branch contains the in-development version. Stable releases are tagged.
+
+Documentation is built from the LaTeX file `bn.tex`. There is also limited documentation in `tommath.h`.
+There is also a document, `tommath.pdf`, which describes the goals of the project and many of the algorithms used.
+
+The project can be build by using `make`. Along with the usual `make`, `make clean` and `make install`,
+there are several other build targets, see the makefile for details.
+There are also makefiles for certain specific platforms.
+
+## Testing
+
+Tests are located in `demo/` and can be built in two flavors.
+* `make test` creates a stand-alone test binary that executes several test routines.
+* `make mtest_opponent` creates a test binary that is intended to be run against `mtest`.
+ `mtest` can be built with `make mtest` and test execution is done like `./mtest/mtest | ./mtest_opponent`.
+ `mtest` is creating test vectors using an alternative MPI library and `test` is consuming these vectors to verify correct behavior of ltm
+
+## Building and Installing
+
+Building is straightforward for GNU Linux only, the section "Building LibTomMath" in the documentation in `doc/bn.pdf` has the details.
ADDED libtommath/appveyor.yml
Index: libtommath/appveyor.yml
==================================================================
--- /dev/null
+++ libtommath/appveyor.yml
@@ -0,0 +1,20 @@
+version: 1.2.1-{build}
+branches:
+ only:
+ - master
+ - develop
+ - /^release/
+ - /^travis/
+image:
+- Visual Studio 2019
+- Visual Studio 2017
+- Visual Studio 2015
+build_script:
+- cmd: >-
+ if "Visual Studio 2019"=="%APPVEYOR_BUILD_WORKER_IMAGE%" call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"
+ if "Visual Studio 2017"=="%APPVEYOR_BUILD_WORKER_IMAGE%" call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat"
+ if "Visual Studio 2015"=="%APPVEYOR_BUILD_WORKER_IMAGE%" call "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x64
+ if "Visual Studio 2015"=="%APPVEYOR_BUILD_WORKER_IMAGE%" call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86_amd64
+ nmake -f makefile.msvc all
+test_script:
+- cmd: test.exe
ADDED libtommath/astylerc
Index: libtommath/astylerc
==================================================================
--- /dev/null
+++ libtommath/astylerc
@@ -0,0 +1,30 @@
+# Artistic Style, see http://astyle.sourceforge.net/
+# full documentation, see: http://astyle.sourceforge.net/astyle.html
+#
+# usage:
+# astyle --options=astylerc *.[ch]
+
+# Do not create backup, annonying in the times of git
+suffix=none
+
+## Bracket Style Options
+style=kr
+
+## Tab Options
+indent=spaces=3
+
+## Bracket Modify Options
+
+## Indentation Options
+min-conditional-indent=0
+
+## Padding Options
+pad-header
+unpad-paren
+align-pointer=name
+
+## Formatting Options
+break-after-logical
+max-code-length=120
+convert-tabs
+mode=c
ADDED libtommath/bn_cutoffs.c
Index: libtommath/bn_cutoffs.c
==================================================================
--- /dev/null
+++ libtommath/bn_cutoffs.c
@@ -0,0 +1,14 @@
+#include "tommath_private.h"
+#ifdef BN_CUTOFFS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#ifndef MP_FIXED_CUTOFFS
+#include "tommath_cutoffs.h"
+int KARATSUBA_MUL_CUTOFF = MP_DEFAULT_KARATSUBA_MUL_CUTOFF,
+ KARATSUBA_SQR_CUTOFF = MP_DEFAULT_KARATSUBA_SQR_CUTOFF,
+ TOOM_MUL_CUTOFF = MP_DEFAULT_TOOM_MUL_CUTOFF,
+ TOOM_SQR_CUTOFF = MP_DEFAULT_TOOM_SQR_CUTOFF;
+#endif
+
+#endif
ADDED libtommath/bn_deprecated.c
Index: libtommath/bn_deprecated.c
==================================================================
--- /dev/null
+++ libtommath/bn_deprecated.c
@@ -0,0 +1,321 @@
+#include "tommath_private.h"
+#ifdef BN_DEPRECATED_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#ifdef BN_MP_GET_BIT_C
+int mp_get_bit(const mp_int *a, int b)
+{
+ if (b < 0) {
+ return MP_VAL;
+ }
+ return (s_mp_get_bit(a, (unsigned int)b) == MP_YES) ? MP_YES : MP_NO;
+}
+#endif
+#ifdef BN_MP_JACOBI_C
+mp_err mp_jacobi(const mp_int *a, const mp_int *n, int *c)
+{
+ if (a->sign == MP_NEG) {
+ return MP_VAL;
+ }
+ if (mp_cmp_d(n, 0uL) != MP_GT) {
+ return MP_VAL;
+ }
+ return mp_kronecker(a, n, c);
+}
+#endif
+#ifdef BN_MP_PRIME_RANDOM_EX_C
+mp_err mp_prime_random_ex(mp_int *a, int t, int size, int flags, private_mp_prime_callback cb, void *dat)
+{
+ return s_mp_prime_random_ex(a, t, size, flags, cb, dat);
+}
+#endif
+#ifdef BN_MP_RAND_DIGIT_C
+mp_err mp_rand_digit(mp_digit *r)
+{
+ mp_err err = s_mp_rand_source(r, sizeof(mp_digit));
+ *r &= MP_MASK;
+ return err;
+}
+#endif
+#ifdef BN_FAST_MP_INVMOD_C
+mp_err fast_mp_invmod(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ return s_mp_invmod_fast(a, b, c);
+}
+#endif
+#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
+mp_err fast_mp_montgomery_reduce(mp_int *x, const mp_int *n, mp_digit rho)
+{
+ return s_mp_montgomery_reduce_fast(x, n, rho);
+}
+#endif
+#ifdef BN_FAST_S_MP_MUL_DIGS_C
+mp_err fast_s_mp_mul_digs(const mp_int *a, const mp_int *b, mp_int *c, int digs)
+{
+ return s_mp_mul_digs_fast(a, b, c, digs);
+}
+#endif
+#ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C
+mp_err fast_s_mp_mul_high_digs(const mp_int *a, const mp_int *b, mp_int *c, int digs)
+{
+ return s_mp_mul_high_digs_fast(a, b, c, digs);
+}
+#endif
+#ifdef BN_FAST_S_MP_SQR_C
+mp_err fast_s_mp_sqr(const mp_int *a, mp_int *b)
+{
+ return s_mp_sqr_fast(a, b);
+}
+#endif
+#ifdef BN_MP_BALANCE_MUL_C
+mp_err mp_balance_mul(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ return s_mp_balance_mul(a, b, c);
+}
+#endif
+#ifdef BN_MP_EXPTMOD_FAST_C
+mp_err mp_exptmod_fast(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y, int redmode)
+{
+ return s_mp_exptmod_fast(G, X, P, Y, redmode);
+}
+#endif
+#ifdef BN_MP_INVMOD_SLOW_C
+mp_err mp_invmod_slow(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ return s_mp_invmod_slow(a, b, c);
+}
+#endif
+#ifdef BN_MP_KARATSUBA_MUL_C
+mp_err mp_karatsuba_mul(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ return s_mp_karatsuba_mul(a, b, c);
+}
+#endif
+#ifdef BN_MP_KARATSUBA_SQR_C
+mp_err mp_karatsuba_sqr(const mp_int *a, mp_int *b)
+{
+ return s_mp_karatsuba_sqr(a, b);
+}
+#endif
+#ifdef BN_MP_TOOM_MUL_C
+mp_err mp_toom_mul(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ return s_mp_toom_mul(a, b, c);
+}
+#endif
+#ifdef BN_MP_TOOM_SQR_C
+mp_err mp_toom_sqr(const mp_int *a, mp_int *b)
+{
+ return s_mp_toom_sqr(a, b);
+}
+#endif
+#ifdef S_MP_REVERSE_C
+void bn_reverse(unsigned char *s, int len)
+{
+ if (len > 0) {
+ s_mp_reverse(s, (size_t)len);
+ }
+}
+#endif
+#ifdef BN_MP_TC_AND_C
+mp_err mp_tc_and(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ return mp_and(a, b, c);
+}
+#endif
+#ifdef BN_MP_TC_OR_C
+mp_err mp_tc_or(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ return mp_or(a, b, c);
+}
+#endif
+#ifdef BN_MP_TC_XOR_C
+mp_err mp_tc_xor(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ return mp_xor(a, b, c);
+}
+#endif
+#ifdef BN_MP_TC_DIV_2D_C
+mp_err mp_tc_div_2d(const mp_int *a, int b, mp_int *c)
+{
+ return mp_signed_rsh(a, b, c);
+}
+#endif
+#ifdef BN_MP_INIT_SET_INT_C
+mp_err mp_init_set_int(mp_int *a, unsigned long b)
+{
+ return mp_init_u32(a, (uint32_t)b);
+}
+#endif
+#ifdef BN_MP_SET_INT_C
+mp_err mp_set_int(mp_int *a, unsigned long b)
+{
+ mp_set_u32(a, (uint32_t)b);
+ return MP_OKAY;
+}
+#endif
+#ifdef BN_MP_SET_LONG_C
+mp_err mp_set_long(mp_int *a, unsigned long b)
+{
+ mp_set_u64(a, b);
+ return MP_OKAY;
+}
+#endif
+#ifdef BN_MP_SET_LONG_LONG_C
+mp_err mp_set_long_long(mp_int *a, unsigned long long b)
+{
+ mp_set_u64(a, b);
+ return MP_OKAY;
+}
+#endif
+#ifdef BN_MP_GET_INT_C
+unsigned long mp_get_int(const mp_int *a)
+{
+ return (unsigned long)mp_get_mag_u32(a);
+}
+#endif
+#ifdef BN_MP_GET_LONG_C
+unsigned long mp_get_long(const mp_int *a)
+{
+ return (unsigned long)mp_get_mag_ul(a);
+}
+#endif
+#ifdef BN_MP_GET_LONG_LONG_C
+unsigned long long mp_get_long_long(const mp_int *a)
+{
+ return mp_get_mag_ull(a);
+}
+#endif
+#ifdef BN_MP_PRIME_IS_DIVISIBLE_C
+mp_err mp_prime_is_divisible(const mp_int *a, mp_bool *result)
+{
+ return s_mp_prime_is_divisible(a, result);
+}
+#endif
+#ifdef BN_MP_EXPT_D_EX_C
+mp_err mp_expt_d_ex(const mp_int *a, mp_digit b, mp_int *c, int fast)
+{
+ (void)fast;
+ if (b > MP_MIN(MP_DIGIT_MAX, UINT32_MAX)) {
+ return MP_VAL;
+ }
+ return mp_expt_u32(a, (uint32_t)b, c);
+}
+#endif
+#ifdef BN_MP_EXPT_D_C
+mp_err mp_expt_d(const mp_int *a, mp_digit b, mp_int *c)
+{
+ if (b > MP_MIN(MP_DIGIT_MAX, UINT32_MAX)) {
+ return MP_VAL;
+ }
+ return mp_expt_u32(a, (uint32_t)b, c);
+}
+#endif
+#ifdef BN_MP_N_ROOT_EX_C
+mp_err mp_n_root_ex(const mp_int *a, mp_digit b, mp_int *c, int fast)
+{
+ (void)fast;
+ if (b > MP_MIN(MP_DIGIT_MAX, UINT32_MAX)) {
+ return MP_VAL;
+ }
+ return mp_root_u32(a, (uint32_t)b, c);
+}
+#endif
+#ifdef BN_MP_N_ROOT_C
+mp_err mp_n_root(const mp_int *a, mp_digit b, mp_int *c)
+{
+ if (b > MP_MIN(MP_DIGIT_MAX, UINT32_MAX)) {
+ return MP_VAL;
+ }
+ return mp_root_u32(a, (uint32_t)b, c);
+}
+#endif
+#ifdef BN_MP_UNSIGNED_BIN_SIZE_C
+int mp_unsigned_bin_size(const mp_int *a)
+{
+ return (int)mp_ubin_size(a);
+}
+#endif
+#ifdef BN_MP_READ_UNSIGNED_BIN_C
+mp_err mp_read_unsigned_bin(mp_int *a, const unsigned char *b, int c)
+{
+ return mp_from_ubin(a, b, (size_t) c);
+}
+#endif
+#ifdef BN_MP_TO_UNSIGNED_BIN_C
+mp_err mp_to_unsigned_bin(const mp_int *a, unsigned char *b)
+{
+ return mp_to_ubin(a, b, SIZE_MAX, NULL);
+}
+#endif
+#ifdef BN_MP_TO_UNSIGNED_BIN_N_C
+mp_err mp_to_unsigned_bin_n(const mp_int *a, unsigned char *b, unsigned long *outlen)
+{
+ size_t n = mp_ubin_size(a);
+ if (*outlen < (unsigned long)n) {
+ return MP_VAL;
+ }
+ *outlen = (unsigned long)n;
+ return mp_to_ubin(a, b, n, NULL);
+}
+#endif
+#ifdef BN_MP_SIGNED_BIN_SIZE_C
+int mp_signed_bin_size(const mp_int *a)
+{
+ return (int)mp_sbin_size(a);
+}
+#endif
+#ifdef BN_MP_READ_SIGNED_BIN_C
+mp_err mp_read_signed_bin(mp_int *a, const unsigned char *b, int c)
+{
+ return mp_from_sbin(a, b, (size_t) c);
+}
+#endif
+#ifdef BN_MP_TO_SIGNED_BIN_C
+mp_err mp_to_signed_bin(const mp_int *a, unsigned char *b)
+{
+ return mp_to_sbin(a, b, SIZE_MAX, NULL);
+}
+#endif
+#ifdef BN_MP_TO_SIGNED_BIN_N_C
+mp_err mp_to_signed_bin_n(const mp_int *a, unsigned char *b, unsigned long *outlen)
+{
+ size_t n = mp_sbin_size(a);
+ if (*outlen < (unsigned long)n) {
+ return MP_VAL;
+ }
+ *outlen = (unsigned long)n;
+ return mp_to_sbin(a, b, n, NULL);
+}
+#endif
+#ifdef BN_MP_TORADIX_N_C
+mp_err mp_toradix_n(const mp_int *a, char *str, int radix, int maxlen)
+{
+ if (maxlen < 0) {
+ return MP_VAL;
+ }
+ return mp_to_radix(a, str, (size_t)maxlen, NULL, radix);
+}
+#endif
+#ifdef BN_MP_TORADIX_C
+mp_err mp_toradix(const mp_int *a, char *str, int radix)
+{
+ return mp_to_radix(a, str, SIZE_MAX, NULL, radix);
+}
+#endif
+#ifdef BN_MP_IMPORT_C
+mp_err mp_import(mp_int *rop, size_t count, int order, size_t size, int endian, size_t nails,
+ const void *op)
+{
+ return mp_unpack(rop, count, order, size, endian, nails, op);
+}
+#endif
+#ifdef BN_MP_EXPORT_C
+mp_err mp_export(void *rop, size_t *countp, int order, size_t size,
+ int endian, size_t nails, const mp_int *op)
+{
+ return mp_pack(rop, SIZE_MAX, countp, order, size, endian, nails, op);
+}
+#endif
+#endif
ADDED libtommath/bn_mp_2expt.c
Index: libtommath/bn_mp_2expt.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_2expt.c
@@ -0,0 +1,35 @@
+#include "tommath_private.h"
+#ifdef BN_MP_2EXPT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* computes a = 2**b
+ *
+ * Simple algorithm which zeroes the int, grows it then just sets one bit
+ * as required.
+ */
+mp_err mp_2expt(mp_int *a, int b)
+{
+ mp_err err;
+
+ if (b < 0) {
+ return MP_VAL;
+ }
+
+ /* zero a as per default */
+ mp_zero(a);
+
+ /* grow a to accomodate the single bit */
+ if ((err = mp_grow(a, (b / MP_DIGIT_BIT) + 1)) != MP_OKAY) {
+ return err;
+ }
+
+ /* set the used count of where the bit will go */
+ a->used = (b / MP_DIGIT_BIT) + 1;
+
+ /* put the single bit in its place */
+ a->dp[b / MP_DIGIT_BIT] = (mp_digit)1 << (mp_digit)(b % MP_DIGIT_BIT);
+
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_mp_abs.c
Index: libtommath/bn_mp_abs.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_abs.c
@@ -0,0 +1,26 @@
+#include "tommath_private.h"
+#ifdef BN_MP_ABS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* b = |a|
+ *
+ * Simple function copies the input and fixes the sign to positive
+ */
+mp_err mp_abs(const mp_int *a, mp_int *b)
+{
+ mp_err err;
+
+ /* copy a to b */
+ if (a != b) {
+ if ((err = mp_copy(a, b)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ /* force the sign of b to positive */
+ b->sign = MP_ZPOS;
+
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_mp_add.c
Index: libtommath/bn_mp_add.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_add.c
@@ -0,0 +1,38 @@
+#include "tommath_private.h"
+#ifdef BN_MP_ADD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* high level addition (handles signs) */
+mp_err mp_add(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ mp_sign sa, sb;
+ mp_err err;
+
+ /* get sign of both inputs */
+ sa = a->sign;
+ sb = b->sign;
+
+ /* handle two cases, not four */
+ if (sa == sb) {
+ /* both positive or both negative */
+ /* add their magnitudes, copy the sign */
+ c->sign = sa;
+ err = s_mp_add(a, b, c);
+ } else {
+ /* one positive, the other negative */
+ /* subtract the one with the greater magnitude from */
+ /* the one of the lesser magnitude. The result gets */
+ /* the sign of the one with the greater magnitude. */
+ if (mp_cmp_mag(a, b) == MP_LT) {
+ c->sign = sb;
+ err = s_mp_sub(b, a, c);
+ } else {
+ c->sign = sa;
+ err = s_mp_sub(a, b, c);
+ }
+ }
+ return err;
+}
+
+#endif
ADDED libtommath/bn_mp_add_d.c
Index: libtommath/bn_mp_add_d.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_add_d.c
@@ -0,0 +1,89 @@
+#include "tommath_private.h"
+#ifdef BN_MP_ADD_D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* single digit addition */
+mp_err mp_add_d(const mp_int *a, mp_digit b, mp_int *c)
+{
+ mp_err err;
+ int ix, oldused;
+ mp_digit *tmpa, *tmpc;
+
+ /* grow c as required */
+ if (c->alloc < (a->used + 1)) {
+ if ((err = mp_grow(c, a->used + 1)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ /* if a is negative and |a| >= b, call c = |a| - b */
+ if ((a->sign == MP_NEG) && ((a->used > 1) || (a->dp[0] >= b))) {
+ mp_int a_ = *a;
+ /* temporarily fix sign of a */
+ a_.sign = MP_ZPOS;
+
+ /* c = |a| - b */
+ err = mp_sub_d(&a_, b, c);
+
+ /* fix sign */
+ c->sign = MP_NEG;
+
+ /* clamp */
+ mp_clamp(c);
+
+ return err;
+ }
+
+ /* old number of used digits in c */
+ oldused = c->used;
+
+ /* source alias */
+ tmpa = a->dp;
+
+ /* destination alias */
+ tmpc = c->dp;
+
+ /* if a is positive */
+ if (a->sign == MP_ZPOS) {
+ /* add digits, mu is carry */
+ mp_digit mu = b;
+ for (ix = 0; ix < a->used; ix++) {
+ *tmpc = *tmpa++ + mu;
+ mu = *tmpc >> MP_DIGIT_BIT;
+ *tmpc++ &= MP_MASK;
+ }
+ /* set final carry */
+ ix++;
+ *tmpc++ = mu;
+
+ /* setup size */
+ c->used = a->used + 1;
+ } else {
+ /* a was negative and |a| < b */
+ c->used = 1;
+
+ /* the result is a single digit */
+ if (a->used == 1) {
+ *tmpc++ = b - a->dp[0];
+ } else {
+ *tmpc++ = b;
+ }
+
+ /* setup count so the clearing of oldused
+ * can fall through correctly
+ */
+ ix = 1;
+ }
+
+ /* sign always positive */
+ c->sign = MP_ZPOS;
+
+ /* now zero to oldused */
+ MP_ZERO_DIGITS(tmpc, oldused - ix);
+ mp_clamp(c);
+
+ return MP_OKAY;
+}
+
+#endif
ADDED libtommath/bn_mp_addmod.c
Index: libtommath/bn_mp_addmod.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_addmod.c
@@ -0,0 +1,25 @@
+#include "tommath_private.h"
+#ifdef BN_MP_ADDMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* d = a + b (mod c) */
+mp_err mp_addmod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d)
+{
+ mp_err err;
+ mp_int t;
+
+ if ((err = mp_init(&t)) != MP_OKAY) {
+ return err;
+ }
+
+ if ((err = mp_add(a, b, &t)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ err = mp_mod(&t, c, d);
+
+LBL_ERR:
+ mp_clear(&t);
+ return err;
+}
+#endif
ADDED libtommath/bn_mp_and.c
Index: libtommath/bn_mp_and.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_and.c
@@ -0,0 +1,56 @@
+#include "tommath_private.h"
+#ifdef BN_MP_AND_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* two complement and */
+mp_err mp_and(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ int used = MP_MAX(a->used, b->used) + 1, i;
+ mp_err err;
+ mp_digit ac = 1, bc = 1, cc = 1;
+ mp_sign csign = ((a->sign == MP_NEG) && (b->sign == MP_NEG)) ? MP_NEG : MP_ZPOS;
+
+ if (c->alloc < used) {
+ if ((err = mp_grow(c, used)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ for (i = 0; i < used; i++) {
+ mp_digit x, y;
+
+ /* convert to two complement if negative */
+ if (a->sign == MP_NEG) {
+ ac += (i >= a->used) ? MP_MASK : (~a->dp[i] & MP_MASK);
+ x = ac & MP_MASK;
+ ac >>= MP_DIGIT_BIT;
+ } else {
+ x = (i >= a->used) ? 0uL : a->dp[i];
+ }
+
+ /* convert to two complement if negative */
+ if (b->sign == MP_NEG) {
+ bc += (i >= b->used) ? MP_MASK : (~b->dp[i] & MP_MASK);
+ y = bc & MP_MASK;
+ bc >>= MP_DIGIT_BIT;
+ } else {
+ y = (i >= b->used) ? 0uL : b->dp[i];
+ }
+
+ c->dp[i] = x & y;
+
+ /* convert to to sign-magnitude if negative */
+ if (csign == MP_NEG) {
+ cc += ~c->dp[i] & MP_MASK;
+ c->dp[i] = cc & MP_MASK;
+ cc >>= MP_DIGIT_BIT;
+ }
+ }
+
+ c->used = used;
+ c->sign = csign;
+ mp_clamp(c);
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_mp_clamp.c
Index: libtommath/bn_mp_clamp.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_clamp.c
@@ -0,0 +1,27 @@
+#include "tommath_private.h"
+#ifdef BN_MP_CLAMP_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* trim unused digits
+ *
+ * This is used to ensure that leading zero digits are
+ * trimed and the leading "used" digit will be non-zero
+ * Typically very fast. Also fixes the sign if there
+ * are no more leading digits
+ */
+void mp_clamp(mp_int *a)
+{
+ /* decrease used while the most significant digit is
+ * zero.
+ */
+ while ((a->used > 0) && (a->dp[a->used - 1] == 0u)) {
+ --(a->used);
+ }
+
+ /* reset the sign flag if used == 0 */
+ if (a->used == 0) {
+ a->sign = MP_ZPOS;
+ }
+}
+#endif
ADDED libtommath/bn_mp_clear.c
Index: libtommath/bn_mp_clear.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_clear.c
@@ -0,0 +1,20 @@
+#include "tommath_private.h"
+#ifdef BN_MP_CLEAR_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* clear one (frees) */
+void mp_clear(mp_int *a)
+{
+ /* only do anything if a hasn't been freed previously */
+ if (a->dp != NULL) {
+ /* free ram */
+ MP_FREE_DIGITS(a->dp, a->alloc);
+
+ /* reset members to make debugging easier */
+ a->dp = NULL;
+ a->alloc = a->used = 0;
+ a->sign = MP_ZPOS;
+ }
+}
+#endif
ADDED libtommath/bn_mp_clear_multi.c
Index: libtommath/bn_mp_clear_multi.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_clear_multi.c
@@ -0,0 +1,19 @@
+#include "tommath_private.h"
+#ifdef BN_MP_CLEAR_MULTI_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#include
+
+void mp_clear_multi(mp_int *mp, ...)
+{
+ mp_int *next_mp = mp;
+ va_list args;
+ va_start(args, mp);
+ while (next_mp != NULL) {
+ mp_clear(next_mp);
+ next_mp = va_arg(args, mp_int *);
+ }
+ va_end(args);
+}
+#endif
ADDED libtommath/bn_mp_cmp.c
Index: libtommath/bn_mp_cmp.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_cmp.c
@@ -0,0 +1,26 @@
+#include "tommath_private.h"
+#ifdef BN_MP_CMP_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* compare two ints (signed)*/
+mp_ord mp_cmp(const mp_int *a, const mp_int *b)
+{
+ /* compare based on sign */
+ if (a->sign != b->sign) {
+ if (a->sign == MP_NEG) {
+ return MP_LT;
+ } else {
+ return MP_GT;
+ }
+ }
+
+ /* compare digits */
+ if (a->sign == MP_NEG) {
+ /* if negative compare opposite direction */
+ return mp_cmp_mag(b, a);
+ } else {
+ return mp_cmp_mag(a, b);
+ }
+}
+#endif
ADDED libtommath/bn_mp_cmp_d.c
Index: libtommath/bn_mp_cmp_d.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_cmp_d.c
@@ -0,0 +1,28 @@
+#include "tommath_private.h"
+#ifdef BN_MP_CMP_D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* compare a digit */
+mp_ord mp_cmp_d(const mp_int *a, mp_digit b)
+{
+ /* compare based on sign */
+ if (a->sign == MP_NEG) {
+ return MP_LT;
+ }
+
+ /* compare based on magnitude */
+ if (a->used > 1) {
+ return MP_GT;
+ }
+
+ /* compare the only digit of a to b */
+ if (a->dp[0] > b) {
+ return MP_GT;
+ } else if (a->dp[0] < b) {
+ return MP_LT;
+ } else {
+ return MP_EQ;
+ }
+}
+#endif
ADDED libtommath/bn_mp_cmp_mag.c
Index: libtommath/bn_mp_cmp_mag.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_cmp_mag.c
@@ -0,0 +1,39 @@
+#include "tommath_private.h"
+#ifdef BN_MP_CMP_MAG_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* compare maginitude of two ints (unsigned) */
+mp_ord mp_cmp_mag(const mp_int *a, const mp_int *b)
+{
+ int n;
+ const mp_digit *tmpa, *tmpb;
+
+ /* compare based on # of non-zero digits */
+ if (a->used > b->used) {
+ return MP_GT;
+ }
+
+ if (a->used < b->used) {
+ return MP_LT;
+ }
+
+ /* alias for a */
+ tmpa = a->dp + (a->used - 1);
+
+ /* alias for b */
+ tmpb = b->dp + (a->used - 1);
+
+ /* compare based on digits */
+ for (n = 0; n < a->used; ++n, --tmpa, --tmpb) {
+ if (*tmpa > *tmpb) {
+ return MP_GT;
+ }
+
+ if (*tmpa < *tmpb) {
+ return MP_LT;
+ }
+ }
+ return MP_EQ;
+}
+#endif
ADDED libtommath/bn_mp_cnt_lsb.c
Index: libtommath/bn_mp_cnt_lsb.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_cnt_lsb.c
@@ -0,0 +1,37 @@
+#include "tommath_private.h"
+#ifdef BN_MP_CNT_LSB_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+static const int lnz[16] = {
+ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+};
+
+/* Counts the number of lsbs which are zero before the first zero bit */
+int mp_cnt_lsb(const mp_int *a)
+{
+ int x;
+ mp_digit q, qq;
+
+ /* easy out */
+ if (MP_IS_ZERO(a)) {
+ return 0;
+ }
+
+ /* scan lower digits until non-zero */
+ for (x = 0; (x < a->used) && (a->dp[x] == 0u); x++) {}
+ q = a->dp[x];
+ x *= MP_DIGIT_BIT;
+
+ /* now scan this digit until a 1 is found */
+ if ((q & 1u) == 0u) {
+ do {
+ qq = q & 15u;
+ x += lnz[qq];
+ q >>= 4;
+ } while (qq == 0u);
+ }
+ return x;
+}
+
+#endif
ADDED libtommath/bn_mp_complement.c
Index: libtommath/bn_mp_complement.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_complement.c
@@ -0,0 +1,12 @@
+#include "tommath_private.h"
+#ifdef BN_MP_COMPLEMENT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* b = ~a */
+mp_err mp_complement(const mp_int *a, mp_int *b)
+{
+ mp_err err = mp_neg(a, b);
+ return (err == MP_OKAY) ? mp_sub_d(b, 1uL, b) : err;
+}
+#endif
ADDED libtommath/bn_mp_copy.c
Index: libtommath/bn_mp_copy.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_copy.c
@@ -0,0 +1,47 @@
+#include "tommath_private.h"
+#ifdef BN_MP_COPY_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* copy, b = a */
+mp_err mp_copy(const mp_int *a, mp_int *b)
+{
+ int n;
+ mp_digit *tmpa, *tmpb;
+ mp_err err;
+
+ /* if dst == src do nothing */
+ if (a == b) {
+ return MP_OKAY;
+ }
+
+ /* grow dest */
+ if (b->alloc < a->used) {
+ if ((err = mp_grow(b, a->used)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ /* zero b and copy the parameters over */
+ /* pointer aliases */
+
+ /* source */
+ tmpa = a->dp;
+
+ /* destination */
+ tmpb = b->dp;
+
+ /* copy all the digits */
+ for (n = 0; n < a->used; n++) {
+ *tmpb++ = *tmpa++;
+ }
+
+ /* clear high digits */
+ MP_ZERO_DIGITS(tmpb, b->used - n);
+
+ /* copy used count and sign */
+ b->used = a->used;
+ b->sign = a->sign;
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_mp_count_bits.c
Index: libtommath/bn_mp_count_bits.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_count_bits.c
@@ -0,0 +1,28 @@
+#include "tommath_private.h"
+#ifdef BN_MP_COUNT_BITS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* returns the number of bits in an int */
+int mp_count_bits(const mp_int *a)
+{
+ int r;
+ mp_digit q;
+
+ /* shortcut */
+ if (MP_IS_ZERO(a)) {
+ return 0;
+ }
+
+ /* get number of digits and add that */
+ r = (a->used - 1) * MP_DIGIT_BIT;
+
+ /* take the last digit and count the bits in it */
+ q = a->dp[a->used - 1];
+ while (q > 0u) {
+ ++r;
+ q >>= 1u;
+ }
+ return r;
+}
+#endif
ADDED libtommath/bn_mp_decr.c
Index: libtommath/bn_mp_decr.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_decr.c
@@ -0,0 +1,34 @@
+#include "tommath_private.h"
+#ifdef BN_MP_DECR_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* Decrement "a" by one like "a--". Changes input! */
+mp_err mp_decr(mp_int *a)
+{
+ if (MP_IS_ZERO(a)) {
+ mp_set(a,1uL);
+ a->sign = MP_NEG;
+ return MP_OKAY;
+ } else if (a->sign == MP_NEG) {
+ mp_err err;
+ a->sign = MP_ZPOS;
+ if ((err = mp_incr(a)) != MP_OKAY) {
+ return err;
+ }
+ /* There is no -0 in LTM */
+ if (!MP_IS_ZERO(a)) {
+ a->sign = MP_NEG;
+ }
+ return MP_OKAY;
+ } else if (a->dp[0] > 1uL) {
+ a->dp[0]--;
+ if (a->dp[0] == 0u) {
+ mp_zero(a);
+ }
+ return MP_OKAY;
+ } else {
+ return mp_sub_d(a, 1uL,a);
+ }
+}
+#endif
ADDED libtommath/bn_mp_div.c
Index: libtommath/bn_mp_div.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_div.c
@@ -0,0 +1,250 @@
+#include "tommath_private.h"
+#ifdef BN_MP_DIV_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#ifdef BN_MP_DIV_SMALL
+
+/* slower bit-bang division... also smaller */
+mp_err mp_div(const mp_int *a, const mp_int *b, mp_int *c, mp_int *d)
+{
+ mp_int ta, tb, tq, q;
+ int n, n2;
+ mp_err err;
+
+ /* is divisor zero ? */
+ if (MP_IS_ZERO(b)) {
+ return MP_VAL;
+ }
+
+ /* if a < b then q=0, r = a */
+ if (mp_cmp_mag(a, b) == MP_LT) {
+ if (d != NULL) {
+ err = mp_copy(a, d);
+ } else {
+ err = MP_OKAY;
+ }
+ if (c != NULL) {
+ mp_zero(c);
+ }
+ return err;
+ }
+
+ /* init our temps */
+ if ((err = mp_init_multi(&ta, &tb, &tq, &q, NULL)) != MP_OKAY) {
+ return err;
+ }
+
+
+ mp_set(&tq, 1uL);
+ n = mp_count_bits(a) - mp_count_bits(b);
+ if ((err = mp_abs(a, &ta)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_abs(b, &tb)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_mul_2d(&tq, n, &tq)) != MP_OKAY) goto LBL_ERR;
+
+ while (n-- >= 0) {
+ if (mp_cmp(&tb, &ta) != MP_GT) {
+ if ((err = mp_sub(&ta, &tb, &ta)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_add(&q, &tq, &q)) != MP_OKAY) goto LBL_ERR;
+ }
+ if ((err = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY) goto LBL_ERR;
+ }
+
+ /* now q == quotient and ta == remainder */
+ n = a->sign;
+ n2 = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
+ if (c != NULL) {
+ mp_exch(c, &q);
+ c->sign = MP_IS_ZERO(c) ? MP_ZPOS : n2;
+ }
+ if (d != NULL) {
+ mp_exch(d, &ta);
+ d->sign = MP_IS_ZERO(d) ? MP_ZPOS : n;
+ }
+LBL_ERR:
+ mp_clear_multi(&ta, &tb, &tq, &q, NULL);
+ return err;
+}
+
+#else
+
+/* integer signed division.
+ * c*b + d == a [e.g. a/b, c=quotient, d=remainder]
+ * HAC pp.598 Algorithm 14.20
+ *
+ * Note that the description in HAC is horribly
+ * incomplete. For example, it doesn't consider
+ * the case where digits are removed from 'x' in
+ * the inner loop. It also doesn't consider the
+ * case that y has fewer than three digits, etc..
+ *
+ * The overall algorithm is as described as
+ * 14.20 from HAC but fixed to treat these cases.
+*/
+mp_err mp_div(const mp_int *a, const mp_int *b, mp_int *c, mp_int *d)
+{
+ mp_int q, x, y, t1, t2;
+ int n, t, i, norm;
+ mp_sign neg;
+ mp_err err;
+
+ /* is divisor zero ? */
+ if (MP_IS_ZERO(b)) {
+ return MP_VAL;
+ }
+
+ /* if a < b then q=0, r = a */
+ if (mp_cmp_mag(a, b) == MP_LT) {
+ if (d != NULL) {
+ err = mp_copy(a, d);
+ } else {
+ err = MP_OKAY;
+ }
+ if (c != NULL) {
+ mp_zero(c);
+ }
+ return err;
+ }
+
+ if ((err = mp_init_size(&q, a->used + 2)) != MP_OKAY) {
+ return err;
+ }
+ q.used = a->used + 2;
+
+ if ((err = mp_init(&t1)) != MP_OKAY) goto LBL_Q;
+
+ if ((err = mp_init(&t2)) != MP_OKAY) goto LBL_T1;
+
+ if ((err = mp_init_copy(&x, a)) != MP_OKAY) goto LBL_T2;
+
+ if ((err = mp_init_copy(&y, b)) != MP_OKAY) goto LBL_X;
+
+ /* fix the sign */
+ neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
+ x.sign = y.sign = MP_ZPOS;
+
+ /* normalize both x and y, ensure that y >= b/2, [b == 2**MP_DIGIT_BIT] */
+ norm = mp_count_bits(&y) % MP_DIGIT_BIT;
+ if (norm < (MP_DIGIT_BIT - 1)) {
+ norm = (MP_DIGIT_BIT - 1) - norm;
+ if ((err = mp_mul_2d(&x, norm, &x)) != MP_OKAY) goto LBL_Y;
+ if ((err = mp_mul_2d(&y, norm, &y)) != MP_OKAY) goto LBL_Y;
+ } else {
+ norm = 0;
+ }
+
+ /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */
+ n = x.used - 1;
+ t = y.used - 1;
+
+ /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */
+ /* y = y*b**{n-t} */
+ if ((err = mp_lshd(&y, n - t)) != MP_OKAY) goto LBL_Y;
+
+ while (mp_cmp(&x, &y) != MP_LT) {
+ ++(q.dp[n - t]);
+ if ((err = mp_sub(&x, &y, &x)) != MP_OKAY) goto LBL_Y;
+ }
+
+ /* reset y by shifting it back down */
+ mp_rshd(&y, n - t);
+
+ /* step 3. for i from n down to (t + 1) */
+ for (i = n; i >= (t + 1); i--) {
+ if (i > x.used) {
+ continue;
+ }
+
+ /* step 3.1 if xi == yt then set q{i-t-1} to b-1,
+ * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */
+ if (x.dp[i] == y.dp[t]) {
+ q.dp[(i - t) - 1] = ((mp_digit)1 << (mp_digit)MP_DIGIT_BIT) - (mp_digit)1;
+ } else {
+ mp_word tmp;
+ tmp = (mp_word)x.dp[i] << (mp_word)MP_DIGIT_BIT;
+ tmp |= (mp_word)x.dp[i - 1];
+ tmp /= (mp_word)y.dp[t];
+ if (tmp > (mp_word)MP_MASK) {
+ tmp = MP_MASK;
+ }
+ q.dp[(i - t) - 1] = (mp_digit)(tmp & (mp_word)MP_MASK);
+ }
+
+ /* while (q{i-t-1} * (yt * b + y{t-1})) >
+ xi * b**2 + xi-1 * b + xi-2
+
+ do q{i-t-1} -= 1;
+ */
+ q.dp[(i - t) - 1] = (q.dp[(i - t) - 1] + 1uL) & (mp_digit)MP_MASK;
+ do {
+ q.dp[(i - t) - 1] = (q.dp[(i - t) - 1] - 1uL) & (mp_digit)MP_MASK;
+
+ /* find left hand */
+ mp_zero(&t1);
+ t1.dp[0] = ((t - 1) < 0) ? 0u : y.dp[t - 1];
+ t1.dp[1] = y.dp[t];
+ t1.used = 2;
+ if ((err = mp_mul_d(&t1, q.dp[(i - t) - 1], &t1)) != MP_OKAY) goto LBL_Y;
+
+ /* find right hand */
+ t2.dp[0] = ((i - 2) < 0) ? 0u : x.dp[i - 2];
+ t2.dp[1] = x.dp[i - 1]; /* i >= 1 always holds */
+ t2.dp[2] = x.dp[i];
+ t2.used = 3;
+ } while (mp_cmp_mag(&t1, &t2) == MP_GT);
+
+ /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */
+ if ((err = mp_mul_d(&y, q.dp[(i - t) - 1], &t1)) != MP_OKAY) goto LBL_Y;
+
+ if ((err = mp_lshd(&t1, (i - t) - 1)) != MP_OKAY) goto LBL_Y;
+
+ if ((err = mp_sub(&x, &t1, &x)) != MP_OKAY) goto LBL_Y;
+
+ /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */
+ if (x.sign == MP_NEG) {
+ if ((err = mp_copy(&y, &t1)) != MP_OKAY) goto LBL_Y;
+ if ((err = mp_lshd(&t1, (i - t) - 1)) != MP_OKAY) goto LBL_Y;
+ if ((err = mp_add(&x, &t1, &x)) != MP_OKAY) goto LBL_Y;
+
+ q.dp[(i - t) - 1] = (q.dp[(i - t) - 1] - 1uL) & MP_MASK;
+ }
+ }
+
+ /* now q is the quotient and x is the remainder
+ * [which we have to normalize]
+ */
+
+ /* get sign before writing to c */
+ x.sign = (x.used == 0) ? MP_ZPOS : a->sign;
+
+ if (c != NULL) {
+ mp_clamp(&q);
+ mp_exch(&q, c);
+ c->sign = neg;
+ }
+
+ if (d != NULL) {
+ if ((err = mp_div_2d(&x, norm, &x, NULL)) != MP_OKAY) goto LBL_Y;
+ mp_exch(&x, d);
+ }
+
+ err = MP_OKAY;
+
+LBL_Y:
+ mp_clear(&y);
+LBL_X:
+ mp_clear(&x);
+LBL_T2:
+ mp_clear(&t2);
+LBL_T1:
+ mp_clear(&t1);
+LBL_Q:
+ mp_clear(&q);
+ return err;
+}
+
+#endif
+
+#endif
ADDED libtommath/bn_mp_div_2.c
Index: libtommath/bn_mp_div_2.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_div_2.c
@@ -0,0 +1,49 @@
+#include "tommath_private.h"
+#ifdef BN_MP_DIV_2_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* b = a/2 */
+mp_err mp_div_2(const mp_int *a, mp_int *b)
+{
+ int x, oldused;
+ mp_digit r, rr, *tmpa, *tmpb;
+ mp_err err;
+
+ /* copy */
+ if (b->alloc < a->used) {
+ if ((err = mp_grow(b, a->used)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ oldused = b->used;
+ b->used = a->used;
+
+ /* source alias */
+ tmpa = a->dp + b->used - 1;
+
+ /* dest alias */
+ tmpb = b->dp + b->used - 1;
+
+ /* carry */
+ r = 0;
+ for (x = b->used - 1; x >= 0; x--) {
+ /* get the carry for the next iteration */
+ rr = *tmpa & 1u;
+
+ /* shift the current digit, add in carry and store */
+ *tmpb-- = (*tmpa-- >> 1) | (r << (MP_DIGIT_BIT - 1));
+
+ /* forward carry to next iteration */
+ r = rr;
+ }
+
+ /* zero excess digits */
+ MP_ZERO_DIGITS(b->dp + b->used, oldused - b->used);
+
+ b->sign = a->sign;
+ mp_clamp(b);
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_mp_div_2d.c
Index: libtommath/bn_mp_div_2d.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_div_2d.c
@@ -0,0 +1,71 @@
+#include "tommath_private.h"
+#ifdef BN_MP_DIV_2D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* shift right by a certain bit count (store quotient in c, optional remainder in d) */
+mp_err mp_div_2d(const mp_int *a, int b, mp_int *c, mp_int *d)
+{
+ mp_digit D, r, rr;
+ int x;
+ mp_err err;
+
+ /* if the shift count is <= 0 then we do no work */
+ if (b <= 0) {
+ err = mp_copy(a, c);
+ if (d != NULL) {
+ mp_zero(d);
+ }
+ return err;
+ }
+
+ /* copy */
+ if ((err = mp_copy(a, c)) != MP_OKAY) {
+ return err;
+ }
+ /* 'a' should not be used after here - it might be the same as d */
+
+ /* get the remainder */
+ if (d != NULL) {
+ if ((err = mp_mod_2d(a, b, d)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ /* shift by as many digits in the bit count */
+ if (b >= MP_DIGIT_BIT) {
+ mp_rshd(c, b / MP_DIGIT_BIT);
+ }
+
+ /* shift any bit count < MP_DIGIT_BIT */
+ D = (mp_digit)(b % MP_DIGIT_BIT);
+ if (D != 0u) {
+ mp_digit *tmpc, mask, shift;
+
+ /* mask */
+ mask = ((mp_digit)1 << D) - 1uL;
+
+ /* shift for lsb */
+ shift = (mp_digit)MP_DIGIT_BIT - D;
+
+ /* alias */
+ tmpc = c->dp + (c->used - 1);
+
+ /* carry */
+ r = 0;
+ for (x = c->used - 1; x >= 0; x--) {
+ /* get the lower bits of this word in a temp */
+ rr = *tmpc & mask;
+
+ /* shift the current word and mix in the carry bits from the previous word */
+ *tmpc = (*tmpc >> D) | (r << shift);
+ --tmpc;
+
+ /* set the carry to the carry bits of the current word found above */
+ r = rr;
+ }
+ }
+ mp_clamp(c);
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_mp_div_3.c
Index: libtommath/bn_mp_div_3.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_div_3.c
@@ -0,0 +1,63 @@
+#include "tommath_private.h"
+#ifdef BN_MP_DIV_3_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* divide by three (based on routine from MPI and the GMP manual) */
+mp_err mp_div_3(const mp_int *a, mp_int *c, mp_digit *d)
+{
+ mp_int q;
+ mp_word w, t;
+ mp_digit b;
+ mp_err err;
+ int ix;
+
+ /* b = 2**MP_DIGIT_BIT / 3 */
+ b = ((mp_word)1 << (mp_word)MP_DIGIT_BIT) / (mp_word)3;
+
+ if ((err = mp_init_size(&q, a->used)) != MP_OKAY) {
+ return err;
+ }
+
+ q.used = a->used;
+ q.sign = a->sign;
+ w = 0;
+ for (ix = a->used - 1; ix >= 0; ix--) {
+ w = (w << (mp_word)MP_DIGIT_BIT) | (mp_word)a->dp[ix];
+
+ if (w >= 3u) {
+ /* multiply w by [1/3] */
+ t = (w * (mp_word)b) >> (mp_word)MP_DIGIT_BIT;
+
+ /* now subtract 3 * [w/3] from w, to get the remainder */
+ w -= t+t+t;
+
+ /* fixup the remainder as required since
+ * the optimization is not exact.
+ */
+ while (w >= 3u) {
+ t += 1u;
+ w -= 3u;
+ }
+ } else {
+ t = 0;
+ }
+ q.dp[ix] = (mp_digit)t;
+ }
+
+ /* [optional] store the remainder */
+ if (d != NULL) {
+ *d = (mp_digit)w;
+ }
+
+ /* [optional] store the quotient */
+ if (c != NULL) {
+ mp_clamp(&q);
+ mp_exch(&q, c);
+ }
+ mp_clear(&q);
+
+ return err;
+}
+
+#endif
ADDED libtommath/bn_mp_div_d.c
Index: libtommath/bn_mp_div_d.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_div_d.c
@@ -0,0 +1,84 @@
+#include "tommath_private.h"
+#ifdef BN_MP_DIV_D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* single digit division (based on routine from MPI) */
+mp_err mp_div_d(const mp_int *a, mp_digit b, mp_int *c, mp_digit *d)
+{
+ mp_int q;
+ mp_word w;
+ mp_digit t;
+ mp_err err;
+ int ix;
+
+ /* cannot divide by zero */
+ if (b == 0u) {
+ return MP_VAL;
+ }
+
+ /* quick outs */
+ if ((b == 1u) || MP_IS_ZERO(a)) {
+ if (d != NULL) {
+ *d = 0;
+ }
+ if (c != NULL) {
+ return mp_copy(a, c);
+ }
+ return MP_OKAY;
+ }
+
+ /* power of two ? */
+ if ((b & (b - 1u)) == 0u) {
+ ix = 1;
+ while ((ix < MP_DIGIT_BIT) && (b != (((mp_digit)1)<dp[0] & (((mp_digit)1<<(mp_digit)ix) - 1uL);
+ }
+ if (c != NULL) {
+ return mp_div_2d(a, ix, c, NULL);
+ }
+ return MP_OKAY;
+ }
+
+ /* three? */
+ if (MP_HAS(MP_DIV_3) && (b == 3u)) {
+ return mp_div_3(a, c, d);
+ }
+
+ /* no easy answer [c'est la vie]. Just division */
+ if ((err = mp_init_size(&q, a->used)) != MP_OKAY) {
+ return err;
+ }
+
+ q.used = a->used;
+ q.sign = a->sign;
+ w = 0;
+ for (ix = a->used - 1; ix >= 0; ix--) {
+ w = (w << (mp_word)MP_DIGIT_BIT) | (mp_word)a->dp[ix];
+
+ if (w >= b) {
+ t = (mp_digit)(w / b);
+ w -= (mp_word)t * (mp_word)b;
+ } else {
+ t = 0;
+ }
+ q.dp[ix] = t;
+ }
+
+ if (d != NULL) {
+ *d = (mp_digit)w;
+ }
+
+ if (c != NULL) {
+ mp_clamp(&q);
+ mp_exch(&q, c);
+ }
+ mp_clear(&q);
+
+ return err;
+}
+
+#endif
ADDED libtommath/bn_mp_dr_is_modulus.c
Index: libtommath/bn_mp_dr_is_modulus.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_dr_is_modulus.c
@@ -0,0 +1,27 @@
+#include "tommath_private.h"
+#ifdef BN_MP_DR_IS_MODULUS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* determines if a number is a valid DR modulus */
+mp_bool mp_dr_is_modulus(const mp_int *a)
+{
+ int ix;
+
+ /* must be at least two digits */
+ if (a->used < 2) {
+ return MP_NO;
+ }
+
+ /* must be of the form b**k - a [a <= b] so all
+ * but the first digit must be equal to -1 (mod b).
+ */
+ for (ix = 1; ix < a->used; ix++) {
+ if (a->dp[ix] != MP_MASK) {
+ return MP_NO;
+ }
+ }
+ return MP_YES;
+}
+
+#endif
ADDED libtommath/bn_mp_dr_reduce.c
Index: libtommath/bn_mp_dr_reduce.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_dr_reduce.c
@@ -0,0 +1,78 @@
+#include "tommath_private.h"
+#ifdef BN_MP_DR_REDUCE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* reduce "x" in place modulo "n" using the Diminished Radix algorithm.
+ *
+ * Based on algorithm from the paper
+ *
+ * "Generating Efficient Primes for Discrete Log Cryptosystems"
+ * Chae Hoon Lim, Pil Joong Lee,
+ * POSTECH Information Research Laboratories
+ *
+ * The modulus must be of a special format [see manual]
+ *
+ * Has been modified to use algorithm 7.10 from the LTM book instead
+ *
+ * Input x must be in the range 0 <= x <= (n-1)**2
+ */
+mp_err mp_dr_reduce(mp_int *x, const mp_int *n, mp_digit k)
+{
+ mp_err err;
+ int i, m;
+ mp_word r;
+ mp_digit mu, *tmpx1, *tmpx2;
+
+ /* m = digits in modulus */
+ m = n->used;
+
+ /* ensure that "x" has at least 2m digits */
+ if (x->alloc < (m + m)) {
+ if ((err = mp_grow(x, m + m)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ /* top of loop, this is where the code resumes if
+ * another reduction pass is required.
+ */
+top:
+ /* aliases for digits */
+ /* alias for lower half of x */
+ tmpx1 = x->dp;
+
+ /* alias for upper half of x, or x/B**m */
+ tmpx2 = x->dp + m;
+
+ /* set carry to zero */
+ mu = 0;
+
+ /* compute (x mod B**m) + k * [x/B**m] inline and inplace */
+ for (i = 0; i < m; i++) {
+ r = ((mp_word)*tmpx2++ * (mp_word)k) + *tmpx1 + mu;
+ *tmpx1++ = (mp_digit)(r & MP_MASK);
+ mu = (mp_digit)(r >> ((mp_word)MP_DIGIT_BIT));
+ }
+
+ /* set final carry */
+ *tmpx1++ = mu;
+
+ /* zero words above m */
+ MP_ZERO_DIGITS(tmpx1, (x->used - m) - 1);
+
+ /* clamp, sub and return */
+ mp_clamp(x);
+
+ /* if x >= n then subtract and reduce again
+ * Each successive "recursion" makes the input smaller and smaller.
+ */
+ if (mp_cmp_mag(x, n) != MP_LT) {
+ if ((err = s_mp_sub(x, n, x)) != MP_OKAY) {
+ return err;
+ }
+ goto top;
+ }
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_mp_dr_setup.c
Index: libtommath/bn_mp_dr_setup.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_dr_setup.c
@@ -0,0 +1,15 @@
+#include "tommath_private.h"
+#ifdef BN_MP_DR_SETUP_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* determines the setup value */
+void mp_dr_setup(const mp_int *a, mp_digit *d)
+{
+ /* the casts are required if MP_DIGIT_BIT is one less than
+ * the number of bits in a mp_digit [e.g. MP_DIGIT_BIT==31]
+ */
+ *d = (mp_digit)(((mp_word)1 << (mp_word)MP_DIGIT_BIT) - (mp_word)a->dp[0]);
+}
+
+#endif
ADDED libtommath/bn_mp_error_to_string.c
Index: libtommath/bn_mp_error_to_string.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_error_to_string.c
@@ -0,0 +1,27 @@
+#include "tommath_private.h"
+#ifdef BN_MP_ERROR_TO_STRING_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* return a char * string for a given code */
+const char *mp_error_to_string(mp_err code)
+{
+ switch (code) {
+ case MP_OKAY:
+ return "Successful";
+ case MP_ERR:
+ return "Unknown error";
+ case MP_MEM:
+ return "Out of heap";
+ case MP_VAL:
+ return "Value out of range";
+ case MP_ITER:
+ return "Max. iterations reached";
+ case MP_BUF:
+ return "Buffer overflow";
+ default:
+ return "Invalid error code";
+ }
+}
+
+#endif
ADDED libtommath/bn_mp_exch.c
Index: libtommath/bn_mp_exch.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_exch.c
@@ -0,0 +1,17 @@
+#include "tommath_private.h"
+#ifdef BN_MP_EXCH_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* swap the elements of two integers, for cases where you can't simply swap the
+ * mp_int pointers around
+ */
+void mp_exch(mp_int *a, mp_int *b)
+{
+ mp_int t;
+
+ t = *a;
+ *a = *b;
+ *b = t;
+}
+#endif
ADDED libtommath/bn_mp_expt_u32.c
Index: libtommath/bn_mp_expt_u32.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_expt_u32.c
@@ -0,0 +1,46 @@
+#include "tommath_private.h"
+#ifdef BN_MP_EXPT_U32_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* calculate c = a**b using a square-multiply algorithm */
+mp_err mp_expt_u32(const mp_int *a, uint32_t b, mp_int *c)
+{
+ mp_err err;
+
+ mp_int g;
+
+ if ((err = mp_init_copy(&g, a)) != MP_OKAY) {
+ return err;
+ }
+
+ /* set initial result */
+ mp_set(c, 1uL);
+
+ while (b > 0u) {
+ /* if the bit is set multiply */
+ if ((b & 1u) != 0u) {
+ if ((err = mp_mul(c, &g, c)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* square */
+ if (b > 1u) {
+ if ((err = mp_sqr(&g, &g)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* shift to next bit */
+ b >>= 1;
+ }
+
+ err = MP_OKAY;
+
+LBL_ERR:
+ mp_clear(&g);
+ return err;
+}
+
+#endif
ADDED libtommath/bn_mp_exptmod.c
Index: libtommath/bn_mp_exptmod.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_exptmod.c
@@ -0,0 +1,76 @@
+#include "tommath_private.h"
+#ifdef BN_MP_EXPTMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* this is a shell function that calls either the normal or Montgomery
+ * exptmod functions. Originally the call to the montgomery code was
+ * embedded in the normal function but that wasted alot of stack space
+ * for nothing (since 99% of the time the Montgomery code would be called)
+ */
+mp_err mp_exptmod(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y)
+{
+ int dr;
+
+ /* modulus P must be positive */
+ if (P->sign == MP_NEG) {
+ return MP_VAL;
+ }
+
+ /* if exponent X is negative we have to recurse */
+ if (X->sign == MP_NEG) {
+ mp_int tmpG, tmpX;
+ mp_err err;
+
+ if (!MP_HAS(MP_INVMOD)) {
+ return MP_VAL;
+ }
+
+ if ((err = mp_init_multi(&tmpG, &tmpX, NULL)) != MP_OKAY) {
+ return err;
+ }
+
+ /* first compute 1/G mod P */
+ if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* now get |X| */
+ if ((err = mp_abs(X, &tmpX)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* and now compute (1/G)**|X| instead of G**X [X < 0] */
+ err = mp_exptmod(&tmpG, &tmpX, P, Y);
+LBL_ERR:
+ mp_clear_multi(&tmpG, &tmpX, NULL);
+ return err;
+ }
+
+ /* modified diminished radix reduction */
+ if (MP_HAS(MP_REDUCE_IS_2K_L) && MP_HAS(MP_REDUCE_2K_L) && MP_HAS(S_MP_EXPTMOD) &&
+ (mp_reduce_is_2k_l(P) == MP_YES)) {
+ return s_mp_exptmod(G, X, P, Y, 1);
+ }
+
+ /* is it a DR modulus? default to no */
+ dr = (MP_HAS(MP_DR_IS_MODULUS) && (mp_dr_is_modulus(P) == MP_YES)) ? 1 : 0;
+
+ /* if not, is it a unrestricted DR modulus? */
+ if (MP_HAS(MP_REDUCE_IS_2K) && (dr == 0)) {
+ dr = (mp_reduce_is_2k(P) == MP_YES) ? 2 : 0;
+ }
+
+ /* if the modulus is odd or dr != 0 use the montgomery method */
+ if (MP_HAS(S_MP_EXPTMOD_FAST) && (MP_IS_ODD(P) || (dr != 0))) {
+ return s_mp_exptmod_fast(G, X, P, Y, dr);
+ } else if (MP_HAS(S_MP_EXPTMOD)) {
+ /* otherwise use the generic Barrett reduction technique */
+ return s_mp_exptmod(G, X, P, Y, 0);
+ } else {
+ /* no exptmod for evens */
+ return MP_VAL;
+ }
+}
+
+#endif
ADDED libtommath/bn_mp_exteuclid.c
Index: libtommath/bn_mp_exteuclid.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_exteuclid.c
@@ -0,0 +1,73 @@
+#include "tommath_private.h"
+#ifdef BN_MP_EXTEUCLID_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* Extended euclidean algorithm of (a, b) produces
+ a*u1 + b*u2 = u3
+ */
+mp_err mp_exteuclid(const mp_int *a, const mp_int *b, mp_int *U1, mp_int *U2, mp_int *U3)
+{
+ mp_int u1, u2, u3, v1, v2, v3, t1, t2, t3, q, tmp;
+ mp_err err;
+
+ if ((err = mp_init_multi(&u1, &u2, &u3, &v1, &v2, &v3, &t1, &t2, &t3, &q, &tmp, NULL)) != MP_OKAY) {
+ return err;
+ }
+
+ /* initialize, (u1,u2,u3) = (1,0,a) */
+ mp_set(&u1, 1uL);
+ if ((err = mp_copy(a, &u3)) != MP_OKAY) goto LBL_ERR;
+
+ /* initialize, (v1,v2,v3) = (0,1,b) */
+ mp_set(&v2, 1uL);
+ if ((err = mp_copy(b, &v3)) != MP_OKAY) goto LBL_ERR;
+
+ /* loop while v3 != 0 */
+ while (!MP_IS_ZERO(&v3)) {
+ /* q = u3/v3 */
+ if ((err = mp_div(&u3, &v3, &q, NULL)) != MP_OKAY) goto LBL_ERR;
+
+ /* (t1,t2,t3) = (u1,u2,u3) - (v1,v2,v3)q */
+ if ((err = mp_mul(&v1, &q, &tmp)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_sub(&u1, &tmp, &t1)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_mul(&v2, &q, &tmp)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_sub(&u2, &tmp, &t2)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_mul(&v3, &q, &tmp)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_sub(&u3, &tmp, &t3)) != MP_OKAY) goto LBL_ERR;
+
+ /* (u1,u2,u3) = (v1,v2,v3) */
+ if ((err = mp_copy(&v1, &u1)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_copy(&v2, &u2)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_copy(&v3, &u3)) != MP_OKAY) goto LBL_ERR;
+
+ /* (v1,v2,v3) = (t1,t2,t3) */
+ if ((err = mp_copy(&t1, &v1)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_copy(&t2, &v2)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_copy(&t3, &v3)) != MP_OKAY) goto LBL_ERR;
+ }
+
+ /* make sure U3 >= 0 */
+ if (u3.sign == MP_NEG) {
+ if ((err = mp_neg(&u1, &u1)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_neg(&u2, &u2)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_neg(&u3, &u3)) != MP_OKAY) goto LBL_ERR;
+ }
+
+ /* copy result out */
+ if (U1 != NULL) {
+ mp_exch(U1, &u1);
+ }
+ if (U2 != NULL) {
+ mp_exch(U2, &u2);
+ }
+ if (U3 != NULL) {
+ mp_exch(U3, &u3);
+ }
+
+ err = MP_OKAY;
+LBL_ERR:
+ mp_clear_multi(&u1, &u2, &u3, &v1, &v2, &v3, &t1, &t2, &t3, &q, &tmp, NULL);
+ return err;
+}
+#endif
ADDED libtommath/bn_mp_fread.c
Index: libtommath/bn_mp_fread.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_fread.c
@@ -0,0 +1,60 @@
+#include "tommath_private.h"
+#ifdef BN_MP_FREAD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#ifndef MP_NO_FILE
+/* read a bigint from a file stream in ASCII */
+mp_err mp_fread(mp_int *a, int radix, FILE *stream)
+{
+ mp_err err;
+ mp_sign neg;
+
+ /* if first digit is - then set negative */
+ int ch = fgetc(stream);
+ if (ch == (int)'-') {
+ neg = MP_NEG;
+ ch = fgetc(stream);
+ } else {
+ neg = MP_ZPOS;
+ }
+
+ /* no digits, return error */
+ if (ch == EOF) {
+ return MP_ERR;
+ }
+
+ /* clear a */
+ mp_zero(a);
+
+ do {
+ int y;
+ unsigned pos = (unsigned)(ch - (int)'(');
+ if (mp_s_rmap_reverse_sz < pos) {
+ break;
+ }
+
+ y = (int)mp_s_rmap_reverse[pos];
+
+ if ((y == 0xff) || (y >= radix)) {
+ break;
+ }
+
+ /* shift up and add */
+ if ((err = mp_mul_d(a, (mp_digit)radix, a)) != MP_OKAY) {
+ return err;
+ }
+ if ((err = mp_add_d(a, (mp_digit)y, a)) != MP_OKAY) {
+ return err;
+ }
+ } while ((ch = fgetc(stream)) != EOF);
+
+ if (a->used != 0) {
+ a->sign = neg;
+ }
+
+ return MP_OKAY;
+}
+#endif
+
+#endif
ADDED libtommath/bn_mp_from_sbin.c
Index: libtommath/bn_mp_from_sbin.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_from_sbin.c
@@ -0,0 +1,25 @@
+#include "tommath_private.h"
+#ifdef BN_MP_FROM_SBIN_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* read signed bin, big endian, first byte is 0==positive or 1==negative */
+mp_err mp_from_sbin(mp_int *a, const unsigned char *buf, size_t size)
+{
+ mp_err err;
+
+ /* read magnitude */
+ if ((err = mp_from_ubin(a, buf + 1, size - 1u)) != MP_OKAY) {
+ return err;
+ }
+
+ /* first byte is 0 for positive, non-zero for negative */
+ if (buf[0] == (unsigned char)0) {
+ a->sign = MP_ZPOS;
+ } else {
+ a->sign = MP_NEG;
+ }
+
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_mp_from_ubin.c
Index: libtommath/bn_mp_from_ubin.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_from_ubin.c
@@ -0,0 +1,39 @@
+#include "tommath_private.h"
+#ifdef BN_MP_FROM_UBIN_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* reads a unsigned char array, assumes the msb is stored first [big endian] */
+mp_err mp_from_ubin(mp_int *a, const unsigned char *buf, size_t size)
+{
+ mp_err err;
+
+ /* make sure there are at least two digits */
+ if (a->alloc < 2) {
+ if ((err = mp_grow(a, 2)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ /* zero the int */
+ mp_zero(a);
+
+ /* read the bytes in */
+ while (size-- > 0u) {
+ if ((err = mp_mul_2d(a, 8, a)) != MP_OKAY) {
+ return err;
+ }
+
+#ifndef MP_8BIT
+ a->dp[0] |= *buf++;
+ a->used += 1;
+#else
+ a->dp[0] = (*buf & MP_MASK);
+ a->dp[1] |= ((*buf++ >> 7) & 1u);
+ a->used += 2;
+#endif
+ }
+ mp_clamp(a);
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_mp_fwrite.c
Index: libtommath/bn_mp_fwrite.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_fwrite.c
@@ -0,0 +1,45 @@
+#include "tommath_private.h"
+#ifdef BN_MP_FWRITE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#ifndef MP_NO_FILE
+mp_err mp_fwrite(const mp_int *a, int radix, FILE *stream)
+{
+ char *buf;
+ mp_err err;
+ int len;
+ size_t written;
+
+ /* TODO: this function is not in this PR */
+ if (MP_HAS(MP_RADIX_SIZE_OVERESTIMATE)) {
+ /* if ((err = mp_radix_size_overestimate(&t, base, &len)) != MP_OKAY) goto LBL_ERR; */
+ } else {
+ if ((err = mp_radix_size(a, radix, &len)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ buf = (char *) MP_MALLOC((size_t)len);
+ if (buf == NULL) {
+ return MP_MEM;
+ }
+
+ if ((err = mp_to_radix(a, buf, (size_t)len, &written, radix)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if (fwrite(buf, written, 1uL, stream) != 1uL) {
+ err = MP_ERR;
+ goto LBL_ERR;
+ }
+ err = MP_OKAY;
+
+
+LBL_ERR:
+ MP_FREE_BUFFER(buf, (size_t)len);
+ return err;
+}
+#endif
+
+#endif
ADDED libtommath/bn_mp_gcd.c
Index: libtommath/bn_mp_gcd.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_gcd.c
@@ -0,0 +1,92 @@
+#include "tommath_private.h"
+#ifdef BN_MP_GCD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* Greatest Common Divisor using the binary method */
+mp_err mp_gcd(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ mp_int u, v;
+ int k, u_lsb, v_lsb;
+ mp_err err;
+
+ /* either zero than gcd is the largest */
+ if (MP_IS_ZERO(a)) {
+ return mp_abs(b, c);
+ }
+ if (MP_IS_ZERO(b)) {
+ return mp_abs(a, c);
+ }
+
+ /* get copies of a and b we can modify */
+ if ((err = mp_init_copy(&u, a)) != MP_OKAY) {
+ return err;
+ }
+
+ if ((err = mp_init_copy(&v, b)) != MP_OKAY) {
+ goto LBL_U;
+ }
+
+ /* must be positive for the remainder of the algorithm */
+ u.sign = v.sign = MP_ZPOS;
+
+ /* B1. Find the common power of two for u and v */
+ u_lsb = mp_cnt_lsb(&u);
+ v_lsb = mp_cnt_lsb(&v);
+ k = MP_MIN(u_lsb, v_lsb);
+
+ if (k > 0) {
+ /* divide the power of two out */
+ if ((err = mp_div_2d(&u, k, &u, NULL)) != MP_OKAY) {
+ goto LBL_V;
+ }
+
+ if ((err = mp_div_2d(&v, k, &v, NULL)) != MP_OKAY) {
+ goto LBL_V;
+ }
+ }
+
+ /* divide any remaining factors of two out */
+ if (u_lsb != k) {
+ if ((err = mp_div_2d(&u, u_lsb - k, &u, NULL)) != MP_OKAY) {
+ goto LBL_V;
+ }
+ }
+
+ if (v_lsb != k) {
+ if ((err = mp_div_2d(&v, v_lsb - k, &v, NULL)) != MP_OKAY) {
+ goto LBL_V;
+ }
+ }
+
+ while (!MP_IS_ZERO(&v)) {
+ /* make sure v is the largest */
+ if (mp_cmp_mag(&u, &v) == MP_GT) {
+ /* swap u and v to make sure v is >= u */
+ mp_exch(&u, &v);
+ }
+
+ /* subtract smallest from largest */
+ if ((err = s_mp_sub(&v, &u, &v)) != MP_OKAY) {
+ goto LBL_V;
+ }
+
+ /* Divide out all factors of two */
+ if ((err = mp_div_2d(&v, mp_cnt_lsb(&v), &v, NULL)) != MP_OKAY) {
+ goto LBL_V;
+ }
+ }
+
+ /* multiply by 2**k which we divided out at the beginning */
+ if ((err = mp_mul_2d(&u, k, c)) != MP_OKAY) {
+ goto LBL_V;
+ }
+ c->sign = MP_ZPOS;
+ err = MP_OKAY;
+LBL_V:
+ mp_clear(&u);
+LBL_U:
+ mp_clear(&v);
+ return err;
+}
+#endif
ADDED libtommath/bn_mp_get_double.c
Index: libtommath/bn_mp_get_double.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_get_double.c
@@ -0,0 +1,18 @@
+#include "tommath_private.h"
+#ifdef BN_MP_GET_DOUBLE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+double mp_get_double(const mp_int *a)
+{
+ int i;
+ double d = 0.0, fac = 1.0;
+ for (i = 0; i < MP_DIGIT_BIT; ++i) {
+ fac *= 2.0;
+ }
+ for (i = a->used; i --> 0;) {
+ d = (d * fac) + (double)a->dp[i];
+ }
+ return (a->sign == MP_NEG) ? -d : d;
+}
+#endif
ADDED libtommath/bn_mp_get_i32.c
Index: libtommath/bn_mp_get_i32.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_get_i32.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef BN_MP_GET_I32_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_GET_SIGNED(mp_get_i32, mp_get_mag_u32, int32_t, uint32_t)
+#endif
ADDED libtommath/bn_mp_get_i64.c
Index: libtommath/bn_mp_get_i64.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_get_i64.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef BN_MP_GET_I64_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_GET_SIGNED(mp_get_i64, mp_get_mag_u64, int64_t, uint64_t)
+#endif
ADDED libtommath/bn_mp_get_l.c
Index: libtommath/bn_mp_get_l.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_get_l.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef BN_MP_GET_L_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_GET_SIGNED(mp_get_l, mp_get_mag_ul, long, unsigned long)
+#endif
ADDED libtommath/bn_mp_get_ll.c
Index: libtommath/bn_mp_get_ll.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_get_ll.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef BN_MP_GET_LL_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_GET_SIGNED(mp_get_ll, mp_get_mag_ull, long long, unsigned long long)
+#endif
ADDED libtommath/bn_mp_get_mag_u32.c
Index: libtommath/bn_mp_get_mag_u32.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_get_mag_u32.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef BN_MP_GET_MAG_U32_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_GET_MAG(mp_get_mag_u32, uint32_t)
+#endif
ADDED libtommath/bn_mp_get_mag_u64.c
Index: libtommath/bn_mp_get_mag_u64.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_get_mag_u64.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef BN_MP_GET_MAG_U64_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_GET_MAG(mp_get_mag_u64, uint64_t)
+#endif
ADDED libtommath/bn_mp_get_mag_ul.c
Index: libtommath/bn_mp_get_mag_ul.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_get_mag_ul.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef BN_MP_GET_MAG_UL_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_GET_MAG(mp_get_mag_ul, unsigned long)
+#endif
ADDED libtommath/bn_mp_get_mag_ull.c
Index: libtommath/bn_mp_get_mag_ull.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_get_mag_ull.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef BN_MP_GET_MAG_ULL_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_GET_MAG(mp_get_mag_ull, unsigned long long)
+#endif
ADDED libtommath/bn_mp_grow.c
Index: libtommath/bn_mp_grow.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_grow.c
@@ -0,0 +1,42 @@
+#include "tommath_private.h"
+#ifdef BN_MP_GROW_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* grow as required */
+mp_err mp_grow(mp_int *a, int size)
+{
+ int i;
+ mp_digit *tmp;
+
+ if (size < 0) {
+ return MP_VAL;
+ }
+
+ /* if the alloc size is smaller alloc more ram */
+ if (a->alloc < size) {
+ /* reallocate the array a->dp
+ *
+ * We store the return in a temporary variable
+ * in case the operation failed we don't want
+ * to overwrite the dp member of a.
+ */
+ tmp = (mp_digit *) MP_REALLOC(a->dp,
+ (size_t)a->alloc * sizeof(mp_digit),
+ (size_t)size * sizeof(mp_digit));
+ if (tmp == NULL) {
+ /* reallocation failed but "a" is still valid [can be freed] */
+ return MP_MEM;
+ }
+
+ /* reallocation succeeded so set a->dp */
+ a->dp = tmp;
+
+ /* zero excess digits */
+ i = a->alloc;
+ a->alloc = size;
+ MP_ZERO_DIGITS(a->dp + i, a->alloc - i);
+ }
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_mp_incr.c
Index: libtommath/bn_mp_incr.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_incr.c
@@ -0,0 +1,30 @@
+#include "tommath_private.h"
+#ifdef BN_MP_INCR_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* Increment "a" by one like "a++". Changes input! */
+mp_err mp_incr(mp_int *a)
+{
+ if (MP_IS_ZERO(a)) {
+ mp_set(a,1uL);
+ return MP_OKAY;
+ } else if (a->sign == MP_NEG) {
+ mp_err err;
+ a->sign = MP_ZPOS;
+ if ((err = mp_decr(a)) != MP_OKAY) {
+ return err;
+ }
+ /* There is no -0 in LTM */
+ if (!MP_IS_ZERO(a)) {
+ a->sign = MP_NEG;
+ }
+ return MP_OKAY;
+ } else if (a->dp[0] < MP_DIGIT_MAX) {
+ a->dp[0]++;
+ return MP_OKAY;
+ } else {
+ return mp_add_d(a, 1uL,a);
+ }
+}
+#endif
ADDED libtommath/bn_mp_init.c
Index: libtommath/bn_mp_init.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_init.c
@@ -0,0 +1,23 @@
+#include "tommath_private.h"
+#ifdef BN_MP_INIT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* init a new mp_int */
+mp_err mp_init(mp_int *a)
+{
+ /* allocate memory required and clear it */
+ a->dp = (mp_digit *) MP_CALLOC((size_t)MP_PREC, sizeof(mp_digit));
+ if (a->dp == NULL) {
+ return MP_MEM;
+ }
+
+ /* set the used to zero, allocated digits to the default precision
+ * and sign to positive */
+ a->used = 0;
+ a->alloc = MP_PREC;
+ a->sign = MP_ZPOS;
+
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_mp_init_copy.c
Index: libtommath/bn_mp_init_copy.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_init_copy.c
@@ -0,0 +1,21 @@
+#include "tommath_private.h"
+#ifdef BN_MP_INIT_COPY_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* creates "a" then copies b into it */
+mp_err mp_init_copy(mp_int *a, const mp_int *b)
+{
+ mp_err err;
+
+ if ((err = mp_init_size(a, b->used)) != MP_OKAY) {
+ return err;
+ }
+
+ if ((err = mp_copy(b, a)) != MP_OKAY) {
+ mp_clear(a);
+ }
+
+ return err;
+}
+#endif
ADDED libtommath/bn_mp_init_i32.c
Index: libtommath/bn_mp_init_i32.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_init_i32.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef BN_MP_INIT_I32_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_INIT_INT(mp_init_i32, mp_set_i32, int32_t)
+#endif
ADDED libtommath/bn_mp_init_i64.c
Index: libtommath/bn_mp_init_i64.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_init_i64.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef BN_MP_INIT_I64_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_INIT_INT(mp_init_i64, mp_set_i64, int64_t)
+#endif
ADDED libtommath/bn_mp_init_l.c
Index: libtommath/bn_mp_init_l.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_init_l.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef BN_MP_INIT_L_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_INIT_INT(mp_init_l, mp_set_l, long)
+#endif
ADDED libtommath/bn_mp_init_ll.c
Index: libtommath/bn_mp_init_ll.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_init_ll.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef BN_MP_INIT_LL_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_INIT_INT(mp_init_ll, mp_set_ll, long long)
+#endif
ADDED libtommath/bn_mp_init_multi.c
Index: libtommath/bn_mp_init_multi.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_init_multi.c
@@ -0,0 +1,41 @@
+#include "tommath_private.h"
+#ifdef BN_MP_INIT_MULTI_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#include
+
+mp_err mp_init_multi(mp_int *mp, ...)
+{
+ mp_err err = MP_OKAY; /* Assume ok until proven otherwise */
+ int n = 0; /* Number of ok inits */
+ mp_int *cur_arg = mp;
+ va_list args;
+
+ va_start(args, mp); /* init args to next argument from caller */
+ while (cur_arg != NULL) {
+ if (mp_init(cur_arg) != MP_OKAY) {
+ /* Oops - error! Back-track and mp_clear what we already
+ succeeded in init-ing, then return error.
+ */
+ va_list clean_args;
+
+ /* now start cleaning up */
+ cur_arg = mp;
+ va_start(clean_args, mp);
+ while (n-- != 0) {
+ mp_clear(cur_arg);
+ cur_arg = va_arg(clean_args, mp_int *);
+ }
+ va_end(clean_args);
+ err = MP_MEM;
+ break;
+ }
+ n++;
+ cur_arg = va_arg(args, mp_int *);
+ }
+ va_end(args);
+ return err; /* Assumed ok, if error flagged above. */
+}
+
+#endif
ADDED libtommath/bn_mp_init_set.c
Index: libtommath/bn_mp_init_set.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_init_set.c
@@ -0,0 +1,16 @@
+#include "tommath_private.h"
+#ifdef BN_MP_INIT_SET_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* initialize and set a digit */
+mp_err mp_init_set(mp_int *a, mp_digit b)
+{
+ mp_err err;
+ if ((err = mp_init(a)) != MP_OKAY) {
+ return err;
+ }
+ mp_set(a, b);
+ return err;
+}
+#endif
ADDED libtommath/bn_mp_init_size.c
Index: libtommath/bn_mp_init_size.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_init_size.c
@@ -0,0 +1,29 @@
+#include "tommath_private.h"
+#ifdef BN_MP_INIT_SIZE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* init an mp_init for a given size */
+mp_err mp_init_size(mp_int *a, int size)
+{
+
+ if (size < 0) {
+ return MP_VAL;
+ }
+
+ size = MP_MAX(MP_MIN_PREC, size);
+
+ /* alloc mem */
+ a->dp = (mp_digit *) MP_CALLOC((size_t)size, sizeof(mp_digit));
+ if (a->dp == NULL) {
+ return MP_MEM;
+ }
+
+ /* set the members */
+ a->used = 0;
+ a->alloc = size;
+ a->sign = MP_ZPOS;
+
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_mp_init_u32.c
Index: libtommath/bn_mp_init_u32.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_init_u32.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef BN_MP_INIT_U32_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_INIT_INT(mp_init_u32, mp_set_u32, uint32_t)
+#endif
ADDED libtommath/bn_mp_init_u64.c
Index: libtommath/bn_mp_init_u64.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_init_u64.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef BN_MP_INIT_U64_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_INIT_INT(mp_init_u64, mp_set_u64, uint64_t)
+#endif
ADDED libtommath/bn_mp_init_ul.c
Index: libtommath/bn_mp_init_ul.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_init_ul.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef BN_MP_INIT_UL_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_INIT_INT(mp_init_ul, mp_set_ul, unsigned long)
+#endif
ADDED libtommath/bn_mp_init_ull.c
Index: libtommath/bn_mp_init_ull.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_init_ull.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef BN_MP_INIT_ULL_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_INIT_INT(mp_init_ull, mp_set_ull, unsigned long long)
+#endif
ADDED libtommath/bn_mp_invmod.c
Index: libtommath/bn_mp_invmod.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_invmod.c
@@ -0,0 +1,23 @@
+#include "tommath_private.h"
+#ifdef BN_MP_INVMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* hac 14.61, pp608 */
+mp_err mp_invmod(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ /* b cannot be negative and has to be >1 */
+ if ((b->sign == MP_NEG) || (mp_cmp_d(b, 1uL) != MP_GT)) {
+ return MP_VAL;
+ }
+
+ /* if the modulus is odd we can use a faster routine instead */
+ if (MP_HAS(S_MP_INVMOD_FAST) && MP_IS_ODD(b)) {
+ return s_mp_invmod_fast(a, b, c);
+ }
+
+ return MP_HAS(S_MP_INVMOD_SLOW)
+ ? s_mp_invmod_slow(a, b, c)
+ : MP_VAL;
+}
+#endif
ADDED libtommath/bn_mp_is_square.c
Index: libtommath/bn_mp_is_square.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_is_square.c
@@ -0,0 +1,93 @@
+#include "tommath_private.h"
+#ifdef BN_MP_IS_SQUARE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* Check if remainders are possible squares - fast exclude non-squares */
+static const char rem_128[128] = {
+ 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1
+};
+
+static const char rem_105[105] = {
+ 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1,
+ 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1,
+ 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1,
+ 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1,
+ 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1
+};
+
+/* Store non-zero to ret if arg is square, and zero if not */
+mp_err mp_is_square(const mp_int *arg, mp_bool *ret)
+{
+ mp_err err;
+ mp_digit c;
+ mp_int t;
+ unsigned long r;
+
+ /* Default to Non-square :) */
+ *ret = MP_NO;
+
+ if (arg->sign == MP_NEG) {
+ return MP_VAL;
+ }
+
+ if (MP_IS_ZERO(arg)) {
+ return MP_OKAY;
+ }
+
+ /* First check mod 128 (suppose that MP_DIGIT_BIT is at least 7) */
+ if (rem_128[127u & arg->dp[0]] == (char)1) {
+ return MP_OKAY;
+ }
+
+ /* Next check mod 105 (3*5*7) */
+ if ((err = mp_mod_d(arg, 105uL, &c)) != MP_OKAY) {
+ return err;
+ }
+ if (rem_105[c] == (char)1) {
+ return MP_OKAY;
+ }
+
+
+ if ((err = mp_init_u32(&t, 11u*13u*17u*19u*23u*29u*31u)) != MP_OKAY) {
+ return err;
+ }
+ if ((err = mp_mod(arg, &t, &t)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ r = mp_get_u32(&t);
+ /* Check for other prime modules, note it's not an ERROR but we must
+ * free "t" so the easiest way is to goto LBL_ERR. We know that err
+ * is already equal to MP_OKAY from the mp_mod call
+ */
+ if (((1uL<<(r%11uL)) & 0x5C4uL) != 0uL) goto LBL_ERR;
+ if (((1uL<<(r%13uL)) & 0x9E4uL) != 0uL) goto LBL_ERR;
+ if (((1uL<<(r%17uL)) & 0x5CE8uL) != 0uL) goto LBL_ERR;
+ if (((1uL<<(r%19uL)) & 0x4F50CuL) != 0uL) goto LBL_ERR;
+ if (((1uL<<(r%23uL)) & 0x7ACCA0uL) != 0uL) goto LBL_ERR;
+ if (((1uL<<(r%29uL)) & 0xC2EDD0CuL) != 0uL) goto LBL_ERR;
+ if (((1uL<<(r%31uL)) & 0x6DE2B848uL) != 0uL) goto LBL_ERR;
+
+ /* Final check - is sqr(sqrt(arg)) == arg ? */
+ if ((err = mp_sqrt(arg, &t)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((err = mp_sqr(&t, &t)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ *ret = (mp_cmp_mag(&t, arg) == MP_EQ) ? MP_YES : MP_NO;
+LBL_ERR:
+ mp_clear(&t);
+ return err;
+}
+#endif
ADDED libtommath/bn_mp_iseven.c
Index: libtommath/bn_mp_iseven.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_iseven.c
@@ -0,0 +1,10 @@
+#include "tommath_private.h"
+#ifdef BN_MP_ISEVEN_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+mp_bool mp_iseven(const mp_int *a)
+{
+ return MP_IS_EVEN(a) ? MP_YES : MP_NO;
+}
+#endif
ADDED libtommath/bn_mp_isodd.c
Index: libtommath/bn_mp_isodd.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_isodd.c
@@ -0,0 +1,10 @@
+#include "tommath_private.h"
+#ifdef BN_MP_ISODD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+mp_bool mp_isodd(const mp_int *a)
+{
+ return MP_IS_ODD(a) ? MP_YES : MP_NO;
+}
+#endif
ADDED libtommath/bn_mp_kronecker.c
Index: libtommath/bn_mp_kronecker.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_kronecker.c
@@ -0,0 +1,129 @@
+#include "tommath_private.h"
+#ifdef BN_MP_KRONECKER_C
+
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/*
+ Kronecker symbol (a|p)
+ Straightforward implementation of algorithm 1.4.10 in
+ Henri Cohen: "A Course in Computational Algebraic Number Theory"
+
+ @book{cohen2013course,
+ title={A course in computational algebraic number theory},
+ author={Cohen, Henri},
+ volume={138},
+ year={2013},
+ publisher={Springer Science \& Business Media}
+ }
+ */
+mp_err mp_kronecker(const mp_int *a, const mp_int *p, int *c)
+{
+ mp_int a1, p1, r;
+ mp_err err;
+ int v, k;
+
+ static const int table[8] = {0, 1, 0, -1, 0, -1, 0, 1};
+
+ if (MP_IS_ZERO(p)) {
+ if ((a->used == 1) && (a->dp[0] == 1u)) {
+ *c = 1;
+ } else {
+ *c = 0;
+ }
+ return MP_OKAY;
+ }
+
+ if (MP_IS_EVEN(a) && MP_IS_EVEN(p)) {
+ *c = 0;
+ return MP_OKAY;
+ }
+
+ if ((err = mp_init_copy(&a1, a)) != MP_OKAY) {
+ return err;
+ }
+ if ((err = mp_init_copy(&p1, p)) != MP_OKAY) {
+ goto LBL_KRON_0;
+ }
+
+ v = mp_cnt_lsb(&p1);
+ if ((err = mp_div_2d(&p1, v, &p1, NULL)) != MP_OKAY) {
+ goto LBL_KRON_1;
+ }
+
+ if ((v & 1) == 0) {
+ k = 1;
+ } else {
+ k = table[a->dp[0] & 7u];
+ }
+
+ if (p1.sign == MP_NEG) {
+ p1.sign = MP_ZPOS;
+ if (a1.sign == MP_NEG) {
+ k = -k;
+ }
+ }
+
+ if ((err = mp_init(&r)) != MP_OKAY) {
+ goto LBL_KRON_1;
+ }
+
+ for (;;) {
+ if (MP_IS_ZERO(&a1)) {
+ if (mp_cmp_d(&p1, 1uL) == MP_EQ) {
+ *c = k;
+ goto LBL_KRON;
+ } else {
+ *c = 0;
+ goto LBL_KRON;
+ }
+ }
+
+ v = mp_cnt_lsb(&a1);
+ if ((err = mp_div_2d(&a1, v, &a1, NULL)) != MP_OKAY) {
+ goto LBL_KRON;
+ }
+
+ if ((v & 1) == 1) {
+ k = k * table[p1.dp[0] & 7u];
+ }
+
+ if (a1.sign == MP_NEG) {
+ /*
+ * Compute k = (-1)^((a1)*(p1-1)/4) * k
+ * a1.dp[0] + 1 cannot overflow because the MSB
+ * of the type mp_digit is not set by definition
+ */
+ if (((a1.dp[0] + 1u) & p1.dp[0] & 2u) != 0u) {
+ k = -k;
+ }
+ } else {
+ /* compute k = (-1)^((a1-1)*(p1-1)/4) * k */
+ if ((a1.dp[0] & p1.dp[0] & 2u) != 0u) {
+ k = -k;
+ }
+ }
+
+ if ((err = mp_copy(&a1, &r)) != MP_OKAY) {
+ goto LBL_KRON;
+ }
+ r.sign = MP_ZPOS;
+ if ((err = mp_mod(&p1, &r, &a1)) != MP_OKAY) {
+ goto LBL_KRON;
+ }
+ if ((err = mp_copy(&r, &p1)) != MP_OKAY) {
+ goto LBL_KRON;
+ }
+ }
+
+LBL_KRON:
+ mp_clear(&r);
+LBL_KRON_1:
+ mp_clear(&p1);
+LBL_KRON_0:
+ mp_clear(&a1);
+
+ return err;
+}
+
+#endif
ADDED libtommath/bn_mp_lcm.c
Index: libtommath/bn_mp_lcm.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_lcm.c
@@ -0,0 +1,44 @@
+#include "tommath_private.h"
+#ifdef BN_MP_LCM_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* computes least common multiple as |a*b|/(a, b) */
+mp_err mp_lcm(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ mp_err err;
+ mp_int t1, t2;
+
+
+ if ((err = mp_init_multi(&t1, &t2, NULL)) != MP_OKAY) {
+ return err;
+ }
+
+ /* t1 = get the GCD of the two inputs */
+ if ((err = mp_gcd(a, b, &t1)) != MP_OKAY) {
+ goto LBL_T;
+ }
+
+ /* divide the smallest by the GCD */
+ if (mp_cmp_mag(a, b) == MP_LT) {
+ /* store quotient in t2 such that t2 * b is the LCM */
+ if ((err = mp_div(a, &t1, &t2, NULL)) != MP_OKAY) {
+ goto LBL_T;
+ }
+ err = mp_mul(b, &t2, c);
+ } else {
+ /* store quotient in t2 such that t2 * a is the LCM */
+ if ((err = mp_div(b, &t1, &t2, NULL)) != MP_OKAY) {
+ goto LBL_T;
+ }
+ err = mp_mul(a, &t2, c);
+ }
+
+ /* fix the sign to positive */
+ c->sign = MP_ZPOS;
+
+LBL_T:
+ mp_clear_multi(&t1, &t2, NULL);
+ return err;
+}
+#endif
ADDED libtommath/bn_mp_log_u32.c
Index: libtommath/bn_mp_log_u32.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_log_u32.c
@@ -0,0 +1,180 @@
+#include "tommath_private.h"
+#ifdef BN_MP_LOG_U32_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* Compute log_{base}(a) */
+static mp_word s_pow(mp_word base, mp_word exponent)
+{
+ mp_word result = 1u;
+ while (exponent != 0u) {
+ if ((exponent & 1u) == 1u) {
+ result *= base;
+ }
+ exponent >>= 1;
+ base *= base;
+ }
+
+ return result;
+}
+
+static mp_digit s_digit_ilogb(mp_digit base, mp_digit n)
+{
+ mp_word bracket_low = 1u, bracket_mid, bracket_high, N;
+ mp_digit ret, high = 1u, low = 0uL, mid;
+
+ if (n < base) {
+ return 0uL;
+ }
+ if (n == base) {
+ return 1uL;
+ }
+
+ bracket_high = (mp_word) base ;
+ N = (mp_word) n;
+
+ while (bracket_high < N) {
+ low = high;
+ bracket_low = bracket_high;
+ high <<= 1;
+ bracket_high *= bracket_high;
+ }
+
+ while (((mp_digit)(high - low)) > 1u) {
+ mid = (low + high) >> 1;
+ bracket_mid = bracket_low * s_pow(base, (mp_word)(mid - low));
+
+ if (N < bracket_mid) {
+ high = mid ;
+ bracket_high = bracket_mid ;
+ }
+ if (N > bracket_mid) {
+ low = mid ;
+ bracket_low = bracket_mid ;
+ }
+ if (N == bracket_mid) {
+ return (mp_digit) mid;
+ }
+ }
+
+ if (bracket_high == N) {
+ ret = high;
+ } else {
+ ret = low;
+ }
+
+ return ret;
+}
+
+/* TODO: output could be "int" because the output of mp_radix_size is int, too,
+ as is the output of mp_bitcount.
+ With the same problem: max size is INT_MAX * MP_DIGIT not INT_MAX only!
+*/
+mp_err mp_log_u32(const mp_int *a, uint32_t base, uint32_t *c)
+{
+ mp_err err;
+ mp_ord cmp;
+ uint32_t high, low, mid;
+ mp_int bracket_low, bracket_high, bracket_mid, t, bi_base;
+
+ err = MP_OKAY;
+
+ if (a->sign == MP_NEG) {
+ return MP_VAL;
+ }
+
+ if (MP_IS_ZERO(a)) {
+ return MP_VAL;
+ }
+
+ if (base < 2u) {
+ return MP_VAL;
+ }
+
+ /* A small shortcut for bases that are powers of two. */
+ if ((base & (base - 1u)) == 0u) {
+ int y, bit_count;
+ for (y=0; (y < 7) && ((base & 1u) == 0u); y++) {
+ base >>= 1;
+ }
+ bit_count = mp_count_bits(a) - 1;
+ *c = (uint32_t)(bit_count/y);
+ return MP_OKAY;
+ }
+
+ if (a->used == 1) {
+ *c = (uint32_t)s_digit_ilogb(base, a->dp[0]);
+ return err;
+ }
+
+ cmp = mp_cmp_d(a, base);
+ if ((cmp == MP_LT) || (cmp == MP_EQ)) {
+ *c = cmp == MP_EQ;
+ return err;
+ }
+
+ if ((err =
+ mp_init_multi(&bracket_low, &bracket_high,
+ &bracket_mid, &t, &bi_base, NULL)) != MP_OKAY) {
+ return err;
+ }
+
+ low = 0u;
+ mp_set(&bracket_low, 1uL);
+ high = 1u;
+
+ mp_set(&bracket_high, base);
+
+ /*
+ A kind of Giant-step/baby-step algorithm.
+ Idea shamelessly stolen from https://programmingpraxis.com/2010/05/07/integer-logarithms/2/
+ The effect is asymptotic, hence needs benchmarks to test if the Giant-step should be skipped
+ for small n.
+ */
+ while (mp_cmp(&bracket_high, a) == MP_LT) {
+ low = high;
+ if ((err = mp_copy(&bracket_high, &bracket_low)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ high <<= 1;
+ if ((err = mp_sqr(&bracket_high, &bracket_high)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+ mp_set(&bi_base, base);
+
+ while ((high - low) > 1u) {
+ mid = (high + low) >> 1;
+
+ if ((err = mp_expt_u32(&bi_base, (uint32_t)(mid - low), &t)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((err = mp_mul(&bracket_low, &t, &bracket_mid)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ cmp = mp_cmp(a, &bracket_mid);
+ if (cmp == MP_LT) {
+ high = mid;
+ mp_exch(&bracket_mid, &bracket_high);
+ }
+ if (cmp == MP_GT) {
+ low = mid;
+ mp_exch(&bracket_mid, &bracket_low);
+ }
+ if (cmp == MP_EQ) {
+ *c = mid;
+ goto LBL_END;
+ }
+ }
+
+ *c = (mp_cmp(&bracket_high, a) == MP_EQ) ? high : low;
+
+LBL_END:
+LBL_ERR:
+ mp_clear_multi(&bracket_low, &bracket_high, &bracket_mid,
+ &t, &bi_base, NULL);
+ return err;
+}
+
+
+#endif
ADDED libtommath/bn_mp_lshd.c
Index: libtommath/bn_mp_lshd.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_lshd.c
@@ -0,0 +1,51 @@
+#include "tommath_private.h"
+#ifdef BN_MP_LSHD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* shift left a certain amount of digits */
+mp_err mp_lshd(mp_int *a, int b)
+{
+ int x;
+ mp_err err;
+ mp_digit *top, *bottom;
+
+ /* if its less than zero return */
+ if (b <= 0) {
+ return MP_OKAY;
+ }
+ /* no need to shift 0 around */
+ if (MP_IS_ZERO(a)) {
+ return MP_OKAY;
+ }
+
+ /* grow to fit the new digits */
+ if (a->alloc < (a->used + b)) {
+ if ((err = mp_grow(a, a->used + b)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ /* increment the used by the shift amount then copy upwards */
+ a->used += b;
+
+ /* top */
+ top = a->dp + a->used - 1;
+
+ /* base */
+ bottom = (a->dp + a->used - 1) - b;
+
+ /* much like mp_rshd this is implemented using a sliding window
+ * except the window goes the otherway around. Copying from
+ * the bottom to the top. see bn_mp_rshd.c for more info.
+ */
+ for (x = a->used - 1; x >= b; x--) {
+ *top-- = *bottom--;
+ }
+
+ /* zero the lower digits */
+ MP_ZERO_DIGITS(a->dp, b);
+
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_mp_mod.c
Index: libtommath/bn_mp_mod.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_mod.c
@@ -0,0 +1,31 @@
+#include "tommath_private.h"
+#ifdef BN_MP_MOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* c = a mod b, 0 <= c < b if b > 0, b < c <= 0 if b < 0 */
+mp_err mp_mod(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ mp_int t;
+ mp_err err;
+
+ if ((err = mp_init_size(&t, b->used)) != MP_OKAY) {
+ return err;
+ }
+
+ if ((err = mp_div(a, b, NULL, &t)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if (MP_IS_ZERO(&t) || (t.sign == b->sign)) {
+ err = MP_OKAY;
+ mp_exch(&t, c);
+ } else {
+ err = mp_add(b, &t, c);
+ }
+
+LBL_ERR:
+ mp_clear(&t);
+ return err;
+}
+#endif
ADDED libtommath/bn_mp_mod_2d.c
Index: libtommath/bn_mp_mod_2d.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_mod_2d.c
@@ -0,0 +1,38 @@
+#include "tommath_private.h"
+#ifdef BN_MP_MOD_2D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* calc a value mod 2**b */
+mp_err mp_mod_2d(const mp_int *a, int b, mp_int *c)
+{
+ int x;
+ mp_err err;
+
+ /* if b is <= 0 then zero the int */
+ if (b <= 0) {
+ mp_zero(c);
+ return MP_OKAY;
+ }
+
+ /* if the modulus is larger than the value than return */
+ if (b >= (a->used * MP_DIGIT_BIT)) {
+ return mp_copy(a, c);
+ }
+
+ /* copy */
+ if ((err = mp_copy(a, c)) != MP_OKAY) {
+ return err;
+ }
+
+ /* zero digits above the last digit of the modulus */
+ x = (b / MP_DIGIT_BIT) + (((b % MP_DIGIT_BIT) == 0) ? 0 : 1);
+ MP_ZERO_DIGITS(c->dp + x, c->used - x);
+
+ /* clear the digit that is not completely outside/inside the modulus */
+ c->dp[b / MP_DIGIT_BIT] &=
+ ((mp_digit)1 << (mp_digit)(b % MP_DIGIT_BIT)) - (mp_digit)1;
+ mp_clamp(c);
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_mp_mod_d.c
Index: libtommath/bn_mp_mod_d.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_mod_d.c
@@ -0,0 +1,10 @@
+#include "tommath_private.h"
+#ifdef BN_MP_MOD_D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+mp_err mp_mod_d(const mp_int *a, mp_digit b, mp_digit *c)
+{
+ return mp_div_d(a, b, NULL, c);
+}
+#endif
ADDED libtommath/bn_mp_montgomery_calc_normalization.c
Index: libtommath/bn_mp_montgomery_calc_normalization.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_montgomery_calc_normalization.c
@@ -0,0 +1,44 @@
+#include "tommath_private.h"
+#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/*
+ * shifts with subtractions when the result is greater than b.
+ *
+ * The method is slightly modified to shift B unconditionally upto just under
+ * the leading bit of b. This saves alot of multiple precision shifting.
+ */
+mp_err mp_montgomery_calc_normalization(mp_int *a, const mp_int *b)
+{
+ int x, bits;
+ mp_err err;
+
+ /* how many bits of last digit does b use */
+ bits = mp_count_bits(b) % MP_DIGIT_BIT;
+
+ if (b->used > 1) {
+ if ((err = mp_2expt(a, ((b->used - 1) * MP_DIGIT_BIT) + bits - 1)) != MP_OKAY) {
+ return err;
+ }
+ } else {
+ mp_set(a, 1uL);
+ bits = 1;
+ }
+
+
+ /* now compute C = A * B mod b */
+ for (x = bits - 1; x < (int)MP_DIGIT_BIT; x++) {
+ if ((err = mp_mul_2(a, a)) != MP_OKAY) {
+ return err;
+ }
+ if (mp_cmp_mag(a, b) != MP_LT) {
+ if ((err = s_mp_sub(a, b, a)) != MP_OKAY) {
+ return err;
+ }
+ }
+ }
+
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_mp_montgomery_reduce.c
Index: libtommath/bn_mp_montgomery_reduce.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_montgomery_reduce.c
@@ -0,0 +1,102 @@
+#include "tommath_private.h"
+#ifdef BN_MP_MONTGOMERY_REDUCE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* computes xR**-1 == x (mod N) via Montgomery Reduction */
+mp_err mp_montgomery_reduce(mp_int *x, const mp_int *n, mp_digit rho)
+{
+ int ix, digs;
+ mp_err err;
+ mp_digit mu;
+
+ /* can the fast reduction [comba] method be used?
+ *
+ * Note that unlike in mul you're safely allowed *less*
+ * than the available columns [255 per default] since carries
+ * are fixed up in the inner loop.
+ */
+ digs = (n->used * 2) + 1;
+ if ((digs < MP_WARRAY) &&
+ (x->used <= MP_WARRAY) &&
+ (n->used < MP_MAXFAST)) {
+ return s_mp_montgomery_reduce_fast(x, n, rho);
+ }
+
+ /* grow the input as required */
+ if (x->alloc < digs) {
+ if ((err = mp_grow(x, digs)) != MP_OKAY) {
+ return err;
+ }
+ }
+ x->used = digs;
+
+ for (ix = 0; ix < n->used; ix++) {
+ /* mu = ai * rho mod b
+ *
+ * The value of rho must be precalculated via
+ * montgomery_setup() such that
+ * it equals -1/n0 mod b this allows the
+ * following inner loop to reduce the
+ * input one digit at a time
+ */
+ mu = (mp_digit)(((mp_word)x->dp[ix] * (mp_word)rho) & MP_MASK);
+
+ /* a = a + mu * m * b**i */
+ {
+ int iy;
+ mp_digit *tmpn, *tmpx, u;
+ mp_word r;
+
+ /* alias for digits of the modulus */
+ tmpn = n->dp;
+
+ /* alias for the digits of x [the input] */
+ tmpx = x->dp + ix;
+
+ /* set the carry to zero */
+ u = 0;
+
+ /* Multiply and add in place */
+ for (iy = 0; iy < n->used; iy++) {
+ /* compute product and sum */
+ r = ((mp_word)mu * (mp_word)*tmpn++) +
+ (mp_word)u + (mp_word)*tmpx;
+
+ /* get carry */
+ u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT);
+
+ /* fix digit */
+ *tmpx++ = (mp_digit)(r & (mp_word)MP_MASK);
+ }
+ /* At this point the ix'th digit of x should be zero */
+
+
+ /* propagate carries upwards as required*/
+ while (u != 0u) {
+ *tmpx += u;
+ u = *tmpx >> MP_DIGIT_BIT;
+ *tmpx++ &= MP_MASK;
+ }
+ }
+ }
+
+ /* at this point the n.used'th least
+ * significant digits of x are all zero
+ * which means we can shift x to the
+ * right by n.used digits and the
+ * residue is unchanged.
+ */
+
+ /* x = x/b**n.used */
+ mp_clamp(x);
+ mp_rshd(x, n->used);
+
+ /* if x >= n then x = x - n */
+ if (mp_cmp_mag(x, n) != MP_LT) {
+ return s_mp_sub(x, n, x);
+ }
+
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_mp_montgomery_setup.c
Index: libtommath/bn_mp_montgomery_setup.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_montgomery_setup.c
@@ -0,0 +1,42 @@
+#include "tommath_private.h"
+#ifdef BN_MP_MONTGOMERY_SETUP_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* setups the montgomery reduction stuff */
+mp_err mp_montgomery_setup(const mp_int *n, mp_digit *rho)
+{
+ mp_digit x, b;
+
+ /* fast inversion mod 2**k
+ *
+ * Based on the fact that
+ *
+ * XA = 1 (mod 2**n) => (X(2-XA)) A = 1 (mod 2**2n)
+ * => 2*X*A - X*X*A*A = 1
+ * => 2*(1) - (1) = 1
+ */
+ b = n->dp[0];
+
+ if ((b & 1u) == 0u) {
+ return MP_VAL;
+ }
+
+ x = (((b + 2u) & 4u) << 1) + b; /* here x*a==1 mod 2**4 */
+ x *= 2u - (b * x); /* here x*a==1 mod 2**8 */
+#if !defined(MP_8BIT)
+ x *= 2u - (b * x); /* here x*a==1 mod 2**16 */
+#endif
+#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT))
+ x *= 2u - (b * x); /* here x*a==1 mod 2**32 */
+#endif
+#ifdef MP_64BIT
+ x *= 2u - (b * x); /* here x*a==1 mod 2**64 */
+#endif
+
+ /* rho = -1/m mod b */
+ *rho = (mp_digit)(((mp_word)1 << (mp_word)MP_DIGIT_BIT) - x) & MP_MASK;
+
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_mp_mul.c
Index: libtommath/bn_mp_mul.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_mul.c
@@ -0,0 +1,52 @@
+#include "tommath_private.h"
+#ifdef BN_MP_MUL_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* high level multiplication (handles sign) */
+mp_err mp_mul(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ mp_err err;
+ int min_len = MP_MIN(a->used, b->used),
+ max_len = MP_MAX(a->used, b->used),
+ digs = a->used + b->used + 1;
+ mp_sign neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
+
+ if (MP_HAS(S_MP_BALANCE_MUL) &&
+ /* Check sizes. The smaller one needs to be larger than the Karatsuba cut-off.
+ * The bigger one needs to be at least about one MP_KARATSUBA_MUL_CUTOFF bigger
+ * to make some sense, but it depends on architecture, OS, position of the
+ * stars... so YMMV.
+ * Using it to cut the input into slices small enough for s_mp_mul_digs_fast
+ * was actually slower on the author's machine, but YMMV.
+ */
+ (min_len >= MP_KARATSUBA_MUL_CUTOFF) &&
+ ((max_len / 2) >= MP_KARATSUBA_MUL_CUTOFF) &&
+ /* Not much effect was observed below a ratio of 1:2, but again: YMMV. */
+ (max_len >= (2 * min_len))) {
+ err = s_mp_balance_mul(a,b,c);
+ } else if (MP_HAS(S_MP_TOOM_MUL) &&
+ (min_len >= MP_TOOM_MUL_CUTOFF)) {
+ err = s_mp_toom_mul(a, b, c);
+ } else if (MP_HAS(S_MP_KARATSUBA_MUL) &&
+ (min_len >= MP_KARATSUBA_MUL_CUTOFF)) {
+ err = s_mp_karatsuba_mul(a, b, c);
+ } else if (MP_HAS(S_MP_MUL_DIGS_FAST) &&
+ /* can we use the fast multiplier?
+ *
+ * The fast multiplier can be used if the output will
+ * have less than MP_WARRAY digits and the number of
+ * digits won't affect carry propagation
+ */
+ (digs < MP_WARRAY) &&
+ (min_len <= MP_MAXFAST)) {
+ err = s_mp_mul_digs_fast(a, b, c, digs);
+ } else if (MP_HAS(S_MP_MUL_DIGS)) {
+ err = s_mp_mul_digs(a, b, c, digs);
+ } else {
+ err = MP_VAL;
+ }
+ c->sign = (c->used > 0) ? neg : MP_ZPOS;
+ return err;
+}
+#endif
ADDED libtommath/bn_mp_mul_2.c
Index: libtommath/bn_mp_mul_2.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_mul_2.c
@@ -0,0 +1,64 @@
+#include "tommath_private.h"
+#ifdef BN_MP_MUL_2_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* b = a*2 */
+mp_err mp_mul_2(const mp_int *a, mp_int *b)
+{
+ int x, oldused;
+ mp_err err;
+
+ /* grow to accomodate result */
+ if (b->alloc < (a->used + 1)) {
+ if ((err = mp_grow(b, a->used + 1)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ oldused = b->used;
+ b->used = a->used;
+
+ {
+ mp_digit r, rr, *tmpa, *tmpb;
+
+ /* alias for source */
+ tmpa = a->dp;
+
+ /* alias for dest */
+ tmpb = b->dp;
+
+ /* carry */
+ r = 0;
+ for (x = 0; x < a->used; x++) {
+
+ /* get what will be the *next* carry bit from the
+ * MSB of the current digit
+ */
+ rr = *tmpa >> (mp_digit)(MP_DIGIT_BIT - 1);
+
+ /* now shift up this digit, add in the carry [from the previous] */
+ *tmpb++ = ((*tmpa++ << 1uL) | r) & MP_MASK;
+
+ /* copy the carry that would be from the source
+ * digit into the next iteration
+ */
+ r = rr;
+ }
+
+ /* new leading digit? */
+ if (r != 0u) {
+ /* add a MSB which is always 1 at this point */
+ *tmpb = 1;
+ ++(b->used);
+ }
+
+ /* now zero any excess digits on the destination
+ * that we didn't write to
+ */
+ MP_ZERO_DIGITS(b->dp + b->used, oldused - b->used);
+ }
+ b->sign = a->sign;
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_mp_mul_2d.c
Index: libtommath/bn_mp_mul_2d.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_mul_2d.c
@@ -0,0 +1,73 @@
+#include "tommath_private.h"
+#ifdef BN_MP_MUL_2D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* shift left by a certain bit count */
+mp_err mp_mul_2d(const mp_int *a, int b, mp_int *c)
+{
+ mp_digit d;
+ mp_err err;
+
+ if (b < 0) {
+ return MP_VAL;
+ }
+
+ /* copy */
+ if (a != c) {
+ if ((err = mp_copy(a, c)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ if (c->alloc < (c->used + (b / MP_DIGIT_BIT) + 1)) {
+ if ((err = mp_grow(c, c->used + (b / MP_DIGIT_BIT) + 1)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ /* shift by as many digits in the bit count */
+ if (b >= MP_DIGIT_BIT) {
+ if ((err = mp_lshd(c, b / MP_DIGIT_BIT)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ /* shift any bit count < MP_DIGIT_BIT */
+ d = (mp_digit)(b % MP_DIGIT_BIT);
+ if (d != 0u) {
+ mp_digit *tmpc, shift, mask, r, rr;
+ int x;
+
+ /* bitmask for carries */
+ mask = ((mp_digit)1 << d) - (mp_digit)1;
+
+ /* shift for msbs */
+ shift = (mp_digit)MP_DIGIT_BIT - d;
+
+ /* alias */
+ tmpc = c->dp;
+
+ /* carry */
+ r = 0;
+ for (x = 0; x < c->used; x++) {
+ /* get the higher bits of the current word */
+ rr = (*tmpc >> shift) & mask;
+
+ /* shift the current word and OR in the carry */
+ *tmpc = ((*tmpc << d) | r) & MP_MASK;
+ ++tmpc;
+
+ /* set the carry to the carry bits of the current word */
+ r = rr;
+ }
+
+ /* set final carry */
+ if (r != 0u) {
+ c->dp[(c->used)++] = r;
+ }
+ }
+ mp_clamp(c);
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_mp_mul_d.c
Index: libtommath/bn_mp_mul_d.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_mul_d.c
@@ -0,0 +1,61 @@
+#include "tommath_private.h"
+#ifdef BN_MP_MUL_D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* multiply by a digit */
+mp_err mp_mul_d(const mp_int *a, mp_digit b, mp_int *c)
+{
+ mp_digit u, *tmpa, *tmpc;
+ mp_word r;
+ mp_err err;
+ int ix, olduse;
+
+ /* make sure c is big enough to hold a*b */
+ if (c->alloc < (a->used + 1)) {
+ if ((err = mp_grow(c, a->used + 1)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ /* get the original destinations used count */
+ olduse = c->used;
+
+ /* set the sign */
+ c->sign = a->sign;
+
+ /* alias for a->dp [source] */
+ tmpa = a->dp;
+
+ /* alias for c->dp [dest] */
+ tmpc = c->dp;
+
+ /* zero carry */
+ u = 0;
+
+ /* compute columns */
+ for (ix = 0; ix < a->used; ix++) {
+ /* compute product and carry sum for this term */
+ r = (mp_word)u + ((mp_word)*tmpa++ * (mp_word)b);
+
+ /* mask off higher bits to get a single digit */
+ *tmpc++ = (mp_digit)(r & (mp_word)MP_MASK);
+
+ /* send carry into next iteration */
+ u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT);
+ }
+
+ /* store final carry [if any] and increment ix offset */
+ *tmpc++ = u;
+ ++ix;
+
+ /* now zero digits above the top */
+ MP_ZERO_DIGITS(tmpc, olduse - ix);
+
+ /* set used count */
+ c->used = a->used + 1;
+ mp_clamp(c);
+
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_mp_mulmod.c
Index: libtommath/bn_mp_mulmod.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_mulmod.c
@@ -0,0 +1,25 @@
+#include "tommath_private.h"
+#ifdef BN_MP_MULMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* d = a * b (mod c) */
+mp_err mp_mulmod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d)
+{
+ mp_err err;
+ mp_int t;
+
+ if ((err = mp_init_size(&t, c->used)) != MP_OKAY) {
+ return err;
+ }
+
+ if ((err = mp_mul(a, b, &t)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ err = mp_mod(&t, c, d);
+
+LBL_ERR:
+ mp_clear(&t);
+ return err;
+}
+#endif
ADDED libtommath/bn_mp_neg.c
Index: libtommath/bn_mp_neg.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_neg.c
@@ -0,0 +1,24 @@
+#include "tommath_private.h"
+#ifdef BN_MP_NEG_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* b = -a */
+mp_err mp_neg(const mp_int *a, mp_int *b)
+{
+ mp_err err;
+ if (a != b) {
+ if ((err = mp_copy(a, b)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ if (!MP_IS_ZERO(b)) {
+ b->sign = (a->sign == MP_ZPOS) ? MP_NEG : MP_ZPOS;
+ } else {
+ b->sign = MP_ZPOS;
+ }
+
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_mp_or.c
Index: libtommath/bn_mp_or.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_or.c
@@ -0,0 +1,56 @@
+#include "tommath_private.h"
+#ifdef BN_MP_OR_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* two complement or */
+mp_err mp_or(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ int used = MP_MAX(a->used, b->used) + 1, i;
+ mp_err err;
+ mp_digit ac = 1, bc = 1, cc = 1;
+ mp_sign csign = ((a->sign == MP_NEG) || (b->sign == MP_NEG)) ? MP_NEG : MP_ZPOS;
+
+ if (c->alloc < used) {
+ if ((err = mp_grow(c, used)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ for (i = 0; i < used; i++) {
+ mp_digit x, y;
+
+ /* convert to two complement if negative */
+ if (a->sign == MP_NEG) {
+ ac += (i >= a->used) ? MP_MASK : (~a->dp[i] & MP_MASK);
+ x = ac & MP_MASK;
+ ac >>= MP_DIGIT_BIT;
+ } else {
+ x = (i >= a->used) ? 0uL : a->dp[i];
+ }
+
+ /* convert to two complement if negative */
+ if (b->sign == MP_NEG) {
+ bc += (i >= b->used) ? MP_MASK : (~b->dp[i] & MP_MASK);
+ y = bc & MP_MASK;
+ bc >>= MP_DIGIT_BIT;
+ } else {
+ y = (i >= b->used) ? 0uL : b->dp[i];
+ }
+
+ c->dp[i] = x | y;
+
+ /* convert to to sign-magnitude if negative */
+ if (csign == MP_NEG) {
+ cc += ~c->dp[i] & MP_MASK;
+ c->dp[i] = cc & MP_MASK;
+ cc >>= MP_DIGIT_BIT;
+ }
+ }
+
+ c->used = used;
+ c->sign = csign;
+ mp_clamp(c);
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_mp_pack.c
Index: libtommath/bn_mp_pack.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_pack.c
@@ -0,0 +1,69 @@
+#include "tommath_private.h"
+#ifdef BN_MP_PACK_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* based on gmp's mpz_export.
+ * see http://gmplib.org/manual/Integer-Import-and-Export.html
+ */
+mp_err mp_pack(void *rop, size_t maxcount, size_t *written, mp_order order, size_t size,
+ mp_endian endian, size_t nails, const mp_int *op)
+{
+ mp_err err;
+ size_t odd_nails, nail_bytes, i, j, count;
+ unsigned char odd_nail_mask;
+
+ mp_int t;
+
+ count = mp_pack_count(op, nails, size);
+
+ if (count > maxcount) {
+ return MP_BUF;
+ }
+
+ if ((err = mp_init_copy(&t, op)) != MP_OKAY) {
+ return err;
+ }
+
+ if (endian == MP_NATIVE_ENDIAN) {
+ MP_GET_ENDIANNESS(endian);
+ }
+
+ odd_nails = (nails % 8u);
+ odd_nail_mask = 0xff;
+ for (i = 0u; i < odd_nails; ++i) {
+ odd_nail_mask ^= (unsigned char)(1u << (7u - i));
+ }
+ nail_bytes = nails / 8u;
+
+ for (i = 0u; i < count; ++i) {
+ for (j = 0u; j < size; ++j) {
+ unsigned char *byte = (unsigned char *)rop +
+ (((order == MP_LSB_FIRST) ? i : ((count - 1u) - i)) * size) +
+ ((endian == MP_LITTLE_ENDIAN) ? j : ((size - 1u) - j));
+
+ if (j >= (size - nail_bytes)) {
+ *byte = 0;
+ continue;
+ }
+
+ *byte = (unsigned char)((j == ((size - nail_bytes) - 1u)) ? (t.dp[0] & odd_nail_mask) : (t.dp[0] & 0xFFuL));
+
+ if ((err = mp_div_2d(&t, (j == ((size - nail_bytes) - 1u)) ? (int)(8u - odd_nails) : 8, &t, NULL)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ }
+ }
+
+ if (written != NULL) {
+ *written = count;
+ }
+ err = MP_OKAY;
+
+LBL_ERR:
+ mp_clear(&t);
+ return err;
+}
+
+#endif
ADDED libtommath/bn_mp_pack_count.c
Index: libtommath/bn_mp_pack_count.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_pack_count.c
@@ -0,0 +1,12 @@
+#include "tommath_private.h"
+#ifdef BN_MP_PACK_COUNT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+size_t mp_pack_count(const mp_int *a, size_t nails, size_t size)
+{
+ size_t bits = (size_t)mp_count_bits(a);
+ return ((bits / ((size * 8u) - nails)) + (((bits % ((size * 8u) - nails)) != 0u) ? 1u : 0u));
+}
+
+#endif
ADDED libtommath/bn_mp_prime_fermat.c
Index: libtommath/bn_mp_prime_fermat.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_prime_fermat.c
@@ -0,0 +1,47 @@
+#include "tommath_private.h"
+#ifdef BN_MP_PRIME_FERMAT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* performs one Fermat test.
+ *
+ * If "a" were prime then b**a == b (mod a) since the order of
+ * the multiplicative sub-group would be phi(a) = a-1. That means
+ * it would be the same as b**(a mod (a-1)) == b**1 == b (mod a).
+ *
+ * Sets result to 1 if the congruence holds, or zero otherwise.
+ */
+mp_err mp_prime_fermat(const mp_int *a, const mp_int *b, mp_bool *result)
+{
+ mp_int t;
+ mp_err err;
+
+ /* default to composite */
+ *result = MP_NO;
+
+ /* ensure b > 1 */
+ if (mp_cmp_d(b, 1uL) != MP_GT) {
+ return MP_VAL;
+ }
+
+ /* init t */
+ if ((err = mp_init(&t)) != MP_OKAY) {
+ return err;
+ }
+
+ /* compute t = b**a mod a */
+ if ((err = mp_exptmod(b, a, a, &t)) != MP_OKAY) {
+ goto LBL_T;
+ }
+
+ /* is it equal to b? */
+ if (mp_cmp(&t, b) == MP_EQ) {
+ *result = MP_YES;
+ }
+
+ err = MP_OKAY;
+LBL_T:
+ mp_clear(&t);
+ return err;
+}
+#endif
ADDED libtommath/bn_mp_prime_frobenius_underwood.c
Index: libtommath/bn_mp_prime_frobenius_underwood.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_prime_frobenius_underwood.c
@@ -0,0 +1,132 @@
+#include "tommath_private.h"
+#ifdef BN_MP_PRIME_FROBENIUS_UNDERWOOD_C
+
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/*
+ * See file bn_mp_prime_is_prime.c or the documentation in doc/bn.tex for the details
+ */
+#ifndef LTM_USE_ONLY_MR
+
+#ifdef MP_8BIT
+/*
+ * floor of positive solution of
+ * (2^16)-1 = (a+4)*(2*a+5)
+ * TODO: Both values are smaller than N^(1/4), would have to use a bigint
+ * for a instead but any a biger than about 120 are already so rare that
+ * it is possible to ignore them and still get enough pseudoprimes.
+ * But it is still a restriction of the set of available pseudoprimes
+ * which makes this implementation less secure if used stand-alone.
+ */
+#define LTM_FROBENIUS_UNDERWOOD_A 177
+#else
+#define LTM_FROBENIUS_UNDERWOOD_A 32764
+#endif
+mp_err mp_prime_frobenius_underwood(const mp_int *N, mp_bool *result)
+{
+ mp_int T1z, T2z, Np1z, sz, tz;
+
+ int a, ap2, length, i, j;
+ mp_err err;
+
+ *result = MP_NO;
+
+ if ((err = mp_init_multi(&T1z, &T2z, &Np1z, &sz, &tz, NULL)) != MP_OKAY) {
+ return err;
+ }
+
+ for (a = 0; a < LTM_FROBENIUS_UNDERWOOD_A; a++) {
+ /* TODO: That's ugly! No, really, it is! */
+ if ((a==2) || (a==4) || (a==7) || (a==8) || (a==10) ||
+ (a==14) || (a==18) || (a==23) || (a==26) || (a==28)) {
+ continue;
+ }
+ /* (32764^2 - 4) < 2^31, no bigint for >MP_8BIT needed) */
+ mp_set_u32(&T1z, (uint32_t)a);
+
+ if ((err = mp_sqr(&T1z, &T1z)) != MP_OKAY) goto LBL_FU_ERR;
+
+ if ((err = mp_sub_d(&T1z, 4uL, &T1z)) != MP_OKAY) goto LBL_FU_ERR;
+
+ if ((err = mp_kronecker(&T1z, N, &j)) != MP_OKAY) goto LBL_FU_ERR;
+
+ if (j == -1) {
+ break;
+ }
+
+ if (j == 0) {
+ /* composite */
+ goto LBL_FU_ERR;
+ }
+ }
+ /* Tell it a composite and set return value accordingly */
+ if (a >= LTM_FROBENIUS_UNDERWOOD_A) {
+ err = MP_ITER;
+ goto LBL_FU_ERR;
+ }
+ /* Composite if N and (a+4)*(2*a+5) are not coprime */
+ mp_set_u32(&T1z, (uint32_t)((a+4)*((2*a)+5)));
+
+ if ((err = mp_gcd(N, &T1z, &T1z)) != MP_OKAY) goto LBL_FU_ERR;
+
+ if (!((T1z.used == 1) && (T1z.dp[0] == 1u))) goto LBL_FU_ERR;
+
+ ap2 = a + 2;
+ if ((err = mp_add_d(N, 1uL, &Np1z)) != MP_OKAY) goto LBL_FU_ERR;
+
+ mp_set(&sz, 1uL);
+ mp_set(&tz, 2uL);
+ length = mp_count_bits(&Np1z);
+
+ for (i = length - 2; i >= 0; i--) {
+ /*
+ * temp = (sz*(a*sz+2*tz))%N;
+ * tz = ((tz-sz)*(tz+sz))%N;
+ * sz = temp;
+ */
+ if ((err = mp_mul_2(&tz, &T2z)) != MP_OKAY) goto LBL_FU_ERR;
+
+ /* a = 0 at about 50% of the cases (non-square and odd input) */
+ if (a != 0) {
+ if ((err = mp_mul_d(&sz, (mp_digit)a, &T1z)) != MP_OKAY) goto LBL_FU_ERR;
+ if ((err = mp_add(&T1z, &T2z, &T2z)) != MP_OKAY) goto LBL_FU_ERR;
+ }
+
+ if ((err = mp_mul(&T2z, &sz, &T1z)) != MP_OKAY) goto LBL_FU_ERR;
+ if ((err = mp_sub(&tz, &sz, &T2z)) != MP_OKAY) goto LBL_FU_ERR;
+ if ((err = mp_add(&sz, &tz, &sz)) != MP_OKAY) goto LBL_FU_ERR;
+ if ((err = mp_mul(&sz, &T2z, &tz)) != MP_OKAY) goto LBL_FU_ERR;
+ if ((err = mp_mod(&tz, N, &tz)) != MP_OKAY) goto LBL_FU_ERR;
+ if ((err = mp_mod(&T1z, N, &sz)) != MP_OKAY) goto LBL_FU_ERR;
+ if (s_mp_get_bit(&Np1z, (unsigned int)i) == MP_YES) {
+ /*
+ * temp = (a+2) * sz + tz
+ * tz = 2 * tz - sz
+ * sz = temp
+ */
+ if (a == 0) {
+ if ((err = mp_mul_2(&sz, &T1z)) != MP_OKAY) goto LBL_FU_ERR;
+ } else {
+ if ((err = mp_mul_d(&sz, (mp_digit)ap2, &T1z)) != MP_OKAY) goto LBL_FU_ERR;
+ }
+ if ((err = mp_add(&T1z, &tz, &T1z)) != MP_OKAY) goto LBL_FU_ERR;
+ if ((err = mp_mul_2(&tz, &T2z)) != MP_OKAY) goto LBL_FU_ERR;
+ if ((err = mp_sub(&T2z, &sz, &tz)) != MP_OKAY) goto LBL_FU_ERR;
+ mp_exch(&sz, &T1z);
+ }
+ }
+
+ mp_set_u32(&T1z, (uint32_t)((2 * a) + 5));
+ if ((err = mp_mod(&T1z, N, &T1z)) != MP_OKAY) goto LBL_FU_ERR;
+ if (MP_IS_ZERO(&sz) && (mp_cmp(&tz, &T1z) == MP_EQ)) {
+ *result = MP_YES;
+ }
+
+LBL_FU_ERR:
+ mp_clear_multi(&tz, &sz, &Np1z, &T2z, &T1z, NULL);
+ return err;
+}
+
+#endif
+#endif
ADDED libtommath/bn_mp_prime_is_prime.c
Index: libtommath/bn_mp_prime_is_prime.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_prime_is_prime.c
@@ -0,0 +1,314 @@
+#include "tommath_private.h"
+#ifdef BN_MP_PRIME_IS_PRIME_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* portable integer log of two with small footprint */
+static unsigned int s_floor_ilog2(int value)
+{
+ unsigned int r = 0;
+ while ((value >>= 1) != 0) {
+ r++;
+ }
+ return r;
+}
+
+
+mp_err mp_prime_is_prime(const mp_int *a, int t, mp_bool *result)
+{
+ mp_int b;
+ int ix, p_max = 0, size_a, len;
+ mp_bool res;
+ mp_err err;
+ unsigned int fips_rand, mask;
+
+ /* default to no */
+ *result = MP_NO;
+
+ /* Some shortcuts */
+ /* N > 3 */
+ if (a->used == 1) {
+ if ((a->dp[0] == 0u) || (a->dp[0] == 1u)) {
+ *result = MP_NO;
+ return MP_OKAY;
+ }
+ if (a->dp[0] == 2u) {
+ *result = MP_YES;
+ return MP_OKAY;
+ }
+ }
+
+ /* N must be odd */
+ if (MP_IS_EVEN(a)) {
+ return MP_OKAY;
+ }
+ /* N is not a perfect square: floor(sqrt(N))^2 != N */
+ if ((err = mp_is_square(a, &res)) != MP_OKAY) {
+ return err;
+ }
+ if (res != MP_NO) {
+ return MP_OKAY;
+ }
+
+ /* is the input equal to one of the primes in the table? */
+ for (ix = 0; ix < PRIVATE_MP_PRIME_TAB_SIZE; ix++) {
+ if (mp_cmp_d(a, s_mp_prime_tab[ix]) == MP_EQ) {
+ *result = MP_YES;
+ return MP_OKAY;
+ }
+ }
+#ifdef MP_8BIT
+ /* The search in the loop above was exhaustive in this case */
+ if ((a->used == 1) && (PRIVATE_MP_PRIME_TAB_SIZE >= 31)) {
+ return MP_OKAY;
+ }
+#endif
+
+ /* first perform trial division */
+ if ((err = s_mp_prime_is_divisible(a, &res)) != MP_OKAY) {
+ return err;
+ }
+
+ /* return if it was trivially divisible */
+ if (res == MP_YES) {
+ return MP_OKAY;
+ }
+
+ /*
+ Run the Miller-Rabin test with base 2 for the BPSW test.
+ */
+ if ((err = mp_init_set(&b, 2uL)) != MP_OKAY) {
+ return err;
+ }
+
+ if ((err = mp_prime_miller_rabin(a, &b, &res)) != MP_OKAY) {
+ goto LBL_B;
+ }
+ if (res == MP_NO) {
+ goto LBL_B;
+ }
+ /*
+ Rumours have it that Mathematica does a second M-R test with base 3.
+ Other rumours have it that their strong L-S test is slightly different.
+ It does not hurt, though, beside a bit of extra runtime.
+ */
+ b.dp[0]++;
+ if ((err = mp_prime_miller_rabin(a, &b, &res)) != MP_OKAY) {
+ goto LBL_B;
+ }
+ if (res == MP_NO) {
+ goto LBL_B;
+ }
+
+ /*
+ * Both, the Frobenius-Underwood test and the the Lucas-Selfridge test are quite
+ * slow so if speed is an issue, define LTM_USE_ONLY_MR to use M-R tests with
+ * bases 2, 3 and t random bases.
+ */
+#ifndef LTM_USE_ONLY_MR
+ if (t >= 0) {
+ /*
+ * Use a Frobenius-Underwood test instead of the Lucas-Selfridge test for
+ * MP_8BIT (It is unknown if the Lucas-Selfridge test works with 16-bit
+ * integers but the necesssary analysis is on the todo-list).
+ */
+#if defined (MP_8BIT) || defined (LTM_USE_FROBENIUS_TEST)
+ err = mp_prime_frobenius_underwood(a, &res);
+ if ((err != MP_OKAY) && (err != MP_ITER)) {
+ goto LBL_B;
+ }
+ if (res == MP_NO) {
+ goto LBL_B;
+ }
+#else
+ if ((err = mp_prime_strong_lucas_selfridge(a, &res)) != MP_OKAY) {
+ goto LBL_B;
+ }
+ if (res == MP_NO) {
+ goto LBL_B;
+ }
+#endif
+ }
+#endif
+
+ /* run at least one Miller-Rabin test with a random base */
+ if (t == 0) {
+ t = 1;
+ }
+
+ /*
+ Only recommended if the input range is known to be < 3317044064679887385961981
+
+ It uses the bases necessary for a deterministic M-R test if the input is
+ smaller than 3317044064679887385961981
+ The caller has to check the size.
+ TODO: can be made a bit finer grained but comparing is not free.
+ */
+ if (t < 0) {
+ /*
+ Sorenson, Jonathan; Webster, Jonathan (2015).
+ "Strong Pseudoprimes to Twelve Prime Bases".
+ */
+ /* 0x437ae92817f9fc85b7e5 = 318665857834031151167461 */
+ if ((err = mp_read_radix(&b, "437ae92817f9fc85b7e5", 16)) != MP_OKAY) {
+ goto LBL_B;
+ }
+
+ if (mp_cmp(a, &b) == MP_LT) {
+ p_max = 12;
+ } else {
+ /* 0x2be6951adc5b22410a5fd = 3317044064679887385961981 */
+ if ((err = mp_read_radix(&b, "2be6951adc5b22410a5fd", 16)) != MP_OKAY) {
+ goto LBL_B;
+ }
+
+ if (mp_cmp(a, &b) == MP_LT) {
+ p_max = 13;
+ } else {
+ err = MP_VAL;
+ goto LBL_B;
+ }
+ }
+
+ /* we did bases 2 and 3 already, skip them */
+ for (ix = 2; ix < p_max; ix++) {
+ mp_set(&b, s_mp_prime_tab[ix]);
+ if ((err = mp_prime_miller_rabin(a, &b, &res)) != MP_OKAY) {
+ goto LBL_B;
+ }
+ if (res == MP_NO) {
+ goto LBL_B;
+ }
+ }
+ }
+ /*
+ Do "t" M-R tests with random bases between 3 and "a".
+ See Fips 186.4 p. 126ff
+ */
+ else if (t > 0) {
+ /*
+ * The mp_digit's have a defined bit-size but the size of the
+ * array a.dp is a simple 'int' and this library can not assume full
+ * compliance to the current C-standard (ISO/IEC 9899:2011) because
+ * it gets used for small embeded processors, too. Some of those MCUs
+ * have compilers that one cannot call standard compliant by any means.
+ * Hence the ugly type-fiddling in the following code.
+ */
+ size_a = mp_count_bits(a);
+ mask = (1u << s_floor_ilog2(size_a)) - 1u;
+ /*
+ Assuming the General Rieman hypothesis (never thought to write that in a
+ comment) the upper bound can be lowered to 2*(log a)^2.
+ E. Bach, "Explicit bounds for primality testing and related problems,"
+ Math. Comp. 55 (1990), 355-380.
+
+ size_a = (size_a/10) * 7;
+ len = 2 * (size_a * size_a);
+
+ E.g.: a number of size 2^2048 would be reduced to the upper limit
+
+ floor(2048/10)*7 = 1428
+ 2 * 1428^2 = 4078368
+
+ (would have been ~4030331.9962 with floats and natural log instead)
+ That number is smaller than 2^28, the default bit-size of mp_digit.
+ */
+
+ /*
+ How many tests, you might ask? Dana Jacobsen of Math::Prime::Util fame
+ does exactly 1. In words: one. Look at the end of _GMP_is_prime() in
+ Math-Prime-Util-GMP-0.50/primality.c if you do not believe it.
+
+ The function mp_rand() goes to some length to use a cryptographically
+ good PRNG. That also means that the chance to always get the same base
+ in the loop is non-zero, although very low.
+ If the BPSW test and/or the addtional Frobenious test have been
+ performed instead of just the Miller-Rabin test with the bases 2 and 3,
+ a single extra test should suffice, so such a very unlikely event
+ will not do much harm.
+
+ To preemptivly answer the dangling question: no, a witness does not
+ need to be prime.
+ */
+ for (ix = 0; ix < t; ix++) {
+ /* mp_rand() guarantees the first digit to be non-zero */
+ if ((err = mp_rand(&b, 1)) != MP_OKAY) {
+ goto LBL_B;
+ }
+ /*
+ * Reduce digit before casting because mp_digit might be bigger than
+ * an unsigned int and "mask" on the other side is most probably not.
+ */
+ fips_rand = (unsigned int)(b.dp[0] & (mp_digit) mask);
+#ifdef MP_8BIT
+ /*
+ * One 8-bit digit is too small, so concatenate two if the size of
+ * unsigned int allows for it.
+ */
+ if ((MP_SIZEOF_BITS(unsigned int)/2) >= MP_SIZEOF_BITS(mp_digit)) {
+ if ((err = mp_rand(&b, 1)) != MP_OKAY) {
+ goto LBL_B;
+ }
+ fips_rand <<= MP_SIZEOF_BITS(mp_digit);
+ fips_rand |= (unsigned int) b.dp[0];
+ fips_rand &= mask;
+ }
+#endif
+ if (fips_rand > (unsigned int)(INT_MAX - MP_DIGIT_BIT)) {
+ len = INT_MAX / MP_DIGIT_BIT;
+ } else {
+ len = (((int)fips_rand + MP_DIGIT_BIT) / MP_DIGIT_BIT);
+ }
+ /* Unlikely. */
+ if (len < 0) {
+ ix--;
+ continue;
+ }
+ /*
+ * As mentioned above, one 8-bit digit is too small and
+ * although it can only happen in the unlikely case that
+ * an "unsigned int" is smaller than 16 bit a simple test
+ * is cheap and the correction even cheaper.
+ */
+#ifdef MP_8BIT
+ /* All "a" < 2^8 have been caught before */
+ if (len == 1) {
+ len++;
+ }
+#endif
+ if ((err = mp_rand(&b, len)) != MP_OKAY) {
+ goto LBL_B;
+ }
+ /*
+ * That number might got too big and the witness has to be
+ * smaller than "a"
+ */
+ len = mp_count_bits(&b);
+ if (len >= size_a) {
+ len = (len - size_a) + 1;
+ if ((err = mp_div_2d(&b, len, &b, NULL)) != MP_OKAY) {
+ goto LBL_B;
+ }
+ }
+ /* Although the chance for b <= 3 is miniscule, try again. */
+ if (mp_cmp_d(&b, 3uL) != MP_GT) {
+ ix--;
+ continue;
+ }
+ if ((err = mp_prime_miller_rabin(a, &b, &res)) != MP_OKAY) {
+ goto LBL_B;
+ }
+ if (res == MP_NO) {
+ goto LBL_B;
+ }
+ }
+ }
+
+ /* passed the test */
+ *result = MP_YES;
+LBL_B:
+ mp_clear(&b);
+ return err;
+}
+
+#endif
ADDED libtommath/bn_mp_prime_miller_rabin.c
Index: libtommath/bn_mp_prime_miller_rabin.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_prime_miller_rabin.c
@@ -0,0 +1,91 @@
+#include "tommath_private.h"
+#ifdef BN_MP_PRIME_MILLER_RABIN_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* Miller-Rabin test of "a" to the base of "b" as described in
+ * HAC pp. 139 Algorithm 4.24
+ *
+ * Sets result to 0 if definitely composite or 1 if probably prime.
+ * Randomly the chance of error is no more than 1/4 and often
+ * very much lower.
+ */
+mp_err mp_prime_miller_rabin(const mp_int *a, const mp_int *b, mp_bool *result)
+{
+ mp_int n1, y, r;
+ mp_err err;
+ int s, j;
+
+ /* default */
+ *result = MP_NO;
+
+ /* ensure b > 1 */
+ if (mp_cmp_d(b, 1uL) != MP_GT) {
+ return MP_VAL;
+ }
+
+ /* get n1 = a - 1 */
+ if ((err = mp_init_copy(&n1, a)) != MP_OKAY) {
+ return err;
+ }
+ if ((err = mp_sub_d(&n1, 1uL, &n1)) != MP_OKAY) {
+ goto LBL_N1;
+ }
+
+ /* set 2**s * r = n1 */
+ if ((err = mp_init_copy(&r, &n1)) != MP_OKAY) {
+ goto LBL_N1;
+ }
+
+ /* count the number of least significant bits
+ * which are zero
+ */
+ s = mp_cnt_lsb(&r);
+
+ /* now divide n - 1 by 2**s */
+ if ((err = mp_div_2d(&r, s, &r, NULL)) != MP_OKAY) {
+ goto LBL_R;
+ }
+
+ /* compute y = b**r mod a */
+ if ((err = mp_init(&y)) != MP_OKAY) {
+ goto LBL_R;
+ }
+ if ((err = mp_exptmod(b, &r, a, &y)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+
+ /* if y != 1 and y != n1 do */
+ if ((mp_cmp_d(&y, 1uL) != MP_EQ) && (mp_cmp(&y, &n1) != MP_EQ)) {
+ j = 1;
+ /* while j <= s-1 and y != n1 */
+ while ((j <= (s - 1)) && (mp_cmp(&y, &n1) != MP_EQ)) {
+ if ((err = mp_sqrmod(&y, a, &y)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+
+ /* if y == 1 then composite */
+ if (mp_cmp_d(&y, 1uL) == MP_EQ) {
+ goto LBL_Y;
+ }
+
+ ++j;
+ }
+
+ /* if y != n1 then composite */
+ if (mp_cmp(&y, &n1) != MP_EQ) {
+ goto LBL_Y;
+ }
+ }
+
+ /* probably prime now */
+ *result = MP_YES;
+LBL_Y:
+ mp_clear(&y);
+LBL_R:
+ mp_clear(&r);
+LBL_N1:
+ mp_clear(&n1);
+ return err;
+}
+#endif
ADDED libtommath/bn_mp_prime_next_prime.c
Index: libtommath/bn_mp_prime_next_prime.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_prime_next_prime.c
@@ -0,0 +1,132 @@
+#include "tommath_private.h"
+#ifdef BN_MP_PRIME_NEXT_PRIME_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* finds the next prime after the number "a" using "t" trials
+ * of Miller-Rabin.
+ *
+ * bbs_style = 1 means the prime must be congruent to 3 mod 4
+ */
+mp_err mp_prime_next_prime(mp_int *a, int t, int bbs_style)
+{
+ int x, y;
+ mp_ord cmp;
+ mp_err err;
+ mp_bool res = MP_NO;
+ mp_digit res_tab[PRIVATE_MP_PRIME_TAB_SIZE], step, kstep;
+ mp_int b;
+
+ /* force positive */
+ a->sign = MP_ZPOS;
+
+ /* simple algo if a is less than the largest prime in the table */
+ if (mp_cmp_d(a, s_mp_prime_tab[PRIVATE_MP_PRIME_TAB_SIZE-1]) == MP_LT) {
+ /* find which prime it is bigger than "a" */
+ for (x = 0; x < PRIVATE_MP_PRIME_TAB_SIZE; x++) {
+ cmp = mp_cmp_d(a, s_mp_prime_tab[x]);
+ if (cmp == MP_EQ) {
+ continue;
+ }
+ if (cmp != MP_GT) {
+ if ((bbs_style == 1) && ((s_mp_prime_tab[x] & 3u) != 3u)) {
+ /* try again until we get a prime congruent to 3 mod 4 */
+ continue;
+ } else {
+ mp_set(a, s_mp_prime_tab[x]);
+ return MP_OKAY;
+ }
+ }
+ }
+ /* fall through to the sieve */
+ }
+
+ /* generate a prime congruent to 3 mod 4 or 1/3 mod 4? */
+ if (bbs_style == 1) {
+ kstep = 4;
+ } else {
+ kstep = 2;
+ }
+
+ /* at this point we will use a combination of a sieve and Miller-Rabin */
+
+ if (bbs_style == 1) {
+ /* if a mod 4 != 3 subtract the correct value to make it so */
+ if ((a->dp[0] & 3u) != 3u) {
+ if ((err = mp_sub_d(a, (a->dp[0] & 3u) + 1u, a)) != MP_OKAY) {
+ return err;
+ }
+ }
+ } else {
+ if (MP_IS_EVEN(a)) {
+ /* force odd */
+ if ((err = mp_sub_d(a, 1uL, a)) != MP_OKAY) {
+ return err;
+ }
+ }
+ }
+
+ /* generate the restable */
+ for (x = 1; x < PRIVATE_MP_PRIME_TAB_SIZE; x++) {
+ if ((err = mp_mod_d(a, s_mp_prime_tab[x], res_tab + x)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ /* init temp used for Miller-Rabin Testing */
+ if ((err = mp_init(&b)) != MP_OKAY) {
+ return err;
+ }
+
+ for (;;) {
+ /* skip to the next non-trivially divisible candidate */
+ step = 0;
+ do {
+ /* y == 1 if any residue was zero [e.g. cannot be prime] */
+ y = 0;
+
+ /* increase step to next candidate */
+ step += kstep;
+
+ /* compute the new residue without using division */
+ for (x = 1; x < PRIVATE_MP_PRIME_TAB_SIZE; x++) {
+ /* add the step to each residue */
+ res_tab[x] += kstep;
+
+ /* subtract the modulus [instead of using division] */
+ if (res_tab[x] >= s_mp_prime_tab[x]) {
+ res_tab[x] -= s_mp_prime_tab[x];
+ }
+
+ /* set flag if zero */
+ if (res_tab[x] == 0u) {
+ y = 1;
+ }
+ }
+ } while ((y == 1) && (step < (((mp_digit)1 << MP_DIGIT_BIT) - kstep)));
+
+ /* add the step */
+ if ((err = mp_add_d(a, step, a)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* if didn't pass sieve and step == MP_MAX then skip test */
+ if ((y == 1) && (step >= (((mp_digit)1 << MP_DIGIT_BIT) - kstep))) {
+ continue;
+ }
+
+ if ((err = mp_prime_is_prime(a, t, &res)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if (res == MP_YES) {
+ break;
+ }
+ }
+
+ err = MP_OKAY;
+LBL_ERR:
+ mp_clear(&b);
+ return err;
+}
+
+#endif
ADDED libtommath/bn_mp_prime_rabin_miller_trials.c
Index: libtommath/bn_mp_prime_rabin_miller_trials.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_prime_rabin_miller_trials.c
@@ -0,0 +1,47 @@
+#include "tommath_private.h"
+#ifdef BN_MP_PRIME_RABIN_MILLER_TRIALS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+static const struct {
+ int k, t;
+} sizes[] = {
+ { 80, -1 }, /* Use deterministic algorithm for size <= 80 bits */
+ { 81, 37 }, /* max. error = 2^(-96)*/
+ { 96, 32 }, /* max. error = 2^(-96)*/
+ { 128, 40 }, /* max. error = 2^(-112)*/
+ { 160, 35 }, /* max. error = 2^(-112)*/
+ { 256, 27 }, /* max. error = 2^(-128)*/
+ { 384, 16 }, /* max. error = 2^(-128)*/
+ { 512, 18 }, /* max. error = 2^(-160)*/
+ { 768, 11 }, /* max. error = 2^(-160)*/
+ { 896, 10 }, /* max. error = 2^(-160)*/
+ { 1024, 12 }, /* max. error = 2^(-192)*/
+ { 1536, 8 }, /* max. error = 2^(-192)*/
+ { 2048, 6 }, /* max. error = 2^(-192)*/
+ { 3072, 4 }, /* max. error = 2^(-192)*/
+ { 4096, 5 }, /* max. error = 2^(-256)*/
+ { 5120, 4 }, /* max. error = 2^(-256)*/
+ { 6144, 4 }, /* max. error = 2^(-256)*/
+ { 8192, 3 }, /* max. error = 2^(-256)*/
+ { 9216, 3 }, /* max. error = 2^(-256)*/
+ { 10240, 2 } /* For bigger keysizes use always at least 2 Rounds */
+};
+
+/* returns # of RM trials required for a given bit size */
+int mp_prime_rabin_miller_trials(int size)
+{
+ int x;
+
+ for (x = 0; x < (int)(sizeof(sizes)/(sizeof(sizes[0]))); x++) {
+ if (sizes[x].k == size) {
+ return sizes[x].t;
+ } else if (sizes[x].k > size) {
+ return (x == 0) ? sizes[0].t : sizes[x - 1].t;
+ }
+ }
+ return sizes[x-1].t;
+}
+
+
+#endif
ADDED libtommath/bn_mp_prime_rand.c
Index: libtommath/bn_mp_prime_rand.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_prime_rand.c
@@ -0,0 +1,141 @@
+#include "tommath_private.h"
+#ifdef BN_MP_PRIME_RAND_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* makes a truly random prime of a given size (bits),
+ *
+ * Flags are as follows:
+ *
+ * MP_PRIME_BBS - make prime congruent to 3 mod 4
+ * MP_PRIME_SAFE - make sure (p-1)/2 is prime as well (implies MP_PRIME_BBS)
+ * MP_PRIME_2MSB_ON - make the 2nd highest bit one
+ *
+ * You have to supply a callback which fills in a buffer with random bytes. "dat" is a parameter you can
+ * have passed to the callback (e.g. a state or something). This function doesn't use "dat" itself
+ * so it can be NULL
+ *
+ */
+
+/* This is possibly the mother of all prime generation functions, muahahahahaha! */
+mp_err s_mp_prime_random_ex(mp_int *a, int t, int size, int flags, private_mp_prime_callback cb, void *dat)
+{
+ unsigned char *tmp, maskAND, maskOR_msb, maskOR_lsb;
+ int bsize, maskOR_msb_offset;
+ mp_bool res;
+ mp_err err;
+
+ /* sanity check the input */
+ if ((size <= 1) || (t <= 0)) {
+ return MP_VAL;
+ }
+
+ /* MP_PRIME_SAFE implies MP_PRIME_BBS */
+ if ((flags & MP_PRIME_SAFE) != 0) {
+ flags |= MP_PRIME_BBS;
+ }
+
+ /* calc the byte size */
+ bsize = (size>>3) + ((size&7)?1:0);
+
+ /* we need a buffer of bsize bytes */
+ tmp = (unsigned char *) MP_MALLOC((size_t)bsize);
+ if (tmp == NULL) {
+ return MP_MEM;
+ }
+
+ /* calc the maskAND value for the MSbyte*/
+ maskAND = ((size&7) == 0) ? 0xFFu : (unsigned char)(0xFFu >> (8 - (size & 7)));
+
+ /* calc the maskOR_msb */
+ maskOR_msb = 0;
+ maskOR_msb_offset = ((size & 7) == 1) ? 1 : 0;
+ if ((flags & MP_PRIME_2MSB_ON) != 0) {
+ maskOR_msb |= (unsigned char)(0x80 >> ((9 - size) & 7));
+ }
+
+ /* get the maskOR_lsb */
+ maskOR_lsb = 1u;
+ if ((flags & MP_PRIME_BBS) != 0) {
+ maskOR_lsb |= 3u;
+ }
+
+ do {
+ /* read the bytes */
+ if (cb(tmp, bsize, dat) != bsize) {
+ err = MP_VAL;
+ goto error;
+ }
+
+ /* work over the MSbyte */
+ tmp[0] &= maskAND;
+ tmp[0] |= (unsigned char)(1 << ((size - 1) & 7));
+
+ /* mix in the maskORs */
+ tmp[maskOR_msb_offset] |= maskOR_msb;
+ tmp[bsize-1] |= maskOR_lsb;
+
+ /* read it in */
+ /* TODO: casting only for now until all lengths have been changed to the type "size_t"*/
+ if ((err = mp_from_ubin(a, tmp, (size_t)bsize)) != MP_OKAY) {
+ goto error;
+ }
+
+ /* is it prime? */
+ if ((err = mp_prime_is_prime(a, t, &res)) != MP_OKAY) {
+ goto error;
+ }
+ if (res == MP_NO) {
+ continue;
+ }
+
+ if ((flags & MP_PRIME_SAFE) != 0) {
+ /* see if (a-1)/2 is prime */
+ if ((err = mp_sub_d(a, 1uL, a)) != MP_OKAY) {
+ goto error;
+ }
+ if ((err = mp_div_2(a, a)) != MP_OKAY) {
+ goto error;
+ }
+
+ /* is it prime? */
+ if ((err = mp_prime_is_prime(a, t, &res)) != MP_OKAY) {
+ goto error;
+ }
+ }
+ } while (res == MP_NO);
+
+ if ((flags & MP_PRIME_SAFE) != 0) {
+ /* restore a to the original value */
+ if ((err = mp_mul_2(a, a)) != MP_OKAY) {
+ goto error;
+ }
+ if ((err = mp_add_d(a, 1uL, a)) != MP_OKAY) {
+ goto error;
+ }
+ }
+
+ err = MP_OKAY;
+error:
+ MP_FREE_BUFFER(tmp, (size_t)bsize);
+ return err;
+}
+
+static int s_mp_rand_cb(unsigned char *dst, int len, void *dat)
+{
+ (void)dat;
+ if (len <= 0) {
+ return len;
+ }
+ if (s_mp_rand_source(dst, (size_t)len) != MP_OKAY) {
+ return 0;
+ }
+ return len;
+}
+
+mp_err mp_prime_rand(mp_int *a, int t, int size, int flags)
+{
+ return s_mp_prime_random_ex(a, t, size, flags, s_mp_rand_cb, NULL);
+}
+
+#endif
ADDED libtommath/bn_mp_prime_strong_lucas_selfridge.c
Index: libtommath/bn_mp_prime_strong_lucas_selfridge.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_prime_strong_lucas_selfridge.c
@@ -0,0 +1,289 @@
+#include "tommath_private.h"
+#ifdef BN_MP_PRIME_STRONG_LUCAS_SELFRIDGE_C
+
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/*
+ * See file bn_mp_prime_is_prime.c or the documentation in doc/bn.tex for the details
+ */
+#ifndef LTM_USE_ONLY_MR
+
+/*
+ * 8-bit is just too small. You can try the Frobenius test
+ * but that frobenius test can fail, too, for the same reason.
+ */
+#ifndef MP_8BIT
+
+/*
+ * multiply bigint a with int d and put the result in c
+ * Like mp_mul_d() but with a signed long as the small input
+ */
+static mp_err s_mp_mul_si(const mp_int *a, int32_t d, mp_int *c)
+{
+ mp_int t;
+ mp_err err;
+
+ if ((err = mp_init(&t)) != MP_OKAY) {
+ return err;
+ }
+
+ /*
+ * mp_digit might be smaller than a long, which excludes
+ * the use of mp_mul_d() here.
+ */
+ mp_set_i32(&t, d);
+ err = mp_mul(a, &t, c);
+ mp_clear(&t);
+ return err;
+}
+/*
+ Strong Lucas-Selfridge test.
+ returns MP_YES if it is a strong L-S prime, MP_NO if it is composite
+
+ Code ported from Thomas Ray Nicely's implementation of the BPSW test
+ at http://www.trnicely.net/misc/bpsw.html
+
+ Freeware copyright (C) 2016 Thomas R. Nicely .
+ Released into the public domain by the author, who disclaims any legal
+ liability arising from its use
+
+ The multi-line comments are made by Thomas R. Nicely and are copied verbatim.
+ Additional comments marked "CZ" (without the quotes) are by the code-portist.
+
+ (If that name sounds familiar, he is the guy who found the fdiv bug in the
+ Pentium (P5x, I think) Intel processor)
+*/
+mp_err mp_prime_strong_lucas_selfridge(const mp_int *a, mp_bool *result)
+{
+ /* CZ TODO: choose better variable names! */
+ mp_int Dz, gcd, Np1, Uz, Vz, U2mz, V2mz, Qmz, Q2mz, Qkdz, T1z, T2z, T3z, T4z, Q2kdz;
+ /* CZ TODO: Some of them need the full 32 bit, hence the (temporary) exclusion of MP_8BIT */
+ int32_t D, Ds, J, sign, P, Q, r, s, u, Nbits;
+ mp_err err;
+ mp_bool oddness;
+
+ *result = MP_NO;
+ /*
+ Find the first element D in the sequence {5, -7, 9, -11, 13, ...}
+ such that Jacobi(D,N) = -1 (Selfridge's algorithm). Theory
+ indicates that, if N is not a perfect square, D will "nearly
+ always" be "small." Just in case, an overflow trap for D is
+ included.
+ */
+
+ if ((err = mp_init_multi(&Dz, &gcd, &Np1, &Uz, &Vz, &U2mz, &V2mz, &Qmz, &Q2mz, &Qkdz, &T1z, &T2z, &T3z, &T4z, &Q2kdz,
+ NULL)) != MP_OKAY) {
+ return err;
+ }
+
+ D = 5;
+ sign = 1;
+
+ for (;;) {
+ Ds = sign * D;
+ sign = -sign;
+ mp_set_u32(&Dz, (uint32_t)D);
+ if ((err = mp_gcd(a, &Dz, &gcd)) != MP_OKAY) goto LBL_LS_ERR;
+
+ /* if 1 < GCD < N then N is composite with factor "D", and
+ Jacobi(D,N) is technically undefined (but often returned
+ as zero). */
+ if ((mp_cmp_d(&gcd, 1uL) == MP_GT) && (mp_cmp(&gcd, a) == MP_LT)) {
+ goto LBL_LS_ERR;
+ }
+ if (Ds < 0) {
+ Dz.sign = MP_NEG;
+ }
+ if ((err = mp_kronecker(&Dz, a, &J)) != MP_OKAY) goto LBL_LS_ERR;
+
+ if (J == -1) {
+ break;
+ }
+ D += 2;
+
+ if (D > (INT_MAX - 2)) {
+ err = MP_VAL;
+ goto LBL_LS_ERR;
+ }
+ }
+
+
+
+ P = 1; /* Selfridge's choice */
+ Q = (1 - Ds) / 4; /* Required so D = P*P - 4*Q */
+
+ /* NOTE: The conditions (a) N does not divide Q, and
+ (b) D is square-free or not a perfect square, are included by
+ some authors; e.g., "Prime numbers and computer methods for
+ factorization," Hans Riesel (2nd ed., 1994, Birkhauser, Boston),
+ p. 130. For this particular application of Lucas sequences,
+ these conditions were found to be immaterial. */
+
+ /* Now calculate N - Jacobi(D,N) = N + 1 (even), and calculate the
+ odd positive integer d and positive integer s for which
+ N + 1 = 2^s*d (similar to the step for N - 1 in Miller's test).
+ The strong Lucas-Selfridge test then returns N as a strong
+ Lucas probable prime (slprp) if any of the following
+ conditions is met: U_d=0, V_d=0, V_2d=0, V_4d=0, V_8d=0,
+ V_16d=0, ..., etc., ending with V_{2^(s-1)*d}=V_{(N+1)/2}=0
+ (all equalities mod N). Thus d is the highest index of U that
+ must be computed (since V_2m is independent of U), compared
+ to U_{N+1} for the standard Lucas-Selfridge test; and no
+ index of V beyond (N+1)/2 is required, just as in the
+ standard Lucas-Selfridge test. However, the quantity Q^d must
+ be computed for use (if necessary) in the latter stages of
+ the test. The result is that the strong Lucas-Selfridge test
+ has a running time only slightly greater (order of 10 %) than
+ that of the standard Lucas-Selfridge test, while producing
+ only (roughly) 30 % as many pseudoprimes (and every strong
+ Lucas pseudoprime is also a standard Lucas pseudoprime). Thus
+ the evidence indicates that the strong Lucas-Selfridge test is
+ more effective than the standard Lucas-Selfridge test, and a
+ Baillie-PSW test based on the strong Lucas-Selfridge test
+ should be more reliable. */
+
+ if ((err = mp_add_d(a, 1uL, &Np1)) != MP_OKAY) goto LBL_LS_ERR;
+ s = mp_cnt_lsb(&Np1);
+
+ /* CZ
+ * This should round towards zero because
+ * Thomas R. Nicely used GMP's mpz_tdiv_q_2exp()
+ * and mp_div_2d() is equivalent. Additionally:
+ * dividing an even number by two does not produce
+ * any leftovers.
+ */
+ if ((err = mp_div_2d(&Np1, s, &Dz, NULL)) != MP_OKAY) goto LBL_LS_ERR;
+ /* We must now compute U_d and V_d. Since d is odd, the accumulated
+ values U and V are initialized to U_1 and V_1 (if the target
+ index were even, U and V would be initialized instead to U_0=0
+ and V_0=2). The values of U_2m and V_2m are also initialized to
+ U_1 and V_1; the FOR loop calculates in succession U_2 and V_2,
+ U_4 and V_4, U_8 and V_8, etc. If the corresponding bits
+ (1, 2, 3, ...) of t are on (the zero bit having been accounted
+ for in the initialization of U and V), these values are then
+ combined with the previous totals for U and V, using the
+ composition formulas for addition of indices. */
+
+ mp_set(&Uz, 1uL); /* U=U_1 */
+ mp_set(&Vz, (mp_digit)P); /* V=V_1 */
+ mp_set(&U2mz, 1uL); /* U_1 */
+ mp_set(&V2mz, (mp_digit)P); /* V_1 */
+
+ mp_set_i32(&Qmz, Q);
+ if ((err = mp_mul_2(&Qmz, &Q2mz)) != MP_OKAY) goto LBL_LS_ERR;
+ /* Initializes calculation of Q^d */
+ mp_set_i32(&Qkdz, Q);
+
+ Nbits = mp_count_bits(&Dz);
+
+ for (u = 1; u < Nbits; u++) { /* zero bit off, already accounted for */
+ /* Formulas for doubling of indices (carried out mod N). Note that
+ * the indices denoted as "2m" are actually powers of 2, specifically
+ * 2^(ul-1) beginning each loop and 2^ul ending each loop.
+ *
+ * U_2m = U_m*V_m
+ * V_2m = V_m*V_m - 2*Q^m
+ */
+
+ if ((err = mp_mul(&U2mz, &V2mz, &U2mz)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_mod(&U2mz, a, &U2mz)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_sqr(&V2mz, &V2mz)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_sub(&V2mz, &Q2mz, &V2mz)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_mod(&V2mz, a, &V2mz)) != MP_OKAY) goto LBL_LS_ERR;
+
+ /* Must calculate powers of Q for use in V_2m, also for Q^d later */
+ if ((err = mp_sqr(&Qmz, &Qmz)) != MP_OKAY) goto LBL_LS_ERR;
+
+ /* prevents overflow */ /* CZ still necessary without a fixed prealloc'd mem.? */
+ if ((err = mp_mod(&Qmz, a, &Qmz)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_mul_2(&Qmz, &Q2mz)) != MP_OKAY) goto LBL_LS_ERR;
+
+ if (s_mp_get_bit(&Dz, (unsigned int)u) == MP_YES) {
+ /* Formulas for addition of indices (carried out mod N);
+ *
+ * U_(m+n) = (U_m*V_n + U_n*V_m)/2
+ * V_(m+n) = (V_m*V_n + D*U_m*U_n)/2
+ *
+ * Be careful with division by 2 (mod N)!
+ */
+ if ((err = mp_mul(&U2mz, &Vz, &T1z)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_mul(&Uz, &V2mz, &T2z)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_mul(&V2mz, &Vz, &T3z)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_mul(&U2mz, &Uz, &T4z)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = s_mp_mul_si(&T4z, Ds, &T4z)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_add(&T1z, &T2z, &Uz)) != MP_OKAY) goto LBL_LS_ERR;
+ if (MP_IS_ODD(&Uz)) {
+ if ((err = mp_add(&Uz, a, &Uz)) != MP_OKAY) goto LBL_LS_ERR;
+ }
+ /* CZ
+ * This should round towards negative infinity because
+ * Thomas R. Nicely used GMP's mpz_fdiv_q_2exp().
+ * But mp_div_2() does not do so, it is truncating instead.
+ */
+ oddness = MP_IS_ODD(&Uz) ? MP_YES : MP_NO;
+ if ((err = mp_div_2(&Uz, &Uz)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((Uz.sign == MP_NEG) && (oddness != MP_NO)) {
+ if ((err = mp_sub_d(&Uz, 1uL, &Uz)) != MP_OKAY) goto LBL_LS_ERR;
+ }
+ if ((err = mp_add(&T3z, &T4z, &Vz)) != MP_OKAY) goto LBL_LS_ERR;
+ if (MP_IS_ODD(&Vz)) {
+ if ((err = mp_add(&Vz, a, &Vz)) != MP_OKAY) goto LBL_LS_ERR;
+ }
+ oddness = MP_IS_ODD(&Vz) ? MP_YES : MP_NO;
+ if ((err = mp_div_2(&Vz, &Vz)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((Vz.sign == MP_NEG) && (oddness != MP_NO)) {
+ if ((err = mp_sub_d(&Vz, 1uL, &Vz)) != MP_OKAY) goto LBL_LS_ERR;
+ }
+ if ((err = mp_mod(&Uz, a, &Uz)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_mod(&Vz, a, &Vz)) != MP_OKAY) goto LBL_LS_ERR;
+
+ /* Calculating Q^d for later use */
+ if ((err = mp_mul(&Qkdz, &Qmz, &Qkdz)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_mod(&Qkdz, a, &Qkdz)) != MP_OKAY) goto LBL_LS_ERR;
+ }
+ }
+
+ /* If U_d or V_d is congruent to 0 mod N, then N is a prime or a
+ strong Lucas pseudoprime. */
+ if (MP_IS_ZERO(&Uz) || MP_IS_ZERO(&Vz)) {
+ *result = MP_YES;
+ goto LBL_LS_ERR;
+ }
+
+ /* NOTE: Ribenboim ("The new book of prime number records," 3rd ed.,
+ 1995/6) omits the condition V0 on p.142, but includes it on
+ p. 130. The condition is NECESSARY; otherwise the test will
+ return false negatives---e.g., the primes 29 and 2000029 will be
+ returned as composite. */
+
+ /* Otherwise, we must compute V_2d, V_4d, V_8d, ..., V_{2^(s-1)*d}
+ by repeated use of the formula V_2m = V_m*V_m - 2*Q^m. If any of
+ these are congruent to 0 mod N, then N is a prime or a strong
+ Lucas pseudoprime. */
+
+ /* Initialize 2*Q^(d*2^r) for V_2m */
+ if ((err = mp_mul_2(&Qkdz, &Q2kdz)) != MP_OKAY) goto LBL_LS_ERR;
+
+ for (r = 1; r < s; r++) {
+ if ((err = mp_sqr(&Vz, &Vz)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_sub(&Vz, &Q2kdz, &Vz)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_mod(&Vz, a, &Vz)) != MP_OKAY) goto LBL_LS_ERR;
+ if (MP_IS_ZERO(&Vz)) {
+ *result = MP_YES;
+ goto LBL_LS_ERR;
+ }
+ /* Calculate Q^{d*2^r} for next r (final iteration irrelevant). */
+ if (r < (s - 1)) {
+ if ((err = mp_sqr(&Qkdz, &Qkdz)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_mod(&Qkdz, a, &Qkdz)) != MP_OKAY) goto LBL_LS_ERR;
+ if ((err = mp_mul_2(&Qkdz, &Q2kdz)) != MP_OKAY) goto LBL_LS_ERR;
+ }
+ }
+LBL_LS_ERR:
+ mp_clear_multi(&Q2kdz, &T4z, &T3z, &T2z, &T1z, &Qkdz, &Q2mz, &Qmz, &V2mz, &U2mz, &Vz, &Uz, &Np1, &gcd, &Dz, NULL);
+ return err;
+}
+#endif
+#endif
+#endif
ADDED libtommath/bn_mp_radix_size.c
Index: libtommath/bn_mp_radix_size.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_radix_size.c
@@ -0,0 +1,65 @@
+#include "tommath_private.h"
+#ifdef BN_MP_RADIX_SIZE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* returns size of ASCII representation */
+mp_err mp_radix_size(const mp_int *a, int radix, int *size)
+{
+ mp_err err;
+ int digs;
+ mp_int t;
+ mp_digit d;
+
+ *size = 0;
+
+ /* make sure the radix is in range */
+ if ((radix < 2) || (radix > 64)) {
+ return MP_VAL;
+ }
+
+ if (MP_IS_ZERO(a)) {
+ *size = 2;
+ return MP_OKAY;
+ }
+
+ /* special case for binary */
+ if (radix == 2) {
+ *size = (mp_count_bits(a) + ((a->sign == MP_NEG) ? 1 : 0) + 1);
+ return MP_OKAY;
+ }
+
+ /* digs is the digit count */
+ digs = 0;
+
+ /* if it's negative add one for the sign */
+ if (a->sign == MP_NEG) {
+ ++digs;
+ }
+
+ /* init a copy of the input */
+ if ((err = mp_init_copy(&t, a)) != MP_OKAY) {
+ return err;
+ }
+
+ /* force temp to positive */
+ t.sign = MP_ZPOS;
+
+ /* fetch out all of the digits */
+ while (!MP_IS_ZERO(&t)) {
+ if ((err = mp_div_d(&t, (mp_digit)radix, &t, &d)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ ++digs;
+ }
+
+ /* return digs + 1, the 1 is for the NULL byte that would be required. */
+ *size = digs + 1;
+ err = MP_OKAY;
+
+LBL_ERR:
+ mp_clear(&t);
+ return err;
+}
+
+#endif
ADDED libtommath/bn_mp_radix_smap.c
Index: libtommath/bn_mp_radix_smap.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_radix_smap.c
@@ -0,0 +1,22 @@
+#include "tommath_private.h"
+#ifdef BN_MP_RADIX_SMAP_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* chars used in radix conversions */
+const char *const mp_s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
+const uint8_t mp_s_rmap_reverse[] = {
+ 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, /* ()*+,-./ */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 01234567 */
+ 0x08, 0x09, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 89:;<=>? */
+ 0xff, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, /* @ABCDEFG */
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, /* HIJKLMNO */
+ 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, /* PQRSTUVW */
+ 0x21, 0x22, 0x23, 0xff, 0xff, 0xff, 0xff, 0xff, /* XYZ[\]^_ */
+ 0xff, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, /* `abcdefg */
+ 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, /* hijklmno */
+ 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, /* pqrstuvw */
+ 0x3b, 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, /* xyz{|}~. */
+};
+const size_t mp_s_rmap_reverse_sz = sizeof(mp_s_rmap_reverse);
+#endif
ADDED libtommath/bn_mp_rand.c
Index: libtommath/bn_mp_rand.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_rand.c
@@ -0,0 +1,46 @@
+#include "tommath_private.h"
+#ifdef BN_MP_RAND_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+mp_err(*s_mp_rand_source)(void *out, size_t size) = s_mp_rand_platform;
+
+void mp_rand_source(mp_err(*source)(void *out, size_t size))
+{
+ s_mp_rand_source = (source == NULL) ? s_mp_rand_platform : source;
+}
+
+mp_err mp_rand(mp_int *a, int digits)
+{
+ int i;
+ mp_err err;
+
+ mp_zero(a);
+
+ if (digits <= 0) {
+ return MP_OKAY;
+ }
+
+ if ((err = mp_grow(a, digits)) != MP_OKAY) {
+ return err;
+ }
+
+ if ((err = s_mp_rand_source(a->dp, (size_t)digits * sizeof(mp_digit))) != MP_OKAY) {
+ return err;
+ }
+
+ /* TODO: We ensure that the highest digit is nonzero. Should this be removed? */
+ while ((a->dp[digits - 1] & MP_MASK) == 0u) {
+ if ((err = s_mp_rand_source(a->dp + digits - 1, sizeof(mp_digit))) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ a->used = digits;
+ for (i = 0; i < digits; ++i) {
+ a->dp[i] &= MP_MASK;
+ }
+
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_mp_read_radix.c
Index: libtommath/bn_mp_read_radix.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_read_radix.c
@@ -0,0 +1,79 @@
+#include "tommath_private.h"
+#ifdef BN_MP_READ_RADIX_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#define MP_TOUPPER(c) ((((c) >= 'a') && ((c) <= 'z')) ? (((c) + 'A') - 'a') : (c))
+
+/* read a string [ASCII] in a given radix */
+mp_err mp_read_radix(mp_int *a, const char *str, int radix)
+{
+ mp_err err;
+ int y;
+ mp_sign neg;
+ unsigned pos;
+ char ch;
+
+ /* zero the digit bignum */
+ mp_zero(a);
+
+ /* make sure the radix is ok */
+ if ((radix < 2) || (radix > 64)) {
+ return MP_VAL;
+ }
+
+ /* if the leading digit is a
+ * minus set the sign to negative.
+ */
+ if (*str == '-') {
+ ++str;
+ neg = MP_NEG;
+ } else {
+ neg = MP_ZPOS;
+ }
+
+ /* set the integer to the default of zero */
+ mp_zero(a);
+
+ /* process each digit of the string */
+ while (*str != '\0') {
+ /* if the radix <= 36 the conversion is case insensitive
+ * this allows numbers like 1AB and 1ab to represent the same value
+ * [e.g. in hex]
+ */
+ ch = (radix <= 36) ? (char)MP_TOUPPER((int)*str) : *str;
+ pos = (unsigned)(ch - '(');
+ if (mp_s_rmap_reverse_sz < pos) {
+ break;
+ }
+ y = (int)mp_s_rmap_reverse[pos];
+
+ /* if the char was found in the map
+ * and is less than the given radix add it
+ * to the number, otherwise exit the loop.
+ */
+ if ((y == 0xff) || (y >= radix)) {
+ break;
+ }
+ if ((err = mp_mul_d(a, (mp_digit)radix, a)) != MP_OKAY) {
+ return err;
+ }
+ if ((err = mp_add_d(a, (mp_digit)y, a)) != MP_OKAY) {
+ return err;
+ }
+ ++str;
+ }
+
+ /* if an illegal character was found, fail. */
+ if (!((*str == '\0') || (*str == '\r') || (*str == '\n'))) {
+ mp_zero(a);
+ return MP_VAL;
+ }
+
+ /* set the sign only if a != 0 */
+ if (!MP_IS_ZERO(a)) {
+ a->sign = neg;
+ }
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_mp_reduce.c
Index: libtommath/bn_mp_reduce.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_reduce.c
@@ -0,0 +1,83 @@
+#include "tommath_private.h"
+#ifdef BN_MP_REDUCE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* reduces x mod m, assumes 0 < x < m**2, mu is
+ * precomputed via mp_reduce_setup.
+ * From HAC pp.604 Algorithm 14.42
+ */
+mp_err mp_reduce(mp_int *x, const mp_int *m, const mp_int *mu)
+{
+ mp_int q;
+ mp_err err;
+ int um = m->used;
+
+ /* q = x */
+ if ((err = mp_init_copy(&q, x)) != MP_OKAY) {
+ return err;
+ }
+
+ /* q1 = x / b**(k-1) */
+ mp_rshd(&q, um - 1);
+
+ /* according to HAC this optimization is ok */
+ if ((mp_digit)um > ((mp_digit)1 << (MP_DIGIT_BIT - 1))) {
+ if ((err = mp_mul(&q, mu, &q)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+ } else if (MP_HAS(S_MP_MUL_HIGH_DIGS)) {
+ if ((err = s_mp_mul_high_digs(&q, mu, &q, um)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+ } else if (MP_HAS(S_MP_MUL_HIGH_DIGS_FAST)) {
+ if ((err = s_mp_mul_high_digs_fast(&q, mu, &q, um)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+ } else {
+ err = MP_VAL;
+ goto CLEANUP;
+ }
+
+ /* q3 = q2 / b**(k+1) */
+ mp_rshd(&q, um + 1);
+
+ /* x = x mod b**(k+1), quick (no division) */
+ if ((err = mp_mod_2d(x, MP_DIGIT_BIT * (um + 1), x)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+
+ /* q = q * m mod b**(k+1), quick (no division) */
+ if ((err = s_mp_mul_digs(&q, m, &q, um + 1)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+
+ /* x = x - q */
+ if ((err = mp_sub(x, &q, x)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+
+ /* If x < 0, add b**(k+1) to it */
+ if (mp_cmp_d(x, 0uL) == MP_LT) {
+ mp_set(&q, 1uL);
+ if ((err = mp_lshd(&q, um + 1)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+ if ((err = mp_add(x, &q, x)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+ }
+
+ /* Back off if it's too big */
+ while (mp_cmp(x, m) != MP_LT) {
+ if ((err = s_mp_sub(x, m, x)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+ }
+
+CLEANUP:
+ mp_clear(&q);
+
+ return err;
+}
+#endif
ADDED libtommath/bn_mp_reduce_2k.c
Index: libtommath/bn_mp_reduce_2k.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_reduce_2k.c
@@ -0,0 +1,48 @@
+#include "tommath_private.h"
+#ifdef BN_MP_REDUCE_2K_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* reduces a modulo n where n is of the form 2**p - d */
+mp_err mp_reduce_2k(mp_int *a, const mp_int *n, mp_digit d)
+{
+ mp_int q;
+ mp_err err;
+ int p;
+
+ if ((err = mp_init(&q)) != MP_OKAY) {
+ return err;
+ }
+
+ p = mp_count_bits(n);
+top:
+ /* q = a/2**p, a = a mod 2**p */
+ if ((err = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if (d != 1u) {
+ /* q = q * d */
+ if ((err = mp_mul_d(&q, d, &q)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* a = a + q */
+ if ((err = s_mp_add(a, &q, a)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if (mp_cmp_mag(a, n) != MP_LT) {
+ if ((err = s_mp_sub(a, n, a)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ goto top;
+ }
+
+LBL_ERR:
+ mp_clear(&q);
+ return err;
+}
+
+#endif
ADDED libtommath/bn_mp_reduce_2k_l.c
Index: libtommath/bn_mp_reduce_2k_l.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_reduce_2k_l.c
@@ -0,0 +1,49 @@
+#include "tommath_private.h"
+#ifdef BN_MP_REDUCE_2K_L_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* reduces a modulo n where n is of the form 2**p - d
+ This differs from reduce_2k since "d" can be larger
+ than a single digit.
+*/
+mp_err mp_reduce_2k_l(mp_int *a, const mp_int *n, const mp_int *d)
+{
+ mp_int q;
+ mp_err err;
+ int p;
+
+ if ((err = mp_init(&q)) != MP_OKAY) {
+ return err;
+ }
+
+ p = mp_count_bits(n);
+top:
+ /* q = a/2**p, a = a mod 2**p */
+ if ((err = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* q = q * d */
+ if ((err = mp_mul(&q, d, &q)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* a = a + q */
+ if ((err = s_mp_add(a, &q, a)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if (mp_cmp_mag(a, n) != MP_LT) {
+ if ((err = s_mp_sub(a, n, a)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ goto top;
+ }
+
+LBL_ERR:
+ mp_clear(&q);
+ return err;
+}
+
+#endif
ADDED libtommath/bn_mp_reduce_2k_setup.c
Index: libtommath/bn_mp_reduce_2k_setup.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_reduce_2k_setup.c
@@ -0,0 +1,32 @@
+#include "tommath_private.h"
+#ifdef BN_MP_REDUCE_2K_SETUP_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* determines the setup value */
+mp_err mp_reduce_2k_setup(const mp_int *a, mp_digit *d)
+{
+ mp_err err;
+ mp_int tmp;
+ int p;
+
+ if ((err = mp_init(&tmp)) != MP_OKAY) {
+ return err;
+ }
+
+ p = mp_count_bits(a);
+ if ((err = mp_2expt(&tmp, p)) != MP_OKAY) {
+ mp_clear(&tmp);
+ return err;
+ }
+
+ if ((err = s_mp_sub(&tmp, a, &tmp)) != MP_OKAY) {
+ mp_clear(&tmp);
+ return err;
+ }
+
+ *d = tmp.dp[0];
+ mp_clear(&tmp);
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_mp_reduce_2k_setup_l.c
Index: libtommath/bn_mp_reduce_2k_setup_l.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_reduce_2k_setup_l.c
@@ -0,0 +1,28 @@
+#include "tommath_private.h"
+#ifdef BN_MP_REDUCE_2K_SETUP_L_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* determines the setup value */
+mp_err mp_reduce_2k_setup_l(const mp_int *a, mp_int *d)
+{
+ mp_err err;
+ mp_int tmp;
+
+ if ((err = mp_init(&tmp)) != MP_OKAY) {
+ return err;
+ }
+
+ if ((err = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if ((err = s_mp_sub(&tmp, a, d)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+LBL_ERR:
+ mp_clear(&tmp);
+ return err;
+}
+#endif
ADDED libtommath/bn_mp_reduce_is_2k.c
Index: libtommath/bn_mp_reduce_is_2k.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_reduce_is_2k.c
@@ -0,0 +1,38 @@
+#include "tommath_private.h"
+#ifdef BN_MP_REDUCE_IS_2K_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* determines if mp_reduce_2k can be used */
+mp_bool mp_reduce_is_2k(const mp_int *a)
+{
+ int ix, iy, iw;
+ mp_digit iz;
+
+ if (a->used == 0) {
+ return MP_NO;
+ } else if (a->used == 1) {
+ return MP_YES;
+ } else if (a->used > 1) {
+ iy = mp_count_bits(a);
+ iz = 1;
+ iw = 1;
+
+ /* Test every bit from the second digit up, must be 1 */
+ for (ix = MP_DIGIT_BIT; ix < iy; ix++) {
+ if ((a->dp[iw] & iz) == 0u) {
+ return MP_NO;
+ }
+ iz <<= 1;
+ if (iz > MP_DIGIT_MAX) {
+ ++iw;
+ iz = 1;
+ }
+ }
+ return MP_YES;
+ } else {
+ return MP_YES;
+ }
+}
+
+#endif
ADDED libtommath/bn_mp_reduce_is_2k_l.c
Index: libtommath/bn_mp_reduce_is_2k_l.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_reduce_is_2k_l.c
@@ -0,0 +1,28 @@
+#include "tommath_private.h"
+#ifdef BN_MP_REDUCE_IS_2K_L_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* determines if reduce_2k_l can be used */
+mp_bool mp_reduce_is_2k_l(const mp_int *a)
+{
+ int ix, iy;
+
+ if (a->used == 0) {
+ return MP_NO;
+ } else if (a->used == 1) {
+ return MP_YES;
+ } else if (a->used > 1) {
+ /* if more than half of the digits are -1 we're sold */
+ for (iy = ix = 0; ix < a->used; ix++) {
+ if (a->dp[ix] == MP_DIGIT_MAX) {
+ ++iy;
+ }
+ }
+ return (iy >= (a->used/2)) ? MP_YES : MP_NO;
+ } else {
+ return MP_NO;
+ }
+}
+
+#endif
ADDED libtommath/bn_mp_reduce_setup.c
Index: libtommath/bn_mp_reduce_setup.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_reduce_setup.c
@@ -0,0 +1,17 @@
+#include "tommath_private.h"
+#ifdef BN_MP_REDUCE_SETUP_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* pre-calculate the value required for Barrett reduction
+ * For a given modulus "b" it calulates the value required in "a"
+ */
+mp_err mp_reduce_setup(mp_int *a, const mp_int *b)
+{
+ mp_err err;
+ if ((err = mp_2expt(a, b->used * 2 * MP_DIGIT_BIT)) != MP_OKAY) {
+ return err;
+ }
+ return mp_div(a, b, a, NULL);
+}
+#endif
ADDED libtommath/bn_mp_root_u32.c
Index: libtommath/bn_mp_root_u32.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_root_u32.c
@@ -0,0 +1,139 @@
+#include "tommath_private.h"
+#ifdef BN_MP_ROOT_U32_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* find the n'th root of an integer
+ *
+ * Result found such that (c)**b <= a and (c+1)**b > a
+ *
+ * This algorithm uses Newton's approximation
+ * x[i+1] = x[i] - f(x[i])/f'(x[i])
+ * which will find the root in log(N) time where
+ * each step involves a fair bit.
+ */
+mp_err mp_root_u32(const mp_int *a, uint32_t b, mp_int *c)
+{
+ mp_int t1, t2, t3, a_;
+ mp_ord cmp;
+ int ilog2;
+ mp_err err;
+
+ /* input must be positive if b is even */
+ if (((b & 1u) == 0u) && (a->sign == MP_NEG)) {
+ return MP_VAL;
+ }
+
+ if ((err = mp_init_multi(&t1, &t2, &t3, NULL)) != MP_OKAY) {
+ return err;
+ }
+
+ /* if a is negative fudge the sign but keep track */
+ a_ = *a;
+ a_.sign = MP_ZPOS;
+
+ /* Compute seed: 2^(log_2(n)/b + 2)*/
+ ilog2 = mp_count_bits(a);
+
+ /*
+ If "b" is larger than INT_MAX it is also larger than
+ log_2(n) because the bit-length of the "n" is measured
+ with an int and hence the root is always < 2 (two).
+ */
+ if (b > (uint32_t)(INT_MAX/2)) {
+ mp_set(c, 1uL);
+ c->sign = a->sign;
+ err = MP_OKAY;
+ goto LBL_ERR;
+ }
+
+ /* "b" is smaller than INT_MAX, we can cast safely */
+ if (ilog2 < (int)b) {
+ mp_set(c, 1uL);
+ c->sign = a->sign;
+ err = MP_OKAY;
+ goto LBL_ERR;
+ }
+ ilog2 = ilog2 / ((int)b);
+ if (ilog2 == 0) {
+ mp_set(c, 1uL);
+ c->sign = a->sign;
+ err = MP_OKAY;
+ goto LBL_ERR;
+ }
+ /* Start value must be larger than root */
+ ilog2 += 2;
+ if ((err = mp_2expt(&t2,ilog2)) != MP_OKAY) goto LBL_ERR;
+ do {
+ /* t1 = t2 */
+ if ((err = mp_copy(&t2, &t1)) != MP_OKAY) goto LBL_ERR;
+
+ /* t2 = t1 - ((t1**b - a) / (b * t1**(b-1))) */
+
+ /* t3 = t1**(b-1) */
+ if ((err = mp_expt_u32(&t1, b - 1u, &t3)) != MP_OKAY) goto LBL_ERR;
+
+ /* numerator */
+ /* t2 = t1**b */
+ if ((err = mp_mul(&t3, &t1, &t2)) != MP_OKAY) goto LBL_ERR;
+
+ /* t2 = t1**b - a */
+ if ((err = mp_sub(&t2, &a_, &t2)) != MP_OKAY) goto LBL_ERR;
+
+ /* denominator */
+ /* t3 = t1**(b-1) * b */
+ if ((err = mp_mul_d(&t3, b, &t3)) != MP_OKAY) goto LBL_ERR;
+
+ /* t3 = (t1**b - a)/(b * t1**(b-1)) */
+ if ((err = mp_div(&t2, &t3, &t3, NULL)) != MP_OKAY) goto LBL_ERR;
+
+ if ((err = mp_sub(&t1, &t3, &t2)) != MP_OKAY) goto LBL_ERR;
+
+ /*
+ Number of rounds is at most log_2(root). If it is more it
+ got stuck, so break out of the loop and do the rest manually.
+ */
+ if (ilog2-- == 0) {
+ break;
+ }
+ } while (mp_cmp(&t1, &t2) != MP_EQ);
+
+ /* result can be off by a few so check */
+ /* Loop beneath can overshoot by one if found root is smaller than actual root */
+ for (;;) {
+ if ((err = mp_expt_u32(&t1, b, &t2)) != MP_OKAY) goto LBL_ERR;
+ cmp = mp_cmp(&t2, &a_);
+ if (cmp == MP_EQ) {
+ err = MP_OKAY;
+ goto LBL_ERR;
+ }
+ if (cmp == MP_LT) {
+ if ((err = mp_add_d(&t1, 1uL, &t1)) != MP_OKAY) goto LBL_ERR;
+ } else {
+ break;
+ }
+ }
+ /* correct overshoot from above or from recurrence */
+ for (;;) {
+ if ((err = mp_expt_u32(&t1, b, &t2)) != MP_OKAY) goto LBL_ERR;
+ if (mp_cmp(&t2, &a_) == MP_GT) {
+ if ((err = mp_sub_d(&t1, 1uL, &t1)) != MP_OKAY) goto LBL_ERR;
+ } else {
+ break;
+ }
+ }
+
+ /* set the result */
+ mp_exch(&t1, c);
+
+ /* set the sign of the result */
+ c->sign = a->sign;
+
+ err = MP_OKAY;
+
+LBL_ERR:
+ mp_clear_multi(&t1, &t2, &t3, NULL);
+ return err;
+}
+
+#endif
ADDED libtommath/bn_mp_rshd.c
Index: libtommath/bn_mp_rshd.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_rshd.c
@@ -0,0 +1,51 @@
+#include "tommath_private.h"
+#ifdef BN_MP_RSHD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* shift right a certain amount of digits */
+void mp_rshd(mp_int *a, int b)
+{
+ int x;
+ mp_digit *bottom, *top;
+
+ /* if b <= 0 then ignore it */
+ if (b <= 0) {
+ return;
+ }
+
+ /* if b > used then simply zero it and return */
+ if (a->used <= b) {
+ mp_zero(a);
+ return;
+ }
+
+ /* shift the digits down */
+
+ /* bottom */
+ bottom = a->dp;
+
+ /* top [offset into digits] */
+ top = a->dp + b;
+
+ /* this is implemented as a sliding window where
+ * the window is b-digits long and digits from
+ * the top of the window are copied to the bottom
+ *
+ * e.g.
+
+ b-2 | b-1 | b0 | b1 | b2 | ... | bb | ---->
+ /\ | ---->
+ \-------------------/ ---->
+ */
+ for (x = 0; x < (a->used - b); x++) {
+ *bottom++ = *top++;
+ }
+
+ /* zero the top digits */
+ MP_ZERO_DIGITS(bottom, a->used - x);
+
+ /* remove excess digits */
+ a->used -= b;
+}
+#endif
ADDED libtommath/bn_mp_sbin_size.c
Index: libtommath/bn_mp_sbin_size.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_sbin_size.c
@@ -0,0 +1,11 @@
+#include "tommath_private.h"
+#ifdef BN_MP_SBIN_SIZE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* get the size for an signed equivalent */
+size_t mp_sbin_size(const mp_int *a)
+{
+ return 1u + mp_ubin_size(a);
+}
+#endif
ADDED libtommath/bn_mp_set.c
Index: libtommath/bn_mp_set.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_set.c
@@ -0,0 +1,14 @@
+#include "tommath_private.h"
+#ifdef BN_MP_SET_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* set to a digit */
+void mp_set(mp_int *a, mp_digit b)
+{
+ a->dp[0] = b & MP_MASK;
+ a->sign = MP_ZPOS;
+ a->used = (a->dp[0] != 0u) ? 1 : 0;
+ MP_ZERO_DIGITS(a->dp + a->used, a->alloc - a->used);
+}
+#endif
ADDED libtommath/bn_mp_set_double.c
Index: libtommath/bn_mp_set_double.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_set_double.c
@@ -0,0 +1,47 @@
+#include "tommath_private.h"
+#ifdef BN_MP_SET_DOUBLE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#if defined(__STDC_IEC_559__) || defined(__GCC_IEC_559)
+mp_err mp_set_double(mp_int *a, double b)
+{
+ uint64_t frac;
+ int exp;
+ mp_err err;
+ union {
+ double dbl;
+ uint64_t bits;
+ } cast;
+ cast.dbl = b;
+
+ exp = (int)((unsigned)(cast.bits >> 52) & 0x7FFu);
+ frac = (cast.bits & (((uint64_t)1 << 52) - (uint64_t)1)) | ((uint64_t)1 << 52);
+
+ if (exp == 0x7FF) { /* +-inf, NaN */
+ return MP_VAL;
+ }
+ exp -= 1023 + 52;
+
+ mp_set_u64(a, frac);
+
+ err = (exp < 0) ? mp_div_2d(a, -exp, a, NULL) : mp_mul_2d(a, exp, a);
+ if (err != MP_OKAY) {
+ return err;
+ }
+
+ if (((cast.bits >> 63) != 0u) && !MP_IS_ZERO(a)) {
+ a->sign = MP_NEG;
+ }
+
+ return MP_OKAY;
+}
+#else
+/* pragma message() not supported by several compilers (in mostly older but still used versions) */
+# ifdef _MSC_VER
+# pragma message("mp_set_double implementation is only available on platforms with IEEE754 floating point format")
+# else
+# warning "mp_set_double implementation is only available on platforms with IEEE754 floating point format"
+# endif
+#endif
+#endif
ADDED libtommath/bn_mp_set_i32.c
Index: libtommath/bn_mp_set_i32.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_set_i32.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef BN_MP_SET_I32_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_SET_SIGNED(mp_set_i32, mp_set_u32, int32_t, uint32_t)
+#endif
ADDED libtommath/bn_mp_set_i64.c
Index: libtommath/bn_mp_set_i64.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_set_i64.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef BN_MP_SET_I64_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_SET_SIGNED(mp_set_i64, mp_set_u64, int64_t, uint64_t)
+#endif
ADDED libtommath/bn_mp_set_l.c
Index: libtommath/bn_mp_set_l.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_set_l.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef BN_MP_SET_L_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_SET_SIGNED(mp_set_l, mp_set_ul, long, unsigned long)
+#endif
ADDED libtommath/bn_mp_set_ll.c
Index: libtommath/bn_mp_set_ll.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_set_ll.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef BN_MP_SET_LL_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_SET_SIGNED(mp_set_ll, mp_set_ull, long long, unsigned long long)
+#endif
ADDED libtommath/bn_mp_set_u32.c
Index: libtommath/bn_mp_set_u32.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_set_u32.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef BN_MP_SET_U32_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_SET_UNSIGNED(mp_set_u32, uint32_t)
+#endif
ADDED libtommath/bn_mp_set_u64.c
Index: libtommath/bn_mp_set_u64.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_set_u64.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef BN_MP_SET_U64_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_SET_UNSIGNED(mp_set_u64, uint64_t)
+#endif
ADDED libtommath/bn_mp_set_ul.c
Index: libtommath/bn_mp_set_ul.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_set_ul.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef BN_MP_SET_UL_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_SET_UNSIGNED(mp_set_ul, unsigned long)
+#endif
ADDED libtommath/bn_mp_set_ull.c
Index: libtommath/bn_mp_set_ull.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_set_ull.c
@@ -0,0 +1,7 @@
+#include "tommath_private.h"
+#ifdef BN_MP_SET_ULL_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+MP_SET_UNSIGNED(mp_set_ull, unsigned long long)
+#endif
ADDED libtommath/bn_mp_shrink.c
Index: libtommath/bn_mp_shrink.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_shrink.c
@@ -0,0 +1,22 @@
+#include "tommath_private.h"
+#ifdef BN_MP_SHRINK_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* shrink a bignum */
+mp_err mp_shrink(mp_int *a)
+{
+ mp_digit *tmp;
+ int alloc = MP_MAX(MP_MIN_PREC, a->used);
+ if (a->alloc != alloc) {
+ if ((tmp = (mp_digit *) MP_REALLOC(a->dp,
+ (size_t)a->alloc * sizeof(mp_digit),
+ (size_t)alloc * sizeof(mp_digit))) == NULL) {
+ return MP_MEM;
+ }
+ a->dp = tmp;
+ a->alloc = alloc;
+ }
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_mp_signed_rsh.c
Index: libtommath/bn_mp_signed_rsh.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_signed_rsh.c
@@ -0,0 +1,22 @@
+#include "tommath_private.h"
+#ifdef BN_MP_SIGNED_RSH_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* shift right by a certain bit count with sign extension */
+mp_err mp_signed_rsh(const mp_int *a, int b, mp_int *c)
+{
+ mp_err res;
+ if (a->sign == MP_ZPOS) {
+ return mp_div_2d(a, b, c, NULL);
+ }
+
+ res = mp_add_d(a, 1uL, c);
+ if (res != MP_OKAY) {
+ return res;
+ }
+
+ res = mp_div_2d(c, b, c, NULL);
+ return (res == MP_OKAY) ? mp_sub_d(c, 1uL, c) : res;
+}
+#endif
ADDED libtommath/bn_mp_sqr.c
Index: libtommath/bn_mp_sqr.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_sqr.c
@@ -0,0 +1,28 @@
+#include "tommath_private.h"
+#ifdef BN_MP_SQR_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* computes b = a*a */
+mp_err mp_sqr(const mp_int *a, mp_int *b)
+{
+ mp_err err;
+ if (MP_HAS(S_MP_TOOM_SQR) && /* use Toom-Cook? */
+ (a->used >= MP_TOOM_SQR_CUTOFF)) {
+ err = s_mp_toom_sqr(a, b);
+ } else if (MP_HAS(S_MP_KARATSUBA_SQR) && /* Karatsuba? */
+ (a->used >= MP_KARATSUBA_SQR_CUTOFF)) {
+ err = s_mp_karatsuba_sqr(a, b);
+ } else if (MP_HAS(S_MP_SQR_FAST) && /* can we use the fast comba multiplier? */
+ (((a->used * 2) + 1) < MP_WARRAY) &&
+ (a->used < (MP_MAXFAST / 2))) {
+ err = s_mp_sqr_fast(a, b);
+ } else if (MP_HAS(S_MP_SQR)) {
+ err = s_mp_sqr(a, b);
+ } else {
+ err = MP_VAL;
+ }
+ b->sign = MP_ZPOS;
+ return err;
+}
+#endif
ADDED libtommath/bn_mp_sqrmod.c
Index: libtommath/bn_mp_sqrmod.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_sqrmod.c
@@ -0,0 +1,25 @@
+#include "tommath_private.h"
+#ifdef BN_MP_SQRMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* c = a * a (mod b) */
+mp_err mp_sqrmod(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ mp_err err;
+ mp_int t;
+
+ if ((err = mp_init(&t)) != MP_OKAY) {
+ return err;
+ }
+
+ if ((err = mp_sqr(a, &t)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ err = mp_mod(&t, b, c);
+
+LBL_ERR:
+ mp_clear(&t);
+ return err;
+}
+#endif
ADDED libtommath/bn_mp_sqrt.c
Index: libtommath/bn_mp_sqrt.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_sqrt.c
@@ -0,0 +1,67 @@
+#include "tommath_private.h"
+#ifdef BN_MP_SQRT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* this function is less generic than mp_n_root, simpler and faster */
+mp_err mp_sqrt(const mp_int *arg, mp_int *ret)
+{
+ mp_err err;
+ mp_int t1, t2;
+
+ /* must be positive */
+ if (arg->sign == MP_NEG) {
+ return MP_VAL;
+ }
+
+ /* easy out */
+ if (MP_IS_ZERO(arg)) {
+ mp_zero(ret);
+ return MP_OKAY;
+ }
+
+ if ((err = mp_init_copy(&t1, arg)) != MP_OKAY) {
+ return err;
+ }
+
+ if ((err = mp_init(&t2)) != MP_OKAY) {
+ goto E2;
+ }
+
+ /* First approx. (not very bad for large arg) */
+ mp_rshd(&t1, t1.used/2);
+
+ /* t1 > 0 */
+ if ((err = mp_div(arg, &t1, &t2, NULL)) != MP_OKAY) {
+ goto E1;
+ }
+ if ((err = mp_add(&t1, &t2, &t1)) != MP_OKAY) {
+ goto E1;
+ }
+ if ((err = mp_div_2(&t1, &t1)) != MP_OKAY) {
+ goto E1;
+ }
+ /* And now t1 > sqrt(arg) */
+ do {
+ if ((err = mp_div(arg, &t1, &t2, NULL)) != MP_OKAY) {
+ goto E1;
+ }
+ if ((err = mp_add(&t1, &t2, &t1)) != MP_OKAY) {
+ goto E1;
+ }
+ if ((err = mp_div_2(&t1, &t1)) != MP_OKAY) {
+ goto E1;
+ }
+ /* t1 >= sqrt(arg) >= t2 at this point */
+ } while (mp_cmp_mag(&t1, &t2) == MP_GT);
+
+ mp_exch(&t1, ret);
+
+E1:
+ mp_clear(&t2);
+E2:
+ mp_clear(&t1);
+ return err;
+}
+
+#endif
ADDED libtommath/bn_mp_sqrtmod_prime.c
Index: libtommath/bn_mp_sqrtmod_prime.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_sqrtmod_prime.c
@@ -0,0 +1,118 @@
+#include "tommath_private.h"
+#ifdef BN_MP_SQRTMOD_PRIME_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* Tonelli-Shanks algorithm
+ * https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm
+ * https://gmplib.org/list-archives/gmp-discuss/2013-April/005300.html
+ *
+ */
+
+mp_err mp_sqrtmod_prime(const mp_int *n, const mp_int *prime, mp_int *ret)
+{
+ mp_err err;
+ int legendre;
+ mp_int t1, C, Q, S, Z, M, T, R, two;
+ mp_digit i;
+
+ /* first handle the simple cases */
+ if (mp_cmp_d(n, 0uL) == MP_EQ) {
+ mp_zero(ret);
+ return MP_OKAY;
+ }
+ if (mp_cmp_d(prime, 2uL) == MP_EQ) return MP_VAL; /* prime must be odd */
+ if ((err = mp_kronecker(n, prime, &legendre)) != MP_OKAY) return err;
+ if (legendre == -1) return MP_VAL; /* quadratic non-residue mod prime */
+
+ if ((err = mp_init_multi(&t1, &C, &Q, &S, &Z, &M, &T, &R, &two, NULL)) != MP_OKAY) {
+ return err;
+ }
+
+ /* SPECIAL CASE: if prime mod 4 == 3
+ * compute directly: err = n^(prime+1)/4 mod prime
+ * Handbook of Applied Cryptography algorithm 3.36
+ */
+ if ((err = mp_mod_d(prime, 4uL, &i)) != MP_OKAY) goto cleanup;
+ if (i == 3u) {
+ if ((err = mp_add_d(prime, 1uL, &t1)) != MP_OKAY) goto cleanup;
+ if ((err = mp_div_2(&t1, &t1)) != MP_OKAY) goto cleanup;
+ if ((err = mp_div_2(&t1, &t1)) != MP_OKAY) goto cleanup;
+ if ((err = mp_exptmod(n, &t1, prime, ret)) != MP_OKAY) goto cleanup;
+ err = MP_OKAY;
+ goto cleanup;
+ }
+
+ /* NOW: Tonelli-Shanks algorithm */
+
+ /* factor out powers of 2 from prime-1, defining Q and S as: prime-1 = Q*2^S */
+ if ((err = mp_copy(prime, &Q)) != MP_OKAY) goto cleanup;
+ if ((err = mp_sub_d(&Q, 1uL, &Q)) != MP_OKAY) goto cleanup;
+ /* Q = prime - 1 */
+ mp_zero(&S);
+ /* S = 0 */
+ while (MP_IS_EVEN(&Q)) {
+ if ((err = mp_div_2(&Q, &Q)) != MP_OKAY) goto cleanup;
+ /* Q = Q / 2 */
+ if ((err = mp_add_d(&S, 1uL, &S)) != MP_OKAY) goto cleanup;
+ /* S = S + 1 */
+ }
+
+ /* find a Z such that the Legendre symbol (Z|prime) == -1 */
+ mp_set_u32(&Z, 2u);
+ /* Z = 2 */
+ for (;;) {
+ if ((err = mp_kronecker(&Z, prime, &legendre)) != MP_OKAY) goto cleanup;
+ if (legendre == -1) break;
+ if ((err = mp_add_d(&Z, 1uL, &Z)) != MP_OKAY) goto cleanup;
+ /* Z = Z + 1 */
+ }
+
+ if ((err = mp_exptmod(&Z, &Q, prime, &C)) != MP_OKAY) goto cleanup;
+ /* C = Z ^ Q mod prime */
+ if ((err = mp_add_d(&Q, 1uL, &t1)) != MP_OKAY) goto cleanup;
+ if ((err = mp_div_2(&t1, &t1)) != MP_OKAY) goto cleanup;
+ /* t1 = (Q + 1) / 2 */
+ if ((err = mp_exptmod(n, &t1, prime, &R)) != MP_OKAY) goto cleanup;
+ /* R = n ^ ((Q + 1) / 2) mod prime */
+ if ((err = mp_exptmod(n, &Q, prime, &T)) != MP_OKAY) goto cleanup;
+ /* T = n ^ Q mod prime */
+ if ((err = mp_copy(&S, &M)) != MP_OKAY) goto cleanup;
+ /* M = S */
+ mp_set_u32(&two, 2u);
+
+ for (;;) {
+ if ((err = mp_copy(&T, &t1)) != MP_OKAY) goto cleanup;
+ i = 0;
+ for (;;) {
+ if (mp_cmp_d(&t1, 1uL) == MP_EQ) break;
+ if ((err = mp_exptmod(&t1, &two, prime, &t1)) != MP_OKAY) goto cleanup;
+ i++;
+ }
+ if (i == 0u) {
+ if ((err = mp_copy(&R, ret)) != MP_OKAY) goto cleanup;
+ err = MP_OKAY;
+ goto cleanup;
+ }
+ if ((err = mp_sub_d(&M, i, &t1)) != MP_OKAY) goto cleanup;
+ if ((err = mp_sub_d(&t1, 1uL, &t1)) != MP_OKAY) goto cleanup;
+ if ((err = mp_exptmod(&two, &t1, prime, &t1)) != MP_OKAY) goto cleanup;
+ /* t1 = 2 ^ (M - i - 1) */
+ if ((err = mp_exptmod(&C, &t1, prime, &t1)) != MP_OKAY) goto cleanup;
+ /* t1 = C ^ (2 ^ (M - i - 1)) mod prime */
+ if ((err = mp_sqrmod(&t1, prime, &C)) != MP_OKAY) goto cleanup;
+ /* C = (t1 * t1) mod prime */
+ if ((err = mp_mulmod(&R, &t1, prime, &R)) != MP_OKAY) goto cleanup;
+ /* R = (R * t1) mod prime */
+ if ((err = mp_mulmod(&T, &C, prime, &T)) != MP_OKAY) goto cleanup;
+ /* T = (T * C) mod prime */
+ mp_set(&M, i);
+ /* M = i */
+ }
+
+cleanup:
+ mp_clear_multi(&t1, &C, &Q, &S, &Z, &M, &T, &R, &two, NULL);
+ return err;
+}
+
+#endif
ADDED libtommath/bn_mp_sub.c
Index: libtommath/bn_mp_sub.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_sub.c
@@ -0,0 +1,40 @@
+#include "tommath_private.h"
+#ifdef BN_MP_SUB_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* high level subtraction (handles signs) */
+mp_err mp_sub(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ mp_sign sa = a->sign, sb = b->sign;
+ mp_err err;
+
+ if (sa != sb) {
+ /* subtract a negative from a positive, OR */
+ /* subtract a positive from a negative. */
+ /* In either case, ADD their magnitudes, */
+ /* and use the sign of the first number. */
+ c->sign = sa;
+ err = s_mp_add(a, b, c);
+ } else {
+ /* subtract a positive from a positive, OR */
+ /* subtract a negative from a negative. */
+ /* First, take the difference between their */
+ /* magnitudes, then... */
+ if (mp_cmp_mag(a, b) != MP_LT) {
+ /* Copy the sign from the first */
+ c->sign = sa;
+ /* The first has a larger or equal magnitude */
+ err = s_mp_sub(a, b, c);
+ } else {
+ /* The result has the *opposite* sign from */
+ /* the first number. */
+ c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS;
+ /* The second has a larger magnitude */
+ err = s_mp_sub(b, a, c);
+ }
+ }
+ return err;
+}
+
+#endif
ADDED libtommath/bn_mp_sub_d.c
Index: libtommath/bn_mp_sub_d.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_sub_d.c
@@ -0,0 +1,74 @@
+#include "tommath_private.h"
+#ifdef BN_MP_SUB_D_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* single digit subtraction */
+mp_err mp_sub_d(const mp_int *a, mp_digit b, mp_int *c)
+{
+ mp_digit *tmpa, *tmpc;
+ mp_err err;
+ int ix, oldused;
+
+ /* grow c as required */
+ if (c->alloc < (a->used + 1)) {
+ if ((err = mp_grow(c, a->used + 1)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ /* if a is negative just do an unsigned
+ * addition [with fudged signs]
+ */
+ if (a->sign == MP_NEG) {
+ mp_int a_ = *a;
+ a_.sign = MP_ZPOS;
+ err = mp_add_d(&a_, b, c);
+ c->sign = MP_NEG;
+
+ /* clamp */
+ mp_clamp(c);
+
+ return err;
+ }
+
+ /* setup regs */
+ oldused = c->used;
+ tmpa = a->dp;
+ tmpc = c->dp;
+
+ /* if a <= b simply fix the single digit */
+ if (((a->used == 1) && (a->dp[0] <= b)) || (a->used == 0)) {
+ if (a->used == 1) {
+ *tmpc++ = b - *tmpa;
+ } else {
+ *tmpc++ = b;
+ }
+ ix = 1;
+
+ /* negative/1digit */
+ c->sign = MP_NEG;
+ c->used = 1;
+ } else {
+ mp_digit mu = b;
+
+ /* positive/size */
+ c->sign = MP_ZPOS;
+ c->used = a->used;
+
+ /* subtract digits, mu is carry */
+ for (ix = 0; ix < a->used; ix++) {
+ *tmpc = *tmpa++ - mu;
+ mu = *tmpc >> (MP_SIZEOF_BITS(mp_digit) - 1u);
+ *tmpc++ &= MP_MASK;
+ }
+ }
+
+ /* zero excess digits */
+ MP_ZERO_DIGITS(tmpc, oldused - ix);
+
+ mp_clamp(c);
+ return MP_OKAY;
+}
+
+#endif
ADDED libtommath/bn_mp_submod.c
Index: libtommath/bn_mp_submod.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_submod.c
@@ -0,0 +1,25 @@
+#include "tommath_private.h"
+#ifdef BN_MP_SUBMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* d = a - b (mod c) */
+mp_err mp_submod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d)
+{
+ mp_err err;
+ mp_int t;
+
+ if ((err = mp_init(&t)) != MP_OKAY) {
+ return err;
+ }
+
+ if ((err = mp_sub(a, b, &t)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ err = mp_mod(&t, c, d);
+
+LBL_ERR:
+ mp_clear(&t);
+ return err;
+}
+#endif
ADDED libtommath/bn_mp_to_radix.c
Index: libtommath/bn_mp_to_radix.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_to_radix.c
@@ -0,0 +1,84 @@
+#include "tommath_private.h"
+#ifdef BN_MP_TO_RADIX_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* stores a bignum as a ASCII string in a given radix (2..64)
+ *
+ * Stores upto "size - 1" chars and always a NULL byte, puts the number of characters
+ * written, including the '\0', in "written".
+ */
+mp_err mp_to_radix(const mp_int *a, char *str, size_t maxlen, size_t *written, int radix)
+{
+ size_t digs;
+ mp_err err;
+ mp_int t;
+ mp_digit d;
+ char *_s = str;
+
+ /* check range of radix and size*/
+ if (maxlen < 2u) {
+ return MP_BUF;
+ }
+ if ((radix < 2) || (radix > 64)) {
+ return MP_VAL;
+ }
+
+ /* quick out if its zero */
+ if (MP_IS_ZERO(a)) {
+ *str++ = '0';
+ *str = '\0';
+ if (written != NULL) {
+ *written = 2u;
+ }
+ return MP_OKAY;
+ }
+
+ if ((err = mp_init_copy(&t, a)) != MP_OKAY) {
+ return err;
+ }
+
+ /* if it is negative output a - */
+ if (t.sign == MP_NEG) {
+ /* we have to reverse our digits later... but not the - sign!! */
+ ++_s;
+
+ /* store the flag and mark the number as positive */
+ *str++ = '-';
+ t.sign = MP_ZPOS;
+
+ /* subtract a char */
+ --maxlen;
+ }
+ digs = 0u;
+ while (!MP_IS_ZERO(&t)) {
+ if (--maxlen < 1u) {
+ /* no more room */
+ err = MP_BUF;
+ goto LBL_ERR;
+ }
+ if ((err = mp_div_d(&t, (mp_digit)radix, &t, &d)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ *str++ = mp_s_rmap[d];
+ ++digs;
+ }
+ /* reverse the digits of the string. In this case _s points
+ * to the first digit [exluding the sign] of the number
+ */
+ s_mp_reverse((unsigned char *)_s, digs);
+
+ /* append a NULL so the string is properly terminated */
+ *str = '\0';
+ digs++;
+
+ if (written != NULL) {
+ *written = (a->sign == MP_NEG) ? (digs + 1u): digs;
+ }
+
+LBL_ERR:
+ mp_clear(&t);
+ return err;
+}
+
+#endif
ADDED libtommath/bn_mp_to_sbin.c
Index: libtommath/bn_mp_to_sbin.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_to_sbin.c
@@ -0,0 +1,22 @@
+#include "tommath_private.h"
+#ifdef BN_MP_TO_SBIN_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* store in signed [big endian] format */
+mp_err mp_to_sbin(const mp_int *a, unsigned char *buf, size_t maxlen, size_t *written)
+{
+ mp_err err;
+ if (maxlen == 0u) {
+ return MP_BUF;
+ }
+ if ((err = mp_to_ubin(a, buf + 1, maxlen - 1u, written)) != MP_OKAY) {
+ return err;
+ }
+ if (written != NULL) {
+ (*written)++;
+ }
+ buf[0] = (a->sign == MP_ZPOS) ? (unsigned char)0 : (unsigned char)1;
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_mp_to_ubin.c
Index: libtommath/bn_mp_to_ubin.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_to_ubin.c
@@ -0,0 +1,41 @@
+#include "tommath_private.h"
+#ifdef BN_MP_TO_UBIN_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* store in unsigned [big endian] format */
+mp_err mp_to_ubin(const mp_int *a, unsigned char *buf, size_t maxlen, size_t *written)
+{
+ size_t x, count;
+ mp_err err;
+ mp_int t;
+
+ count = mp_ubin_size(a);
+ if (count > maxlen) {
+ return MP_BUF;
+ }
+
+ if ((err = mp_init_copy(&t, a)) != MP_OKAY) {
+ return err;
+ }
+
+ for (x = count; x --> 0u;) {
+#ifndef MP_8BIT
+ buf[x] = (unsigned char)(t.dp[0] & 255u);
+#else
+ buf[x] = (unsigned char)(t.dp[0] | ((t.dp[1] & 1u) << 7));
+#endif
+ if ((err = mp_div_2d(&t, 8, &t, NULL)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ if (written != NULL) {
+ *written = count;
+ }
+
+LBL_ERR:
+ mp_clear(&t);
+ return err;
+}
+#endif
ADDED libtommath/bn_mp_ubin_size.c
Index: libtommath/bn_mp_ubin_size.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_ubin_size.c
@@ -0,0 +1,12 @@
+#include "tommath_private.h"
+#ifdef BN_MP_UBIN_SIZE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* get the size for an unsigned equivalent */
+size_t mp_ubin_size(const mp_int *a)
+{
+ size_t size = (size_t)mp_count_bits(a);
+ return (size / 8u) + (((size & 7u) != 0u) ? 1u : 0u);
+}
+#endif
ADDED libtommath/bn_mp_unpack.c
Index: libtommath/bn_mp_unpack.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_unpack.c
@@ -0,0 +1,49 @@
+#include "tommath_private.h"
+#ifdef BN_MP_UNPACK_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* based on gmp's mpz_import.
+ * see http://gmplib.org/manual/Integer-Import-and-Export.html
+ */
+mp_err mp_unpack(mp_int *rop, size_t count, mp_order order, size_t size,
+ mp_endian endian, size_t nails, const void *op)
+{
+ mp_err err;
+ size_t odd_nails, nail_bytes, i, j;
+ unsigned char odd_nail_mask;
+
+ mp_zero(rop);
+
+ if (endian == MP_NATIVE_ENDIAN) {
+ MP_GET_ENDIANNESS(endian);
+ }
+
+ odd_nails = (nails % 8u);
+ odd_nail_mask = 0xff;
+ for (i = 0; i < odd_nails; ++i) {
+ odd_nail_mask ^= (unsigned char)(1u << (7u - i));
+ }
+ nail_bytes = nails / 8u;
+
+ for (i = 0; i < count; ++i) {
+ for (j = 0; j < (size - nail_bytes); ++j) {
+ unsigned char byte = *((const unsigned char *)op +
+ (((order == MP_MSB_FIRST) ? i : ((count - 1u) - i)) * size) +
+ ((endian == MP_BIG_ENDIAN) ? (j + nail_bytes) : (((size - 1u) - j) - nail_bytes)));
+
+ if ((err = mp_mul_2d(rop, (j == 0u) ? (int)(8u - odd_nails) : 8, rop)) != MP_OKAY) {
+ return err;
+ }
+
+ rop->dp[0] |= (j == 0u) ? (mp_digit)(byte & odd_nail_mask) : (mp_digit)byte;
+ rop->used += 1;
+ }
+ }
+
+ mp_clamp(rop);
+
+ return MP_OKAY;
+}
+
+#endif
ADDED libtommath/bn_mp_xor.c
Index: libtommath/bn_mp_xor.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_xor.c
@@ -0,0 +1,56 @@
+#include "tommath_private.h"
+#ifdef BN_MP_XOR_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* two complement xor */
+mp_err mp_xor(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ int used = MP_MAX(a->used, b->used) + 1, i;
+ mp_err err;
+ mp_digit ac = 1, bc = 1, cc = 1;
+ mp_sign csign = (a->sign != b->sign) ? MP_NEG : MP_ZPOS;
+
+ if (c->alloc < used) {
+ if ((err = mp_grow(c, used)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ for (i = 0; i < used; i++) {
+ mp_digit x, y;
+
+ /* convert to two complement if negative */
+ if (a->sign == MP_NEG) {
+ ac += (i >= a->used) ? MP_MASK : (~a->dp[i] & MP_MASK);
+ x = ac & MP_MASK;
+ ac >>= MP_DIGIT_BIT;
+ } else {
+ x = (i >= a->used) ? 0uL : a->dp[i];
+ }
+
+ /* convert to two complement if negative */
+ if (b->sign == MP_NEG) {
+ bc += (i >= b->used) ? MP_MASK : (~b->dp[i] & MP_MASK);
+ y = bc & MP_MASK;
+ bc >>= MP_DIGIT_BIT;
+ } else {
+ y = (i >= b->used) ? 0uL : b->dp[i];
+ }
+
+ c->dp[i] = x ^ y;
+
+ /* convert to to sign-magnitude if negative */
+ if (csign == MP_NEG) {
+ cc += ~c->dp[i] & MP_MASK;
+ c->dp[i] = cc & MP_MASK;
+ cc >>= MP_DIGIT_BIT;
+ }
+ }
+
+ c->used = used;
+ c->sign = csign;
+ mp_clamp(c);
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_mp_zero.c
Index: libtommath/bn_mp_zero.c
==================================================================
--- /dev/null
+++ libtommath/bn_mp_zero.c
@@ -0,0 +1,13 @@
+#include "tommath_private.h"
+#ifdef BN_MP_ZERO_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* set to zero */
+void mp_zero(mp_int *a)
+{
+ a->sign = MP_ZPOS;
+ a->used = 0;
+ MP_ZERO_DIGITS(a->dp, a->alloc);
+}
+#endif
ADDED libtommath/bn_prime_tab.c
Index: libtommath/bn_prime_tab.c
==================================================================
--- /dev/null
+++ libtommath/bn_prime_tab.c
@@ -0,0 +1,61 @@
+#include "tommath_private.h"
+#ifdef BN_PRIME_TAB_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+const mp_digit ltm_prime_tab[] = {
+ 0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013,
+ 0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035,
+ 0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059,
+ 0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F,
+#ifndef MP_8BIT
+ 0x0083,
+ 0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD,
+ 0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF,
+ 0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107,
+ 0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137,
+
+ 0x0139, 0x013D, 0x014B, 0x0151, 0x015B, 0x015D, 0x0161, 0x0167,
+ 0x016F, 0x0175, 0x017B, 0x017F, 0x0185, 0x018D, 0x0191, 0x0199,
+ 0x01A3, 0x01A5, 0x01AF, 0x01B1, 0x01B7, 0x01BB, 0x01C1, 0x01C9,
+ 0x01CD, 0x01CF, 0x01D3, 0x01DF, 0x01E7, 0x01EB, 0x01F3, 0x01F7,
+ 0x01FD, 0x0209, 0x020B, 0x021D, 0x0223, 0x022D, 0x0233, 0x0239,
+ 0x023B, 0x0241, 0x024B, 0x0251, 0x0257, 0x0259, 0x025F, 0x0265,
+ 0x0269, 0x026B, 0x0277, 0x0281, 0x0283, 0x0287, 0x028D, 0x0293,
+ 0x0295, 0x02A1, 0x02A5, 0x02AB, 0x02B3, 0x02BD, 0x02C5, 0x02CF,
+
+ 0x02D7, 0x02DD, 0x02E3, 0x02E7, 0x02EF, 0x02F5, 0x02F9, 0x0301,
+ 0x0305, 0x0313, 0x031D, 0x0329, 0x032B, 0x0335, 0x0337, 0x033B,
+ 0x033D, 0x0347, 0x0355, 0x0359, 0x035B, 0x035F, 0x036D, 0x0371,
+ 0x0373, 0x0377, 0x038B, 0x038F, 0x0397, 0x03A1, 0x03A9, 0x03AD,
+ 0x03B3, 0x03B9, 0x03C7, 0x03CB, 0x03D1, 0x03D7, 0x03DF, 0x03E5,
+ 0x03F1, 0x03F5, 0x03FB, 0x03FD, 0x0407, 0x0409, 0x040F, 0x0419,
+ 0x041B, 0x0425, 0x0427, 0x042D, 0x043F, 0x0443, 0x0445, 0x0449,
+ 0x044F, 0x0455, 0x045D, 0x0463, 0x0469, 0x047F, 0x0481, 0x048B,
+
+ 0x0493, 0x049D, 0x04A3, 0x04A9, 0x04B1, 0x04BD, 0x04C1, 0x04C7,
+ 0x04CD, 0x04CF, 0x04D5, 0x04E1, 0x04EB, 0x04FD, 0x04FF, 0x0503,
+ 0x0509, 0x050B, 0x0511, 0x0515, 0x0517, 0x051B, 0x0527, 0x0529,
+ 0x052F, 0x0551, 0x0557, 0x055D, 0x0565, 0x0577, 0x0581, 0x058F,
+ 0x0593, 0x0595, 0x0599, 0x059F, 0x05A7, 0x05AB, 0x05AD, 0x05B3,
+ 0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7,
+ 0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623,
+ 0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653
+#endif
+};
+
+#if defined(__GNUC__) && __GNUC__ >= 4
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+const mp_digit *s_mp_prime_tab = ltm_prime_tab;
+#pragma GCC diagnostic pop
+#elif defined(_MSC_VER) && _MSC_VER >= 1500
+#pragma warning(push)
+#pragma warning(disable: 4996)
+const mp_digit *s_mp_prime_tab = ltm_prime_tab;
+#pragma warning(pop)
+#else
+const mp_digit *s_mp_prime_tab = ltm_prime_tab;
+#endif
+
+#endif
ADDED libtommath/bn_s_mp_add.c
Index: libtommath/bn_s_mp_add.c
==================================================================
--- /dev/null
+++ libtommath/bn_s_mp_add.c
@@ -0,0 +1,91 @@
+#include "tommath_private.h"
+#ifdef BN_S_MP_ADD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* low level addition, based on HAC pp.594, Algorithm 14.7 */
+mp_err s_mp_add(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ const mp_int *x;
+ mp_err err;
+ int olduse, min, max;
+
+ /* find sizes, we let |a| <= |b| which means we have to sort
+ * them. "x" will point to the input with the most digits
+ */
+ if (a->used > b->used) {
+ min = b->used;
+ max = a->used;
+ x = a;
+ } else {
+ min = a->used;
+ max = b->used;
+ x = b;
+ }
+
+ /* init result */
+ if (c->alloc < (max + 1)) {
+ if ((err = mp_grow(c, max + 1)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ /* get old used digit count and set new one */
+ olduse = c->used;
+ c->used = max + 1;
+
+ {
+ mp_digit u, *tmpa, *tmpb, *tmpc;
+ int i;
+
+ /* alias for digit pointers */
+
+ /* first input */
+ tmpa = a->dp;
+
+ /* second input */
+ tmpb = b->dp;
+
+ /* destination */
+ tmpc = c->dp;
+
+ /* zero the carry */
+ u = 0;
+ for (i = 0; i < min; i++) {
+ /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */
+ *tmpc = *tmpa++ + *tmpb++ + u;
+
+ /* U = carry bit of T[i] */
+ u = *tmpc >> (mp_digit)MP_DIGIT_BIT;
+
+ /* take away carry bit from T[i] */
+ *tmpc++ &= MP_MASK;
+ }
+
+ /* now copy higher words if any, that is in A+B
+ * if A or B has more digits add those in
+ */
+ if (min != max) {
+ for (; i < max; i++) {
+ /* T[i] = X[i] + U */
+ *tmpc = x->dp[i] + u;
+
+ /* U = carry bit of T[i] */
+ u = *tmpc >> (mp_digit)MP_DIGIT_BIT;
+
+ /* take away carry bit from T[i] */
+ *tmpc++ &= MP_MASK;
+ }
+ }
+
+ /* add carry */
+ *tmpc++ = u;
+
+ /* clear digits above oldused */
+ MP_ZERO_DIGITS(tmpc, olduse - c->used);
+ }
+
+ mp_clamp(c);
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_s_mp_balance_mul.c
Index: libtommath/bn_s_mp_balance_mul.c
==================================================================
--- /dev/null
+++ libtommath/bn_s_mp_balance_mul.c
@@ -0,0 +1,81 @@
+#include "tommath_private.h"
+#ifdef BN_S_MP_BALANCE_MUL_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* single-digit multiplication with the smaller number as the single-digit */
+mp_err s_mp_balance_mul(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ int count, len_a, len_b, nblocks, i, j, bsize;
+ mp_int a0, tmp, A, B, r;
+ mp_err err;
+
+ len_a = a->used;
+ len_b = b->used;
+
+ nblocks = MP_MAX(a->used, b->used) / MP_MIN(a->used, b->used);
+ bsize = MP_MIN(a->used, b->used) ;
+
+ if ((err = mp_init_size(&a0, bsize + 2)) != MP_OKAY) {
+ return err;
+ }
+ if ((err = mp_init_multi(&tmp, &r, NULL)) != MP_OKAY) {
+ mp_clear(&a0);
+ return err;
+ }
+
+ /* Make sure that A is the larger one*/
+ if (len_a < len_b) {
+ B = *a;
+ A = *b;
+ } else {
+ A = *a;
+ B = *b;
+ }
+
+ for (i = 0, j=0; i < nblocks; i++) {
+ /* Cut a slice off of a */
+ a0.used = 0;
+ for (count = 0; count < bsize; count++) {
+ a0.dp[count] = A.dp[ j++ ];
+ a0.used++;
+ }
+ mp_clamp(&a0);
+ /* Multiply with b */
+ if ((err = mp_mul(&a0, &B, &tmp)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ /* Shift tmp to the correct position */
+ if ((err = mp_lshd(&tmp, bsize * i)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ /* Add to output. No carry needed */
+ if ((err = mp_add(&r, &tmp, &r)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+ /* The left-overs; there are always left-overs */
+ if (j < A.used) {
+ a0.used = 0;
+ for (count = 0; j < A.used; count++) {
+ a0.dp[count] = A.dp[ j++ ];
+ a0.used++;
+ }
+ mp_clamp(&a0);
+ if ((err = mp_mul(&a0, &B, &tmp)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((err = mp_lshd(&tmp, bsize * i)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((err = mp_add(&r, &tmp, &r)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ mp_exch(&r,c);
+LBL_ERR:
+ mp_clear_multi(&a0, &tmp, &r,NULL);
+ return err;
+}
+#endif
ADDED libtommath/bn_s_mp_exptmod.c
Index: libtommath/bn_s_mp_exptmod.c
==================================================================
--- /dev/null
+++ libtommath/bn_s_mp_exptmod.c
@@ -0,0 +1,198 @@
+#include "tommath_private.h"
+#ifdef BN_S_MP_EXPTMOD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#ifdef MP_LOW_MEM
+# define TAB_SIZE 32
+# define MAX_WINSIZE 5
+#else
+# define TAB_SIZE 256
+# define MAX_WINSIZE 0
+#endif
+
+mp_err s_mp_exptmod(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y, int redmode)
+{
+ mp_int M[TAB_SIZE], res, mu;
+ mp_digit buf;
+ mp_err err;
+ int bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
+ mp_err(*redux)(mp_int *x, const mp_int *m, const mp_int *mu);
+
+ /* find window size */
+ x = mp_count_bits(X);
+ if (x <= 7) {
+ winsize = 2;
+ } else if (x <= 36) {
+ winsize = 3;
+ } else if (x <= 140) {
+ winsize = 4;
+ } else if (x <= 450) {
+ winsize = 5;
+ } else if (x <= 1303) {
+ winsize = 6;
+ } else if (x <= 3529) {
+ winsize = 7;
+ } else {
+ winsize = 8;
+ }
+
+ winsize = MAX_WINSIZE ? MP_MIN(MAX_WINSIZE, winsize) : winsize;
+
+ /* init M array */
+ /* init first cell */
+ if ((err = mp_init(&M[1])) != MP_OKAY) {
+ return err;
+ }
+
+ /* now init the second half of the array */
+ for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+ if ((err = mp_init(&M[x])) != MP_OKAY) {
+ for (y = 1<<(winsize-1); y < x; y++) {
+ mp_clear(&M[y]);
+ }
+ mp_clear(&M[1]);
+ return err;
+ }
+ }
+
+ /* create mu, used for Barrett reduction */
+ if ((err = mp_init(&mu)) != MP_OKAY) goto LBL_M;
+
+ if (redmode == 0) {
+ if ((err = mp_reduce_setup(&mu, P)) != MP_OKAY) goto LBL_MU;
+ redux = mp_reduce;
+ } else {
+ if ((err = mp_reduce_2k_setup_l(P, &mu)) != MP_OKAY) goto LBL_MU;
+ redux = mp_reduce_2k_l;
+ }
+
+ /* create M table
+ *
+ * The M table contains powers of the base,
+ * e.g. M[x] = G**x mod P
+ *
+ * The first half of the table is not
+ * computed though accept for M[0] and M[1]
+ */
+ if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) goto LBL_MU;
+
+ /* compute the value at M[1<<(winsize-1)] by squaring
+ * M[1] (winsize-1) times
+ */
+ if ((err = mp_copy(&M[1], &M[(size_t)1 << (winsize - 1)])) != MP_OKAY) goto LBL_MU;
+
+ for (x = 0; x < (winsize - 1); x++) {
+ /* square it */
+ if ((err = mp_sqr(&M[(size_t)1 << (winsize - 1)],
+ &M[(size_t)1 << (winsize - 1)])) != MP_OKAY) goto LBL_MU;
+
+ /* reduce modulo P */
+ if ((err = redux(&M[(size_t)1 << (winsize - 1)], P, &mu)) != MP_OKAY) goto LBL_MU;
+ }
+
+ /* create upper table, that is M[x] = M[x-1] * M[1] (mod P)
+ * for x = (2**(winsize - 1) + 1) to (2**winsize - 1)
+ */
+ for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
+ if ((err = mp_mul(&M[x - 1], &M[1], &M[x])) != MP_OKAY) goto LBL_MU;
+ if ((err = redux(&M[x], P, &mu)) != MP_OKAY) goto LBL_MU;
+ }
+
+ /* setup result */
+ if ((err = mp_init(&res)) != MP_OKAY) goto LBL_MU;
+ mp_set(&res, 1uL);
+
+ /* set initial mode and bit cnt */
+ mode = 0;
+ bitcnt = 1;
+ buf = 0;
+ digidx = X->used - 1;
+ bitcpy = 0;
+ bitbuf = 0;
+
+ for (;;) {
+ /* grab next digit as required */
+ if (--bitcnt == 0) {
+ /* if digidx == -1 we are out of digits */
+ if (digidx == -1) {
+ break;
+ }
+ /* read next digit and reset the bitcnt */
+ buf = X->dp[digidx--];
+ bitcnt = (int)MP_DIGIT_BIT;
+ }
+
+ /* grab the next msb from the exponent */
+ y = (buf >> (mp_digit)(MP_DIGIT_BIT - 1)) & 1uL;
+ buf <<= (mp_digit)1;
+
+ /* if the bit is zero and mode == 0 then we ignore it
+ * These represent the leading zero bits before the first 1 bit
+ * in the exponent. Technically this opt is not required but it
+ * does lower the # of trivial squaring/reductions used
+ */
+ if ((mode == 0) && (y == 0)) {
+ continue;
+ }
+
+ /* if the bit is zero and mode == 1 then we square */
+ if ((mode == 1) && (y == 0)) {
+ if ((err = mp_sqr(&res, &res)) != MP_OKAY) goto LBL_RES;
+ if ((err = redux(&res, P, &mu)) != MP_OKAY) goto LBL_RES;
+ continue;
+ }
+
+ /* else we add it to the window */
+ bitbuf |= (y << (winsize - ++bitcpy));
+ mode = 2;
+
+ if (bitcpy == winsize) {
+ /* ok window is filled so square as required and multiply */
+ /* square first */
+ for (x = 0; x < winsize; x++) {
+ if ((err = mp_sqr(&res, &res)) != MP_OKAY) goto LBL_RES;
+ if ((err = redux(&res, P, &mu)) != MP_OKAY) goto LBL_RES;
+ }
+
+ /* then multiply */
+ if ((err = mp_mul(&res, &M[bitbuf], &res)) != MP_OKAY) goto LBL_RES;
+ if ((err = redux(&res, P, &mu)) != MP_OKAY) goto LBL_RES;
+
+ /* empty window and reset */
+ bitcpy = 0;
+ bitbuf = 0;
+ mode = 1;
+ }
+ }
+
+ /* if bits remain then square/multiply */
+ if ((mode == 2) && (bitcpy > 0)) {
+ /* square then multiply if the bit is set */
+ for (x = 0; x < bitcpy; x++) {
+ if ((err = mp_sqr(&res, &res)) != MP_OKAY) goto LBL_RES;
+ if ((err = redux(&res, P, &mu)) != MP_OKAY) goto LBL_RES;
+
+ bitbuf <<= 1;
+ if ((bitbuf & (1 << winsize)) != 0) {
+ /* then multiply */
+ if ((err = mp_mul(&res, &M[1], &res)) != MP_OKAY) goto LBL_RES;
+ if ((err = redux(&res, P, &mu)) != MP_OKAY) goto LBL_RES;
+ }
+ }
+ }
+
+ mp_exch(&res, Y);
+ err = MP_OKAY;
+LBL_RES:
+ mp_clear(&res);
+LBL_MU:
+ mp_clear(&mu);
+LBL_M:
+ mp_clear(&M[1]);
+ for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+ mp_clear(&M[x]);
+ }
+ return err;
+}
+#endif
ADDED libtommath/bn_s_mp_exptmod_fast.c
Index: libtommath/bn_s_mp_exptmod_fast.c
==================================================================
--- /dev/null
+++ libtommath/bn_s_mp_exptmod_fast.c
@@ -0,0 +1,254 @@
+#include "tommath_private.h"
+#ifdef BN_S_MP_EXPTMOD_FAST_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85
+ *
+ * Uses a left-to-right k-ary sliding window to compute the modular exponentiation.
+ * The value of k changes based on the size of the exponent.
+ *
+ * Uses Montgomery or Diminished Radix reduction [whichever appropriate]
+ */
+
+#ifdef MP_LOW_MEM
+# define TAB_SIZE 32
+# define MAX_WINSIZE 5
+#else
+# define TAB_SIZE 256
+# define MAX_WINSIZE 0
+#endif
+
+mp_err s_mp_exptmod_fast(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y, int redmode)
+{
+ mp_int M[TAB_SIZE], res;
+ mp_digit buf, mp;
+ int bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
+ mp_err err;
+
+ /* use a pointer to the reduction algorithm. This allows us to use
+ * one of many reduction algorithms without modding the guts of
+ * the code with if statements everywhere.
+ */
+ mp_err(*redux)(mp_int *x, const mp_int *n, mp_digit rho);
+
+ /* find window size */
+ x = mp_count_bits(X);
+ if (x <= 7) {
+ winsize = 2;
+ } else if (x <= 36) {
+ winsize = 3;
+ } else if (x <= 140) {
+ winsize = 4;
+ } else if (x <= 450) {
+ winsize = 5;
+ } else if (x <= 1303) {
+ winsize = 6;
+ } else if (x <= 3529) {
+ winsize = 7;
+ } else {
+ winsize = 8;
+ }
+
+ winsize = MAX_WINSIZE ? MP_MIN(MAX_WINSIZE, winsize) : winsize;
+
+ /* init M array */
+ /* init first cell */
+ if ((err = mp_init_size(&M[1], P->alloc)) != MP_OKAY) {
+ return err;
+ }
+
+ /* now init the second half of the array */
+ for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+ if ((err = mp_init_size(&M[x], P->alloc)) != MP_OKAY) {
+ for (y = 1<<(winsize-1); y < x; y++) {
+ mp_clear(&M[y]);
+ }
+ mp_clear(&M[1]);
+ return err;
+ }
+ }
+
+ /* determine and setup reduction code */
+ if (redmode == 0) {
+ if (MP_HAS(MP_MONTGOMERY_SETUP)) {
+ /* now setup montgomery */
+ if ((err = mp_montgomery_setup(P, &mp)) != MP_OKAY) goto LBL_M;
+ } else {
+ err = MP_VAL;
+ goto LBL_M;
+ }
+
+ /* automatically pick the comba one if available (saves quite a few calls/ifs) */
+ if (MP_HAS(S_MP_MONTGOMERY_REDUCE_FAST) &&
+ (((P->used * 2) + 1) < MP_WARRAY) &&
+ (P->used < MP_MAXFAST)) {
+ redux = s_mp_montgomery_reduce_fast;
+ } else if (MP_HAS(MP_MONTGOMERY_REDUCE)) {
+ /* use slower baseline Montgomery method */
+ redux = mp_montgomery_reduce;
+ } else {
+ err = MP_VAL;
+ goto LBL_M;
+ }
+ } else if (redmode == 1) {
+ if (MP_HAS(MP_DR_SETUP) && MP_HAS(MP_DR_REDUCE)) {
+ /* setup DR reduction for moduli of the form B**k - b */
+ mp_dr_setup(P, &mp);
+ redux = mp_dr_reduce;
+ } else {
+ err = MP_VAL;
+ goto LBL_M;
+ }
+ } else if (MP_HAS(MP_REDUCE_2K_SETUP) && MP_HAS(MP_REDUCE_2K)) {
+ /* setup DR reduction for moduli of the form 2**k - b */
+ if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) goto LBL_M;
+ redux = mp_reduce_2k;
+ } else {
+ err = MP_VAL;
+ goto LBL_M;
+ }
+
+ /* setup result */
+ if ((err = mp_init_size(&res, P->alloc)) != MP_OKAY) goto LBL_M;
+
+ /* create M table
+ *
+
+ *
+ * The first half of the table is not computed though accept for M[0] and M[1]
+ */
+
+ if (redmode == 0) {
+ if (MP_HAS(MP_MONTGOMERY_CALC_NORMALIZATION)) {
+ /* now we need R mod m */
+ if ((err = mp_montgomery_calc_normalization(&res, P)) != MP_OKAY) goto LBL_RES;
+
+ /* now set M[1] to G * R mod m */
+ if ((err = mp_mulmod(G, &res, P, &M[1])) != MP_OKAY) goto LBL_RES;
+ } else {
+ err = MP_VAL;
+ goto LBL_RES;
+ }
+ } else {
+ mp_set(&res, 1uL);
+ if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) goto LBL_RES;
+ }
+
+ /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */
+ if ((err = mp_copy(&M[1], &M[(size_t)1 << (winsize - 1)])) != MP_OKAY) goto LBL_RES;
+
+ for (x = 0; x < (winsize - 1); x++) {
+ if ((err = mp_sqr(&M[(size_t)1 << (winsize - 1)], &M[(size_t)1 << (winsize - 1)])) != MP_OKAY) goto LBL_RES;
+ if ((err = redux(&M[(size_t)1 << (winsize - 1)], P, mp)) != MP_OKAY) goto LBL_RES;
+ }
+
+ /* create upper table */
+ for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
+ if ((err = mp_mul(&M[x - 1], &M[1], &M[x])) != MP_OKAY) goto LBL_RES;
+ if ((err = redux(&M[x], P, mp)) != MP_OKAY) goto LBL_RES;
+ }
+
+ /* set initial mode and bit cnt */
+ mode = 0;
+ bitcnt = 1;
+ buf = 0;
+ digidx = X->used - 1;
+ bitcpy = 0;
+ bitbuf = 0;
+
+ for (;;) {
+ /* grab next digit as required */
+ if (--bitcnt == 0) {
+ /* if digidx == -1 we are out of digits so break */
+ if (digidx == -1) {
+ break;
+ }
+ /* read next digit and reset bitcnt */
+ buf = X->dp[digidx--];
+ bitcnt = (int)MP_DIGIT_BIT;
+ }
+
+ /* grab the next msb from the exponent */
+ y = (mp_digit)(buf >> (MP_DIGIT_BIT - 1)) & 1uL;
+ buf <<= (mp_digit)1;
+
+ /* if the bit is zero and mode == 0 then we ignore it
+ * These represent the leading zero bits before the first 1 bit
+ * in the exponent. Technically this opt is not required but it
+ * does lower the # of trivial squaring/reductions used
+ */
+ if ((mode == 0) && (y == 0)) {
+ continue;
+ }
+
+ /* if the bit is zero and mode == 1 then we square */
+ if ((mode == 1) && (y == 0)) {
+ if ((err = mp_sqr(&res, &res)) != MP_OKAY) goto LBL_RES;
+ if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES;
+ continue;
+ }
+
+ /* else we add it to the window */
+ bitbuf |= (y << (winsize - ++bitcpy));
+ mode = 2;
+
+ if (bitcpy == winsize) {
+ /* ok window is filled so square as required and multiply */
+ /* square first */
+ for (x = 0; x < winsize; x++) {
+ if ((err = mp_sqr(&res, &res)) != MP_OKAY) goto LBL_RES;
+ if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES;
+ }
+
+ /* then multiply */
+ if ((err = mp_mul(&res, &M[bitbuf], &res)) != MP_OKAY) goto LBL_RES;
+ if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES;
+
+ /* empty window and reset */
+ bitcpy = 0;
+ bitbuf = 0;
+ mode = 1;
+ }
+ }
+
+ /* if bits remain then square/multiply */
+ if ((mode == 2) && (bitcpy > 0)) {
+ /* square then multiply if the bit is set */
+ for (x = 0; x < bitcpy; x++) {
+ if ((err = mp_sqr(&res, &res)) != MP_OKAY) goto LBL_RES;
+ if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES;
+
+ /* get next bit of the window */
+ bitbuf <<= 1;
+ if ((bitbuf & (1 << winsize)) != 0) {
+ /* then multiply */
+ if ((err = mp_mul(&res, &M[1], &res)) != MP_OKAY) goto LBL_RES;
+ if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES;
+ }
+ }
+ }
+
+ if (redmode == 0) {
+ /* fixup result if Montgomery reduction is used
+ * recall that any value in a Montgomery system is
+ * actually multiplied by R mod n. So we have
+ * to reduce one more time to cancel out the factor
+ * of R.
+ */
+ if ((err = redux(&res, P, mp)) != MP_OKAY) goto LBL_RES;
+ }
+
+ /* swap res with Y */
+ mp_exch(&res, Y);
+ err = MP_OKAY;
+LBL_RES:
+ mp_clear(&res);
+LBL_M:
+ mp_clear(&M[1]);
+ for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+ mp_clear(&M[x]);
+ }
+ return err;
+}
+#endif
ADDED libtommath/bn_s_mp_get_bit.c
Index: libtommath/bn_s_mp_get_bit.c
==================================================================
--- /dev/null
+++ libtommath/bn_s_mp_get_bit.c
@@ -0,0 +1,21 @@
+#include "tommath_private.h"
+#ifdef BN_S_MP_GET_BIT_C
+
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* Get bit at position b and return MP_YES if the bit is 1, MP_NO if it is 0 */
+mp_bool s_mp_get_bit(const mp_int *a, unsigned int b)
+{
+ mp_digit bit;
+ int limb = (int)(b / MP_DIGIT_BIT);
+
+ if (limb >= a->used) {
+ return MP_NO;
+ }
+
+ bit = (mp_digit)1 << (b % MP_DIGIT_BIT);
+ return ((a->dp[limb] & bit) != 0u) ? MP_YES : MP_NO;
+}
+
+#endif
ADDED libtommath/bn_s_mp_invmod_fast.c
Index: libtommath/bn_s_mp_invmod_fast.c
==================================================================
--- /dev/null
+++ libtommath/bn_s_mp_invmod_fast.c
@@ -0,0 +1,118 @@
+#include "tommath_private.h"
+#ifdef BN_S_MP_INVMOD_FAST_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* computes the modular inverse via binary extended euclidean algorithm,
+ * that is c = 1/a mod b
+ *
+ * Based on slow invmod except this is optimized for the case where b is
+ * odd as per HAC Note 14.64 on pp. 610
+ */
+mp_err s_mp_invmod_fast(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ mp_int x, y, u, v, B, D;
+ mp_sign neg;
+ mp_err err;
+
+ /* 2. [modified] b must be odd */
+ if (MP_IS_EVEN(b)) {
+ return MP_VAL;
+ }
+
+ /* init all our temps */
+ if ((err = mp_init_multi(&x, &y, &u, &v, &B, &D, NULL)) != MP_OKAY) {
+ return err;
+ }
+
+ /* x == modulus, y == value to invert */
+ if ((err = mp_copy(b, &x)) != MP_OKAY) goto LBL_ERR;
+
+ /* we need y = |a| */
+ if ((err = mp_mod(a, b, &y)) != MP_OKAY) goto LBL_ERR;
+
+ /* if one of x,y is zero return an error! */
+ if (MP_IS_ZERO(&x) || MP_IS_ZERO(&y)) {
+ err = MP_VAL;
+ goto LBL_ERR;
+ }
+
+ /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */
+ if ((err = mp_copy(&x, &u)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_copy(&y, &v)) != MP_OKAY) goto LBL_ERR;
+ mp_set(&D, 1uL);
+
+top:
+ /* 4. while u is even do */
+ while (MP_IS_EVEN(&u)) {
+ /* 4.1 u = u/2 */
+ if ((err = mp_div_2(&u, &u)) != MP_OKAY) goto LBL_ERR;
+
+ /* 4.2 if B is odd then */
+ if (MP_IS_ODD(&B)) {
+ if ((err = mp_sub(&B, &x, &B)) != MP_OKAY) goto LBL_ERR;
+ }
+ /* B = B/2 */
+ if ((err = mp_div_2(&B, &B)) != MP_OKAY) goto LBL_ERR;
+ }
+
+ /* 5. while v is even do */
+ while (MP_IS_EVEN(&v)) {
+ /* 5.1 v = v/2 */
+ if ((err = mp_div_2(&v, &v)) != MP_OKAY) goto LBL_ERR;
+
+ /* 5.2 if D is odd then */
+ if (MP_IS_ODD(&D)) {
+ /* D = (D-x)/2 */
+ if ((err = mp_sub(&D, &x, &D)) != MP_OKAY) goto LBL_ERR;
+ }
+ /* D = D/2 */
+ if ((err = mp_div_2(&D, &D)) != MP_OKAY) goto LBL_ERR;
+ }
+
+ /* 6. if u >= v then */
+ if (mp_cmp(&u, &v) != MP_LT) {
+ /* u = u - v, B = B - D */
+ if ((err = mp_sub(&u, &v, &u)) != MP_OKAY) goto LBL_ERR;
+
+ if ((err = mp_sub(&B, &D, &B)) != MP_OKAY) goto LBL_ERR;
+ } else {
+ /* v - v - u, D = D - B */
+ if ((err = mp_sub(&v, &u, &v)) != MP_OKAY) goto LBL_ERR;
+
+ if ((err = mp_sub(&D, &B, &D)) != MP_OKAY) goto LBL_ERR;
+ }
+
+ /* if not zero goto step 4 */
+ if (!MP_IS_ZERO(&u)) {
+ goto top;
+ }
+
+ /* now a = C, b = D, gcd == g*v */
+
+ /* if v != 1 then there is no inverse */
+ if (mp_cmp_d(&v, 1uL) != MP_EQ) {
+ err = MP_VAL;
+ goto LBL_ERR;
+ }
+
+ /* b is now the inverse */
+ neg = a->sign;
+ while (D.sign == MP_NEG) {
+ if ((err = mp_add(&D, b, &D)) != MP_OKAY) goto LBL_ERR;
+ }
+
+ /* too big */
+ while (mp_cmp_mag(&D, b) != MP_LT) {
+ if ((err = mp_sub(&D, b, &D)) != MP_OKAY) goto LBL_ERR;
+ }
+
+ mp_exch(&D, c);
+ c->sign = neg;
+ err = MP_OKAY;
+
+LBL_ERR:
+ mp_clear_multi(&x, &y, &u, &v, &B, &D, NULL);
+ return err;
+}
+#endif
ADDED libtommath/bn_s_mp_invmod_slow.c
Index: libtommath/bn_s_mp_invmod_slow.c
==================================================================
--- /dev/null
+++ libtommath/bn_s_mp_invmod_slow.c
@@ -0,0 +1,119 @@
+#include "tommath_private.h"
+#ifdef BN_S_MP_INVMOD_SLOW_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* hac 14.61, pp608 */
+mp_err s_mp_invmod_slow(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ mp_int x, y, u, v, A, B, C, D;
+ mp_err err;
+
+ /* b cannot be negative */
+ if ((b->sign == MP_NEG) || MP_IS_ZERO(b)) {
+ return MP_VAL;
+ }
+
+ /* init temps */
+ if ((err = mp_init_multi(&x, &y, &u, &v,
+ &A, &B, &C, &D, NULL)) != MP_OKAY) {
+ return err;
+ }
+
+ /* x = a, y = b */
+ if ((err = mp_mod(a, b, &x)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_copy(b, &y)) != MP_OKAY) goto LBL_ERR;
+
+ /* 2. [modified] if x,y are both even then return an error! */
+ if (MP_IS_EVEN(&x) && MP_IS_EVEN(&y)) {
+ err = MP_VAL;
+ goto LBL_ERR;
+ }
+
+ /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */
+ if ((err = mp_copy(&x, &u)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_copy(&y, &v)) != MP_OKAY) goto LBL_ERR;
+ mp_set(&A, 1uL);
+ mp_set(&D, 1uL);
+
+top:
+ /* 4. while u is even do */
+ while (MP_IS_EVEN(&u)) {
+ /* 4.1 u = u/2 */
+ if ((err = mp_div_2(&u, &u)) != MP_OKAY) goto LBL_ERR;
+
+ /* 4.2 if A or B is odd then */
+ if (MP_IS_ODD(&A) || MP_IS_ODD(&B)) {
+ /* A = (A+y)/2, B = (B-x)/2 */
+ if ((err = mp_add(&A, &y, &A)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_sub(&B, &x, &B)) != MP_OKAY) goto LBL_ERR;
+ }
+ /* A = A/2, B = B/2 */
+ if ((err = mp_div_2(&A, &A)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_div_2(&B, &B)) != MP_OKAY) goto LBL_ERR;
+ }
+
+ /* 5. while v is even do */
+ while (MP_IS_EVEN(&v)) {
+ /* 5.1 v = v/2 */
+ if ((err = mp_div_2(&v, &v)) != MP_OKAY) goto LBL_ERR;
+
+ /* 5.2 if C or D is odd then */
+ if (MP_IS_ODD(&C) || MP_IS_ODD(&D)) {
+ /* C = (C+y)/2, D = (D-x)/2 */
+ if ((err = mp_add(&C, &y, &C)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_sub(&D, &x, &D)) != MP_OKAY) goto LBL_ERR;
+ }
+ /* C = C/2, D = D/2 */
+ if ((err = mp_div_2(&C, &C)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_div_2(&D, &D)) != MP_OKAY) goto LBL_ERR;
+ }
+
+ /* 6. if u >= v then */
+ if (mp_cmp(&u, &v) != MP_LT) {
+ /* u = u - v, A = A - C, B = B - D */
+ if ((err = mp_sub(&u, &v, &u)) != MP_OKAY) goto LBL_ERR;
+
+ if ((err = mp_sub(&A, &C, &A)) != MP_OKAY) goto LBL_ERR;
+
+ if ((err = mp_sub(&B, &D, &B)) != MP_OKAY) goto LBL_ERR;
+ } else {
+ /* v - v - u, C = C - A, D = D - B */
+ if ((err = mp_sub(&v, &u, &v)) != MP_OKAY) goto LBL_ERR;
+
+ if ((err = mp_sub(&C, &A, &C)) != MP_OKAY) goto LBL_ERR;
+
+ if ((err = mp_sub(&D, &B, &D)) != MP_OKAY) goto LBL_ERR;
+ }
+
+ /* if not zero goto step 4 */
+ if (!MP_IS_ZERO(&u)) {
+ goto top;
+ }
+
+ /* now a = C, b = D, gcd == g*v */
+
+ /* if v != 1 then there is no inverse */
+ if (mp_cmp_d(&v, 1uL) != MP_EQ) {
+ err = MP_VAL;
+ goto LBL_ERR;
+ }
+
+ /* if its too low */
+ while (mp_cmp_d(&C, 0uL) == MP_LT) {
+ if ((err = mp_add(&C, b, &C)) != MP_OKAY) goto LBL_ERR;
+ }
+
+ /* too big */
+ while (mp_cmp_mag(&C, b) != MP_LT) {
+ if ((err = mp_sub(&C, b, &C)) != MP_OKAY) goto LBL_ERR;
+ }
+
+ /* C is now the inverse */
+ mp_exch(&C, c);
+ err = MP_OKAY;
+LBL_ERR:
+ mp_clear_multi(&x, &y, &u, &v, &A, &B, &C, &D, NULL);
+ return err;
+}
+#endif
ADDED libtommath/bn_s_mp_karatsuba_mul.c
Index: libtommath/bn_s_mp_karatsuba_mul.c
==================================================================
--- /dev/null
+++ libtommath/bn_s_mp_karatsuba_mul.c
@@ -0,0 +1,174 @@
+#include "tommath_private.h"
+#ifdef BN_S_MP_KARATSUBA_MUL_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* c = |a| * |b| using Karatsuba Multiplication using
+ * three half size multiplications
+ *
+ * Let B represent the radix [e.g. 2**MP_DIGIT_BIT] and
+ * let n represent half of the number of digits in
+ * the min(a,b)
+ *
+ * a = a1 * B**n + a0
+ * b = b1 * B**n + b0
+ *
+ * Then, a * b =>
+ a1b1 * B**2n + ((a1 + a0)(b1 + b0) - (a0b0 + a1b1)) * B + a0b0
+ *
+ * Note that a1b1 and a0b0 are used twice and only need to be
+ * computed once. So in total three half size (half # of
+ * digit) multiplications are performed, a0b0, a1b1 and
+ * (a1+b1)(a0+b0)
+ *
+ * Note that a multiplication of half the digits requires
+ * 1/4th the number of single precision multiplications so in
+ * total after one call 25% of the single precision multiplications
+ * are saved. Note also that the call to mp_mul can end up back
+ * in this function if the a0, a1, b0, or b1 are above the threshold.
+ * This is known as divide-and-conquer and leads to the famous
+ * O(N**lg(3)) or O(N**1.584) work which is asymptopically lower than
+ * the standard O(N**2) that the baseline/comba methods use.
+ * Generally though the overhead of this method doesn't pay off
+ * until a certain size (N ~ 80) is reached.
+ */
+mp_err s_mp_karatsuba_mul(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ mp_int x0, x1, y0, y1, t1, x0y0, x1y1;
+ int B;
+ mp_err err = MP_MEM; /* default the return code to an error */
+
+ /* min # of digits */
+ B = MP_MIN(a->used, b->used);
+
+ /* now divide in two */
+ B = B >> 1;
+
+ /* init copy all the temps */
+ if (mp_init_size(&x0, B) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if (mp_init_size(&x1, a->used - B) != MP_OKAY) {
+ goto X0;
+ }
+ if (mp_init_size(&y0, B) != MP_OKAY) {
+ goto X1;
+ }
+ if (mp_init_size(&y1, b->used - B) != MP_OKAY) {
+ goto Y0;
+ }
+
+ /* init temps */
+ if (mp_init_size(&t1, B * 2) != MP_OKAY) {
+ goto Y1;
+ }
+ if (mp_init_size(&x0y0, B * 2) != MP_OKAY) {
+ goto T1;
+ }
+ if (mp_init_size(&x1y1, B * 2) != MP_OKAY) {
+ goto X0Y0;
+ }
+
+ /* now shift the digits */
+ x0.used = y0.used = B;
+ x1.used = a->used - B;
+ y1.used = b->used - B;
+
+ {
+ int x;
+ mp_digit *tmpa, *tmpb, *tmpx, *tmpy;
+
+ /* we copy the digits directly instead of using higher level functions
+ * since we also need to shift the digits
+ */
+ tmpa = a->dp;
+ tmpb = b->dp;
+
+ tmpx = x0.dp;
+ tmpy = y0.dp;
+ for (x = 0; x < B; x++) {
+ *tmpx++ = *tmpa++;
+ *tmpy++ = *tmpb++;
+ }
+
+ tmpx = x1.dp;
+ for (x = B; x < a->used; x++) {
+ *tmpx++ = *tmpa++;
+ }
+
+ tmpy = y1.dp;
+ for (x = B; x < b->used; x++) {
+ *tmpy++ = *tmpb++;
+ }
+ }
+
+ /* only need to clamp the lower words since by definition the
+ * upper words x1/y1 must have a known number of digits
+ */
+ mp_clamp(&x0);
+ mp_clamp(&y0);
+
+ /* now calc the products x0y0 and x1y1 */
+ /* after this x0 is no longer required, free temp [x0==t2]! */
+ if (mp_mul(&x0, &y0, &x0y0) != MP_OKAY) {
+ goto X1Y1; /* x0y0 = x0*y0 */
+ }
+ if (mp_mul(&x1, &y1, &x1y1) != MP_OKAY) {
+ goto X1Y1; /* x1y1 = x1*y1 */
+ }
+
+ /* now calc x1+x0 and y1+y0 */
+ if (s_mp_add(&x1, &x0, &t1) != MP_OKAY) {
+ goto X1Y1; /* t1 = x1 - x0 */
+ }
+ if (s_mp_add(&y1, &y0, &x0) != MP_OKAY) {
+ goto X1Y1; /* t2 = y1 - y0 */
+ }
+ if (mp_mul(&t1, &x0, &t1) != MP_OKAY) {
+ goto X1Y1; /* t1 = (x1 + x0) * (y1 + y0) */
+ }
+
+ /* add x0y0 */
+ if (mp_add(&x0y0, &x1y1, &x0) != MP_OKAY) {
+ goto X1Y1; /* t2 = x0y0 + x1y1 */
+ }
+ if (s_mp_sub(&t1, &x0, &t1) != MP_OKAY) {
+ goto X1Y1; /* t1 = (x1+x0)*(y1+y0) - (x1y1 + x0y0) */
+ }
+
+ /* shift by B */
+ if (mp_lshd(&t1, B) != MP_OKAY) {
+ goto X1Y1; /* t1 = (x0y0 + x1y1 - (x1-x0)*(y1-y0))<used;
+
+ /* now divide in two */
+ B = B >> 1;
+
+ /* init copy all the temps */
+ if (mp_init_size(&x0, B) != MP_OKAY)
+ goto LBL_ERR;
+ if (mp_init_size(&x1, a->used - B) != MP_OKAY)
+ goto X0;
+
+ /* init temps */
+ if (mp_init_size(&t1, a->used * 2) != MP_OKAY)
+ goto X1;
+ if (mp_init_size(&t2, a->used * 2) != MP_OKAY)
+ goto T1;
+ if (mp_init_size(&x0x0, B * 2) != MP_OKAY)
+ goto T2;
+ if (mp_init_size(&x1x1, (a->used - B) * 2) != MP_OKAY)
+ goto X0X0;
+
+ {
+ int x;
+ mp_digit *dst, *src;
+
+ src = a->dp;
+
+ /* now shift the digits */
+ dst = x0.dp;
+ for (x = 0; x < B; x++) {
+ *dst++ = *src++;
+ }
+
+ dst = x1.dp;
+ for (x = B; x < a->used; x++) {
+ *dst++ = *src++;
+ }
+ }
+
+ x0.used = B;
+ x1.used = a->used - B;
+
+ mp_clamp(&x0);
+
+ /* now calc the products x0*x0 and x1*x1 */
+ if (mp_sqr(&x0, &x0x0) != MP_OKAY)
+ goto X1X1; /* x0x0 = x0*x0 */
+ if (mp_sqr(&x1, &x1x1) != MP_OKAY)
+ goto X1X1; /* x1x1 = x1*x1 */
+
+ /* now calc (x1+x0)**2 */
+ if (s_mp_add(&x1, &x0, &t1) != MP_OKAY)
+ goto X1X1; /* t1 = x1 - x0 */
+ if (mp_sqr(&t1, &t1) != MP_OKAY)
+ goto X1X1; /* t1 = (x1 - x0) * (x1 - x0) */
+
+ /* add x0y0 */
+ if (s_mp_add(&x0x0, &x1x1, &t2) != MP_OKAY)
+ goto X1X1; /* t2 = x0x0 + x1x1 */
+ if (s_mp_sub(&t1, &t2, &t1) != MP_OKAY)
+ goto X1X1; /* t1 = (x1+x0)**2 - (x0x0 + x1x1) */
+
+ /* shift by B */
+ if (mp_lshd(&t1, B) != MP_OKAY)
+ goto X1X1; /* t1 = (x0x0 + x1x1 - (x1-x0)*(x1-x0))<used > MP_WARRAY) {
+ return MP_VAL;
+ }
+
+ /* get old used count */
+ olduse = x->used;
+
+ /* grow a as required */
+ if (x->alloc < (n->used + 1)) {
+ if ((err = mp_grow(x, n->used + 1)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ /* first we have to get the digits of the input into
+ * an array of double precision words W[...]
+ */
+ {
+ mp_word *_W;
+ mp_digit *tmpx;
+
+ /* alias for the W[] array */
+ _W = W;
+
+ /* alias for the digits of x*/
+ tmpx = x->dp;
+
+ /* copy the digits of a into W[0..a->used-1] */
+ for (ix = 0; ix < x->used; ix++) {
+ *_W++ = *tmpx++;
+ }
+
+ /* zero the high words of W[a->used..m->used*2] */
+ if (ix < ((n->used * 2) + 1)) {
+ MP_ZERO_BUFFER(_W, sizeof(mp_word) * (size_t)(((n->used * 2) + 1) - ix));
+ }
+ }
+
+ /* now we proceed to zero successive digits
+ * from the least significant upwards
+ */
+ for (ix = 0; ix < n->used; ix++) {
+ /* mu = ai * m' mod b
+ *
+ * We avoid a double precision multiplication (which isn't required)
+ * by casting the value down to a mp_digit. Note this requires
+ * that W[ix-1] have the carry cleared (see after the inner loop)
+ */
+ mp_digit mu;
+ mu = ((W[ix] & MP_MASK) * rho) & MP_MASK;
+
+ /* a = a + mu * m * b**i
+ *
+ * This is computed in place and on the fly. The multiplication
+ * by b**i is handled by offseting which columns the results
+ * are added to.
+ *
+ * Note the comba method normally doesn't handle carries in the
+ * inner loop In this case we fix the carry from the previous
+ * column since the Montgomery reduction requires digits of the
+ * result (so far) [see above] to work. This is
+ * handled by fixing up one carry after the inner loop. The
+ * carry fixups are done in order so after these loops the
+ * first m->used words of W[] have the carries fixed
+ */
+ {
+ int iy;
+ mp_digit *tmpn;
+ mp_word *_W;
+
+ /* alias for the digits of the modulus */
+ tmpn = n->dp;
+
+ /* Alias for the columns set by an offset of ix */
+ _W = W + ix;
+
+ /* inner loop */
+ for (iy = 0; iy < n->used; iy++) {
+ *_W++ += (mp_word)mu * (mp_word)*tmpn++;
+ }
+ }
+
+ /* now fix carry for next digit, W[ix+1] */
+ W[ix + 1] += W[ix] >> (mp_word)MP_DIGIT_BIT;
+ }
+
+ /* now we have to propagate the carries and
+ * shift the words downward [all those least
+ * significant digits we zeroed].
+ */
+ {
+ mp_digit *tmpx;
+ mp_word *_W, *_W1;
+
+ /* nox fix rest of carries */
+
+ /* alias for current word */
+ _W1 = W + ix;
+
+ /* alias for next word, where the carry goes */
+ _W = W + ++ix;
+
+ for (; ix < ((n->used * 2) + 1); ix++) {
+ *_W++ += *_W1++ >> (mp_word)MP_DIGIT_BIT;
+ }
+
+ /* copy out, A = A/b**n
+ *
+ * The result is A/b**n but instead of converting from an
+ * array of mp_word to mp_digit than calling mp_rshd
+ * we just copy them in the right order
+ */
+
+ /* alias for destination word */
+ tmpx = x->dp;
+
+ /* alias for shifted double precision result */
+ _W = W + n->used;
+
+ for (ix = 0; ix < (n->used + 1); ix++) {
+ *tmpx++ = *_W++ & (mp_word)MP_MASK;
+ }
+
+ /* zero oldused digits, if the input a was larger than
+ * m->used+1 we'll have to clear the digits
+ */
+ MP_ZERO_DIGITS(tmpx, olduse - ix);
+ }
+
+ /* set the max used and clamp */
+ x->used = n->used + 1;
+ mp_clamp(x);
+
+ /* if A >= m then A = A - m */
+ if (mp_cmp_mag(x, n) != MP_LT) {
+ return s_mp_sub(x, n, x);
+ }
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_s_mp_mul_digs.c
Index: libtommath/bn_s_mp_mul_digs.c
==================================================================
--- /dev/null
+++ libtommath/bn_s_mp_mul_digs.c
@@ -0,0 +1,78 @@
+#include "tommath_private.h"
+#ifdef BN_S_MP_MUL_DIGS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* multiplies |a| * |b| and only computes upto digs digits of result
+ * HAC pp. 595, Algorithm 14.12 Modified so you can control how
+ * many digits of output are created.
+ */
+mp_err s_mp_mul_digs(const mp_int *a, const mp_int *b, mp_int *c, int digs)
+{
+ mp_int t;
+ mp_err err;
+ int pa, pb, ix, iy;
+ mp_digit u;
+ mp_word r;
+ mp_digit tmpx, *tmpt, *tmpy;
+
+ if (digs < 0) {
+ return MP_VAL;
+ }
+
+ /* can we use the fast multiplier? */
+ if ((digs < MP_WARRAY) &&
+ (MP_MIN(a->used, b->used) < MP_MAXFAST)) {
+ return s_mp_mul_digs_fast(a, b, c, digs);
+ }
+
+ if ((err = mp_init_size(&t, digs)) != MP_OKAY) {
+ return err;
+ }
+ t.used = digs;
+
+ /* compute the digits of the product directly */
+ pa = a->used;
+ for (ix = 0; ix < pa; ix++) {
+ /* set the carry to zero */
+ u = 0;
+
+ /* limit ourselves to making digs digits of output */
+ pb = MP_MIN(b->used, digs - ix);
+
+ /* setup some aliases */
+ /* copy of the digit from a used within the nested loop */
+ tmpx = a->dp[ix];
+
+ /* an alias for the destination shifted ix places */
+ tmpt = t.dp + ix;
+
+ /* an alias for the digits of b */
+ tmpy = b->dp;
+
+ /* compute the columns of the output and propagate the carry */
+ for (iy = 0; iy < pb; iy++) {
+ /* compute the column as a mp_word */
+ r = (mp_word)*tmpt +
+ ((mp_word)tmpx * (mp_word)*tmpy++) +
+ (mp_word)u;
+
+ /* the new column is the lower part of the result */
+ *tmpt++ = (mp_digit)(r & (mp_word)MP_MASK);
+
+ /* get the carry word from the result */
+ u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT);
+ }
+ /* set carry if it is placed below digs */
+ if ((ix + iy) < digs) {
+ *tmpt = u;
+ }
+ }
+
+ mp_clamp(&t);
+ mp_exch(&t, c);
+
+ mp_clear(&t);
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_s_mp_mul_digs_fast.c
Index: libtommath/bn_s_mp_mul_digs_fast.c
==================================================================
--- /dev/null
+++ libtommath/bn_s_mp_mul_digs_fast.c
@@ -0,0 +1,94 @@
+#include "tommath_private.h"
+#ifdef BN_S_MP_MUL_DIGS_FAST_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* Fast (comba) multiplier
+ *
+ * This is the fast column-array [comba] multiplier. It is
+ * designed to compute the columns of the product first
+ * then handle the carries afterwards. This has the effect
+ * of making the nested loops that compute the columns very
+ * simple and schedulable on super-scalar processors.
+ *
+ * This has been modified to produce a variable number of
+ * digits of output so if say only a half-product is required
+ * you don't have to compute the upper half (a feature
+ * required for fast Barrett reduction).
+ *
+ * Based on Algorithm 14.12 on pp.595 of HAC.
+ *
+ */
+mp_err s_mp_mul_digs_fast(const mp_int *a, const mp_int *b, mp_int *c, int digs)
+{
+ int olduse, pa, ix, iz;
+ mp_err err;
+ mp_digit W[MP_WARRAY];
+ mp_word _W;
+
+ if (digs < 0) {
+ return MP_VAL;
+ }
+
+ /* grow the destination as required */
+ if (c->alloc < digs) {
+ if ((err = mp_grow(c, digs)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ /* number of output digits to produce */
+ pa = MP_MIN(digs, a->used + b->used);
+
+ /* clear the carry */
+ _W = 0;
+ for (ix = 0; ix < pa; ix++) {
+ int tx, ty;
+ int iy;
+ mp_digit *tmpx, *tmpy;
+
+ /* get offsets into the two bignums */
+ ty = MP_MIN(b->used-1, ix);
+ tx = ix - ty;
+
+ /* setup temp aliases */
+ tmpx = a->dp + tx;
+ tmpy = b->dp + ty;
+
+ /* this is the number of times the loop will iterrate, essentially
+ while (tx++ < a->used && ty-- >= 0) { ... }
+ */
+ iy = MP_MIN(a->used-tx, ty+1);
+
+ /* execute loop */
+ for (iz = 0; iz < iy; ++iz) {
+ _W += (mp_word)*tmpx++ * (mp_word)*tmpy--;
+
+ }
+
+ /* store term */
+ W[ix] = (mp_digit)_W & MP_MASK;
+
+ /* make next carry */
+ _W = _W >> (mp_word)MP_DIGIT_BIT;
+ }
+
+ /* setup dest */
+ olduse = c->used;
+ c->used = pa;
+
+ {
+ mp_digit *tmpc;
+ tmpc = c->dp;
+ for (ix = 0; ix < pa; ix++) {
+ /* now extract the previous digit [below the carry] */
+ *tmpc++ = W[ix];
+ }
+
+ /* clear unused digits [that existed in the old copy of c] */
+ MP_ZERO_DIGITS(tmpc, olduse - ix);
+ }
+ mp_clamp(c);
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_s_mp_mul_high_digs.c
Index: libtommath/bn_s_mp_mul_high_digs.c
==================================================================
--- /dev/null
+++ libtommath/bn_s_mp_mul_high_digs.c
@@ -0,0 +1,68 @@
+#include "tommath_private.h"
+#ifdef BN_S_MP_MUL_HIGH_DIGS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* multiplies |a| * |b| and does not compute the lower digs digits
+ * [meant to get the higher part of the product]
+ */
+mp_err s_mp_mul_high_digs(const mp_int *a, const mp_int *b, mp_int *c, int digs)
+{
+ mp_int t;
+ int pa, pb, ix, iy;
+ mp_err err;
+ mp_digit u;
+ mp_word r;
+ mp_digit tmpx, *tmpt, *tmpy;
+
+ if (digs < 0) {
+ return MP_VAL;
+ }
+
+ /* can we use the fast multiplier? */
+ if (MP_HAS(S_MP_MUL_HIGH_DIGS_FAST)
+ && ((a->used + b->used + 1) < MP_WARRAY)
+ && (MP_MIN(a->used, b->used) < MP_MAXFAST)) {
+ return s_mp_mul_high_digs_fast(a, b, c, digs);
+ }
+
+ if ((err = mp_init_size(&t, a->used + b->used + 1)) != MP_OKAY) {
+ return err;
+ }
+ t.used = a->used + b->used + 1;
+
+ pa = a->used;
+ pb = b->used;
+ for (ix = 0; ix < pa; ix++) {
+ /* clear the carry */
+ u = 0;
+
+ /* left hand side of A[ix] * B[iy] */
+ tmpx = a->dp[ix];
+
+ /* alias to the address of where the digits will be stored */
+ tmpt = &(t.dp[digs]);
+
+ /* alias for where to read the right hand side from */
+ tmpy = b->dp + (digs - ix);
+
+ for (iy = digs - ix; iy < pb; iy++) {
+ /* calculate the double precision result */
+ r = (mp_word)*tmpt +
+ ((mp_word)tmpx * (mp_word)*tmpy++) +
+ (mp_word)u;
+
+ /* get the lower part */
+ *tmpt++ = (mp_digit)(r & (mp_word)MP_MASK);
+
+ /* carry the carry */
+ u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT);
+ }
+ *tmpt = u;
+ }
+ mp_clamp(&t);
+ mp_exch(&t, c);
+ mp_clear(&t);
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_s_mp_mul_high_digs_fast.c
Index: libtommath/bn_s_mp_mul_high_digs_fast.c
==================================================================
--- /dev/null
+++ libtommath/bn_s_mp_mul_high_digs_fast.c
@@ -0,0 +1,85 @@
+#include "tommath_private.h"
+#ifdef BN_S_MP_MUL_HIGH_DIGS_FAST_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* this is a modified version of s_mp_mul_digs_fast that only produces
+ * output digits *above* digs. See the comments for s_mp_mul_digs_fast
+ * to see how it works.
+ *
+ * This is used in the Barrett reduction since for one of the multiplications
+ * only the higher digits were needed. This essentially halves the work.
+ *
+ * Based on Algorithm 14.12 on pp.595 of HAC.
+ */
+mp_err s_mp_mul_high_digs_fast(const mp_int *a, const mp_int *b, mp_int *c, int digs)
+{
+ int olduse, pa, ix, iz;
+ mp_err err;
+ mp_digit W[MP_WARRAY];
+ mp_word _W;
+
+ if (digs < 0) {
+ return MP_VAL;
+ }
+
+ /* grow the destination as required */
+ pa = a->used + b->used;
+ if (c->alloc < pa) {
+ if ((err = mp_grow(c, pa)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ /* number of output digits to produce */
+ pa = a->used + b->used;
+ _W = 0;
+ for (ix = digs; ix < pa; ix++) {
+ int tx, ty, iy;
+ mp_digit *tmpx, *tmpy;
+
+ /* get offsets into the two bignums */
+ ty = MP_MIN(b->used-1, ix);
+ tx = ix - ty;
+
+ /* setup temp aliases */
+ tmpx = a->dp + tx;
+ tmpy = b->dp + ty;
+
+ /* this is the number of times the loop will iterrate, essentially its
+ while (tx++ < a->used && ty-- >= 0) { ... }
+ */
+ iy = MP_MIN(a->used-tx, ty+1);
+
+ /* execute loop */
+ for (iz = 0; iz < iy; iz++) {
+ _W += (mp_word)*tmpx++ * (mp_word)*tmpy--;
+ }
+
+ /* store term */
+ W[ix] = (mp_digit)_W & MP_MASK;
+
+ /* make next carry */
+ _W = _W >> (mp_word)MP_DIGIT_BIT;
+ }
+
+ /* setup dest */
+ olduse = c->used;
+ c->used = pa;
+
+ {
+ mp_digit *tmpc;
+
+ tmpc = c->dp + digs;
+ for (ix = digs; ix < pa; ix++) {
+ /* now extract the previous digit [below the carry] */
+ *tmpc++ = W[ix];
+ }
+
+ /* clear unused digits [that existed in the old copy of c] */
+ MP_ZERO_DIGITS(tmpc, olduse - ix);
+ }
+ mp_clamp(c);
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_s_mp_prime_is_divisible.c
Index: libtommath/bn_s_mp_prime_is_divisible.c
==================================================================
--- /dev/null
+++ libtommath/bn_s_mp_prime_is_divisible.c
@@ -0,0 +1,35 @@
+#include "tommath_private.h"
+#ifdef BN_S_MP_PRIME_IS_DIVISIBLE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* determines if an integers is divisible by one
+ * of the first PRIME_SIZE primes or not
+ *
+ * sets result to 0 if not, 1 if yes
+ */
+mp_err s_mp_prime_is_divisible(const mp_int *a, mp_bool *result)
+{
+ int ix;
+ mp_err err;
+ mp_digit res;
+
+ /* default to not */
+ *result = MP_NO;
+
+ for (ix = 0; ix < PRIVATE_MP_PRIME_TAB_SIZE; ix++) {
+ /* what is a mod LBL_prime_tab[ix] */
+ if ((err = mp_mod_d(a, s_mp_prime_tab[ix], &res)) != MP_OKAY) {
+ return err;
+ }
+
+ /* is the residue zero? */
+ if (res == 0u) {
+ *result = MP_YES;
+ return MP_OKAY;
+ }
+ }
+
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_s_mp_rand_jenkins.c
Index: libtommath/bn_s_mp_rand_jenkins.c
==================================================================
--- /dev/null
+++ libtommath/bn_s_mp_rand_jenkins.c
@@ -0,0 +1,52 @@
+#include "tommath_private.h"
+#ifdef BN_S_MP_RAND_JENKINS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* Bob Jenkins' http://burtleburtle.net/bob/rand/smallprng.html */
+/* Chosen for speed and a good "mix" */
+typedef struct {
+ uint64_t a;
+ uint64_t b;
+ uint64_t c;
+ uint64_t d;
+} ranctx;
+
+static ranctx jenkins_x;
+
+#define rot(x,k) (((x)<<(k))|((x)>>(64-(k))))
+static uint64_t s_rand_jenkins_val(void)
+{
+ uint64_t e = jenkins_x.a - rot(jenkins_x.b, 7);
+ jenkins_x.a = jenkins_x.b ^ rot(jenkins_x.c, 13);
+ jenkins_x.b = jenkins_x.c + rot(jenkins_x.d, 37);
+ jenkins_x.c = jenkins_x.d + e;
+ jenkins_x.d = e + jenkins_x.a;
+ return jenkins_x.d;
+}
+
+void s_mp_rand_jenkins_init(uint64_t seed)
+{
+ int i;
+ jenkins_x.a = 0xf1ea5eedULL;
+ jenkins_x.b = jenkins_x.c = jenkins_x.d = seed;
+ for (i = 0; i < 20; ++i) {
+ (void)s_rand_jenkins_val();
+ }
+}
+
+mp_err s_mp_rand_jenkins(void *p, size_t n)
+{
+ char *q = (char *)p;
+ while (n > 0u) {
+ int i;
+ uint64_t x = s_rand_jenkins_val();
+ for (i = 0; (i < 8) && (n > 0u); ++i, --n) {
+ *q++ = (char)(x & 0xFFuLL);
+ x >>= 8;
+ }
+ }
+ return MP_OKAY;
+}
+
+#endif
ADDED libtommath/bn_s_mp_rand_platform.c
Index: libtommath/bn_s_mp_rand_platform.c
==================================================================
--- /dev/null
+++ libtommath/bn_s_mp_rand_platform.c
@@ -0,0 +1,148 @@
+#include "tommath_private.h"
+#ifdef BN_S_MP_RAND_PLATFORM_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* First the OS-specific special cases
+ * - *BSD
+ * - Windows
+ */
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
+#define BN_S_READ_ARC4RANDOM_C
+static mp_err s_read_arc4random(void *p, size_t n)
+{
+ arc4random_buf(p, n);
+ return MP_OKAY;
+}
+#endif
+
+#if defined(_WIN32) || defined(_WIN32_WCE)
+#define BN_S_READ_WINCSP_C
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0400
+#endif
+#ifdef _WIN32_WCE
+#define UNDER_CE
+#define ARM
+#endif
+
+#define WIN32_LEAN_AND_MEAN
+#include
+#include
+
+static mp_err s_read_wincsp(void *p, size_t n)
+{
+ static HCRYPTPROV hProv = 0;
+ if (hProv == 0) {
+ HCRYPTPROV h = 0;
+ if (!CryptAcquireContext(&h, NULL, MS_DEF_PROV, PROV_RSA_FULL,
+ (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET)) &&
+ !CryptAcquireContext(&h, NULL, MS_DEF_PROV, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET)) {
+ return MP_ERR;
+ }
+ hProv = h;
+ }
+ return CryptGenRandom(hProv, (DWORD)n, (BYTE *)p) == TRUE ? MP_OKAY : MP_ERR;
+}
+#endif /* WIN32 */
+
+#if !defined(BN_S_READ_WINCSP_C) && defined(__linux__) && defined(__GLIBC_PREREQ)
+#if __GLIBC_PREREQ(2, 25)
+#define BN_S_READ_GETRANDOM_C
+#include
+#include
+
+static mp_err s_read_getrandom(void *p, size_t n)
+{
+ char *q = (char *)p;
+ while (n > 0u) {
+ ssize_t ret = getrandom(q, n, 0);
+ if (ret < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ return MP_ERR;
+ }
+ q += ret;
+ n -= (size_t)ret;
+ }
+ return MP_OKAY;
+}
+#endif
+#endif
+
+/* We assume all platforms besides windows provide "/dev/urandom".
+ * In case yours doesn't, define MP_NO_DEV_URANDOM at compile-time.
+ */
+#if !defined(BN_S_READ_WINCSP_C) && !defined(MP_NO_DEV_URANDOM)
+#define BN_S_READ_URANDOM_C
+#ifndef MP_DEV_URANDOM
+#define MP_DEV_URANDOM "/dev/urandom"
+#endif
+#include
+#include
+#include
+
+static mp_err s_read_urandom(void *p, size_t n)
+{
+ int fd;
+ char *q = (char *)p;
+
+ do {
+ fd = open(MP_DEV_URANDOM, O_RDONLY);
+ } while ((fd == -1) && (errno == EINTR));
+ if (fd == -1) return MP_ERR;
+
+ while (n > 0u) {
+ ssize_t ret = read(fd, p, n);
+ if (ret < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ close(fd);
+ return MP_ERR;
+ }
+ q += ret;
+ n -= (size_t)ret;
+ }
+
+ close(fd);
+ return MP_OKAY;
+}
+#endif
+
+#if defined(MP_PRNG_ENABLE_LTM_RNG)
+#define BN_S_READ_LTM_RNG
+unsigned long (*ltm_rng)(unsigned char *out, unsigned long outlen, void (*callback)(void));
+void (*ltm_rng_callback)(void);
+
+static mp_err s_read_ltm_rng(void *p, size_t n)
+{
+ unsigned long res;
+ if (ltm_rng == NULL) return MP_ERR;
+ res = ltm_rng(p, n, ltm_rng_callback);
+ if (res != n) return MP_ERR;
+ return MP_OKAY;
+}
+#endif
+
+mp_err s_read_arc4random(void *p, size_t n);
+mp_err s_read_wincsp(void *p, size_t n);
+mp_err s_read_getrandom(void *p, size_t n);
+mp_err s_read_urandom(void *p, size_t n);
+mp_err s_read_ltm_rng(void *p, size_t n);
+
+mp_err s_mp_rand_platform(void *p, size_t n)
+{
+ mp_err err = MP_ERR;
+ if ((err != MP_OKAY) && MP_HAS(S_READ_ARC4RANDOM)) err = s_read_arc4random(p, n);
+ if ((err != MP_OKAY) && MP_HAS(S_READ_WINCSP)) err = s_read_wincsp(p, n);
+ if ((err != MP_OKAY) && MP_HAS(S_READ_GETRANDOM)) err = s_read_getrandom(p, n);
+ if ((err != MP_OKAY) && MP_HAS(S_READ_URANDOM)) err = s_read_urandom(p, n);
+ if ((err != MP_OKAY) && MP_HAS(S_READ_LTM_RNG)) err = s_read_ltm_rng(p, n);
+ return err;
+}
+
+#endif
ADDED libtommath/bn_s_mp_reverse.c
Index: libtommath/bn_s_mp_reverse.c
==================================================================
--- /dev/null
+++ libtommath/bn_s_mp_reverse.c
@@ -0,0 +1,22 @@
+#include "tommath_private.h"
+#ifdef BN_S_MP_REVERSE_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* reverse an array, used for radix code */
+void s_mp_reverse(unsigned char *s, size_t len)
+{
+ size_t ix, iy;
+ unsigned char t;
+
+ ix = 0u;
+ iy = len - 1u;
+ while (ix < iy) {
+ t = s[ix];
+ s[ix] = s[iy];
+ s[iy] = t;
+ ++ix;
+ --iy;
+ }
+}
+#endif
ADDED libtommath/bn_s_mp_sqr.c
Index: libtommath/bn_s_mp_sqr.c
==================================================================
--- /dev/null
+++ libtommath/bn_s_mp_sqr.c
@@ -0,0 +1,69 @@
+#include "tommath_private.h"
+#ifdef BN_S_MP_SQR_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */
+mp_err s_mp_sqr(const mp_int *a, mp_int *b)
+{
+ mp_int t;
+ int ix, iy, pa;
+ mp_err err;
+ mp_word r;
+ mp_digit u, tmpx, *tmpt;
+
+ pa = a->used;
+ if ((err = mp_init_size(&t, (2 * pa) + 1)) != MP_OKAY) {
+ return err;
+ }
+
+ /* default used is maximum possible size */
+ t.used = (2 * pa) + 1;
+
+ for (ix = 0; ix < pa; ix++) {
+ /* first calculate the digit at 2*ix */
+ /* calculate double precision result */
+ r = (mp_word)t.dp[2*ix] +
+ ((mp_word)a->dp[ix] * (mp_word)a->dp[ix]);
+
+ /* store lower part in result */
+ t.dp[ix+ix] = (mp_digit)(r & (mp_word)MP_MASK);
+
+ /* get the carry */
+ u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT);
+
+ /* left hand side of A[ix] * A[iy] */
+ tmpx = a->dp[ix];
+
+ /* alias for where to store the results */
+ tmpt = t.dp + ((2 * ix) + 1);
+
+ for (iy = ix + 1; iy < pa; iy++) {
+ /* first calculate the product */
+ r = (mp_word)tmpx * (mp_word)a->dp[iy];
+
+ /* now calculate the double precision result, note we use
+ * addition instead of *2 since it's easier to optimize
+ */
+ r = (mp_word)*tmpt + r + r + (mp_word)u;
+
+ /* store lower part */
+ *tmpt++ = (mp_digit)(r & (mp_word)MP_MASK);
+
+ /* get carry */
+ u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT);
+ }
+ /* propagate upwards */
+ while (u != 0uL) {
+ r = (mp_word)*tmpt + (mp_word)u;
+ *tmpt++ = (mp_digit)(r & (mp_word)MP_MASK);
+ u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT);
+ }
+ }
+
+ mp_clamp(&t);
+ mp_exch(&t, b);
+ mp_clear(&t);
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_s_mp_sqr_fast.c
Index: libtommath/bn_s_mp_sqr_fast.c
==================================================================
--- /dev/null
+++ libtommath/bn_s_mp_sqr_fast.c
@@ -0,0 +1,97 @@
+#include "tommath_private.h"
+#ifdef BN_S_MP_SQR_FAST_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* the jist of squaring...
+ * you do like mult except the offset of the tmpx [one that
+ * starts closer to zero] can't equal the offset of tmpy.
+ * So basically you set up iy like before then you min it with
+ * (ty-tx) so that it never happens. You double all those
+ * you add in the inner loop
+
+After that loop you do the squares and add them in.
+*/
+
+mp_err s_mp_sqr_fast(const mp_int *a, mp_int *b)
+{
+ int olduse, pa, ix, iz;
+ mp_digit W[MP_WARRAY], *tmpx;
+ mp_word W1;
+ mp_err err;
+
+ /* grow the destination as required */
+ pa = a->used + a->used;
+ if (b->alloc < pa) {
+ if ((err = mp_grow(b, pa)) != MP_OKAY) {
+ return err;
+ }
+ }
+
+ /* number of output digits to produce */
+ W1 = 0;
+ for (ix = 0; ix < pa; ix++) {
+ int tx, ty, iy;
+ mp_word _W;
+ mp_digit *tmpy;
+
+ /* clear counter */
+ _W = 0;
+
+ /* get offsets into the two bignums */
+ ty = MP_MIN(a->used-1, ix);
+ tx = ix - ty;
+
+ /* setup temp aliases */
+ tmpx = a->dp + tx;
+ tmpy = a->dp + ty;
+
+ /* this is the number of times the loop will iterrate, essentially
+ while (tx++ < a->used && ty-- >= 0) { ... }
+ */
+ iy = MP_MIN(a->used-tx, ty+1);
+
+ /* now for squaring tx can never equal ty
+ * we halve the distance since they approach at a rate of 2x
+ * and we have to round because odd cases need to be executed
+ */
+ iy = MP_MIN(iy, ((ty-tx)+1)>>1);
+
+ /* execute loop */
+ for (iz = 0; iz < iy; iz++) {
+ _W += (mp_word)*tmpx++ * (mp_word)*tmpy--;
+ }
+
+ /* double the inner product and add carry */
+ _W = _W + _W + W1;
+
+ /* even columns have the square term in them */
+ if (((unsigned)ix & 1u) == 0u) {
+ _W += (mp_word)a->dp[ix>>1] * (mp_word)a->dp[ix>>1];
+ }
+
+ /* store it */
+ W[ix] = (mp_digit)_W & MP_MASK;
+
+ /* make next carry */
+ W1 = _W >> (mp_word)MP_DIGIT_BIT;
+ }
+
+ /* setup dest */
+ olduse = b->used;
+ b->used = a->used+a->used;
+
+ {
+ mp_digit *tmpb;
+ tmpb = b->dp;
+ for (ix = 0; ix < pa; ix++) {
+ *tmpb++ = W[ix] & MP_MASK;
+ }
+
+ /* clear unused digits [that existed in the old copy of c] */
+ MP_ZERO_DIGITS(tmpb, olduse - ix);
+ }
+ mp_clamp(b);
+ return MP_OKAY;
+}
+#endif
ADDED libtommath/bn_s_mp_sub.c
Index: libtommath/bn_s_mp_sub.c
==================================================================
--- /dev/null
+++ libtommath/bn_s_mp_sub.c
@@ -0,0 +1,71 @@
+#include "tommath_private.h"
+#ifdef BN_S_MP_SUB_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */
+mp_err s_mp_sub(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ int olduse, min, max;
+ mp_err err;
+
+ /* find sizes */
+ min = b->used;
+ max = a->used;
+
+ /* init result */
+ if (c->alloc < max) {
+ if ((err = mp_grow(c, max)) != MP_OKAY) {
+ return err;
+ }
+ }
+ olduse = c->used;
+ c->used = max;
+
+ {
+ mp_digit u, *tmpa, *tmpb, *tmpc;
+ int i;
+
+ /* alias for digit pointers */
+ tmpa = a->dp;
+ tmpb = b->dp;
+ tmpc = c->dp;
+
+ /* set carry to zero */
+ u = 0;
+ for (i = 0; i < min; i++) {
+ /* T[i] = A[i] - B[i] - U */
+ *tmpc = (*tmpa++ - *tmpb++) - u;
+
+ /* U = carry bit of T[i]
+ * Note this saves performing an AND operation since
+ * if a carry does occur it will propagate all the way to the
+ * MSB. As a result a single shift is enough to get the carry
+ */
+ u = *tmpc >> (MP_SIZEOF_BITS(mp_digit) - 1u);
+
+ /* Clear carry from T[i] */
+ *tmpc++ &= MP_MASK;
+ }
+
+ /* now copy higher words if any, e.g. if A has more digits than B */
+ for (; i < max; i++) {
+ /* T[i] = A[i] - U */
+ *tmpc = *tmpa++ - u;
+
+ /* U = carry bit of T[i] */
+ u = *tmpc >> (MP_SIZEOF_BITS(mp_digit) - 1u);
+
+ /* Clear carry from T[i] */
+ *tmpc++ &= MP_MASK;
+ }
+
+ /* clear digits above used (since we may not have grown result above) */
+ MP_ZERO_DIGITS(tmpc, olduse - c->used);
+ }
+
+ mp_clamp(c);
+ return MP_OKAY;
+}
+
+#endif
ADDED libtommath/bn_s_mp_toom_mul.c
Index: libtommath/bn_s_mp_toom_mul.c
==================================================================
--- /dev/null
+++ libtommath/bn_s_mp_toom_mul.c
@@ -0,0 +1,215 @@
+#include "tommath_private.h"
+#ifdef BN_S_MP_TOOM_MUL_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* multiplication using the Toom-Cook 3-way algorithm
+ *
+ * Much more complicated than Karatsuba but has a lower
+ * asymptotic running time of O(N**1.464). This algorithm is
+ * only particularly useful on VERY large inputs
+ * (we're talking 1000s of digits here...).
+*/
+
+/*
+ This file contains code from J. Arndt's book "Matters Computational"
+ and the accompanying FXT-library with permission of the author.
+*/
+
+/*
+ Setup from
+
+ Chung, Jaewook, and M. Anwar Hasan. "Asymmetric squaring formulae."
+ 18th IEEE Symposium on Computer Arithmetic (ARITH'07). IEEE, 2007.
+
+ The interpolation from above needed one temporary variable more
+ than the interpolation here:
+
+ Bodrato, Marco, and Alberto Zanoni. "What about Toom-Cook matrices optimality."
+ Centro Vito Volterra Universita di Roma Tor Vergata (2006)
+*/
+
+mp_err s_mp_toom_mul(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ mp_int S1, S2, T1, a0, a1, a2, b0, b1, b2;
+ int B, count;
+ mp_err err;
+
+ /* init temps */
+ if ((err = mp_init_multi(&S1, &S2, &T1, NULL)) != MP_OKAY) {
+ return err;
+ }
+
+ /* B */
+ B = MP_MIN(a->used, b->used) / 3;
+
+ /** a = a2 * x^2 + a1 * x + a0; */
+ if ((err = mp_init_size(&a0, B)) != MP_OKAY) goto LBL_ERRa0;
+
+ for (count = 0; count < B; count++) {
+ a0.dp[count] = a->dp[count];
+ a0.used++;
+ }
+ mp_clamp(&a0);
+ if ((err = mp_init_size(&a1, B)) != MP_OKAY) goto LBL_ERRa1;
+ for (; count < (2 * B); count++) {
+ a1.dp[count - B] = a->dp[count];
+ a1.used++;
+ }
+ mp_clamp(&a1);
+ if ((err = mp_init_size(&a2, B + (a->used - (3 * B)))) != MP_OKAY) goto LBL_ERRa2;
+ for (; count < a->used; count++) {
+ a2.dp[count - (2 * B)] = a->dp[count];
+ a2.used++;
+ }
+ mp_clamp(&a2);
+
+ /** b = b2 * x^2 + b1 * x + b0; */
+ if ((err = mp_init_size(&b0, B)) != MP_OKAY) goto LBL_ERRb0;
+ for (count = 0; count < B; count++) {
+ b0.dp[count] = b->dp[count];
+ b0.used++;
+ }
+ mp_clamp(&b0);
+ if ((err = mp_init_size(&b1, B)) != MP_OKAY) goto LBL_ERRb1;
+ for (; count < (2 * B); count++) {
+ b1.dp[count - B] = b->dp[count];
+ b1.used++;
+ }
+ mp_clamp(&b1);
+ if ((err = mp_init_size(&b2, B + (b->used - (3 * B)))) != MP_OKAY) goto LBL_ERRb2;
+ for (; count < b->used; count++) {
+ b2.dp[count - (2 * B)] = b->dp[count];
+ b2.used++;
+ }
+ mp_clamp(&b2);
+
+ /** \\ S1 = (a2+a1+a0) * (b2+b1+b0); */
+ /** T1 = a2 + a1; */
+ if ((err = mp_add(&a2, &a1, &T1)) != MP_OKAY) goto LBL_ERR;
+
+ /** S2 = T1 + a0; */
+ if ((err = mp_add(&T1, &a0, &S2)) != MP_OKAY) goto LBL_ERR;
+
+ /** c = b2 + b1; */
+ if ((err = mp_add(&b2, &b1, c)) != MP_OKAY) goto LBL_ERR;
+
+ /** S1 = c + b0; */
+ if ((err = mp_add(c, &b0, &S1)) != MP_OKAY) goto LBL_ERR;
+
+ /** S1 = S1 * S2; */
+ if ((err = mp_mul(&S1, &S2, &S1)) != MP_OKAY) goto LBL_ERR;
+
+ /** \\S2 = (4*a2+2*a1+a0) * (4*b2+2*b1+b0); */
+ /** T1 = T1 + a2; */
+ if ((err = mp_add(&T1, &a2, &T1)) != MP_OKAY) goto LBL_ERR;
+
+ /** T1 = T1 << 1; */
+ if ((err = mp_mul_2(&T1, &T1)) != MP_OKAY) goto LBL_ERR;
+
+ /** T1 = T1 + a0; */
+ if ((err = mp_add(&T1, &a0, &T1)) != MP_OKAY) goto LBL_ERR;
+
+ /** c = c + b2; */
+ if ((err = mp_add(c, &b2, c)) != MP_OKAY) goto LBL_ERR;
+
+ /** c = c << 1; */
+ if ((err = mp_mul_2(c, c)) != MP_OKAY) goto LBL_ERR;
+
+ /** c = c + b0; */
+ if ((err = mp_add(c, &b0, c)) != MP_OKAY) goto LBL_ERR;
+
+ /** S2 = T1 * c; */
+ if ((err = mp_mul(&T1, c, &S2)) != MP_OKAY) goto LBL_ERR;
+
+ /** \\S3 = (a2-a1+a0) * (b2-b1+b0); */
+ /** a1 = a2 - a1; */
+ if ((err = mp_sub(&a2, &a1, &a1)) != MP_OKAY) goto LBL_ERR;
+
+ /** a1 = a1 + a0; */
+ if ((err = mp_add(&a1, &a0, &a1)) != MP_OKAY) goto LBL_ERR;
+
+ /** b1 = b2 - b1; */
+ if ((err = mp_sub(&b2, &b1, &b1)) != MP_OKAY) goto LBL_ERR;
+
+ /** b1 = b1 + b0; */
+ if ((err = mp_add(&b1, &b0, &b1)) != MP_OKAY) goto LBL_ERR;
+
+ /** a1 = a1 * b1; */
+ if ((err = mp_mul(&a1, &b1, &a1)) != MP_OKAY) goto LBL_ERR;
+
+ /** b1 = a2 * b2; */
+ if ((err = mp_mul(&a2, &b2, &b1)) != MP_OKAY) goto LBL_ERR;
+
+ /** \\S2 = (S2 - S3)/3; */
+ /** S2 = S2 - a1; */
+ if ((err = mp_sub(&S2, &a1, &S2)) != MP_OKAY) goto LBL_ERR;
+
+ /** S2 = S2 / 3; \\ this is an exact division */
+ if ((err = mp_div_3(&S2, &S2, NULL)) != MP_OKAY) goto LBL_ERR;
+
+ /** a1 = S1 - a1; */
+ if ((err = mp_sub(&S1, &a1, &a1)) != MP_OKAY) goto LBL_ERR;
+
+ /** a1 = a1 >> 1; */
+ if ((err = mp_div_2(&a1, &a1)) != MP_OKAY) goto LBL_ERR;
+
+ /** a0 = a0 * b0; */
+ if ((err = mp_mul(&a0, &b0, &a0)) != MP_OKAY) goto LBL_ERR;
+
+ /** S1 = S1 - a0; */
+ if ((err = mp_sub(&S1, &a0, &S1)) != MP_OKAY) goto LBL_ERR;
+
+ /** S2 = S2 - S1; */
+ if ((err = mp_sub(&S2, &S1, &S2)) != MP_OKAY) goto LBL_ERR;
+
+ /** S2 = S2 >> 1; */
+ if ((err = mp_div_2(&S2, &S2)) != MP_OKAY) goto LBL_ERR;
+
+ /** S1 = S1 - a1; */
+ if ((err = mp_sub(&S1, &a1, &S1)) != MP_OKAY) goto LBL_ERR;
+
+ /** S1 = S1 - b1; */
+ if ((err = mp_sub(&S1, &b1, &S1)) != MP_OKAY) goto LBL_ERR;
+
+ /** T1 = b1 << 1; */
+ if ((err = mp_mul_2(&b1, &T1)) != MP_OKAY) goto LBL_ERR;
+
+ /** S2 = S2 - T1; */
+ if ((err = mp_sub(&S2, &T1, &S2)) != MP_OKAY) goto LBL_ERR;
+
+ /** a1 = a1 - S2; */
+ if ((err = mp_sub(&a1, &S2, &a1)) != MP_OKAY) goto LBL_ERR;
+
+
+ /** P = b1*x^4+ S2*x^3+ S1*x^2+ a1*x + a0; */
+ if ((err = mp_lshd(&b1, 4 * B)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_lshd(&S2, 3 * B)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_add(&b1, &S2, &b1)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_lshd(&S1, 2 * B)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_add(&b1, &S1, &b1)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_lshd(&a1, 1 * B)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_add(&b1, &a1, &b1)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_add(&b1, &a0, c)) != MP_OKAY) goto LBL_ERR;
+
+ /** a * b - P */
+
+
+LBL_ERR:
+ mp_clear(&b2);
+LBL_ERRb2:
+ mp_clear(&b1);
+LBL_ERRb1:
+ mp_clear(&b0);
+LBL_ERRb0:
+ mp_clear(&a2);
+LBL_ERRa2:
+ mp_clear(&a1);
+LBL_ERRa1:
+ mp_clear(&a0);
+LBL_ERRa0:
+ mp_clear_multi(&S1, &S2, &T1, NULL);
+ return err;
+}
+
+#endif
ADDED libtommath/bn_s_mp_toom_sqr.c
Index: libtommath/bn_s_mp_toom_sqr.c
==================================================================
--- /dev/null
+++ libtommath/bn_s_mp_toom_sqr.c
@@ -0,0 +1,147 @@
+#include "tommath_private.h"
+#ifdef BN_S_MP_TOOM_SQR_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* squaring using Toom-Cook 3-way algorithm */
+
+/*
+ This file contains code from J. Arndt's book "Matters Computational"
+ and the accompanying FXT-library with permission of the author.
+*/
+
+/* squaring using Toom-Cook 3-way algorithm */
+/*
+ Setup and interpolation from algorithm SQR_3 in
+
+ Chung, Jaewook, and M. Anwar Hasan. "Asymmetric squaring formulae."
+ 18th IEEE Symposium on Computer Arithmetic (ARITH'07). IEEE, 2007.
+
+*/
+mp_err s_mp_toom_sqr(const mp_int *a, mp_int *b)
+{
+ mp_int S0, a0, a1, a2;
+ mp_digit *tmpa, *tmpc;
+ int B, count;
+ mp_err err;
+
+
+ /* init temps */
+ if ((err = mp_init(&S0)) != MP_OKAY) {
+ return err;
+ }
+
+ /* B */
+ B = a->used / 3;
+
+ /** a = a2 * x^2 + a1 * x + a0; */
+ if ((err = mp_init_size(&a0, B)) != MP_OKAY) goto LBL_ERRa0;
+
+ a0.used = B;
+ if ((err = mp_init_size(&a1, B)) != MP_OKAY) goto LBL_ERRa1;
+ a1.used = B;
+ if ((err = mp_init_size(&a2, B + (a->used - (3 * B)))) != MP_OKAY) goto LBL_ERRa2;
+
+ tmpa = a->dp;
+ tmpc = a0.dp;
+ for (count = 0; count < B; count++) {
+ *tmpc++ = *tmpa++;
+ }
+ tmpc = a1.dp;
+ for (; count < (2 * B); count++) {
+ *tmpc++ = *tmpa++;
+ }
+ tmpc = a2.dp;
+ for (; count < a->used; count++) {
+ *tmpc++ = *tmpa++;
+ a2.used++;
+ }
+ mp_clamp(&a0);
+ mp_clamp(&a1);
+ mp_clamp(&a2);
+
+ /** S0 = a0^2; */
+ if ((err = mp_sqr(&a0, &S0)) != MP_OKAY) goto LBL_ERR;
+
+ /** \\S1 = (a2 + a1 + a0)^2 */
+ /** \\S2 = (a2 - a1 + a0)^2 */
+ /** \\S1 = a0 + a2; */
+ /** a0 = a0 + a2; */
+ if ((err = mp_add(&a0, &a2, &a0)) != MP_OKAY) goto LBL_ERR;
+ /** \\S2 = S1 - a1; */
+ /** b = a0 - a1; */
+ if ((err = mp_sub(&a0, &a1, b)) != MP_OKAY) goto LBL_ERR;
+ /** \\S1 = S1 + a1; */
+ /** a0 = a0 + a1; */
+ if ((err = mp_add(&a0, &a1, &a0)) != MP_OKAY) goto LBL_ERR;
+ /** \\S1 = S1^2; */
+ /** a0 = a0^2; */
+ if ((err = mp_sqr(&a0, &a0)) != MP_OKAY) goto LBL_ERR;
+ /** \\S2 = S2^2; */
+ /** b = b^2; */
+ if ((err = mp_sqr(b, b)) != MP_OKAY) goto LBL_ERR;
+
+ /** \\ S3 = 2 * a1 * a2 */
+ /** \\S3 = a1 * a2; */
+ /** a1 = a1 * a2; */
+ if ((err = mp_mul(&a1, &a2, &a1)) != MP_OKAY) goto LBL_ERR;
+ /** \\S3 = S3 << 1; */
+ /** a1 = a1 << 1; */
+ if ((err = mp_mul_2(&a1, &a1)) != MP_OKAY) goto LBL_ERR;
+
+ /** \\S4 = a2^2; */
+ /** a2 = a2^2; */
+ if ((err = mp_sqr(&a2, &a2)) != MP_OKAY) goto LBL_ERR;
+
+ /** \\ tmp = (S1 + S2)/2 */
+ /** \\tmp = S1 + S2; */
+ /** b = a0 + b; */
+ if ((err = mp_add(&a0, b, b)) != MP_OKAY) goto LBL_ERR;
+ /** \\tmp = tmp >> 1; */
+ /** b = b >> 1; */
+ if ((err = mp_div_2(b, b)) != MP_OKAY) goto LBL_ERR;
+
+ /** \\ S1 = S1 - tmp - S3 */
+ /** \\S1 = S1 - tmp; */
+ /** a0 = a0 - b; */
+ if ((err = mp_sub(&a0, b, &a0)) != MP_OKAY) goto LBL_ERR;
+ /** \\S1 = S1 - S3; */
+ /** a0 = a0 - a1; */
+ if ((err = mp_sub(&a0, &a1, &a0)) != MP_OKAY) goto LBL_ERR;
+
+ /** \\S2 = tmp - S4 -S0 */
+ /** \\S2 = tmp - S4; */
+ /** b = b - a2; */
+ if ((err = mp_sub(b, &a2, b)) != MP_OKAY) goto LBL_ERR;
+ /** \\S2 = S2 - S0; */
+ /** b = b - S0; */
+ if ((err = mp_sub(b, &S0, b)) != MP_OKAY) goto LBL_ERR;
+
+
+ /** \\P = S4*x^4 + S3*x^3 + S2*x^2 + S1*x + S0; */
+ /** P = a2*x^4 + a1*x^3 + b*x^2 + a0*x + S0; */
+
+ if ((err = mp_lshd(&a2, 4 * B)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_lshd(&a1, 3 * B)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_lshd(b, 2 * B)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_lshd(&a0, 1 * B)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_add(&a2, &a1, &a2)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_add(&a2, b, b)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_add(b, &a0, b)) != MP_OKAY) goto LBL_ERR;
+ if ((err = mp_add(b, &S0, b)) != MP_OKAY) goto LBL_ERR;
+ /** a^2 - P */
+
+
+LBL_ERR:
+ mp_clear(&a2);
+LBL_ERRa2:
+ mp_clear(&a1);
+LBL_ERRa1:
+ mp_clear(&a0);
+LBL_ERRa0:
+ mp_clear(&S0);
+
+ return err;
+}
+
+#endif
ADDED libtommath/changes.txt
Index: libtommath/changes.txt
==================================================================
--- /dev/null
+++ libtommath/changes.txt
@@ -0,0 +1,502 @@
+Sep 04th, 2023
+v1.2.1
+ -- Bugfix release because of potential integer overflow
+ c.f. PR #546 resp. CVE-2023-36328
+
+Oct 22nd, 2019
+v1.2.0
+ -- A huge refactoring of the library happened - renaming,
+ deprecating and replacing existing functions by improved API's.
+
+ All deprecated functions, macros and symbols are only marked as such
+ so this version is still API and ABI compatible to v1.x.
+
+ -- Daniel Mendler was pushing for those changes and contributing a load of patches,
+ refactorings, code reviews and whatnotelse.
+ -- Christoph Zurnieden re-worked internals of the library, improved the performance,
+ did code reviews and wrote documentation.
+ -- Francois Perrad did some refactoring and took again care of linting the sources and
+ provided all fixes.
+ -- Jan Nijtmans, Karel Miko and Joachim Breitner contributed various patches.
+
+ -- Private symbols can now be hidden for the shared library builds, disabled by default.
+ -- All API's follow a single code style, are prefixed the same etc.
+ -- Unified, safer and improved API's
+ -- Less magic numbers - return values (where appropriate) and most flags are now enums,
+ this was implemented in a backwards compatible way where return values were int.
+ -- API's with return values are now by default marked as "warn on unsused result", this
+ can be disabled if required (which will most likely hide bugs), c.f. MP_WUR in tommath.h
+ -- Provide a whole set of setters&getters for different primitive types (long, uint32_t, etc.)
+ -- All those primitive setters are now optimized.
+ -- It's possible to automatically tune the cutoff values for Karatsuba&Toom-Cook
+ -- The custom allocators which were formerly known as XMALLOC(), XFREE() etc. are now available
+ as MP_MALLOC(), MP_REALLOC(), MP_CALLOC() and MP_FREE(). MP_REALLOC() and MP_FREE() now also
+ provide the allocated size to ease the usage of simple allocators without tracking.
+ -- Building is now also possible with MSVC 2015, 2017 and 2019 (use makefile.msvc)
+ -- Added mp_decr() and mp_incr()
+ -- Added mp_log_u32()
+ -- Improved prime-checking
+ -- Improved Toom-Cook multiplication
+ -- Removed the LTM book (`make docs` now builds the user manual)
+
+
+Jan 28th, 2019
+v1.1.0
+ -- Christoph Zurnieden contributed FIPS 186.4 compliant
+ prime-checking (PR #113), several other fixes and a load of documentation
+ -- Daniel Mendler provided two's-complement functions (PR #124)
+ and mp_{set,get}_double() (PR #123)
+ -- Francois Perrad took care of linting the sources, provided all fixes and
+ a astylerc to auto-format the sources.
+ -- A bunch of patches by Kevin B Kenny have been back-ported from TCL
+ -- Jan Nijtmans provided the patches to `const`ify all API
+ function arguments (also from TCL)
+ -- mp_rand() has now several native random provider implementations
+ and doesn't rely on `rand()` anymore
+ -- Karel Miko provided fixes when building for MS Windows
+ and re-worked the makefile generating process
+ -- The entire environment and build logic has been extended and improved
+ regarding auto-detection of platforms, libtool and a lot more
+ -- Prevent some potential BOF cases
+ -- Improved/fixed mp_lshd() and mp_invmod()
+ -- A load more bugs were fixed by various contributors
+
+
+Aug 29th, 2017
+v1.0.1
+ -- Dmitry Kovalenko provided fixes to mp_add_d() and mp_init_copy()
+ -- Matt Johnston contributed some improvements to mp_div_2d(),
+ mp_exptmod_fast(), mp_mod() and mp_mulmod()
+ -- Julien Nabet provided a fix to the error handling in mp_init_multi()
+ -- Ben Gardner provided a fix regarding usage of reserved keywords
+ -- Fixed mp_rand() to fill the correct number of bits
+ -- Fixed mp_invmod()
+ -- Use the same 64-bit detection code as in libtomcrypt
+ -- Correct usage of DESTDIR, PREFIX, etc. when installing the library
+ -- Francois Perrad updated all the perl scripts to an actual perl version
+
+
+Feb 5th, 2016
+v1.0
+ -- Bump to 1.0
+ -- Dirkjan Bussink provided a faster version of mp_expt_d()
+ -- Moritz Lenz contributed a fix to mp_mod()
+ and provided mp_get_long() and mp_set_long()
+ -- Fixed bugs in mp_read_radix(), mp_radix_size
+ Thanks to shameister, Gerhard R,
+ -- Christopher Brown provided mp_export() and mp_import()
+ -- Improvements in the code of mp_init_copy()
+ Thanks to ramkumarkoppu,
+ -- lomereiter provided mp_balance_mul()
+ -- Alexander Boström from the heimdal project contributed patches to
+ mp_prime_next_prime() and mp_invmod() and added a mp_isneg() macro
+ -- Fix build issues for Linux x32 ABI
+ -- Added mp_get_long_long() and mp_set_long_long()
+ -- Carlin provided a patch to use arc4random() instead of rand()
+ on platforms where it is supported
+ -- Karel Miko provided mp_sqrtmod_prime()
+
+
+July 23rd, 2010
+v0.42.0
+ -- Fix for mp_prime_next_prime() bug when checking generated prime
+ -- allow mp_shrink to shrink initialized, but empty MPI's
+ -- Added project and solution files for Visual Studio 2005 and Visual Studio 2008.
+
+March 10th, 2007
+v0.41 -- Wolfgang Ehrhardt suggested a quick fix to mp_div_d() which makes the detection of powers of two quicker.
+ -- [CRI] Added libtommath.dsp for Visual C++ users.
+
+December 24th, 2006
+v0.40 -- Updated makefile to properly support LIBNAME
+ -- Fixed bug in fast_s_mp_mul_high_digs() which overflowed (line 83), thanks Valgrind!
+
+April 4th, 2006
+v0.39 -- Jim Wigginton pointed out my Montgomery examples in figures 6.4 and 6.6 were off by one, k should be 9 not 8
+ -- Bruce Guenter suggested I use --tag=CC for libtool builds where the compiler may think it's C++.
+ -- "mm" from sci.crypt pointed out that my mp_gcd was sub-optimal (I also updated and corrected the book)
+ -- updated some of the @@ tags in tommath.src to reflect source changes.
+ -- updated email and url info in all source files
+
+Jan 26th, 2006
+v0.38 -- broken makefile.shared fixed
+ -- removed some carry stores that were not required [updated text]
+
+November 18th, 2005
+v0.37 -- [Don Porter] reported on a TCL list [HEY SEND ME BUGREPORTS ALREADY!!!] that mp_add_d() would compute -0 with some inputs. Fixed.
+ -- [rinick@gmail.com] reported the makefile.bcc was messed up. Fixed.
+ -- [Kevin Kenny] reported some issues with mp_toradix_n(). Now it doesn't require a min of 3 chars of output.
+ -- Made the make command renamable. Wee
+
+August 1st, 2005
+v0.36 -- LTM_PRIME_2MSB_ON was fixed and the "OFF" flag was removed.
+ -- [Peter LaDow] found a typo in the XREALLOC macro
+ -- [Peter LaDow] pointed out that mp_read_(un)signed_bin should have "const" on the input
+ -- Ported LTC patch to fix the prime_random_ex() function to get the bitsize correct [and the maskOR flags]
+ -- Kevin Kenny pointed out a stray //
+ -- David Hulton pointed out a typo in the textbook [mp_montgomery_setup() pseudo-code]
+ -- Neal Hamilton (Elliptic Semiconductor) pointed out that my Karatsuba notation was backwards and that I could use
+ unsigned operations in the routine.
+ -- Paul Schmidt pointed out a linking error in mp_exptmod() when BN_S_MP_EXPTMOD_C is undefined (and another for read_radix)
+ -- Updated makefiles to be way more flexible
+
+March 12th, 2005
+v0.35 -- Stupid XOR function missing line again... oops.
+ -- Fixed bug in invmod not handling negative inputs correctly [Wolfgang Ehrhardt]
+ -- Made exteuclid always give positive u3 output...[ Wolfgang Ehrhardt ]
+ -- [Wolfgang Ehrhardt] Suggested a fix for mp_reduce() which avoided underruns. ;-)
+ -- mp_rand() would emit one too many digits and it was possible to get a 0 out of it ... oops
+ -- Added montgomery to the testing to make sure it handles 1..10 digit moduli correctly
+ -- Fixed bug in comba that would lead to possible erroneous outputs when "pa < digs"
+ -- Fixed bug in mp_toradix_size for "0" [Kevin Kenny]
+ -- Updated chapters 1-5 of the textbook ;-) It now talks about the new comba code!
+
+February 12th, 2005
+v0.34 -- Fixed two more small errors in mp_prime_random_ex()
+ -- Fixed overflow in mp_mul_d() [Kevin Kenny]
+ -- Added mp_to_(un)signed_bin_n() functions which do bounds checking for ya [and report the size]
+ -- Added "large" diminished radix support. Speeds up things like DSA where the moduli is of the form 2^k - P for some P < 2^(k/2) or so
+ Actually is faster than Montgomery on my AMD64 (and probably much faster on a P4)
+ -- Updated the manual a bit
+ -- Ok so I haven't done the textbook work yet... My current freelance gig has landed me in France till the
+ end of Feb/05. Once I get back I'll have tons of free time and I plan to go to town on the book.
+ As of this release the API will freeze. At least until the book catches up with all the changes. I welcome
+ bug reports but new algorithms will have to wait.
+
+December 23rd, 2004
+v0.33 -- Fixed "small" variant for mp_div() which would munge with negative dividends...
+ -- Fixed bug in mp_prime_random_ex() which would set the most significant byte to zero when
+ no special flags were set
+ -- Fixed overflow [minor] bug in fast_s_mp_sqr()
+ -- Made the makefiles easier to configure the group/user that ltm will install as
+ -- Fixed "final carry" bug in comba multipliers. (Volkan Ceylan)
+ -- Matt Johnston pointed out a missing semi-colon in mp_exptmod
+
+October 29th, 2004
+v0.32 -- Added "makefile.shared" for shared object support
+ -- Added more to the build options/configs in the manual
+ -- Started the Depends framework, wrote dep.pl to scan deps and
+ produce "callgraph.txt" ;-)
+ -- Wrote SC_RSA_1 which will enable close to the minimum required to perform
+ RSA on 32-bit [or 64-bit] platforms with LibTomCrypt
+ -- Merged in the small/slower mp_div replacement. You can now toggle which
+ you want to use as your mp_div() at build time. Saves roughly 8KB or so.
+ -- Renamed a few files and changed some comments to make depends system work better.
+ (No changes to function names)
+ -- Merged in new Combas that perform 2 reads per inner loop instead of the older
+ 3reads/2writes per inner loop of the old code. Really though if you want speed
+ learn to use TomsFastMath ;-)
+
+August 9th, 2004
+v0.31 -- "profiled" builds now :-) new timings for Intel Northwoods
+ -- Added "pretty" build target
+ -- Update mp_init() to actually assign 0's instead of relying on calloc()
+ -- "Wolfgang Ehrhardt" found a bug in mp_mul() where if
+ you multiply a negative by zero you get negative zero as the result. Oops.
+ -- J Harper from PeerSec let me toy with his AMD64 and I got 60-bit digits working properly
+ [this also means that I fixed a bug where if sizeof(int) < sizeof(mp_digit) it would bug]
+
+April 11th, 2004
+v0.30 -- Added "mp_toradix_n" which stores upto "n-1" least significant digits of an mp_int
+ -- Johan Lindh sent a patch so MSVC wouldn't whine about redefining malloc [in weird dll modes]
+ -- Henrik Goldman spotted a missing OPT_CAST in mp_fwrite()
+ -- Tuned tommath.h so that when MP_LOW_MEM is defined MP_PREC shall be reduced.
+ [I also allow MP_PREC to be externally defined now]
+ -- Sped up mp_cnt_lsb() by using a 4x4 table [e.g. 4x speedup]
+ -- Added mp_prime_random_ex() which is a more versatile prime generator accurate to
+ exact bit lengths (unlike the deprecated but still available mp_prime_random() which
+ is only accurate to byte lengths). See the new LTM_PRIME_* flags ;-)
+ -- Alex Polushin contributed an optimized mp_sqrt() as well as mp_get_int() and mp_is_square().
+ I've cleaned them all up to be a little more consistent [along with one bug fix] for this release.
+ -- Added mp_init_set and mp_init_set_int to initialize and set small constants with one function
+ call.
+ -- Removed /etclib directory [um LibTomPoly deprecates this].
+ -- Fixed mp_mod() so the sign of the result agrees with the sign of the modulus.
+ ++ N.B. My semester is almost up so expect updates to the textbook to be posted to the libtomcrypt.org
+ website.
+
+Jan 25th, 2004
+v0.29 ++ Note: "Henrik" from the v0.28 changelog refers to Henrik Goldman ;-)
+ -- Added fix to mp_shrink to prevent a realloc when used == 0 [e.g. realloc zero bytes???]
+ -- Made the mp_prime_rabin_miller_trials() function internal table smaller and also
+ set the minimum number of tests to two (sounds a bit safer).
+ -- Added a mp_exteuclid() which computes the extended euclidean algorithm.
+ -- Fixed a memory leak in s_mp_exptmod() [called when Barrett reduction is to be used] which would arise
+ if a multiplication or subsequent reduction failed [would not free the temp result].
+ -- Made an API change to mp_radix_size(). It now returns an error code and stores the required size
+ through an "int star" passed to it.
+
+Dec 24th, 2003
+v0.28 -- Henrik Goldman suggested I add casts to the montomgery code [stores into mu...] so compilers wouldn't
+ spew [erroneous] diagnostics... fixed.
+ -- Henrik Goldman also spotted two typos. One in mp_radix_size() and another in mp_toradix().
+ -- Added fix to mp_shrink() to avoid a memory leak.
+ -- Added mp_prime_random() which requires a callback to make truly random primes of a given nature
+ (idea from chat with Niels Ferguson at Crypto'03)
+ -- Picked up a second wind. I'm filled with Gooo. Mission Gooo!
+ -- Removed divisions from mp_reduce_is_2k()
+ -- Sped up mp_div_d() [general case] to use only one division per digit instead of two.
+ -- Added the heap macros from LTC to LTM. Now you can easily [by editing four lines of tommath.h]
+ change the name of the heap functions used in LTM [also compatible with LTC via MPI mode]
+ -- Added bn_prime_rabin_miller_trials() which gives the number of Rabin-Miller trials to achieve
+ a failure rate of less than 2^-96
+ -- fixed bug in fast_mp_invmod(). The initial testing logic was wrong. An invalid input is not when
+ "a" and "b" are even it's when "b" is even [the algo is for odd moduli only].
+ -- Started a new manual [finally]. It is incomplete and will be finished as time goes on. I had to stop
+ adding full demos around half way in chapter three so I could at least get a good portion of the
+ manual done. If you really need help using the library you can always email me!
+ -- My Textbook is now included as part of the package [all Public Domain]
+
+Sept 19th, 2003
+v0.27 -- Removed changes.txt~ which was made by accident since "kate" decided it was
+ a good time to re-enable backups... [kde is fun!]
+ -- In mp_grow() "a->dp" is not overwritten by realloc call [re: memory leak]
+ Now if mp_grow() fails the mp_int is still valid and can be cleared via
+ mp_clear() to reclaim the memory.
+ -- Henrik Goldman found a buffer overflow bug in mp_add_d(). Fixed.
+ -- Cleaned up mp_mul_d() to be much easier to read and follow.
+
+Aug 29th, 2003
+v0.26 -- Fixed typo that caused warning with GCC 3.2
+ -- Martin Marcel noticed a bug in mp_neg() that allowed negative zeroes.
+ Also, Martin is the fellow who noted the bugs in mp_gcd() of 0.24/0.25.
+ -- Martin Marcel noticed an optimization [and slight bug] in mp_lcm().
+ -- Added fix to mp_read_unsigned_bin to prevent a buffer overflow.
+ -- Beefed up the comments in the baseline multipliers [and montgomery]
+ -- Added "mont" demo to the makefile.msvc in etc/
+ -- Optimized sign compares in mp_cmp from 4 to 2 cases.
+
+Aug 4th, 2003
+v0.25 -- Fix to mp_gcd again... oops (0,-a) == (-a, 0) == a
+ -- Fix to mp_clear which didn't reset the sign [Greg Rose]
+ -- Added mp_error_to_string() to convert return codes to strings. [Greg Rose]
+ -- Optimized fast_mp_invmod() to do the test for invalid inputs [both even]
+ first so temps don't have to be initialized if it's going to fail.
+ -- Optimized mp_gcd() by removing mp_div_2d calls for when one of the inputs
+ is odd.
+ -- Tons of new comments, some indentation fixups, etc.
+ -- mp_jacobi() returns MP_VAL if the modulus is less than or equal to zero.
+ -- fixed two typos in the header of each file :-)
+ -- LibTomMath is officially Public Domain [see LICENSE]
+
+July 15th, 2003
+v0.24 -- Optimized mp_add_d and mp_sub_d to not allocate temporary variables
+ -- Fixed mp_gcd() so the gcd of 0,0 is 0. Allows the gcd operation to be chained
+ e.g. (0,0,a) == a [instead of 1]
+ -- Should be one of the last release for a while. Working on LibTomMath book now.
+ -- optimized the pprime demo [/etc/pprime.c] to first make a huge table of single
+ digit primes then it reads them randomly instead of randomly choosing/testing single
+ digit primes.
+
+July 12th, 2003
+v0.23 -- Optimized mp_prime_next_prime() to not use mp_mod [via is_divisible()] in each
+ iteration. Instead now a smaller table is kept of the residues which can be updated
+ without division.
+ -- Fixed a bug in next_prime() where an input of zero would be treated as odd and
+ have two added to it [to move to the next odd].
+ -- fixed a bug in prime_fermat() and prime_miller_rabin() which allowed the base
+ to be negative, zero or one. Normally the test is only valid if the base is
+ greater than one.
+ -- changed the next_prime() prototype to accept a new parameter "bbs_style" which
+ will find the next prime congruent to 3 mod 4. The default [bbs_style==0] will
+ make primes which are either congruent to 1 or 3 mod 4.
+ -- fixed mp_read_unsigned_bin() so that it doesn't include both code for
+ the case DIGIT_BIT < 8 and >= 8
+ -- optimized div_d() to easy out on division by 1 [or if a == 0] and use
+ logical shifts if the divisor is a power of two.
+ -- the default DIGIT_BIT type was not int for non-default builds. Fixed.
+
+July 2nd, 2003
+v0.22 -- Fixed up mp_invmod so the result is properly in range now [was always congruent to the inverse...]
+ -- Fixed up s_mp_exptmod and mp_exptmod_fast so the lower half of the pre-computed table isn't allocated
+ which makes the algorithm use half as much ram.
+ -- Fixed the install script not to make the book :-) [which isn't included anyways]
+ -- added mp_cnt_lsb() which counts how many of the lsbs are zero
+ -- optimized mp_gcd() to use the new mp_cnt_lsb() to replace multiple divisions by two by a single division.
+ -- applied similar optimization to mp_prime_miller_rabin().
+ -- Fixed a bug in both mp_invmod() and fast_mp_invmod() which tested for odd
+ via "mp_iseven() == 0" which is not valid [since zero is not even either].
+
+June 19th, 2003
+v0.21 -- Fixed bug in mp_mul_d which would not handle sign correctly [would not always forward it]
+ -- Removed the #line lines from gen.pl [was in violation of ISO C]
+
+June 8th, 2003
+v0.20 -- Removed the book from the package. Added the TDCAL license document.
+ -- This release is officially pure-bred TDCAL again [last officially TDCAL based release was v0.16]
+
+June 6th, 2003
+v0.19 -- Fixed a bug in mp_montgomery_reduce() which was introduced when I tweaked mp_rshd() in the previous release.
+ Essentially the digits were not trimmed before the compare which cause a subtraction to occur all the time.
+ -- Fixed up etc/tune.c a bit to stop testing new cutoffs after 16 failures [to find more optimal points].
+ Brute force ho!
+
+
+May 29th, 2003
+v0.18 -- Fixed a bug in s_mp_sqr which would handle carries properly just not very elegantly.
+ (e.g. correct result, just bad looking code)
+ -- Fixed bug in mp_sqr which still had a 512 constant instead of MP_WARRAY
+ -- Added Toom-Cook multipliers [needs tuning!]
+ -- Added efficient divide by 3 algorithm mp_div_3
+ -- Re-wrote mp_div_d to be faster than calling mp_div
+ -- Added in a donated BCC makefile and a single page LTM poster (ahalhabsi@sbcglobal.net)
+ -- Added mp_reduce_2k which reduces an input modulo n = 2**p - k for any single digit k
+ -- Made the exptmod system be aware of the 2k reduction algorithms.
+ -- Rewrote mp_dr_reduce to be smaller, simpler and easier to understand.
+
+May 17th, 2003
+v0.17 -- Benjamin Goldberg submitted optimized mp_add and mp_sub routines. A new gen.pl as well
+ as several smaller suggestions. Thanks!
+ -- removed call to mp_cmp in inner loop of mp_div and put mp_cmp_mag in its place :-)
+ -- Fixed bug in mp_exptmod that would cause it to fail for odd moduli when DIGIT_BIT != 28
+ -- mp_exptmod now also returns errors if the modulus is negative and will handle negative exponents
+ -- mp_prime_is_prime will now return true if the input is one of the primes in the prime table
+ -- Damian M Gryski (dgryski@uwaterloo.ca) found a index out of bounds error in the
+ mp_fast_s_mp_mul_high_digs function which didn't come up before. (fixed)
+ -- Refactored the DR reduction code so there is only one function per file.
+ -- Fixed bug in the mp_mul() which would erroneously avoid the faster multiplier [comba] when it was
+ allowed. The bug would not cause the incorrect value to be produced just less efficient (fixed)
+ -- Fixed similar bug in the Montgomery reduction code.
+ -- Added tons of (mp_digit) casts so the 7/15/28/31 bit digit code will work flawlessly out of the box.
+ Also added limited support for 64-bit machines with a 60-bit digit. Both thanks to Tom Wu (tom@arcot.com)
+ -- Added new comments here and there, cleaned up some code [style stuff]
+ -- Fixed a lingering typo in mp_exptmod* that would set bitcnt to zero then one. Very silly stuff :-)
+ -- Fixed up mp_exptmod_fast so it would set "redux" to the comba Montgomery reduction if allowed. This
+ saves quite a few calls and if statements.
+ -- Added etc/mont.c a test of the Montgomery reduction [assuming all else works :-| ]
+ -- Fixed up etc/tune.c to use a wider test range [more appropriate] also added a x86 based addition which
+ uses RDTSC for high precision timing.
+ -- Updated demo/demo.c to remove MPI stuff [won't work anyways], made the tests run for 2 seconds each so its
+ not so insanely slow. Also made the output space delimited [and fixed up various errors]
+ -- Added logs directory, logs/graph.dem which will use gnuplot to make a series of PNG files
+ that go with the pre-made index.html. You have to build [via make timing] and run ltmtest first in the
+ root of the package.
+ -- Fixed a bug in mp_sub and mp_add where "-a - -a" or "-a + a" would produce -0 as the result [obviously invalid].
+ -- Fixed a bug in mp_rshd. If the count == a.used it should zero/return [instead of shifting]
+ -- Fixed a "off-by-one" bug in mp_mul2d. The initial size check on alloc would be off by one if the residue
+ shifting caused a carry.
+ -- Fixed a bug where s_mp_mul_digs() would not call the Comba based routine if allowed. This made Barrett reduction
+ slower than it had to be.
+
+Mar 29th, 2003
+v0.16 -- Sped up mp_div by making normalization one shift call
+ -- Sped up mp_mul_2d/mp_div_2d by aliasing pointers :-)
+ -- Cleaned up mp_gcd to use the macros for odd/even detection
+ -- Added comments here and there, mostly there but occasionally here too.
+
+Mar 22nd, 2003
+v0.15 -- Added series of prime testing routines to lib
+ -- Fixed up etc/tune.c
+ -- Added DR reduction algorithm
+ -- Beefed up the manual more.
+ -- Fixed up demo/demo.c so it doesn't have so many warnings and it does the full series of
+ tests
+ -- Added "pre-gen" directory which will hold a "gen.pl"'ed copy of the entire lib [done at
+ zipup time so its always the latest]
+ -- Added conditional casts for C++ users [boo!]
+
+Mar 15th, 2003
+v0.14 -- Tons of manual updates
+ -- cleaned up the directory
+ -- added MSVC makefiles
+ -- source changes [that I don't recall]
+ -- Fixed up the lshd/rshd code to use pointer aliasing
+ -- Fixed up the mul_2d and div_2d to not call rshd/lshd unless needed
+ -- Fixed up etc/tune.c a tad
+ -- fixed up demo/demo.c to output comma-delimited results of timing
+ also fixed up timing demo to use a finer granularity for various functions
+ -- fixed up demo/demo.c testing to pause during testing so my Duron won't catch on fire
+ [stays around 31-35C during testing :-)]
+
+Feb 13th, 2003
+v0.13 -- tons of minor speed-ups in low level add, sub, mul_2 and div_2 which propagate
+ to other functions like mp_invmod, mp_div, etc...
+ -- Sped up mp_exptmod_fast by using new code to find R mod m [e.g. B^n mod m]
+ -- minor fixes
+
+Jan 17th, 2003
+v0.12 -- re-wrote the majority of the makefile so its more portable and will
+ install via "make install" on most *nix platforms
+ -- Re-packaged all the source as seperate files. Means the library a single
+ file packagage any more. Instead of just adding "bn.c" you have to add
+ libtommath.a
+ -- Renamed "bn.h" to "tommath.h"
+ -- Changes to the manual to reflect all of this
+ -- Used GNU Indent to clean up the source
+
+Jan 15th, 2003
+v0.11 -- More subtle fixes
+ -- Moved to gentoo linux [hurrah!] so made *nix specific fixes to the make process
+ -- Sped up the montgomery reduction code quite a bit
+ -- fixed up demo so when building timing for the x86 it assumes ELF format now
+
+Jan 9th, 2003
+v0.10 -- Pekka Riikonen suggested fixes to the radix conversion code.
+ -- Added baseline montgomery and comba montgomery reductions, sped up exptmods
+ [to a point, see bn.h for MONTGOMERY_EXPT_CUTOFF]
+
+Jan 6th, 2003
+v0.09 -- Updated the manual to reflect recent changes. :-)
+ -- Added Jacobi function (mp_jacobi) to supplement the number theory side of the lib
+ -- Added a Mersenne prime finder demo in ./etc/mersenne.c
+
+Jan 2nd, 2003
+v0.08 -- Sped up the multipliers by moving the inner loop variables into a smaller scope
+ -- Corrected a bunch of small "warnings"
+ -- Added more comments
+ -- Made "mtest" be able to use /dev/random, /dev/urandom or stdin for RNG data
+ -- Corrected some bugs where error messages were potentially ignored
+ -- add etc/pprime.c program which makes numbers which are provably prime.
+
+Jan 1st, 2003
+v0.07 -- Removed alot of heap operations from core functions to speed them up
+ -- Added a root finding function [and mp_sqrt macro like from MPI]
+ -- Added more to manual
+
+Dec 31st, 2002
+v0.06 -- Sped up the s_mp_add, s_mp_sub which inturn sped up mp_invmod, mp_exptmod, etc...
+ -- Cleaned up the header a bit more
+
+Dec 30th, 2002
+v0.05 -- Builds with MSVC out of the box
+ -- Fixed a bug in mp_invmod w.r.t. even moduli
+ -- Made mp_toradix and mp_read_radix use char instead of unsigned char arrays
+ -- Fixed up exptmod to use fewer multiplications
+ -- Fixed up mp_init_size to use only one heap operation
+ -- Note there is a slight "off-by-one" bug in the library somewhere
+ without the padding (see the source for comment) the library
+ crashes in libtomcrypt. Anyways a reasonable workaround is to pad the
+ numbers which will always correct it since as the numbers grow the padding
+ will still be beyond the end of the number
+ -- Added more to the manual
+
+Dec 29th, 2002
+v0.04 -- Fixed a memory leak in mp_to_unsigned_bin
+ -- optimized invmod code
+ -- Fixed bug in mp_div
+ -- use exchange instead of copy for results
+ -- added a bit more to the manual
+
+Dec 27th, 2002
+v0.03 -- Sped up s_mp_mul_high_digs by not computing the carries of the lower digits
+ -- Fixed a bug where mp_set_int wouldn't zero the value first and set the used member.
+ -- fixed a bug in s_mp_mul_high_digs where the limit placed on the result digits was not calculated properly
+ -- fixed bugs in add/sub/mul/sqr_mod functions where if the modulus and dest were the same it wouldn't work
+ -- fixed a bug in mp_mod and mp_mod_d concerning negative inputs
+ -- mp_mul_d didn't preserve sign
+ -- Many many many many fixes
+ -- Works in LibTomCrypt now :-)
+ -- Added iterations to the timing demos... more accurate.
+ -- Tom needs a job.
+
+Dec 26th, 2002
+v0.02 -- Fixed a few "slips" in the manual. This is "LibTomMath" afterall :-)
+ -- Added mp_cmp_mag, mp_neg, mp_abs and mp_radix_size that were missing.
+ -- Sped up the fast [comba] multipliers more [yahoo!]
+
+Dec 25th,2002
+v0.01 -- Initial release. Gimme a break.
+ -- Todo list,
+ add details to manual [e.g. algorithms]
+ more comments in code
+ example programs
ADDED libtommath/demo/shared.c
Index: libtommath/demo/shared.c
==================================================================
--- /dev/null
+++ libtommath/demo/shared.c
@@ -0,0 +1,42 @@
+#include "shared.h"
+
+void ndraw(mp_int *a, const char *name)
+{
+ char *buf = NULL;
+ int size;
+
+ mp_radix_size(a, 10, &size);
+ buf = (char *)malloc((size_t) size);
+ if (buf == NULL) {
+ fprintf(stderr, "\nndraw: malloc(%d) failed\n", size);
+ exit(EXIT_FAILURE);
+ }
+
+ printf("%s: ", name);
+ mp_to_decimal(a, buf, (size_t) size);
+ printf("%s\n", buf);
+ mp_to_hex(a, buf, (size_t) size);
+ printf("0x%s\n", buf);
+
+ free(buf);
+}
+
+void print_header(void)
+{
+#ifdef MP_8BIT
+ printf("Digit size 8 Bit \n");
+#endif
+#ifdef MP_16BIT
+ printf("Digit size 16 Bit \n");
+#endif
+#ifdef MP_32BIT
+ printf("Digit size 32 Bit \n");
+#endif
+#ifdef MP_64BIT
+ printf("Digit size 64 Bit \n");
+#endif
+ printf("Size of mp_digit: %u\n", (unsigned int)sizeof(mp_digit));
+ printf("Size of mp_word: %u\n", (unsigned int)sizeof(mp_word));
+ printf("MP_DIGIT_BIT: %d\n", MP_DIGIT_BIT);
+ printf("MP_PREC: %d\n", MP_PREC);
+}
ADDED libtommath/demo/shared.h
Index: libtommath/demo/shared.h
==================================================================
--- /dev/null
+++ libtommath/demo/shared.h
@@ -0,0 +1,21 @@
+#include
+#include
+#include
+
+/*
+ * Configuration
+ */
+#ifndef LTM_DEMO_TEST_REDUCE_2K_L
+/* This test takes a moment so we disable it by default, but it can be:
+ * 0 to disable testing
+ * 1 to make the test with P = 2^1024 - 0x2A434 B9FDEC95 D8F9D550 FFFFFFFF FFFFFFFF
+ * 2 to make the test with P = 2^2048 - 0x1 00000000 00000000 00000000 00000000 4945DDBF 8EA2A91D 5776399B B83E188F
+ */
+#define LTM_DEMO_TEST_REDUCE_2K_L 0
+#endif
+
+#define MP_WUR /* TODO: result checks disabled for now */
+#include "tommath_private.h"
+
+extern void ndraw(mp_int* a, const char* name);
+extern void print_header(void);
ADDED libtommath/demo/test.c
Index: libtommath/demo/test.c
==================================================================
--- /dev/null
+++ libtommath/demo/test.c
@@ -0,0 +1,2522 @@
+#include
+#include "shared.h"
+
+static long rand_long(void)
+{
+ long x;
+ if (s_mp_rand_source(&x, sizeof(x)) != MP_OKAY) {
+ fprintf(stderr, "s_mp_rand_source failed\n");
+ exit(EXIT_FAILURE);
+ }
+ return x;
+}
+
+static int rand_int(void)
+{
+ int x;
+ if (s_mp_rand_source(&x, sizeof(x)) != MP_OKAY) {
+ fprintf(stderr, "s_mp_rand_source failed\n");
+ exit(EXIT_FAILURE);
+ }
+ return x;
+}
+
+static int32_t rand_int32(void)
+{
+ int32_t x;
+ if (s_mp_rand_source(&x, sizeof(x)) != MP_OKAY) {
+ fprintf(stderr, "s_mp_rand_source failed\n");
+ exit(EXIT_FAILURE);
+ }
+ return x;
+}
+
+static int64_t rand_int64(void)
+{
+ int64_t x;
+ if (s_mp_rand_source(&x, sizeof(x)) != MP_OKAY) {
+ fprintf(stderr, "s_mp_rand_source failed\n");
+ exit(EXIT_FAILURE);
+ }
+ return x;
+}
+
+static uint32_t uabs32(int32_t x)
+{
+ return x > 0 ? (uint32_t)x : -(uint32_t)x;
+}
+
+static uint64_t uabs64(int64_t x)
+{
+ return x > 0 ? (uint64_t)x : -(uint64_t)x;
+}
+
+/* This function prototype is needed
+ * to test dead code elimination
+ * which is used for feature detection.
+ *
+ * If the feature detection does not
+ * work as desired we will get a linker error.
+ */
+void does_not_exist(void);
+
+static int test_feature_detection(void)
+{
+#define BN_TEST_FEATURE1_C
+ if (!MP_HAS(TEST_FEATURE1)) {
+ does_not_exist();
+ return EXIT_FAILURE;
+ }
+
+#define BN_TEST_FEATURE2_C 1
+ if (MP_HAS(TEST_FEATURE2)) {
+ does_not_exist();
+ return EXIT_FAILURE;
+ }
+
+#define BN_TEST_FEATURE3_C 0
+ if (MP_HAS(TEST_FEATURE3)) {
+ does_not_exist();
+ return EXIT_FAILURE;
+ }
+
+#define BN_TEST_FEATURE4_C something
+ if (MP_HAS(TEST_FEATURE4)) {
+ does_not_exist();
+ return EXIT_FAILURE;
+ }
+
+ if (MP_HAS(TEST_FEATURE5)) {
+ does_not_exist();
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+static int test_trivial_stuff(void)
+{
+ mp_int a, b, c, d;
+ mp_err e;
+ if ((e = mp_init_multi(&a, &b, &c, &d, NULL)) != MP_OKAY) {
+ return EXIT_FAILURE;
+ }
+ (void)mp_error_to_string(e);
+
+ /* a: 0->5 */
+ mp_set(&a, 5u);
+ /* a: 5-> b: -5 */
+ mp_neg(&a, &b);
+ if (mp_cmp(&a, &b) != MP_GT) {
+ goto LBL_ERR;
+ }
+ if (mp_cmp(&b, &a) != MP_LT) {
+ goto LBL_ERR;
+ }
+ /* a: 5-> a: -5 */
+ mp_neg(&a, &a);
+ if (mp_cmp(&b, &a) != MP_EQ) {
+ goto LBL_ERR;
+ }
+ /* a: -5-> b: 5 */
+ mp_abs(&a, &b);
+ if (mp_isneg(&b) != MP_NO) {
+ goto LBL_ERR;
+ }
+ /* a: -5-> b: -4 */
+ mp_add_d(&a, 1uL, &b);
+ if (mp_isneg(&b) != MP_YES) {
+ goto LBL_ERR;
+ }
+ if (mp_get_i32(&b) != -4) {
+ goto LBL_ERR;
+ }
+ if (mp_get_u32(&b) != (uint32_t)-4) {
+ goto LBL_ERR;
+ }
+ if (mp_get_mag_u32(&b) != 4) {
+ goto LBL_ERR;
+ }
+ /* a: -5-> b: 1 */
+ mp_add_d(&a, 6uL, &b);
+ if (mp_get_u32(&b) != 1) {
+ goto LBL_ERR;
+ }
+ /* a: -5-> a: 1 */
+ mp_add_d(&a, 6uL, &a);
+ if (mp_get_u32(&a) != 1) {
+ goto LBL_ERR;
+ }
+ mp_zero(&a);
+ /* a: 0-> a: 6 */
+ mp_add_d(&a, 6uL, &a);
+ if (mp_get_u32(&a) != 6) {
+ goto LBL_ERR;
+ }
+
+ mp_set(&a, 42u);
+ mp_set(&b, 1u);
+ mp_neg(&b, &b);
+ mp_set(&c, 1u);
+ mp_exptmod(&a, &b, &c, &d);
+
+ mp_set(&c, 7u);
+ mp_exptmod(&a, &b, &c, &d);
+
+ if (mp_iseven(&a) == mp_isodd(&a)) {
+ goto LBL_ERR;
+ }
+
+ mp_clear_multi(&a, &b, &c, &d, NULL);
+ return EXIT_SUCCESS;
+LBL_ERR:
+ mp_clear_multi(&a, &b, &c, &d, NULL);
+ return EXIT_FAILURE;
+}
+
+static int check_get_set_i32(mp_int *a, int32_t b)
+{
+ mp_clear(a);
+ if (mp_shrink(a) != MP_OKAY) return EXIT_FAILURE;
+
+ mp_set_i32(a, b);
+ if (mp_shrink(a) != MP_OKAY) return EXIT_FAILURE;
+ if (mp_get_i32(a) != b) return EXIT_FAILURE;
+ if (mp_get_u32(a) != (uint32_t)b) return EXIT_FAILURE;
+ if (mp_get_mag_u32(a) != uabs32(b)) return EXIT_FAILURE;
+
+ mp_set_u32(a, (uint32_t)b);
+ if (mp_get_u32(a) != (uint32_t)b) return EXIT_FAILURE;
+ if (mp_get_i32(a) != (int32_t)(uint32_t)b) return EXIT_FAILURE;
+
+ return EXIT_SUCCESS;
+}
+
+static int test_mp_get_set_i32(void)
+{
+ int i;
+ mp_int a;
+
+ if (mp_init(&a) != MP_OKAY) {
+ return EXIT_FAILURE;
+ }
+
+ check_get_set_i32(&a, 0);
+ check_get_set_i32(&a, -1);
+ check_get_set_i32(&a, 1);
+ check_get_set_i32(&a, INT32_MIN);
+ check_get_set_i32(&a, INT32_MAX);
+
+ for (i = 0; i < 1000; ++i) {
+ int32_t b = rand_int32();
+ if (check_get_set_i32(&a, b) != EXIT_SUCCESS) {
+ goto LBL_ERR;
+ }
+ }
+
+ mp_clear(&a);
+ return EXIT_SUCCESS;
+LBL_ERR:
+ mp_clear(&a);
+ return EXIT_FAILURE;
+}
+
+static int check_get_set_i64(mp_int *a, int64_t b)
+{
+ mp_clear(a);
+ if (mp_shrink(a) != MP_OKAY) return EXIT_FAILURE;
+
+ mp_set_i64(a, b);
+ if (mp_shrink(a) != MP_OKAY) return EXIT_FAILURE;
+ if (mp_get_i64(a) != b) return EXIT_FAILURE;
+ if (mp_get_u64(a) != (uint64_t)b) return EXIT_FAILURE;
+ if (mp_get_mag_u64(a) != uabs64(b)) return EXIT_FAILURE;
+
+ mp_set_u64(a, (uint64_t)b);
+ if (mp_get_u64(a) != (uint64_t)b) return EXIT_FAILURE;
+ if (mp_get_i64(a) != (int64_t)(uint64_t)b) return EXIT_FAILURE;
+
+ return EXIT_SUCCESS;
+}
+
+static int test_mp_get_set_i64(void)
+{
+ int i;
+ mp_int a;
+
+ if (mp_init(&a) != MP_OKAY) {
+ return EXIT_FAILURE;
+ }
+
+ check_get_set_i64(&a, 0);
+ check_get_set_i64(&a, -1);
+ check_get_set_i64(&a, 1);
+ check_get_set_i64(&a, INT64_MIN);
+ check_get_set_i64(&a, INT64_MAX);
+
+ for (i = 0; i < 1000; ++i) {
+ int64_t b = rand_int64();
+ if (check_get_set_i64(&a, b) != EXIT_SUCCESS) {
+ goto LBL_ERR;
+ }
+ }
+
+ mp_clear(&a);
+ return EXIT_SUCCESS;
+LBL_ERR:
+ mp_clear(&a);
+ return EXIT_FAILURE;
+}
+
+static int test_mp_fread_fwrite(void)
+{
+ mp_int a, b;
+ mp_err e;
+ FILE *tmp = NULL;
+ if ((e = mp_init_multi(&a, &b, NULL)) != MP_OKAY) {
+ return EXIT_FAILURE;
+ }
+
+ mp_set_ul(&a, 123456uL);
+ tmp = tmpfile();
+ if ((e = mp_fwrite(&a, 64, tmp)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ rewind(tmp);
+ if ((e = mp_fread(&b, 64, tmp)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if (mp_get_u32(&b) != 123456uL) {
+ goto LBL_ERR;
+ }
+ fclose(tmp);
+
+ mp_clear_multi(&a, &b, NULL);
+ return EXIT_SUCCESS;
+LBL_ERR:
+ if (tmp != NULL) fclose(tmp);
+ mp_clear_multi(&a, &b, NULL);
+ return EXIT_FAILURE;
+}
+
+static mp_err very_random_source(void *out, size_t size)
+{
+ memset(out, 0xff, size);
+ return MP_OKAY;
+}
+
+static int test_mp_rand(void)
+{
+ mp_int a, b;
+ int n;
+ mp_err err;
+ if (mp_init_multi(&a, &b, NULL)!= MP_OKAY) {
+ return EXIT_FAILURE;
+ }
+ mp_rand_source(very_random_source);
+ for (n = 1; n < 1024; ++n) {
+ if ((err = mp_rand(&a, n)) != MP_OKAY) {
+ printf("Failed mp_rand() %s.\n", mp_error_to_string(err));
+ break;
+ }
+ if ((err = mp_incr(&a)) != MP_OKAY) {
+ printf("Failed mp_incr() %s.\n", mp_error_to_string(err));
+ break;
+ }
+ if ((err = mp_div_2d(&a, n * MP_DIGIT_BIT, &b, NULL)) != MP_OKAY) {
+ printf("Failed mp_div_2d() %s.\n", mp_error_to_string(err));
+ break;
+ }
+ if (mp_cmp_d(&b, 1) != MP_EQ) {
+ ndraw(&a, "mp_rand() a");
+ ndraw(&b, "mp_rand() b");
+ err = MP_ERR;
+ break;
+ }
+ }
+ mp_rand_source(s_mp_rand_jenkins);
+ mp_clear_multi(&a, &b, NULL);
+ return err == MP_OKAY ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+static int test_mp_kronecker(void)
+{
+ struct mp_kronecker_st {
+ long n;
+ int c[21];
+ };
+ static struct mp_kronecker_st kronecker[] = {
+ /*-10, -9, -8, -7,-6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10*/
+ { -10, { 0, -1, 0, -1, 0, 0, 0, 1, 0, -1, 0, 1, 0, -1, 0, 0, 0, 1, 0, 1, 0 } },
+ { -9, { -1, 0, -1, 1, 0, -1, -1, 0, -1, -1, 0, 1, 1, 0, 1, 1, 0, -1, 1, 0, 1 } },
+ { -8, { 0, -1, 0, 1, 0, 1, 0, -1, 0, -1, 0, 1, 0, 1, 0, -1, 0, -1, 0, 1, 0 } },
+ { -7, { 1, -1, -1, 0, 1, 1, -1, 1, -1, -1, 0, 1, 1, -1, 1, -1, -1, 0, 1, 1, -1 } },
+ { -6, { 0, 0, 0, -1, 0, -1, 0, 0, 0, -1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0 } },
+ { -5, { 0, -1, 1, -1, 1, 0, -1, -1, 1, -1, 0, 1, -1, 1, 1, 0, -1, 1, -1, 1, 0 } },
+ { -4, { 0, -1, 0, 1, 0, -1, 0, 1, 0, -1, 0, 1, 0, -1, 0, 1, 0, -1, 0, 1, 0 } },
+ { -3, { -1, 0, 1, -1, 0, 1, -1, 0, 1, -1, 0, 1, -1, 0, 1, -1, 0, 1, -1, 0, 1 } },
+ { -2, { 0, -1, 0, 1, 0, 1, 0, -1, 0, -1, 0, 1, 0, 1, 0, -1, 0, -1, 0, 1, 0 } },
+ { -1, { -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1 } },
+ { 0, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+ { 1, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } },
+ { 2, { 0, 1, 0, 1, 0, -1, 0, -1, 0, 1, 0, 1, 0, -1, 0, -1, 0, 1, 0, 1, 0 } },
+ { 3, { 1, 0, -1, -1, 0, -1, 1, 0, -1, 1, 0, 1, -1, 0, 1, -1, 0, -1, -1, 0, 1 } },
+ { 4, { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 } },
+ { 5, { 0, 1, -1, -1, 1, 0, 1, -1, -1, 1, 0, 1, -1, -1, 1, 0, 1, -1, -1, 1, 0 } },
+ { 6, { 0, 0, 0, -1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, -1, 0, 0, 0 } },
+ { 7, { -1, 1, 1, 0, 1, -1, 1, 1, 1, 1, 0, 1, 1, 1, 1, -1, 1, 0, 1, 1, -1 } },
+ { 8, { 0, 1, 0, 1, 0, -1, 0, -1, 0, 1, 0, 1, 0, -1, 0, -1, 0, 1, 0, 1, 0 } },
+ { 9, { 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1 } },
+ { 10, { 0, 1, 0, -1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, -1, 0, 1, 0 } }
+ };
+
+ long k, m;
+ int i, cnt;
+ mp_err err;
+ mp_int a, b;
+ if (mp_init_multi(&a, &b, NULL)!= MP_OKAY) {
+ return EXIT_FAILURE;
+ }
+
+ mp_set_ul(&a, 0uL);
+ mp_set_ul(&b, 1uL);
+ if ((err = mp_kronecker(&a, &b, &i)) != MP_OKAY) {
+ printf("Failed executing mp_kronecker(0 | 1) %s.\n", mp_error_to_string(err));
+ goto LBL_ERR;
+ }
+ if (i != 1) {
+ printf("Failed trivial mp_kronecker(0 | 1) %d != 1\n", i);
+ goto LBL_ERR;
+ }
+ for (cnt = 0; cnt < (int)(sizeof(kronecker)/sizeof(kronecker[0])); ++cnt) {
+ k = kronecker[cnt].n;
+ mp_set_l(&a, k);
+ /* only test positive values of a */
+ for (m = -10; m <= 10; m++) {
+ mp_set_l(&b, m);
+ if ((err = mp_kronecker(&a, &b, &i)) != MP_OKAY) {
+ printf("Failed executing mp_kronecker(%ld | %ld) %s.\n", kronecker[cnt].n, m, mp_error_to_string(err));
+ goto LBL_ERR;
+ }
+ if ((err == MP_OKAY) && (i != kronecker[cnt].c[m + 10])) {
+ printf("Failed trivial mp_kronecker(%ld | %ld) %d != %d\n", kronecker[cnt].n, m, i, kronecker[cnt].c[m + 10]);
+ goto LBL_ERR;
+ }
+ }
+ }
+
+ mp_clear_multi(&a, &b, NULL);
+ return EXIT_SUCCESS;
+LBL_ERR:
+ mp_clear_multi(&a, &b, NULL);
+ return EXIT_FAILURE;
+}
+
+static int test_mp_complement(void)
+{
+ int i;
+
+ mp_int a, b, c;
+ if (mp_init_multi(&a, &b, &c, NULL)!= MP_OKAY) {
+ return EXIT_FAILURE;
+ }
+
+ for (i = 0; i < 1000; ++i) {
+ long l = rand_long();
+ mp_set_l(&a, l);
+ mp_complement(&a, &b);
+
+ l = ~l;
+ mp_set_l(&c, l);
+
+ if (mp_cmp(&b, &c) != MP_EQ) {
+ printf("\nmp_complement() bad result!");
+ goto LBL_ERR;
+ }
+ }
+
+ mp_clear_multi(&a, &b, &c, NULL);
+ return EXIT_SUCCESS;
+LBL_ERR:
+ mp_clear_multi(&a, &b, &c, NULL);
+ return EXIT_FAILURE;
+}
+
+static int test_mp_signed_rsh(void)
+{
+ int i;
+
+ mp_int a, b, d;
+ if (mp_init_multi(&a, &b, &d, NULL)!= MP_OKAY) {
+ return EXIT_FAILURE;
+ }
+
+ for (i = 0; i < 1000; ++i) {
+ long l;
+ int em;
+
+ l = rand_long();
+ mp_set_l(&a, l);
+
+ em = abs(rand_int()) % 32;
+
+ mp_set_l(&d, l >> em);
+
+ mp_signed_rsh(&a, em, &b);
+ if (mp_cmp(&b, &d) != MP_EQ) {
+ printf("\nmp_signed_rsh() bad result!");
+ goto LBL_ERR;
+ }
+ }
+
+ mp_clear_multi(&a, &b, &d, NULL);
+ return EXIT_SUCCESS;
+LBL_ERR:
+ mp_clear_multi(&a, &b, &d, NULL);
+ return EXIT_FAILURE;
+
+}
+
+static int test_mp_xor(void)
+{
+ int i;
+
+ mp_int a, b, c, d;
+ if (mp_init_multi(&a, &b, &c, &d, NULL)!= MP_OKAY) {
+ return EXIT_FAILURE;
+ }
+
+ for (i = 0; i < 1000; ++i) {
+ long l, em;
+
+ l = rand_long();
+ mp_set_l(&a,l);
+
+ em = rand_long();
+ mp_set_l(&b, em);
+
+ mp_set_l(&d, l ^ em);
+
+ mp_xor(&a, &b, &c);
+ if (mp_cmp(&c, &d) != MP_EQ) {
+ printf("\nmp_xor() bad result!");
+ goto LBL_ERR;
+ }
+ }
+
+ mp_clear_multi(&a, &b, &c, &d, NULL);
+ return EXIT_SUCCESS;
+LBL_ERR:
+ mp_clear_multi(&a, &b, &c, &d, NULL);
+ return EXIT_FAILURE;
+
+}
+
+static int test_mp_or(void)
+{
+ int i;
+
+ mp_int a, b, c, d;
+ if (mp_init_multi(&a, &b, &c, &d, NULL)!= MP_OKAY) {
+ return EXIT_FAILURE;
+ }
+
+ for (i = 0; i < 1000; ++i) {
+ long l, em;
+
+ l = rand_long();
+ mp_set_l(&a, l);
+
+ em = rand_long();
+ mp_set_l(&b, em);
+
+ mp_set_l(&d, l | em);
+
+ mp_or(&a, &b, &c);
+ if (mp_cmp(&c, &d) != MP_EQ) {
+ printf("\nmp_or() bad result!");
+ goto LBL_ERR;
+ }
+ }
+
+ mp_clear_multi(&a, &b, &c, &d, NULL);
+ return EXIT_SUCCESS;
+LBL_ERR:
+ mp_clear_multi(&a, &b, &c, &d, NULL);
+ return EXIT_FAILURE;
+}
+
+static int test_mp_and(void)
+{
+ int i;
+
+ mp_int a, b, c, d;
+ if (mp_init_multi(&a, &b, &c, &d, NULL)!= MP_OKAY) {
+ return EXIT_FAILURE;
+ }
+
+ for (i = 0; i < 1000; ++i) {
+ long l, em;
+
+ l = rand_long();
+ mp_set_l(&a, l);
+
+ em = rand_long();
+ mp_set_l(&b, em);
+
+ mp_set_l(&d, l & em);
+
+ mp_and(&a, &b, &c);
+ if (mp_cmp(&c, &d) != MP_EQ) {
+ printf("\nmp_and() bad result!");
+ goto LBL_ERR;
+ }
+ }
+
+ mp_clear_multi(&a, &b, &c, &d, NULL);
+ return EXIT_SUCCESS;
+LBL_ERR:
+ mp_clear_multi(&a, &b, &c, &d, NULL);
+ return EXIT_FAILURE;
+}
+
+static int test_mp_invmod(void)
+{
+ mp_int a, b, c, d;
+ if (mp_init_multi(&a, &b, &c, &d, NULL)!= MP_OKAY) {
+ return EXIT_FAILURE;
+ }
+
+ /* mp_invmod corner-case of https://github.com/libtom/libtommath/issues/118 */
+ {
+ const char *a_ = "47182BB8DF0FFE9F61B1F269BACC066B48BA145D35137D426328DC3F88A5EA44";
+ const char *b_ = "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF";
+ const char *should_ = "0521A82E10376F8E4FDEF9A32A427AC2A0FFF686E00290D39E3E4B5522409596";
+
+ if (mp_read_radix(&a, a_, 16) != MP_OKAY) {
+ printf("\nmp_read_radix(a) failed!");
+ goto LBL_ERR;
+ }
+ if (mp_read_radix(&b, b_, 16) != MP_OKAY) {
+ printf("\nmp_read_radix(b) failed!");
+ goto LBL_ERR;
+ }
+ if (mp_read_radix(&c, should_, 16) != MP_OKAY) {
+ printf("\nmp_read_radix(should) failed!");
+ goto LBL_ERR;
+ }
+
+ if (mp_invmod(&a, &b, &d) != MP_OKAY) {
+ printf("\nmp_invmod() failed!");
+ goto LBL_ERR;
+ }
+
+ if (mp_cmp(&c, &d) != MP_EQ) {
+ printf("\nmp_invmod() bad result!");
+ goto LBL_ERR;
+ }
+ }
+
+ mp_clear_multi(&a, &b, &c, &d, NULL);
+ return EXIT_SUCCESS;
+LBL_ERR:
+ mp_clear_multi(&a, &b, &c, &d, NULL);
+ return EXIT_FAILURE;
+
+}
+
+#if defined(__STDC_IEC_559__) || defined(__GCC_IEC_559)
+static int test_mp_set_double(void)
+{
+ int i;
+
+ mp_int a, b;
+ if (mp_init_multi(&a, &b, NULL)!= MP_OKAY) {
+ return EXIT_FAILURE;
+ }
+
+ /* test mp_get_double/mp_set_double */
+ if (mp_set_double(&a, +1.0/0.0) != MP_VAL) {
+ printf("\nmp_set_double should return MP_VAL for +inf");
+ goto LBL_ERR;
+ }
+ if (mp_set_double(&a, -1.0/0.0) != MP_VAL) {
+ printf("\nmp_set_double should return MP_VAL for -inf");
+ goto LBL_ERR;
+ }
+ if (mp_set_double(&a, +0.0/0.0) != MP_VAL) {
+ printf("\nmp_set_double should return MP_VAL for NaN");
+ goto LBL_ERR;
+ }
+ if (mp_set_double(&a, -0.0/0.0) != MP_VAL) {
+ printf("\nmp_set_double should return MP_VAL for NaN");
+ goto LBL_ERR;
+ }
+
+ for (i = 0; i < 1000; ++i) {
+ int tmp = rand_int();
+ double dbl = (double)tmp * rand_int() + 1;
+ if (mp_set_double(&a, dbl) != MP_OKAY) {
+ printf("\nmp_set_double() failed");
+ goto LBL_ERR;
+ }
+ if (dbl != mp_get_double(&a)) {
+ printf("\nmp_get_double() bad result!");
+ goto LBL_ERR;
+ }
+ if (mp_set_double(&a, -dbl) != MP_OKAY) {
+ printf("\nmp_set_double() failed");
+ goto LBL_ERR;
+ }
+ if (-dbl != mp_get_double(&a)) {
+ printf("\nmp_get_double() bad result!");
+ goto LBL_ERR;
+ }
+ }
+
+ mp_clear_multi(&a, &b, NULL);
+ return EXIT_SUCCESS;
+LBL_ERR:
+ mp_clear_multi(&a, &b, NULL);
+ return EXIT_FAILURE;
+
+}
+#endif
+
+static int test_mp_get_u32(void)
+{
+ unsigned long t;
+ int i;
+
+ mp_int a, b;
+ if (mp_init_multi(&a, &b, NULL)!= MP_OKAY) {
+ return EXIT_FAILURE;
+ }
+
+ for (i = 0; i < 1000; ++i) {
+ t = (unsigned long)rand_long() & 0xFFFFFFFFuL;
+ mp_set_ul(&a, t);
+ if (t != mp_get_u32(&a)) {
+ printf("\nmp_get_u32() bad result!");
+ goto LBL_ERR;
+ }
+ }
+ mp_set_ul(&a, 0uL);
+ if (mp_get_u32(&a) != 0) {
+ printf("\nmp_get_u32() bad result!");
+ goto LBL_ERR;
+ }
+ mp_set_ul(&a, 0xFFFFFFFFuL);
+ if (mp_get_u32(&a) != 0xFFFFFFFFuL) {
+ printf("\nmp_get_u32() bad result!");
+ goto LBL_ERR;
+ }
+
+ mp_clear_multi(&a, &b, NULL);
+ return EXIT_SUCCESS;
+LBL_ERR:
+ mp_clear_multi(&a, &b, NULL);
+ return EXIT_FAILURE;
+}
+
+static int test_mp_get_ul(void)
+{
+ unsigned long s, t;
+ int i;
+
+ mp_int a, b;
+ if (mp_init_multi(&a, &b, NULL)!= MP_OKAY) {
+ return EXIT_FAILURE;
+ }
+
+ for (i = 0; i < ((int)MP_SIZEOF_BITS(unsigned long) - 1); ++i) {
+ t = (1UL << (i+1)) - 1;
+ if (!t)
+ t = ~0UL;
+ printf(" t = 0x%lx i = %d\r", t, i);
+ do {
+ mp_set_ul(&a, t);
+ s = mp_get_ul(&a);
+ if (s != t) {
+ printf("\nmp_get_ul() bad result! 0x%lx != 0x%lx", s, t);
+ goto LBL_ERR;
+ }
+ t <<= 1;
+ } while (t != 0uL);
+ }
+
+ mp_clear_multi(&a, &b, NULL);
+ return EXIT_SUCCESS;
+LBL_ERR:
+ mp_clear_multi(&a, &b, NULL);
+ return EXIT_FAILURE;
+}
+
+static int test_mp_get_u64(void)
+{
+ uint64_t q, r;
+ int i;
+
+ mp_int a, b;
+ if (mp_init_multi(&a, &b, NULL)!= MP_OKAY) {
+ return EXIT_FAILURE;
+ }
+
+ for (i = 0; i < (int)(MP_SIZEOF_BITS(uint64_t) - 1); ++i) {
+ r = ((uint64_t)1 << (i+1)) - 1;
+ if (!r)
+ r = UINT64_MAX;
+ printf(" r = 0x%" PRIx64 " i = %d\r", r, i);
+ do {
+ mp_set_u64(&a, r);
+ q = mp_get_u64(&a);
+ if (q != r) {
+ printf("\nmp_get_u64() bad result! 0x%" PRIx64 " != 0x%" PRIx64, q, r);
+ goto LBL_ERR;
+ }
+ r <<= 1;
+ } while (r != 0u);
+ }
+
+ mp_clear_multi(&a, &b, NULL);
+ return EXIT_SUCCESS;
+LBL_ERR:
+ mp_clear_multi(&a, &b, NULL);
+ return EXIT_FAILURE;
+
+}
+
+static int test_mp_sqrt(void)
+{
+ int i, n;
+
+ mp_int a, b, c;
+ if (mp_init_multi(&a, &b, &c, NULL)!= MP_OKAY) {
+ return EXIT_FAILURE;
+ }
+
+ for (i = 0; i < 1000; ++i) {
+ printf("%6d\r", i);
+ fflush(stdout);
+ n = (rand_int() & 15) + 1;
+ mp_rand(&a, n);
+ if (mp_sqrt(&a, &b) != MP_OKAY) {
+ printf("\nmp_sqrt() error!");
+ goto LBL_ERR;
+ }
+ mp_root_u32(&a, 2uL, &c);
+ if (mp_cmp_mag(&b, &c) != MP_EQ) {
+ printf("mp_sqrt() bad result!\n");
+ goto LBL_ERR;
+ }
+ }
+
+ mp_clear_multi(&a, &b, &c, NULL);
+ return EXIT_SUCCESS;
+LBL_ERR:
+ mp_clear_multi(&a, &b, &c, NULL);
+ return EXIT_FAILURE;
+}
+
+static int test_mp_is_square(void)
+{
+ int i, n;
+
+ mp_int a, b;
+ mp_bool res;
+
+ if (mp_init_multi(&a, &b, NULL)!= MP_OKAY) {
+ return EXIT_FAILURE;
+ }
+
+ for (i = 0; i < 1000; ++i) {
+ printf("%6d\r", i);
+ fflush(stdout);
+
+ /* test mp_is_square false negatives */
+ n = (rand_int() & 7) + 1;
+ mp_rand(&a, n);
+ mp_sqr(&a, &a);
+ if (mp_is_square(&a, &res) != MP_OKAY) {
+ printf("\nfn:mp_is_square() error!");
+ goto LBL_ERR;
+ }
+ if (res == MP_NO) {
+ printf("\nfn:mp_is_square() bad result!");
+ goto LBL_ERR;
+ }
+
+ /* test for false positives */
+ mp_add_d(&a, 1uL, &a);
+ if (mp_is_square(&a, &res) != MP_OKAY) {
+ printf("\nfp:mp_is_square() error!");
+ goto LBL_ERR;
+ }
+ if (res == MP_YES) {
+ printf("\nfp:mp_is_square() bad result!");
+ goto LBL_ERR;
+ }
+
+ }
+ printf("\n\n");
+
+ mp_clear_multi(&a, &b, NULL);
+ return EXIT_SUCCESS;
+LBL_ERR:
+ mp_clear_multi(&a, &b, NULL);
+ return EXIT_FAILURE;
+}
+
+static int test_mp_sqrtmod_prime(void)
+{
+ struct mp_sqrtmod_prime_st {
+ unsigned long p;
+ unsigned long n;
+ mp_digit r;
+ };
+
+ static struct mp_sqrtmod_prime_st sqrtmod_prime[] = {
+ { 5, 14, 3 },
+ { 7, 9, 4 },
+ { 113, 2, 62 }
+ };
+ int i;
+
+ mp_int a, b, c;
+ if (mp_init_multi(&a, &b, &c, NULL)!= MP_OKAY) {
+ return EXIT_FAILURE;
+ }
+
+ /* r^2 = n (mod p) */
+ for (i = 0; i < (int)(sizeof(sqrtmod_prime)/sizeof(sqrtmod_prime[0])); ++i) {
+ mp_set_ul(&a, sqrtmod_prime[i].p);
+ mp_set_ul(&b, sqrtmod_prime[i].n);
+ if (mp_sqrtmod_prime(&b, &a, &c) != MP_OKAY) {
+ printf("Failed executing %d. mp_sqrtmod_prime\n", (i+1));
+ goto LBL_ERR;
+ }
+ if (mp_cmp_d(&c, sqrtmod_prime[i].r) != MP_EQ) {
+ printf("Failed %d. trivial mp_sqrtmod_prime\n", (i+1));
+ ndraw(&c, "r");
+ goto LBL_ERR;
+ }
+ }
+
+ mp_clear_multi(&a, &b, &c, NULL);
+ return EXIT_SUCCESS;
+LBL_ERR:
+ mp_clear_multi(&a, &b, &c, NULL);
+ return EXIT_FAILURE;
+}
+
+static int test_mp_prime_rand(void)
+{
+ int ix;
+ mp_err err;
+ mp_int a, b;
+ if (mp_init_multi(&a, &b, NULL)!= MP_OKAY) {
+ return EXIT_FAILURE;
+ }
+
+ /* test for size */
+ for (ix = 10; ix < 128; ix++) {
+ printf("Testing (not safe-prime): %9d bits \r", ix);
+ fflush(stdout);
+ err = mp_prime_rand(&a, 8, ix, (rand_int() & 1) ? 0 : MP_PRIME_2MSB_ON);
+ if (err != MP_OKAY) {
+ printf("\nfailed with error: %s\n", mp_error_to_string(err));
+ goto LBL_ERR;
+ }
+ if (mp_count_bits(&a) != ix) {
+ printf("Prime is %d not %d bits!!!\n", mp_count_bits(&a), ix);
+ goto LBL_ERR;
+ }
+ }
+ printf("\n");
+
+ mp_clear_multi(&a, &b, NULL);
+ return EXIT_SUCCESS;
+LBL_ERR:
+ mp_clear_multi(&a, &b, NULL);
+ return EXIT_FAILURE;
+}
+
+static int test_mp_prime_is_prime(void)
+{
+ int ix;
+ mp_err err;
+ mp_bool cnt, fu;
+
+ mp_int a, b;
+ if (mp_init_multi(&a, &b, NULL)!= MP_OKAY) {
+ return EXIT_FAILURE;
+ }
+
+ /* strong Miller-Rabin pseudoprime to the first 200 primes (F. Arnault) */
+ puts("Testing mp_prime_is_prime() with Arnault's pseudoprime 803...901 \n");
+ mp_read_radix(&a,
+ "91xLNF3roobhzgTzoFIG6P13ZqhOVYSN60Fa7Cj2jVR1g0k89zdahO9/kAiRprpfO1VAp1aBHucLFV/qLKLFb+zonV7R2Vxp1K13ClwUXStpV0oxTNQVjwybmFb5NBEHImZ6V7P6+udRJuH8VbMEnS0H8/pSqQrg82OoQQ2fPpAk6G1hkjqoCv5s/Yr",
+ 64);
+ mp_prime_is_prime(&a, mp_prime_rabin_miller_trials(mp_count_bits(&a)), &cnt);
+ if (cnt == MP_YES) {
+ printf("Arnault's pseudoprime is not prime but mp_prime_is_prime says it is.\n");
+ goto LBL_ERR;
+ }
+ /* About the same size as Arnault's pseudoprime */
+ puts("Testing mp_prime_is_prime() with certified prime 2^1119 + 53\n");
+ mp_set(&a, 1uL);
+ mp_mul_2d(&a,1119,&a);
+ mp_add_d(&a, 53uL, &a);
+ err = mp_prime_is_prime(&a, mp_prime_rabin_miller_trials(mp_count_bits(&a)), &cnt);
+ /* small problem */
+ if (err != MP_OKAY) {
+ printf("\nfailed with error: %s\n", mp_error_to_string(err));
+ }
+ /* large problem */
+ if (cnt == MP_NO) {
+ printf("A certified prime is a prime but mp_prime_is_prime says it is not.\n");
+ }
+ if ((err != MP_OKAY) || (cnt == MP_NO)) {
+ printf("prime tested was: 0x");
+ mp_fwrite(&a,16,stdout);
+ putchar('\n');
+ goto LBL_ERR;
+ }
+ for (ix = 16; ix < 128; ix++) {
+ printf("Testing ( safe-prime): %9d bits \r", ix);
+ fflush(stdout);
+ err = mp_prime_rand(&a, 8, ix, ((rand_int() & 1) ? 0 : MP_PRIME_2MSB_ON) | MP_PRIME_SAFE);
+ if (err != MP_OKAY) {
+ printf("\nfailed with error: %s\n", mp_error_to_string(err));
+ goto LBL_ERR;
+ }
+ if (mp_count_bits(&a) != ix) {
+ printf("Prime is %d not %d bits!!!\n", mp_count_bits(&a), ix);
+ goto LBL_ERR;
+ }
+ /* let's see if it's really a safe prime */
+ mp_sub_d(&a, 1uL, &b);
+ mp_div_2(&b, &b);
+ err = mp_prime_is_prime(&b, mp_prime_rabin_miller_trials(mp_count_bits(&b)), &cnt);
+ /* small problem */
+ if (err != MP_OKAY) {
+ printf("\nfailed with error: %s\n", mp_error_to_string(err));
+ }
+ /* large problem */
+ if (cnt == MP_NO) {
+ printf("\nsub is not prime!\n");
+ }
+ mp_prime_frobenius_underwood(&b, &fu);
+ if (fu == MP_NO) {
+ printf("\nfrobenius-underwood says sub is not prime!\n");
+ }
+ if ((err != MP_OKAY) || (cnt == MP_NO)) {
+ printf("prime tested was: 0x");
+ mp_fwrite(&a,16,stdout);
+ putchar('\n');
+ printf("sub tested was: 0x");
+ mp_fwrite(&b,16,stdout);
+ putchar('\n');
+ goto LBL_ERR;
+ }
+
+ }
+ /* Check regarding problem #143 */
+#ifndef MP_8BIT
+ mp_read_radix(&a,
+ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF",
+ 16);
+ err = mp_prime_strong_lucas_selfridge(&a, &cnt);
+ /* small problem */
+ if (err != MP_OKAY) {
+ printf("\nmp_prime_strong_lucas_selfridge failed with error: %s\n", mp_error_to_string(err));
+ }
+ /* large problem */
+ if (cnt == MP_NO) {
+ printf("\n\nissue #143 - mp_prime_strong_lucas_selfridge FAILED!\n");
+ }
+ if ((err != MP_OKAY) || (cnt == MP_NO)) {
+ printf("prime tested was: 0x");
+ mp_fwrite(&a,16,stdout);
+ putchar('\n');
+ goto LBL_ERR;
+ }
+#endif
+
+ printf("\n\n");
+
+ mp_clear_multi(&a, &b, NULL);
+ return EXIT_SUCCESS;
+LBL_ERR:
+ mp_clear_multi(&a, &b, NULL);
+ return EXIT_FAILURE;
+
+}
+
+
+static int test_mp_prime_next_prime(void)
+{
+ mp_err err;
+ mp_int a, b, c;
+
+ mp_init_multi(&a, &b, &c, NULL);
+
+
+ /* edge cases */
+ mp_set(&a, 0u);
+ if ((err = mp_prime_next_prime(&a, 5, 0)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if (mp_cmp_d(&a, 2u) != MP_EQ) {
+ printf("mp_prime_next_prime: output should have been 2 but was: ");
+ mp_fwrite(&a,10,stdout);
+ putchar('\n');
+ goto LBL_ERR;
+ }
+
+ mp_set(&a, 0u);
+ if ((err = mp_prime_next_prime(&a, 5, 1)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if (mp_cmp_d(&a, 3u) != MP_EQ) {
+ printf("mp_prime_next_prime: output should have been 3 but was: ");
+ mp_fwrite(&a,10,stdout);
+ putchar('\n');
+ goto LBL_ERR;
+ }
+
+ mp_set(&a, 2u);
+ if ((err = mp_prime_next_prime(&a, 5, 0)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if (mp_cmp_d(&a, 3u) != MP_EQ) {
+ printf("mp_prime_next_prime: output should have been 3 but was: ");
+ mp_fwrite(&a,10,stdout);
+ putchar('\n');
+ goto LBL_ERR;
+ }
+
+ mp_set(&a, 2u);
+ if ((err = mp_prime_next_prime(&a, 5, 1)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if (mp_cmp_d(&a, 3u) != MP_EQ) {
+ printf("mp_prime_next_prime: output should have been 3 but was: ");
+ mp_fwrite(&a,10,stdout);
+ putchar('\n');
+ goto LBL_ERR;
+ }
+ mp_set(&a, 8);
+ if ((err = mp_prime_next_prime(&a, 5, 1)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if (mp_cmp_d(&a, 11u) != MP_EQ) {
+ printf("mp_prime_next_prime: output should have been 11 but was: ");
+ mp_fwrite(&a,10,stdout);
+ putchar('\n');
+ goto LBL_ERR;
+ }
+ /* 2^300 + 157 is a 300 bit large prime to guarantee a multi-limb bigint */
+ if ((err = mp_2expt(&a, 300)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ mp_set_u32(&b, 157);
+ if ((err = mp_add(&a, &b, &a)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((err = mp_copy(&a, &b)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* 2^300 + 385 is the next prime */
+ mp_set_u32(&c, 228);
+ if ((err = mp_add(&b, &c, &b)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((err = mp_prime_next_prime(&a, 5, 0)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if (mp_cmp(&a, &b) != MP_EQ) {
+ printf("mp_prime_next_prime: output should have been\n");
+ mp_fwrite(&b,10,stdout);
+ putchar('\n');
+ printf("but was:\n");
+ mp_fwrite(&a,10,stdout);
+ putchar('\n');
+ goto LBL_ERR;
+ }
+
+ /* Use another temporary variable or recompute? Mmh... */
+ if ((err = mp_2expt(&a, 300)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ mp_set_u32(&b, 157);
+ if ((err = mp_add(&a, &b, &a)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((err = mp_copy(&a, &b)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* 2^300 + 631 is the next prime congruent to 3 mod 4*/
+ mp_set_u32(&c, 474);
+ if ((err = mp_add(&b, &c, &b)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((err = mp_prime_next_prime(&a, 5, 1)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if (mp_cmp(&a, &b) != MP_EQ) {
+ printf("mp_prime_next_prime (bbs): output should have been\n");
+ mp_fwrite(&b,10,stdout);
+ putchar('\n');
+ printf("but was:\n");
+ mp_fwrite(&a,10,stdout);
+ putchar('\n');
+ goto LBL_ERR;
+ }
+
+ mp_clear_multi(&a, &b, &c, NULL);
+ return EXIT_SUCCESS;
+LBL_ERR:
+ mp_clear_multi(&a, &b, &c, NULL);
+ return EXIT_FAILURE;
+}
+
+static int test_mp_montgomery_reduce(void)
+{
+ mp_digit mp;
+ int ix, i, n;
+ char buf[4096];
+
+ /* size_t written; */
+
+ mp_int a, b, c, d, e;
+ if (mp_init_multi(&a, &b, &c, &d, &e, NULL)!= MP_OKAY) {
+ return EXIT_FAILURE;
+ }
+
+ /* test montgomery */
+ for (i = 1; i <= 10; i++) {
+ if (i == 10)
+ i = 1000;
+ printf(" digit size: %2d\r", i);
+ fflush(stdout);
+ for (n = 0; n < 1000; n++) {
+ mp_rand(&a, i);
+ a.dp[0] |= 1;
+
+ /* let's see if R is right */
+ mp_montgomery_calc_normalization(&b, &a);
+ mp_montgomery_setup(&a, &mp);
+
+ /* now test a random reduction */
+ for (ix = 0; ix < 100; ix++) {
+ mp_rand(&c, 1 + abs(rand_int()) % (2*i));
+ mp_copy(&c, &d);
+ mp_copy(&c, &e);
+
+ mp_mod(&d, &a, &d);
+ mp_montgomery_reduce(&c, &a, mp);
+ mp_mulmod(&c, &b, &a, &c);
+
+ if (mp_cmp(&c, &d) != MP_EQ) {
+/* *INDENT-OFF* */
+ printf("d = e mod a, c = e MOD a\n");
+ mp_to_decimal(&a, buf, sizeof(buf)); printf("a = %s\n", buf);
+ mp_to_decimal(&e, buf, sizeof(buf)); printf("e = %s\n", buf);
+ mp_to_decimal(&d, buf, sizeof(buf)); printf("d = %s\n", buf);
+ mp_to_decimal(&c, buf, sizeof(buf)); printf("c = %s\n", buf);
+
+ printf("compare no compare!\n"); goto LBL_ERR;
+/* *INDENT-ON* */
+ }
+ /* only one big montgomery reduction */
+ if (i > 10) {
+ n = 1000;
+ ix = 100;
+ }
+ }
+ }
+ }
+
+ printf("\n\n");
+
+ mp_clear_multi(&a, &b, &c, &d, &e, NULL);
+ return EXIT_SUCCESS;
+LBL_ERR:
+ mp_clear_multi(&a, &b, &c, &d, &e, NULL);
+ return EXIT_FAILURE;
+
+}
+
+static int test_mp_read_radix(void)
+{
+ char buf[4096];
+ size_t written;
+ mp_err err;
+
+ mp_int a;
+ if (mp_init_multi(&a, NULL)!= MP_OKAY) goto LTM_ERR;
+
+ if ((err = mp_read_radix(&a, "123456", 10)) != MP_OKAY) goto LTM_ERR;
+
+ if ((err = mp_to_radix(&a, buf, SIZE_MAX, &written, 10)) != MP_OKAY) goto LTM_ERR;
+ printf(" '123456' a == %s, length = %zu\n", buf, written);
+
+ /* See comment in bn_mp_to_radix.c */
+ /*
+ if( (err = mp_to_radix(&a, buf, 3u, &written, 10) ) != MP_OKAY) goto LTM_ERR;
+ printf(" '56' a == %s, length = %zu\n", buf, written);
+
+ if( (err = mp_to_radix(&a, buf, 4u, &written, 10) ) != MP_OKAY) goto LTM_ERR;
+ printf(" '456' a == %s, length = %zu\n", buf, written);
+ if( (err = mp_to_radix(&a, buf, 30u, &written, 10) ) != MP_OKAY) goto LTM_ERR;
+ printf(" '123456' a == %s, length = %zu, error = %s\n",
+ buf, written, mp_error_to_string(err));
+ */
+ if ((err = mp_read_radix(&a, "-123456", 10)) != MP_OKAY) goto LTM_ERR;
+ if ((err = mp_to_radix(&a, buf, SIZE_MAX, &written, 10)) != MP_OKAY) goto LTM_ERR;
+ printf(" '-123456' a == %s, length = %zu\n", buf, written);
+
+ if ((err = mp_read_radix(&a, "0", 10)) != MP_OKAY) goto LTM_ERR;
+ if ((err = mp_to_radix(&a, buf, SIZE_MAX, &written, 10)) != MP_OKAY) goto LTM_ERR;
+ printf(" '0' a == %s, length = %zu\n", buf, written);
+
+
+
+ /* Although deprecated it needs to function as long as it isn't dropped */
+ /*
+ printf("Testing deprecated mp_toradix_n\n");
+ if( (err = mp_read_radix(&a, "-123456", 10) ) != MP_OKAY) goto LTM_ERR;
+ if( (err = mp_toradix_n(&a, buf, 10, 3) ) != MP_OKAY) goto LTM_ERR;
+ printf("a == %s\n", buf);
+ if( (err = mp_toradix_n(&a, buf, 10, 4) ) != MP_OKAY) goto LTM_ERR;
+ printf("a == %s\n", buf);
+ if( (err = mp_toradix_n(&a, buf, 10, 30) ) != MP_OKAY) goto LTM_ERR;
+ printf("a == %s\n", buf);
+ */
+
+
+ while (0) {
+ char *s = fgets(buf, sizeof(buf), stdin);
+ if (s != buf) break;
+ mp_read_radix(&a, buf, 10);
+ mp_prime_next_prime(&a, 5, 1);
+ mp_to_radix(&a, buf, sizeof(buf), NULL, 10);
+ printf("%s, %lu\n", buf, (unsigned long)a.dp[0] & 3uL);
+ }
+
+ mp_clear(&a);
+ return EXIT_SUCCESS;
+LTM_ERR:
+ mp_clear(&a);
+ return EXIT_FAILURE;
+}
+
+static int test_mp_cnt_lsb(void)
+{
+ int ix;
+
+ mp_int a, b;
+ if (mp_init_multi(&a, &b, NULL)!= MP_OKAY) {
+ return EXIT_FAILURE;
+ }
+
+ mp_set(&a, 1uL);
+ for (ix = 0; ix < 1024; ix++) {
+ if (mp_cnt_lsb(&a) != ix) {
+ printf("Failed at %d, %d\n", ix, mp_cnt_lsb(&a));
+ goto LBL_ERR;
+ }
+ mp_mul_2(&a, &a);
+ }
+
+ mp_clear_multi(&a, &b, NULL);
+ return EXIT_SUCCESS;
+LBL_ERR:
+ mp_clear_multi(&a, &b, NULL);
+ return EXIT_FAILURE;
+
+}
+
+static int test_mp_reduce_2k(void)
+{
+ int ix, cnt;
+
+ mp_int a, b, c, d;
+ if (mp_init_multi(&a, &b, &c, &d, NULL)!= MP_OKAY) {
+ return EXIT_FAILURE;
+ }
+
+ /* test mp_reduce_2k */
+ for (cnt = 3; cnt <= 128; ++cnt) {
+ mp_digit tmp;
+
+ mp_2expt(&a, cnt);
+ mp_sub_d(&a, 2uL, &a); /* a = 2**cnt - 2 */
+
+ printf("\r %4d bits", cnt);
+ printf("(%d)", mp_reduce_is_2k(&a));
+ mp_reduce_2k_setup(&a, &tmp);
+ printf("(%lu)", (unsigned long) tmp);
+ for (ix = 0; ix < 1000; ix++) {
+ if (!(ix & 127)) {
+ printf(".");
+ fflush(stdout);
+ }
+ mp_rand(&b, (cnt / MP_DIGIT_BIT + 1) * 2);
+ mp_copy(&c, &b);
+ mp_mod(&c, &a, &c);
+ mp_reduce_2k(&b, &a, 2uL);
+ if (mp_cmp(&c, &b) != MP_EQ) {
+ printf("FAILED\n");
+ goto LBL_ERR;
+ }
+ }
+ }
+
+ mp_clear_multi(&a, &b, &c, &d, NULL);
+ return EXIT_SUCCESS;
+LBL_ERR:
+ mp_clear_multi(&a, &b, &c, &d, NULL);
+ return EXIT_FAILURE;
+}
+
+static int test_mp_div_3(void)
+{
+ int cnt;
+
+ mp_int a, b, c, d, e;
+ if (mp_init_multi(&a, &b, &c, &d, &e, NULL)!= MP_OKAY) {
+ return EXIT_FAILURE;
+ }
+
+ /* test mp_div_3 */
+ mp_set(&d, 3uL);
+ for (cnt = 0; cnt < 10000;) {
+ mp_digit r2;
+
+ if (!(++cnt & 127)) {
+ printf("%9d\r", cnt);
+ fflush(stdout);
+ }
+ mp_rand(&a, abs(rand_int()) % 128 + 1);
+ mp_div(&a, &d, &b, &e);
+ mp_div_3(&a, &c, &r2);
+
+ if (mp_cmp(&b, &c) || mp_cmp_d(&e, r2)) {
+ printf("\nmp_div_3 => Failure\n");
+ goto LBL_ERR;
+ }
+ }
+ printf("\nPassed div_3 testing");
+
+ mp_clear_multi(&a, &b, &c, &d, &e, NULL);
+ return EXIT_SUCCESS;
+LBL_ERR:
+ mp_clear_multi(&a, &b, &c, &d, &e, NULL);
+ return EXIT_FAILURE;
+}
+
+static int test_mp_dr_reduce(void)
+{
+ mp_digit mp;
+ int cnt;
+ unsigned rr;
+ int ix;
+
+ mp_int a, b, c;
+ if (mp_init_multi(&a, &b, &c, NULL)!= MP_OKAY) {
+ return EXIT_FAILURE;
+ }
+
+ /* test the DR reduction */
+ for (cnt = 2; cnt < 32; cnt++) {
+ printf("\r%d digit modulus", cnt);
+ mp_grow(&a, cnt);
+ mp_zero(&a);
+ for (ix = 1; ix < cnt; ix++) {
+ a.dp[ix] = MP_MASK;
+ }
+ a.used = cnt;
+ a.dp[0] = 3;
+
+ mp_rand(&b, cnt - 1);
+ mp_copy(&b, &c);
+
+ rr = 0;
+ do {
+ if (!(rr & 127)) {
+ printf(".");
+ fflush(stdout);
+ }
+ mp_sqr(&b, &b);
+ mp_add_d(&b, 1uL, &b);
+ mp_copy(&b, &c);
+
+ mp_mod(&b, &a, &b);
+ mp_dr_setup(&a, &mp);
+ mp_dr_reduce(&c, &a, mp);
+
+ if (mp_cmp(&b, &c) != MP_EQ) {
+ printf("Failed on trial %u\n", rr);
+ goto LBL_ERR;
+ }
+ } while (++rr < 500);
+ printf(" passed");
+ fflush(stdout);
+ }
+
+ mp_clear_multi(&a, &b, &c, NULL);
+ return EXIT_SUCCESS;
+LBL_ERR:
+ mp_clear_multi(&a, &b, &c, NULL);
+ return EXIT_FAILURE;
+}
+
+static int test_mp_reduce_2k_l(void)
+{
+# if LTM_DEMO_TEST_REDUCE_2K_L
+ mp_int a, b, c, d;
+ int cnt;
+ char buf[4096];
+ size_t length[1];
+ if (mp_init_multi(&a, &b, NULL)!= MP_OKAY) {
+ return EXIT_FAILURE;
+ }
+ /* test the mp_reduce_2k_l code */
+# if LTM_DEMO_TEST_REDUCE_2K_L == 1
+ /* first load P with 2^1024 - 0x2A434 B9FDEC95 D8F9D550 FFFFFFFF FFFFFFFF */
+ mp_2expt(&a, 1024);
+ mp_read_radix(&b, "2A434B9FDEC95D8F9D550FFFFFFFFFFFFFFFF", 16);
+ mp_sub(&a, &b, &a);
+# elif LTM_DEMO_TEST_REDUCE_2K_L == 2
+ /* p = 2^2048 - 0x1 00000000 00000000 00000000 00000000 4945DDBF 8EA2A91D 5776399B B83E188F */
+ mp_2expt(&a, 2048);
+ mp_read_radix(&b,
+ "1000000000000000000000000000000004945DDBF8EA2A91D5776399BB83E188F",
+ 16);
+ mp_sub(&a, &b, &a);
+# else
+# error oops
+# endif
+ *length = sizeof(buf);
+ mp_to_radix(&a, buf, length, 10);
+ printf("\n\np==%s, length = %zu\n", buf, *length);
+ /* now mp_reduce_is_2k_l() should return */
+ if (mp_reduce_is_2k_l(&a) != 1) {
+ printf("mp_reduce_is_2k_l() return 0, should be 1\n");
+ goto LBL_ERR;
+ }
+ mp_reduce_2k_setup_l(&a, &d);
+ /* now do a million square+1 to see if it varies */
+ mp_rand(&b, 64);
+ mp_mod(&b, &a, &b);
+ mp_copy(&b, &c);
+ printf("Testing: mp_reduce_2k_l...");
+ fflush(stdout);
+ for (cnt = 0; cnt < (int)(1uL << 20); cnt++) {
+ mp_sqr(&b, &b);
+ mp_add_d(&b, 1uL, &b);
+ mp_reduce_2k_l(&b, &a, &d);
+ mp_sqr(&c, &c);
+ mp_add_d(&c, 1uL, &c);
+ mp_mod(&c, &a, &c);
+ if (mp_cmp(&b, &c) != MP_EQ) {
+ printf("mp_reduce_2k_l() failed at step %d\n", cnt);
+ mp_to_hex(&b, buf, sizeof(buf));
+ printf("b == %s\n", buf);
+ mp_to_hex(&c, buf, sizeof(buf));
+ printf("c == %s\n", buf);
+ goto LBL_ERR;
+ }
+ }
+
+ mp_clear_multi(&a, &b, NULL);
+ return EXIT_SUCCESS;
+LBL_ERR:
+ mp_clear_multi(&a, &b, NULL);
+ return EXIT_FAILURE;
+#else
+ return EXIT_SUCCESS;
+# endif /* LTM_DEMO_TEST_REDUCE_2K_L */
+}
+/* stripped down version of mp_radix_size. The faster version can be off by up t
+o +3 */
+/* TODO: This function should be removed, replaced by mp_radix_size, mp_radix_size_overestimate in 2.0 */
+static mp_err s_rs(const mp_int *a, int radix, uint32_t *size)
+{
+ mp_err res;
+ uint32_t digs = 0u;
+ mp_int t;
+ mp_digit d;
+ *size = 0u;
+ if (mp_iszero(a) == MP_YES) {
+ *size = 2u;
+ return MP_OKAY;
+ }
+ if (radix == 2) {
+ *size = (uint32_t)mp_count_bits(a) + 1u;
+ return MP_OKAY;
+ }
+ if ((res = mp_init_copy(&t, a)) != MP_OKAY) {
+ return res;
+ }
+ t.sign = MP_ZPOS;
+ while (mp_iszero(&t) == MP_NO) {
+ if ((res = mp_div_d(&t, (mp_digit)radix, &t, &d)) != MP_OKAY) {
+ mp_clear(&t);
+ return res;
+ }
+ ++digs;
+ }
+ mp_clear(&t);
+ *size = digs + 1;
+ return MP_OKAY;
+}
+static int test_mp_log_u32(void)
+{
+ mp_int a;
+ mp_digit d;
+ uint32_t base, lb, size;
+ const uint32_t max_base = MP_MIN(UINT32_MAX, MP_DIGIT_MAX);
+
+ if (mp_init(&a) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /*
+ base a result
+ 0 x MP_VAL
+ 1 x MP_VAL
+ */
+ mp_set(&a, 42uL);
+ base = 0u;
+ if (mp_log_u32(&a, base, &lb) != MP_VAL) {
+ goto LBL_ERR;
+ }
+ base = 1u;
+ if (mp_log_u32(&a, base, &lb) != MP_VAL) {
+ goto LBL_ERR;
+ }
+ /*
+ base a result
+ 2 0 MP_VAL
+ 2 1 0
+ 2 2 1
+ 2 3 1
+ */
+ base = 2u;
+ mp_zero(&a);
+ if (mp_log_u32(&a, base, &lb) != MP_VAL) {
+ goto LBL_ERR;
+ }
+
+ for (d = 1; d < 4; d++) {
+ mp_set(&a, d);
+ if (mp_log_u32(&a, base, &lb) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if (lb != ((d == 1)?0uL:1uL)) {
+ goto LBL_ERR;
+ }
+ }
+ /*
+ base a result
+ 3 0 MP_VAL
+ 3 1 0
+ 3 2 0
+ 3 3 1
+ */
+ base = 3u;
+ mp_zero(&a);
+ if (mp_log_u32(&a, base, &lb) != MP_VAL) {
+ goto LBL_ERR;
+ }
+ for (d = 1; d < 4; d++) {
+ mp_set(&a, d);
+ if (mp_log_u32(&a, base, &lb) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if (lb != ((d < base)?0uL:1uL)) {
+ goto LBL_ERR;
+ }
+ }
+
+ /*
+ bases 2..64 with "a" a random large constant.
+ The range of bases tested allows to check with
+ radix_size.
+ */
+ if (mp_rand(&a, 10) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ for (base = 2u; base < 65u; base++) {
+ if (mp_log_u32(&a, base, &lb) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if (s_rs(&a,(int)base, &size) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ /* radix_size includes the memory needed for '\0', too*/
+ size -= 2;
+ if (lb != size) {
+ goto LBL_ERR;
+ }
+ }
+
+ /*
+ bases 2..64 with "a" a random small constant to
+ test the part of mp_ilogb that uses native types.
+ */
+ if (mp_rand(&a, 1) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ for (base = 2u; base < 65u; base++) {
+ if (mp_log_u32(&a, base, &lb) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if (s_rs(&a,(int)base, &size) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ size -= 2;
+ if (lb != size) {
+ goto LBL_ERR;
+ }
+ }
+
+ /*Test upper edgecase with base UINT32_MAX and number (UINT32_MAX/2)*UINT32_MAX^10 */
+ mp_set(&a, max_base);
+ if (mp_expt_u32(&a, 10uL, &a) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if (mp_add_d(&a, max_base / 2, &a) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if (mp_log_u32(&a, max_base, &lb) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if (lb != 10u) {
+ goto LBL_ERR;
+ }
+
+ mp_clear(&a);
+ return EXIT_SUCCESS;
+LBL_ERR:
+ mp_clear(&a);
+ return EXIT_FAILURE;
+}
+
+static int test_mp_incr(void)
+{
+ mp_int a, b;
+ mp_err e = MP_OKAY;
+
+ if ((e = mp_init_multi(&a, &b, NULL)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+
+ /* Does it increment inside the limits of a MP_xBIT limb? */
+ mp_set(&a, MP_MASK/2);
+ if ((e = mp_incr(&a)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if (mp_cmp_d(&a, (MP_MASK/2uL) + 1uL) != MP_EQ) {
+ goto LTM_ERR;
+ }
+
+ /* Does it increment outside of the limits of a MP_xBIT limb? */
+ mp_set(&a, MP_MASK);
+ mp_set(&b, MP_MASK);
+ if ((e = mp_incr(&a)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if ((e = mp_add_d(&b, 1uL, &b)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if (mp_cmp(&a, &b) != MP_EQ) {
+ goto LTM_ERR;
+ }
+
+ /* Does it increment from -1 to 0? */
+ mp_set(&a, 1uL);
+ a.sign = MP_NEG;
+ if ((e = mp_incr(&a)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if (mp_cmp_d(&a, 0uL) != MP_EQ) {
+ goto LTM_ERR;
+ }
+
+ /* Does it increment from -(MP_MASK + 1) to -MP_MASK? */
+ mp_set(&a, MP_MASK);
+ if ((e = mp_add_d(&a, 1uL, &a)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ a.sign = MP_NEG;
+ if ((e = mp_incr(&a)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if (a.sign != MP_NEG) {
+ goto LTM_ERR;
+ }
+ a.sign = MP_ZPOS;
+ if (mp_cmp_d(&a, MP_MASK) != MP_EQ) {
+ goto LTM_ERR;
+ }
+
+ mp_clear_multi(&a, &b, NULL);
+ return EXIT_SUCCESS;
+LTM_ERR:
+ mp_clear_multi(&a, &b, NULL);
+ return EXIT_FAILURE;
+}
+
+static int test_mp_decr(void)
+{
+ mp_int a, b;
+ mp_err e = MP_OKAY;
+
+ if ((e = mp_init_multi(&a, &b, NULL)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+
+ /* Does it decrement inside the limits of a MP_xBIT limb? */
+ mp_set(&a, MP_MASK/2);
+ if ((e = mp_decr(&a)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if (mp_cmp_d(&a, (MP_MASK/2uL) - 1uL) != MP_EQ) {
+ goto LTM_ERR;
+ }
+
+ /* Does it decrement outside of the limits of a MP_xBIT limb? */
+ mp_set(&a, MP_MASK);
+ if ((e = mp_add_d(&a, 1uL, &a)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if ((e = mp_decr(&a)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if (mp_cmp_d(&a, MP_MASK) != MP_EQ) {
+ goto LTM_ERR;
+ }
+
+ /* Does it decrement from 0 to -1? */
+ mp_zero(&a);
+ if ((e = mp_decr(&a)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if (a.sign == MP_NEG) {
+ a.sign = MP_ZPOS;
+ if (mp_cmp_d(&a, 1uL) != MP_EQ) {
+ goto LTM_ERR;
+ }
+ } else {
+ goto LTM_ERR;
+ }
+
+
+ /* Does it decrement from -MP_MASK to -(MP_MASK + 1)? */
+ mp_set(&a, MP_MASK);
+ a.sign = MP_NEG;
+ mp_set(&b, MP_MASK);
+ b.sign = MP_NEG;
+ if ((e = mp_sub_d(&b, 1uL, &b)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if ((e = mp_decr(&a)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if (mp_cmp(&a, &b) != MP_EQ) {
+ goto LTM_ERR;
+ }
+
+ mp_clear_multi(&a, &b, NULL);
+ return EXIT_SUCCESS;
+LTM_ERR:
+ mp_clear_multi(&a, &b, NULL);
+ return EXIT_FAILURE;
+}
+
+/*
+ Cannot test mp_exp(_d) without mp_root and vice versa.
+ So one of the two has to be tested from scratch.
+
+ Numbers generated by
+ for i in {1..10}
+ do
+ seed=$(head -c 10000 /dev/urandom | tr -dc '[:digit:]' | head -c 120);
+ echo $seed;
+ convertbase $seed 10 64;
+ done
+
+ (The program "convertbase" uses libtommath's to/from_radix functions)
+
+ Roots were precalculated with Pari/GP
+
+ default(realprecision,1000);
+ for(n=3,100,r = floor(a^(1/n));printf("\"" r "\", "))
+
+ All numbers as strings to simplifiy things, especially for the
+ low-mp branch.
+*/
+
+static int test_mp_root_u32(void)
+{
+ mp_int a, c, r;
+ mp_err e;
+ int i, j;
+
+ const char *input[] = {
+ "4n9cbk886QtLQmofprid3l2Q0GD8Yv979Lh8BdZkFE8g2pDUUSMBET/+M/YFyVZ3mBp",
+ "5NlgzHhmIX05O5YoW5yW5reAlVNtRAlIcN2dfoATnNdc1Cw5lHZUTwNthmK6/ZLKfY6",
+ "3gweiHDX+ji5utraSe46IJX+uuh7iggs63xIpMP5MriU4Np+LpHI5are8RzS9pKh9xP",
+ "5QOJUSKMrfe7LkeyJOlupS8h7bjT+TXmZkDzOjZtfj7mdA7cbg0lRX3CuafhjIrpK8S",
+ "4HtYFldVkyVbrlg/s7kmaA7j45PvLQm+1bbn6ehgP8tVoBmGbv2yDQI1iQQze4AlHyN",
+ "3bwCUx79NAR7c68OPSp5ZabhZ9aBEr7rWNTO2oMY7zhbbbw7p6shSMxqE9K9nrTNucf",
+ "4j5RGb78TfuYSzrXn0z6tiAoWiRI81hGY3el9AEa9S+gN4x/AmzotHT2Hvj6lyBpE7q",
+ "4lwg30SXqZhEHNsl5LIXdyu7UNt0VTWebP3m7+WUL+hsnFW9xJe7UnzYngZsvWh14IE",
+ "1+tcqFeRuGqjRADRoRUJ8gL4UUSFQVrVVoV6JpwVcKsuBq5G0pABn0dLcQQQMViiVRj",
+ "hXwxuFySNSFcmbrs/coz4FUAaUYaOEt+l4V5V8vY71KyBvQPxRq/6lsSrG2FHvWDax"
+ };
+ /* roots 3-100 of the above */
+ const char *root[10][100] = {
+ {
+ "9163694094944489658600517465135586130944",
+ "936597377180979771960755204040", "948947857956884030956907",
+ "95727185767390496595", "133844854039712620", "967779611885360",
+ "20926191452627", "974139547476", "79203891950", "9784027073",
+ "1667309744", "365848129", "98268452", "31109156", "11275351",
+ "4574515", "2040800", "986985", "511525", "281431", "163096",
+ "98914", "62437", "40832", "27556", "19127", "13614", "9913",
+ "7367", "5577", "4294", "3357", "2662", "2138", "1738", "1428",
+ "1185", "993", "839", "715", "613", "530", "461", "403", "355",
+ "314", "279", "249", "224", "202", "182", "166", "151", "138",
+ "126", "116", "107", "99", "92", "85", "79", "74", "69", "65", "61",
+ "57", "54", "51", "48", "46", "43", "41", "39", "37", "36", "34",
+ "32", "31", "30", "28", "27", "26", "25", "24", "23", "23", "22",
+ "21", "20", "20", "19", "18", "18", "17", "17", "16", "16", "15"
+ }, {
+ "9534798256755061606359588498764080011382",
+ "964902943621813525741417593772", "971822399862464674540423",
+ "97646291566833512831", "136141536090599560", "982294733581430",
+ "21204945933335", "985810529393", "80066084985", "9881613813",
+ "1682654547", "368973625", "99051783", "31341581", "11354620",
+ "4604882", "2053633", "992879", "514434", "282959", "163942",
+ "99406", "62736", "41020", "27678", "19208", "13670", "9952",
+ "7395", "5598", "4310", "3369", "2671", "2145", "1744", "1433",
+ "1189", "996", "842", "717", "615", "531", "462", "404", "356",
+ "315", "280", "250", "224", "202", "183", "166", "151", "138",
+ "127", "116", "107", "99", "92", "85", "80", "74", "70", "65", "61",
+ "58", "54", "51", "48", "46", "43", "41", "39", "37", "36", "34",
+ "32", "31", "30", "29", "27", "26", "25", "24", "23", "23", "22",
+ "21", "20", "20", "19", "18", "18", "17", "17", "16", "16", "15"
+ }, {
+ "8398539113202579297642815367509019445624",
+ "877309458945432597462853440936", "900579899458998599215071",
+ "91643543761699761637", "128935656335800903", "936647990947203",
+ "20326748623514", "948988882684", "77342677787", "9573063447",
+ "1634096832", "359076114", "96569670", "30604705", "11103188",
+ "4508519", "2012897", "974160", "505193", "278105", "161251",
+ "97842", "61788", "40423", "27291", "18949", "13492", "9826",
+ "7305", "5532", "4260", "3332", "2642", "2123", "1726", "1418",
+ "1177", "986", "834", "710", "610", "527", "458", "401", "353",
+ "312", "278", "248", "223", "201", "181", "165", "150", "137",
+ "126", "116", "107", "99", "91", "85", "79", "74", "69", "65", "61",
+ "57", "54", "51", "48", "46", "43", "41", "39", "37", "35", "34",
+ "32", "31", "30", "28", "27", "26", "25", "24", "23", "22", "22",
+ "21", "20", "20", "19", "18", "18", "17", "17", "16", "16", "15"
+ }, {
+ "9559098494021810340217797724866627755195",
+ "966746709063325235560830083787", "973307706084821682248292",
+ "97770642291138756434", "136290128605981259", "983232784778520",
+ "21222944848922", "986563584410", "80121684894", "9887903837",
+ "1683643206", "369174929", "99102220", "31356542", "11359721",
+ "4606836", "2054458", "993259", "514621", "283057", "163997",
+ "99437", "62755", "41032", "27686", "19213", "13674", "9955",
+ "7397", "5599", "4311", "3370", "2672", "2146", "1744", "1433",
+ "1189", "996", "842", "717", "615", "532", "462", "404", "356",
+ "315", "280", "250", "224", "202", "183", "166", "151", "138",
+ "127", "116", "107", "99", "92", "86", "80", "74", "70", "65", "61",
+ "58", "54", "51", "48", "46", "43", "41", "39", "37", "36", "34",
+ "32", "31", "30", "29", "27", "26", "25", "24", "23", "23", "22",
+ "21", "20", "20", "19", "18", "18", "17", "17", "16", "16", "15"
+ }, {
+ "8839202025813295923132694443541993309220",
+ "911611499784863252820288596270", "928640961450376817534853",
+ "94017030509441723821", "131792686685970629", "954783483196511",
+ "20676214073400", "963660189823", "78428929840", "9696237956",
+ "1653495486", "363032624", "97562430", "30899570", "11203842",
+ "4547110", "2029216", "981661", "508897", "280051", "162331",
+ "98469", "62168", "40663", "27446", "19053", "13563", "9877",
+ "7341", "5558", "4280", "3347", "2654", "2132", "1733", "1424",
+ "1182", "990", "837", "713", "612", "529", "460", "402", "354",
+ "313", "279", "249", "223", "201", "182", "165", "150", "138",
+ "126", "116", "107", "99", "92", "85", "79", "74", "69", "65", "61",
+ "57", "54", "51", "48", "46", "43", "41", "39", "37", "36", "34",
+ "32", "31", "30", "28", "27", "26", "25", "24", "23", "23", "22",
+ "21", "20", "20", "19", "18", "18", "17", "17", "16", "16", "15"
+ }, {
+ "8338442683973420410660145045849076963795",
+ "872596990706967613912664152945", "896707843885562730147307",
+ "91315073695274540969", "128539440806486007", "934129001105825",
+ "20278149285734", "946946589774", "77191347471", "9555892093",
+ "1631391010", "358523975", "96431070", "30563524", "11089126",
+ "4503126", "2010616", "973111", "504675", "277833", "161100",
+ "97754", "61734", "40390", "27269", "18934", "13482", "9819",
+ "7300", "5528", "4257", "3330", "2641", "2122", "1725", "1417",
+ "1177", "986", "833", "710", "609", "527", "458", "401", "353",
+ "312", "278", "248", "222", "200", "181", "165", "150", "137",
+ "126", "116", "107", "99", "91", "85", "79", "74", "69", "65", "61",
+ "57", "54", "51", "48", "46", "43", "41", "39", "37", "35", "34",
+ "32", "31", "30", "28", "27", "26", "25", "24", "23", "22", "22",
+ "21", "20", "20", "19", "18", "18", "17", "17", "16", "16", "15"
+ }, {
+ "9122818552483814953977703257848970704164",
+ "933462289569511464780529972314", "946405863353935713909178",
+ "95513446972056321834", "133588658082928446",
+ "966158521967027", "20895030642048", "972833934108",
+ "79107381638", "9773098125", "1665590516", "365497822",
+ "98180628", "31083090", "11266459", "4571108", "2039360",
+ "986323", "511198", "281260", "163001", "98858",
+ "62404", "40811", "27543", "19117", "13608", "9908",
+ "7363", "5575", "4292", "3356", "2661", "2138",
+ "1737", "1428", "1185", "993", "839", "714", "613",
+ "530", "461", "403", "355", "314", "279", "249",
+ "224", "202", "182", "165", "151", "138", "126",
+ "116", "107", "99", "92", "85", "79", "74", "69",
+ "65", "61", "57", "54", "51", "48", "46", "43",
+ "41", "39", "37", "36", "34", "32", "31", "30",
+ "28", "27", "26", "25", "24", "23", "23", "22",
+ "21", "20", "20", "19", "18", "18", "17", "17",
+ "16", "16", "15"
+ }, {
+ "9151329724083804100369546479681933027521",
+ "935649419557299174433860420387", "948179413831316112751907",
+ "95662582675170358900", "133767426788182384",
+ "967289728859610", "20916775466497", "973745045600",
+ "79174731802", "9780725058", "1666790321", "365742295",
+ "98241919", "31101281", "11272665", "4573486", "2040365",
+ "986785", "511426", "281380", "163067", "98897",
+ "62427", "40826", "27552", "19124", "13612", "9911",
+ "7366", "5576", "4294", "3357", "2662", "2138",
+ "1738", "1428", "1185", "993", "839", "715", "613",
+ "530", "461", "403", "355", "314", "279", "249",
+ "224", "202", "182", "165", "151", "138", "126",
+ "116", "107", "99", "92", "85", "79", "74", "69",
+ "65", "61", "57", "54", "51", "48", "46", "43",
+ "41", "39", "37", "36", "34", "32", "31", "30",
+ "28", "27", "26", "25", "24", "23", "23", "22",
+ "21", "20", "20", "19", "18", "18", "17", "17",
+ "16", "16", "15"
+ }, {
+ "6839396355168045468586008471269923213531",
+ "752078770083218822016981965090", "796178899357307807726034",
+ "82700643015444840424", "118072966296549115",
+ "867224751770392", "18981881485802", "892288574037",
+ "73130030771", "9093989389", "1558462688", "343617470",
+ "92683740", "29448679", "10708016", "4356820", "1948676",
+ "944610", "490587", "270425", "156989", "95362",
+ "60284", "39477", "26675", "18536", "13208", "9627",
+ "7161", "5426", "4181", "3272", "2596", "2087",
+ "1697", "1395", "1159", "971", "821", "700", "601",
+ "520", "452", "396", "348", "308", "274", "245",
+ "220", "198", "179", "163", "148", "136", "124",
+ "114", "106", "98", "91", "84", "78", "73", "68",
+ "64", "60", "57", "53", "50", "48", "45", "43",
+ "41", "39", "37", "35", "34", "32", "31", "29",
+ "28", "27", "26", "25", "24", "23", "22", "22",
+ "21", "20", "19", "19", "18", "18", "17", "17",
+ "16", "16", "15"
+ }, {
+ "4788090721380022347683138981782307670424",
+ "575601315594614059890185238256", "642831903229558719812840",
+ "69196031110028430211", "101340693763170691",
+ "758683936560287", "16854690815260", "801767985909",
+ "66353290503", "8318415180", "1435359033", "318340531",
+ "86304307", "27544217", "10054988", "4105446", "1841996",
+ "895414", "466223", "257591", "149855", "91205",
+ "57758", "37886", "25639", "17842", "12730", "9290",
+ "6918", "5248", "4048", "3170", "2518", "2026",
+ "1649", "1357", "1128", "946", "800", "682", "586",
+ "507", "441", "387", "341", "302", "268", "240",
+ "215", "194", "176", "160", "146", "133", "122",
+ "112", "104", "96", "89", "83", "77", "72", "67",
+ "63", "59", "56", "53", "50", "47", "45", "42",
+ "40", "38", "36", "35", "33", "32", "30", "29",
+ "28", "27", "26", "25", "24", "23", "22", "21",
+ "21", "20", "19", "19", "18", "17", "17", "16",
+ "16", "15", "15"
+ }
+ };
+
+ if ((e = mp_init_multi(&a, &c, &r, NULL)) != MP_OKAY) {
+ return EXIT_FAILURE;
+ }
+#ifdef MP_8BIT
+ for (i = 0; i < 1; i++) {
+#else
+ for (i = 0; i < 10; i++) {
+#endif
+ mp_read_radix(&a, input[i], 64);
+#ifdef MP_8BIT
+ for (j = 3; j < 10; j++) {
+#else
+ for (j = 3; j < 100; j++) {
+#endif
+ mp_root_u32(&a, (uint32_t)j, &c);
+ mp_read_radix(&r, root[i][j-3], 10);
+ if (mp_cmp(&r, &c) != MP_EQ) {
+ fprintf(stderr, "mp_root_u32 failed at input #%d, root #%d\n", i, j);
+ goto LTM_ERR;
+ }
+ }
+ }
+ mp_clear_multi(&a, &c, &r, NULL);
+ return EXIT_SUCCESS;
+LTM_ERR:
+ mp_clear_multi(&a, &c, &r, NULL);
+ return EXIT_FAILURE;
+}
+
+static int test_s_mp_balance_mul(void)
+{
+ mp_int a, b, c;
+ mp_err e = MP_OKAY;
+
+ const char *na =
+ "4b0I5uMTujCysw+1OOuOyH2FX2WymrHUqi8BBDb7XpkV/4i7vXTbEYUy/kdIfCKu5jT5JEqYkdmnn3jAYo8XShPzNLxZx9yoLjxYRyptSuOI2B1DspvbIVYXY12sxPZ4/HCJ4Usm2MU5lO/006KnDMxuxiv1rm6YZJZ0eZU";
+ const char *nb = "3x9vs0yVi4hIq7poAeVcggC3WoRt0zRLKO";
+ const char *nc =
+ "HzrSq9WVt1jDTVlwUxSKqxctu2GVD+N8+SVGaPFRqdxyld6IxDBbj27BPJzYUdR96k3sWpkO8XnDBvupGPnehpQe4KlO/KmN1PjFov/UTZYM+LYzkFcBPyV6hkkL8ePC1rlFLAHzgJMBCXVp4mRqtkQrDsZXXlcqlbTFu69wF6zDEysiX2cAtn/kP9ldblJiwYPCD8hG";
+
+ if ((e = mp_init_multi(&a, &b, &c, NULL)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+
+ if ((e = mp_read_radix(&a, na, 64)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if ((e = mp_read_radix(&b, nb, 64)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+
+ if ((e = s_mp_balance_mul(&a, &b, &c)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+
+ if ((e = mp_read_radix(&b, nc, 64)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+
+ if (mp_cmp(&b, &c) != MP_EQ) {
+ goto LTM_ERR;
+ }
+
+ mp_clear_multi(&a, &b, &c, NULL);
+ return EXIT_SUCCESS;
+LTM_ERR:
+ mp_clear_multi(&a, &b, &c, NULL);
+ return EXIT_FAILURE;
+}
+
+#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1)
+static int test_s_mp_karatsuba_mul(void)
+{
+ mp_int a, b, c, d;
+ int size, err;
+
+ if ((err = mp_init_multi(&a, &b, &c, &d, NULL)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ for (size = MP_KARATSUBA_MUL_CUTOFF; size < MP_KARATSUBA_MUL_CUTOFF + 20; size++) {
+ if ((err = mp_rand(&a, size)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if ((err = mp_rand(&b, size)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if ((err = s_mp_karatsuba_mul(&a, &b, &c)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if ((err = s_mp_mul(&a,&b,&d)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if (mp_cmp(&c, &d) != MP_EQ) {
+ fprintf(stderr, "Karatsuba multiplication failed at size %d\n", size);
+ goto LTM_ERR;
+ }
+ }
+
+ mp_clear_multi(&a, &b, &c, &d, NULL);
+ return EXIT_SUCCESS;
+LTM_ERR:
+ mp_clear_multi(&a, &b, &c, &d, NULL);
+ return EXIT_FAILURE;
+}
+
+static int test_s_mp_karatsuba_sqr(void)
+{
+ mp_int a, b, c;
+ int size, err;
+
+ if ((err = mp_init_multi(&a, &b, &c, NULL)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ for (size = MP_KARATSUBA_SQR_CUTOFF; size < MP_KARATSUBA_SQR_CUTOFF + 20; size++) {
+ if ((err = mp_rand(&a, size)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if ((err = s_mp_karatsuba_sqr(&a, &b)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if ((err = s_mp_sqr(&a, &c)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if (mp_cmp(&b, &c) != MP_EQ) {
+ fprintf(stderr, "Karatsuba squaring failed at size %d\n", size);
+ goto LTM_ERR;
+ }
+ }
+
+ mp_clear_multi(&a, &b, &c, NULL);
+ return EXIT_SUCCESS;
+LTM_ERR:
+ mp_clear_multi(&a, &b, &c, NULL);
+ return EXIT_FAILURE;
+}
+
+static int test_s_mp_toom_mul(void)
+{
+ mp_int a, b, c, d;
+ int size, err;
+
+#if (MP_DIGIT_BIT == 60)
+ int tc_cutoff;
+#endif
+
+ if ((err = mp_init_multi(&a, &b, &c, &d, NULL)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ /* This number construction is limb-size specific */
+#if (MP_DIGIT_BIT == 60)
+ if ((err = mp_rand(&a, 1196)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if ((err = mp_mul_2d(&a,71787 - mp_count_bits(&a), &a)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+
+ if ((err = mp_rand(&b, 1338)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if ((err = mp_mul_2d(&b, 80318 - mp_count_bits(&b), &b)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if ((err = mp_mul_2d(&b, 6310, &b)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if ((err = mp_2expt(&c, 99000 - 1000)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if ((err = mp_add(&b, &c, &b)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+
+ tc_cutoff = TOOM_MUL_CUTOFF;
+ TOOM_MUL_CUTOFF = INT_MAX;
+ if ((err = mp_mul(&a, &b, &c)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ TOOM_MUL_CUTOFF = tc_cutoff;
+ if ((err = mp_mul(&a, &b, &d)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if (mp_cmp(&c, &d) != MP_EQ) {
+ fprintf(stderr, "Toom-Cook 3-way multiplication failed for edgecase f1 * f2\n");
+ goto LTM_ERR;
+ }
+#endif
+
+ for (size = MP_TOOM_MUL_CUTOFF; size < MP_TOOM_MUL_CUTOFF + 20; size++) {
+ if ((err = mp_rand(&a, size)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if ((err = mp_rand(&b, size)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if ((err = s_mp_toom_mul(&a, &b, &c)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if ((err = s_mp_mul(&a,&b,&d)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if (mp_cmp(&c, &d) != MP_EQ) {
+ fprintf(stderr, "Toom-Cook 3-way multiplication failed at size %d\n", size);
+ goto LTM_ERR;
+ }
+ }
+
+ mp_clear_multi(&a, &b, &c, &d, NULL);
+ return EXIT_SUCCESS;
+LTM_ERR:
+ mp_clear_multi(&a, &b, &c, &d, NULL);
+ return EXIT_FAILURE;
+}
+
+static int test_s_mp_toom_sqr(void)
+{
+ mp_int a, b, c;
+ int size, err;
+
+ if ((err = mp_init_multi(&a, &b, &c, NULL)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ for (size = MP_TOOM_SQR_CUTOFF; size < MP_TOOM_SQR_CUTOFF + 20; size++) {
+ if ((err = mp_rand(&a, size)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if ((err = s_mp_toom_sqr(&a, &b)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if ((err = s_mp_sqr(&a, &c)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if (mp_cmp(&b, &c) != MP_EQ) {
+ fprintf(stderr, "Toom-Cook 3-way squaring failed at size %d\n", size);
+ goto LTM_ERR;
+ }
+ }
+
+ mp_clear_multi(&a, &b, &c, NULL);
+ return EXIT_SUCCESS;
+LTM_ERR:
+ mp_clear_multi(&a, &b, &c, NULL);
+ return EXIT_FAILURE;
+}
+
+static int test_mp_read_write_ubin(void)
+{
+ mp_int a, b, c;
+ int err;
+ size_t size, len;
+ unsigned char *buf = NULL;
+
+ if ((err = mp_init_multi(&a, &b, &c, NULL)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+
+ if ((err = mp_rand(&a, 15)) != MP_OKAY) goto LTM_ERR;
+ if ((err = mp_neg(&a, &b)) != MP_OKAY) goto LTM_ERR;
+
+ size = mp_ubin_size(&a);
+ printf("mp_to_ubin_size %zu\n", size);
+ buf = (unsigned char *)malloc(sizeof(*buf) * size);
+ if (buf == NULL) {
+ fprintf(stderr, "test_read_write_binaries (u) failed to allocate %zu bytes\n",
+ sizeof(*buf) * size);
+ goto LTM_ERR;
+ }
+
+ if ((err = mp_to_ubin(&a, buf, size, &len)) != MP_OKAY) goto LTM_ERR;
+ printf("mp_to_ubin len = %zu\n", len);
+
+ if ((err = mp_from_ubin(&c, buf, len)) != MP_OKAY) goto LTM_ERR;
+
+ if (mp_cmp(&a, &c) != MP_EQ) {
+ fprintf(stderr, "to/from ubin cycle failed\n");
+ goto LTM_ERR;
+ }
+ free(buf);
+ mp_clear_multi(&a, &b, &c, NULL);
+ return EXIT_SUCCESS;
+LTM_ERR:
+ free(buf);
+ mp_clear_multi(&a, &b, &c, NULL);
+ return EXIT_FAILURE;
+}
+
+static int test_mp_read_write_sbin(void)
+{
+ mp_int a, b, c;
+ int err;
+ size_t size, len;
+ unsigned char *buf = NULL;
+
+ if ((err = mp_init_multi(&a, &b, &c, NULL)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+
+ if ((err = mp_rand(&a, 15)) != MP_OKAY) goto LTM_ERR;
+ if ((err = mp_neg(&a, &b)) != MP_OKAY) goto LTM_ERR;
+
+ size = mp_sbin_size(&a);
+ printf("mp_to_sbin_size %zu\n", size);
+ buf = (unsigned char *)malloc(sizeof(*buf) * size);
+ if (buf == NULL) {
+ fprintf(stderr, "test_read_write_binaries (s) failed to allocate %zu bytes\n",
+ sizeof(*buf) * size);
+ goto LTM_ERR;
+ }
+
+ if ((err = mp_to_sbin(&b, buf, size, &len)) != MP_OKAY) goto LTM_ERR;
+ printf("mp_to_sbin len = %zu\n", len);
+
+ if ((err = mp_from_sbin(&c, buf, len)) != MP_OKAY) goto LTM_ERR;
+
+ if (mp_cmp(&b, &c) != MP_EQ) {
+ fprintf(stderr, "to/from ubin cycle failed\n");
+ goto LTM_ERR;
+ }
+
+ free(buf);
+ mp_clear_multi(&a, &b, &c, NULL);
+ return EXIT_SUCCESS;
+LTM_ERR:
+ free(buf);
+ mp_clear_multi(&a, &b, &c, NULL);
+ return EXIT_FAILURE;
+}
+
+static int test_mp_pack_unpack(void)
+{
+ mp_int a, b;
+ int err;
+ size_t written, count;
+ unsigned char *buf = NULL;
+
+ mp_order order = MP_LSB_FIRST;
+ mp_endian endianess = MP_NATIVE_ENDIAN;
+
+ if ((err = mp_init_multi(&a, &b, NULL)) != MP_OKAY) goto LTM_ERR;
+ if ((err = mp_rand(&a, 15)) != MP_OKAY) goto LTM_ERR;
+
+ count = mp_pack_count(&a, 0, 1);
+
+ buf = (unsigned char *)malloc(count);
+ if (buf == NULL) {
+ fprintf(stderr, "test_pack_unpack failed to allocate\n");
+ goto LTM_ERR;
+ }
+
+ if ((err = mp_pack((void *)buf, count, &written, order, 1,
+ endianess, 0, &a)) != MP_OKAY) goto LTM_ERR;
+ if ((err = mp_unpack(&b, count, order, 1,
+ endianess, 0, (const void *)buf)) != MP_OKAY) goto LTM_ERR;
+
+ if (mp_cmp(&a, &b) != MP_EQ) {
+ fprintf(stderr, "pack/unpack cycle failed\n");
+ goto LTM_ERR;
+ }
+
+ free(buf);
+ mp_clear_multi(&a, &b, NULL);
+ return EXIT_SUCCESS;
+LTM_ERR:
+ free(buf);
+ mp_clear_multi(&a, &b, NULL);
+ return EXIT_FAILURE;
+}
+
+static int unit_tests(int argc, char **argv)
+{
+ static const struct {
+ const char *name;
+ int (*fn)(void);
+ } test[] = {
+#define T0(n) { #n, test_##n }
+#define T1(n, o) { #n, MP_HAS(o) ? test_##n : NULL }
+#define T2(n, o1, o2) { #n, MP_HAS(o1) && MP_HAS(o2) ? test_##n : NULL }
+ T0(feature_detection),
+ T0(trivial_stuff),
+ T2(mp_get_set_i32, MP_GET_I32, MP_GET_MAG_U32),
+ T2(mp_get_set_i64, MP_GET_I64, MP_GET_MAG_U64),
+ T1(mp_and, MP_AND),
+ T1(mp_cnt_lsb, MP_CNT_LSB),
+ T1(mp_complement, MP_COMPLEMENT),
+ T1(mp_decr, MP_DECR),
+ T1(mp_div_3, MP_DIV_3),
+ T1(mp_dr_reduce, MP_DR_REDUCE),
+ T2(mp_pack_unpack,MP_PACK, MP_UNPACK),
+ T2(mp_fread_fwrite, MP_FREAD, MP_FWRITE),
+ T1(mp_get_u32, MP_GET_I32),
+ T1(mp_get_u64, MP_GET_I64),
+ T1(mp_get_ul, MP_GET_L),
+ T1(mp_log_u32, MP_LOG_U32),
+ T1(mp_incr, MP_INCR),
+ T1(mp_invmod, MP_INVMOD),
+ T1(mp_is_square, MP_IS_SQUARE),
+ T1(mp_kronecker, MP_KRONECKER),
+ T1(mp_montgomery_reduce, MP_MONTGOMERY_REDUCE),
+ T1(mp_root_u32, MP_ROOT_U32),
+ T1(mp_or, MP_OR),
+ T1(mp_prime_is_prime, MP_PRIME_IS_PRIME),
+ T1(mp_prime_next_prime, MP_PRIME_NEXT_PRIME),
+ T1(mp_prime_rand, MP_PRIME_RAND),
+ T1(mp_rand, MP_RAND),
+ T1(mp_read_radix, MP_READ_RADIX),
+ T1(mp_read_write_ubin, MP_TO_UBIN),
+ T1(mp_read_write_sbin, MP_TO_SBIN),
+ T1(mp_reduce_2k, MP_REDUCE_2K),
+ T1(mp_reduce_2k_l, MP_REDUCE_2K_L),
+#if defined(__STDC_IEC_559__) || defined(__GCC_IEC_559)
+ T1(mp_set_double, MP_SET_DOUBLE),
+#endif
+ T1(mp_signed_rsh, MP_SIGNED_RSH),
+ T1(mp_sqrt, MP_SQRT),
+ T1(mp_sqrtmod_prime, MP_SQRTMOD_PRIME),
+ T1(mp_xor, MP_XOR),
+ T1(s_mp_balance_mul, S_MP_BALANCE_MUL),
+ T1(s_mp_karatsuba_mul, S_MP_KARATSUBA_MUL),
+ T1(s_mp_karatsuba_sqr, S_MP_KARATSUBA_SQR),
+ T1(s_mp_toom_mul, S_MP_TOOM_MUL),
+ T1(s_mp_toom_sqr, S_MP_TOOM_SQR)
+#undef T2
+#undef T1
+ };
+ unsigned long i, ok, fail, nop;
+ uint64_t t;
+ int j;
+
+ ok = fail = nop = 0;
+
+ t = (uint64_t)time(NULL);
+ printf("SEED: 0x%" PRIx64 "\n\n", t);
+ s_mp_rand_jenkins_init(t);
+ mp_rand_source(s_mp_rand_jenkins);
+
+ for (i = 0; i < sizeof(test) / sizeof(test[0]); ++i) {
+ if (argc > 1) {
+ for (j = 1; j < argc; ++j) {
+ if (strstr(test[i].name, argv[j]) != NULL) {
+ break;
+ }
+ }
+ if (j == argc) continue;
+ }
+ printf("TEST %s\n\n", test[i].name);
+ if (test[i].fn == NULL) {
+ nop++;
+ printf("NOP %s\n\n", test[i].name);
+ } else if (test[i].fn() == EXIT_SUCCESS) {
+ ok++;
+ printf("\n\n");
+ } else {
+ fail++;
+ printf("\n\nFAIL %s\n\n", test[i].name);
+ }
+ }
+ printf("Tests OK/NOP/FAIL: %lu/%lu/%lu\n", ok, nop, fail);
+
+ if (fail != 0) return EXIT_FAILURE;
+ else return EXIT_SUCCESS;
+}
+
+int main(int argc, char **argv)
+{
+ print_header();
+
+ return unit_tests(argc, argv);
+}
ADDED libtommath/helper.pl
Index: libtommath/helper.pl
==================================================================
--- /dev/null
+++ libtommath/helper.pl
@@ -0,0 +1,482 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+
+use Getopt::Long;
+use File::Find 'find';
+use File::Basename 'basename';
+use File::Glob 'bsd_glob';
+
+sub read_file {
+ my $f = shift;
+ open my $fh, "<", $f or die "FATAL: read_rawfile() cannot open file '$f': $!";
+ binmode $fh;
+ return do { local $/; <$fh> };
+}
+
+sub write_file {
+ my ($f, $data) = @_;
+ die "FATAL: write_file() no data" unless defined $data;
+ open my $fh, ">", $f or die "FATAL: write_file() cannot open file '$f': $!";
+ binmode $fh;
+ print $fh $data or die "FATAL: write_file() cannot write to '$f': $!";
+ close $fh or die "FATAL: write_file() cannot close '$f': $!";
+ return;
+}
+
+sub sanitize_comments {
+ my($content) = @_;
+ $content =~ s{/\*(.*?)\*/}{my $x=$1; $x =~ s/\w/x/g; "/*$x*/";}egs;
+ return $content;
+}
+
+sub check_source {
+ my @all_files = (
+ bsd_glob("makefile*"),
+ bsd_glob("*.{h,c,sh,pl}"),
+ bsd_glob("*/*.{h,c,sh,pl}"),
+ );
+
+ my $fails = 0;
+ for my $file (sort @all_files) {
+ my $troubles = {};
+ my $lineno = 1;
+ my $content = read_file($file);
+ $content = sanitize_comments $content;
+ push @{$troubles->{crlf_line_end}}, '?' if $content =~ /\r/;
+ for my $l (split /\n/, $content) {
+ push @{$troubles->{merge_conflict}}, $lineno if $l =~ /^(<<<<<<<|=======|>>>>>>>)([^<=>]|$)/;
+ push @{$troubles->{trailing_space}}, $lineno if $l =~ / $/;
+ push @{$troubles->{tab}}, $lineno if $l =~ /\t/ && basename($file) !~ /^makefile/i;
+ push @{$troubles->{non_ascii_char}}, $lineno if $l =~ /[^[:ascii:]]/;
+ push @{$troubles->{cpp_comment}}, $lineno if $file =~ /\.(c|h)$/ && ($l =~ /\s\/\// || $l =~ /\/\/\s/);
+ # we prefer using MP_MALLOC, MP_FREE, MP_REALLOC, MP_CALLOC ...
+ push @{$troubles->{unwanted_malloc}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bmalloc\s*\(/;
+ push @{$troubles->{unwanted_realloc}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\brealloc\s*\(/;
+ push @{$troubles->{unwanted_calloc}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bcalloc\s*\(/;
+ push @{$troubles->{unwanted_free}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bfree\s*\(/;
+ # and we probably want to also avoid the following
+ push @{$troubles->{unwanted_memcpy}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bmemcpy\s*\(/;
+ push @{$troubles->{unwanted_memset}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bmemset\s*\(/;
+ push @{$troubles->{unwanted_memcpy}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bmemcpy\s*\(/;
+ push @{$troubles->{unwanted_memmove}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bmemmove\s*\(/;
+ push @{$troubles->{unwanted_memcmp}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bmemcmp\s*\(/;
+ push @{$troubles->{unwanted_strcmp}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bstrcmp\s*\(/;
+ push @{$troubles->{unwanted_strcpy}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bstrcpy\s*\(/;
+ push @{$troubles->{unwanted_strncpy}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bstrncpy\s*\(/;
+ push @{$troubles->{unwanted_clock}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bclock\s*\(/;
+ push @{$troubles->{unwanted_qsort}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bqsort\s*\(/;
+ push @{$troubles->{sizeof_no_brackets}}, $lineno if $file =~ /^[^\/]+\.c$/ && $l =~ /\bsizeof\s*[^\(]/;
+ if ($file =~ m|^[^\/]+\.c$| && $l =~ /^static(\s+[a-zA-Z0-9_]+)+\s+([a-zA-Z0-9_]+)\s*\(/) {
+ my $funcname = $2;
+ # static functions should start with s_
+ push @{$troubles->{staticfunc_name}}, "$lineno($funcname)" if $funcname !~ /^s_/;
+ }
+ $lineno++;
+ }
+ for my $k (sort keys %$troubles) {
+ warn "[$k] $file line:" . join(",", @{$troubles->{$k}}) . "\n";
+ $fails++;
+ }
+ }
+
+ warn( $fails > 0 ? "check-source: FAIL $fails\n" : "check-source: PASS\n" );
+ return $fails;
+}
+
+sub check_comments {
+ my $fails = 0;
+ my $first_comment = <<'MARKER';
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+MARKER
+ #my @all_files = (bsd_glob("*.{h,c}"), bsd_glob("*/*.{h,c}"));
+ my @all_files = (bsd_glob("*.{h,c}"));
+ for my $f (@all_files) {
+ my $txt = read_file($f);
+ if ($txt !~ /\Q$first_comment\E/s) {
+ warn "[first_comment] $f\n";
+ $fails++;
+ }
+ }
+ warn( $fails > 0 ? "check-comments: FAIL $fails\n" : "check-comments: PASS\n" );
+ return $fails;
+}
+
+sub check_doc {
+ my $fails = 0;
+ my $tex = read_file('doc/bn.tex');
+ my $tmh = read_file('tommath.h');
+ my @functions = $tmh =~ /\n\s*[a-zA-Z0-9_* ]+?(mp_[a-z0-9_]+)\s*\([^\)]+\)\s*;/sg;
+ my @macros = $tmh =~ /\n\s*#define\s+([a-z0-9_]+)\s*\([^\)]+\)/sg;
+ for my $n (sort @functions) {
+ (my $nn = $n) =~ s/_/\\_/g; # mp_sub_d >> mp\_sub\_d
+ if ($tex !~ /index\Q{$nn}\E/) {
+ warn "[missing_doc_for_function] $n\n";
+ $fails++
+ }
+ }
+ for my $n (sort @macros) {
+ (my $nn = $n) =~ s/_/\\_/g; # mp_iszero >> mp\_iszero
+ if ($tex !~ /index\Q{$nn}\E/) {
+ warn "[missing_doc_for_macro] $n\n";
+ $fails++
+ }
+ }
+ warn( $fails > 0 ? "check_doc: FAIL $fails\n" : "check-doc: PASS\n" );
+ return $fails;
+}
+
+sub prepare_variable {
+ my ($varname, @list) = @_;
+ my $output = "$varname=";
+ my $len = length($output);
+ foreach my $obj (sort @list) {
+ $len = $len + length $obj;
+ $obj =~ s/\*/\$/;
+ if ($len > 100) {
+ $output .= "\\\n";
+ $len = length $obj;
+ }
+ $output .= $obj . ' ';
+ }
+ $output =~ s/ $//;
+ return $output;
+}
+
+sub prepare_msvc_files_xml {
+ my ($all, $exclude_re, $targets) = @_;
+ my $last = [];
+ my $depth = 2;
+
+ # sort files in the same order as visual studio (ugly, I know)
+ my @parts = ();
+ for my $orig (@$all) {
+ my $p = $orig;
+ $p =~ s|/|/~|g;
+ $p =~ s|/~([^/]+)$|/$1|g;
+ my @l = map { sprintf "% -99s", $_ } split /\//, $p;
+ push @parts, [ $orig, join(':', @l) ];
+ }
+ my @sorted = map { $_->[0] } sort { $a->[1] cmp $b->[1] } @parts;
+
+ my $files = "\r\n";
+ for my $full (@sorted) {
+ my @items = split /\//, $full; # split by '/'
+ $full =~ s|/|\\|g; # replace '/' bt '\'
+ shift @items; # drop first one (src)
+ pop @items; # drop last one (filename.ext)
+ my $current = \@items;
+ if (join(':', @$current) ne join(':', @$last)) {
+ my $common = 0;
+ $common++ while ($last->[$common] && $current->[$common] && $last->[$common] eq $current->[$common]);
+ my $back = @$last - $common;
+ if ($back > 0) {
+ $files .= ("\t" x --$depth) . "\r\n" for (1..$back);
+ }
+ my $fwd = [ @$current ]; splice(@$fwd, 0, $common);
+ for my $i (0..scalar(@$fwd) - 1) {
+ $files .= ("\t" x $depth) . "[$i]\"\r\n";
+ $files .= ("\t" x $depth) . "\t>\r\n";
+ $depth++;
+ }
+ $last = $current;
+ }
+ $files .= ("\t" x $depth) . "\r\n";
+ if ($full =~ $exclude_re) {
+ for (@$targets) {
+ $files .= ("\t" x $depth) . "\t\r\n";
+ $files .= ("\t" x $depth) . "\t\t\r\n";
+ $files .= ("\t" x $depth) . "\t\r\n";
+ }
+ }
+ $files .= ("\t" x $depth) . "\r\n";
+ }
+ $files .= ("\t" x --$depth) . "\r\n" for (@$last);
+ $files .= "\t";
+ return $files;
+}
+
+sub patch_file {
+ my ($content, @variables) = @_;
+ for my $v (@variables) {
+ if ($v =~ /^([A-Z0-9_]+)\s*=.*$/si) {
+ my $name = $1;
+ $content =~ s/\n\Q$name\E\b.*?[^\\]\n/\n$v\n/s;
+ }
+ else {
+ die "patch_file failed: " . substr($v, 0, 30) . "..";
+ }
+ }
+ return $content;
+}
+
+sub process_makefiles {
+ my $write = shift;
+ my $changed_count = 0;
+ my @o = map { my $x = $_; $x =~ s/\.c$/.o/; $x } bsd_glob("*.c");
+ my @all = bsd_glob("*.{c,h}");
+
+ my $var_o = prepare_variable("OBJECTS", @o);
+ (my $var_obj = $var_o) =~ s/\.o\b/.obj/sg;
+
+ # update MSVC project files
+ my $msvc_files = prepare_msvc_files_xml(\@all, qr/NOT_USED_HERE/, ['Debug|Win32', 'Release|Win32', 'Debug|x64', 'Release|x64']);
+ for my $m (qw/libtommath_VS2008.vcproj/) {
+ my $old = read_file($m);
+ my $new = $old;
+ $new =~ s|.*|$msvc_files|s;
+ if ($old ne $new) {
+ write_file($m, $new) if $write;
+ warn "changed: $m\n";
+ $changed_count++;
+ }
+ }
+
+ # update OBJECTS + HEADERS in makefile*
+ for my $m (qw/ makefile makefile.shared makefile_include.mk makefile.msvc makefile.unix makefile.mingw /) {
+ my $old = read_file($m);
+ my $new = $m eq 'makefile.msvc' ? patch_file($old, $var_obj)
+ : patch_file($old, $var_o);
+ if ($old ne $new) {
+ write_file($m, $new) if $write;
+ warn "changed: $m\n";
+ $changed_count++;
+ }
+ }
+
+ if ($write) {
+ return 0; # no failures
+ }
+ else {
+ warn( $changed_count > 0 ? "check-makefiles: FAIL $changed_count\n" : "check-makefiles: PASS\n" );
+ return $changed_count;
+ }
+}
+
+sub draw_func
+{
+ my ($deplist, $depmap, $out, $indent, $funcslist) = @_;
+ my @funcs = split ',', $funcslist;
+ # try this if you want to have a look at a minimized version of the callgraph without all the trivial functions
+ #if ($deplist =~ /$funcs[0]/ || $funcs[0] =~ /BN_MP_(ADD|SUB|CLEAR|CLEAR_\S+|DIV|MUL|COPY|ZERO|GROW|CLAMP|INIT|INIT_\S+|SET|ABS|CMP|CMP_D|EXCH)_C/) {
+ if ($deplist =~ /$funcs[0]/) {
+ return $deplist;
+ } else {
+ $deplist = $deplist . $funcs[0];
+ }
+ if ($indent == 0) {
+ } elsif ($indent >= 1) {
+ print {$out} '| ' x ($indent - 1) . '+--->';
+ }
+ print {$out} $funcs[0] . "\n";
+ shift @funcs;
+ my $olddeplist = $deplist;
+ foreach my $i (@funcs) {
+ $deplist = draw_func($deplist, $depmap, $out, $indent + 1, ${$depmap}{$i}) if exists ${$depmap}{$i};
+ }
+ return $olddeplist;
+}
+
+sub update_dep
+{
+ #open class file and write preamble
+ open(my $class, '>', 'tommath_class.h') or die "Couldn't open tommath_class.h for writing\n";
+ print {$class} << 'EOS';
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#if !(defined(LTM1) && defined(LTM2) && defined(LTM3))
+#define LTM_INSIDE
+#if defined(LTM2)
+# define LTM3
+#endif
+#if defined(LTM1)
+# define LTM2
+#endif
+#define LTM1
+#if defined(LTM_ALL)
+EOS
+
+ foreach my $filename (glob 'bn*.c') {
+ my $define = $filename;
+
+ print "Processing $filename\n";
+
+ # convert filename to upper case so we can use it as a define
+ $define =~ tr/[a-z]/[A-Z]/;
+ $define =~ tr/\./_/;
+ print {$class} "# define $define\n";
+
+ # now copy text and apply #ifdef as required
+ my $apply = 0;
+ open(my $src, '<', $filename);
+ open(my $out, '>', 'tmp');
+
+ # first line will be the #ifdef
+ my $line = <$src>;
+ if ($line =~ /include/) {
+ print {$out} $line;
+ } else {
+ print {$out} << "EOS";
+#include "tommath_private.h"
+#ifdef $define
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+$line
+EOS
+ $apply = 1;
+ }
+ while (<$src>) {
+ if ($_ !~ /tommath\.h/) {
+ print {$out} $_;
+ }
+ }
+ if ($apply == 1) {
+ print {$out} "#endif\n";
+ }
+ close $src;
+ close $out;
+
+ unlink $filename;
+ rename 'tmp', $filename;
+ }
+ print {$class} "#endif\n#endif\n";
+
+ # now do classes
+ my %depmap;
+ foreach my $filename (glob 'bn*.c') {
+ my $content;
+ if ($filename =~ "bn_deprecated.c") {
+ open(my $src, '<', $filename) or die "Can't open source file!\n";
+ read $src, $content, -s $src;
+ close $src;
+ } else {
+ my $cc = $ENV{'CC'} || 'gcc';
+ $content = `$cc -E -x c -DLTM_ALL $filename`;
+ $content =~ s/^# 1 "$filename".*?^# 2 "$filename"//ms;
+ }
+
+ # convert filename to upper case so we can use it as a define
+ $filename =~ tr/[a-z]/[A-Z]/;
+ $filename =~ tr/\./_/;
+
+ print {$class} "#if defined($filename)\n";
+ my $list = $filename;
+
+ # strip comments
+ $content =~ s{/\*.*?\*/}{}gs;
+
+ # scan for mp_* and make classes
+ my @deps = ();
+ foreach my $line (split /\n/, $content) {
+ while ($line =~ /(fast_)?(s_)?mp\_[a-z_0-9]*((?=\;)|(?=\())|(?<=\()mp\_[a-z_0-9]*(?=\()/g) {
+ my $a = $&;
+ next if $a eq "mp_err";
+ $a =~ tr/[a-z]/[A-Z]/;
+ $a = 'BN_' . $a . '_C';
+ push @deps, $a;
+ }
+ }
+ @deps = sort(@deps);
+ foreach my $a (@deps) {
+ if ($list !~ /$a/) {
+ print {$class} "# define $a\n";
+ }
+ $list = $list . ',' . $a;
+ }
+ $depmap{$filename} = $list;
+
+ print {$class} "#endif\n\n";
+ }
+
+ print {$class} << 'EOS';
+#ifdef LTM_INSIDE
+#undef LTM_INSIDE
+#ifdef LTM3
+# define LTM_LAST
+#endif
+
+#include "tommath_superclass.h"
+#include "tommath_class.h"
+#else
+# define LTM_LAST
+#endif
+EOS
+ close $class;
+
+ #now let's make a cool call graph...
+
+ open(my $out, '>', 'callgraph.txt');
+ foreach (sort keys %depmap) {
+ draw_func("", \%depmap, $out, 0, $depmap{$_});
+ print {$out} "\n\n";
+ }
+ close $out;
+
+ return 0;
+}
+
+sub generate_def {
+ my @files = split /\n/, `git ls-files`;
+ @files = grep(/\.c/, @files);
+ @files = map { my $x = $_; $x =~ s/^bn_|\.c$//g; $x; } @files;
+ @files = grep(!/mp_radix_smap/, @files);
+
+ push(@files, qw(mp_set_int mp_set_long mp_set_long_long mp_get_int mp_get_long mp_get_long_long mp_init_set_int));
+
+ my $files = join("\n ", sort(grep(/^mp_/, @files)));
+ write_file "tommath.def", "; libtommath
+;
+; Use this command to produce a 32-bit .lib file, for use in any MSVC version
+; lib -machine:X86 -name:libtommath.dll -def:tommath.def -out:tommath.lib
+; Use this command to produce a 64-bit .lib file, for use in any MSVC version
+; lib -machine:X64 -name:libtommath.dll -def:tommath.def -out:tommath.lib
+;
+EXPORTS
+ $files
+";
+ return 0;
+}
+
+sub die_usage {
+ die <<"MARKER";
+usage: $0 -s OR $0 --check-source
+ $0 -o OR $0 --check-comments
+ $0 -m OR $0 --check-makefiles
+ $0 -a OR $0 --check-all
+ $0 -u OR $0 --update-files
+MARKER
+}
+
+GetOptions( "s|check-source" => \my $check_source,
+ "o|check-comments" => \my $check_comments,
+ "m|check-makefiles" => \my $check_makefiles,
+ "d|check-doc" => \my $check_doc,
+ "a|check-all" => \my $check_all,
+ "u|update-files" => \my $update_files,
+ "h|help" => \my $help
+ ) or die_usage;
+
+my $failure;
+$failure ||= check_source() if $check_all || $check_source;
+$failure ||= check_comments() if $check_all || $check_comments;
+$failure ||= check_doc() if $check_doc; # temporarily excluded from --check-all
+$failure ||= process_makefiles(0) if $check_all || $check_makefiles;
+$failure ||= process_makefiles(1) if $update_files;
+$failure ||= update_dep() if $update_files;
+$failure ||= generate_def() if $update_files;
+
+die_usage unless defined $failure;
+exit $failure ? 1 : 0;
ADDED libtommath/libtommath.pc.in
Index: libtommath/libtommath.pc.in
==================================================================
--- /dev/null
+++ libtommath/libtommath.pc.in
@@ -0,0 +1,10 @@
+prefix=@to-be-replaced@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+Name: LibTomMath
+Description: public domain library for manipulating large integer numbers
+Version: @to-be-replaced@
+Libs: -L${libdir} -ltommath
+Cflags: -I${includedir}
ADDED libtommath/libtommath_VS2008.sln
Index: libtommath/libtommath_VS2008.sln
==================================================================
--- /dev/null
+++ libtommath/libtommath_VS2008.sln
@@ -0,0 +1,29 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tommath", "libtommath_VS2008.vcproj", "{42109FEE-B0B9-4FCD-9E56-2863BF8C55D2}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {42109FEE-B0B9-4FCD-9E56-2863BF8C55D2}.Debug|Win32.ActiveCfg = Debug|Win32
+ {42109FEE-B0B9-4FCD-9E56-2863BF8C55D2}.Debug|Win32.Build.0 = Debug|Win32
+ {42109FEE-B0B9-4FCD-9E56-2863BF8C55D2}.Debug|x64.ActiveCfg = Debug|x64
+ {42109FEE-B0B9-4FCD-9E56-2863BF8C55D2}.Debug|x64.Build.0 = Debug|x64
+ {42109FEE-B0B9-4FCD-9E56-2863BF8C55D2}.Release|Win32.ActiveCfg = Release|Win32
+ {42109FEE-B0B9-4FCD-9E56-2863BF8C55D2}.Release|Win32.Build.0 = Release|Win32
+ {42109FEE-B0B9-4FCD-9E56-2863BF8C55D2}.Release|x64.ActiveCfg = Release|x64
+ {42109FEE-B0B9-4FCD-9E56-2863BF8C55D2}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {83B84178-7B4F-4B78-9C5D-17B8201D5B61}
+ EndGlobalSection
+EndGlobal
ADDED libtommath/libtommath_VS2008.vcproj
Index: libtommath/libtommath_VS2008.vcproj
==================================================================
--- /dev/null
+++ libtommath/libtommath_VS2008.vcproj
@@ -0,0 +1,966 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
ADDED libtommath/makefile
Index: libtommath/makefile
==================================================================
--- /dev/null
+++ libtommath/makefile
@@ -0,0 +1,165 @@
+#Makefile for GCC
+#
+#Tom St Denis
+
+ifeq ($V,1)
+silent=
+else
+silent=@
+endif
+
+#default files to install
+ifndef LIBNAME
+ LIBNAME=libtommath.a
+endif
+
+coverage: LIBNAME:=-Wl,--whole-archive $(LIBNAME) -Wl,--no-whole-archive
+
+include makefile_include.mk
+
+%.o: %.c $(HEADERS)
+ifneq ($V,1)
+ @echo " * ${CC} $@"
+endif
+ ${silent} ${CC} -c ${LTM_CFLAGS} $< -o $@
+
+LCOV_ARGS=--directory .
+
+#START_INS
+OBJECTS=bn_cutoffs.o bn_deprecated.o bn_mp_2expt.o bn_mp_abs.o bn_mp_add.o bn_mp_add_d.o bn_mp_addmod.o \
+bn_mp_and.o bn_mp_clamp.o bn_mp_clear.o bn_mp_clear_multi.o bn_mp_cmp.o bn_mp_cmp_d.o bn_mp_cmp_mag.o \
+bn_mp_cnt_lsb.o bn_mp_complement.o bn_mp_copy.o bn_mp_count_bits.o bn_mp_decr.o bn_mp_div.o bn_mp_div_2.o \
+bn_mp_div_2d.o bn_mp_div_3.o bn_mp_div_d.o bn_mp_dr_is_modulus.o bn_mp_dr_reduce.o bn_mp_dr_setup.o \
+bn_mp_error_to_string.o bn_mp_exch.o bn_mp_expt_u32.o bn_mp_exptmod.o bn_mp_exteuclid.o bn_mp_fread.o \
+bn_mp_from_sbin.o bn_mp_from_ubin.o bn_mp_fwrite.o bn_mp_gcd.o bn_mp_get_double.o bn_mp_get_i32.o \
+bn_mp_get_i64.o bn_mp_get_l.o bn_mp_get_ll.o bn_mp_get_mag_u32.o bn_mp_get_mag_u64.o bn_mp_get_mag_ul.o \
+bn_mp_get_mag_ull.o bn_mp_grow.o bn_mp_incr.o bn_mp_init.o bn_mp_init_copy.o bn_mp_init_i32.o \
+bn_mp_init_i64.o bn_mp_init_l.o bn_mp_init_ll.o bn_mp_init_multi.o bn_mp_init_set.o bn_mp_init_size.o \
+bn_mp_init_u32.o bn_mp_init_u64.o bn_mp_init_ul.o bn_mp_init_ull.o bn_mp_invmod.o bn_mp_is_square.o \
+bn_mp_iseven.o bn_mp_isodd.o bn_mp_kronecker.o bn_mp_lcm.o bn_mp_log_u32.o bn_mp_lshd.o bn_mp_mod.o \
+bn_mp_mod_2d.o bn_mp_mod_d.o bn_mp_montgomery_calc_normalization.o bn_mp_montgomery_reduce.o \
+bn_mp_montgomery_setup.o bn_mp_mul.o bn_mp_mul_2.o bn_mp_mul_2d.o bn_mp_mul_d.o bn_mp_mulmod.o bn_mp_neg.o \
+bn_mp_or.o bn_mp_pack.o bn_mp_pack_count.o bn_mp_prime_fermat.o bn_mp_prime_frobenius_underwood.o \
+bn_mp_prime_is_prime.o bn_mp_prime_miller_rabin.o bn_mp_prime_next_prime.o \
+bn_mp_prime_rabin_miller_trials.o bn_mp_prime_rand.o bn_mp_prime_strong_lucas_selfridge.o \
+bn_mp_radix_size.o bn_mp_radix_smap.o bn_mp_rand.o bn_mp_read_radix.o bn_mp_reduce.o bn_mp_reduce_2k.o \
+bn_mp_reduce_2k_l.o bn_mp_reduce_2k_setup.o bn_mp_reduce_2k_setup_l.o bn_mp_reduce_is_2k.o \
+bn_mp_reduce_is_2k_l.o bn_mp_reduce_setup.o bn_mp_root_u32.o bn_mp_rshd.o bn_mp_sbin_size.o bn_mp_set.o \
+bn_mp_set_double.o bn_mp_set_i32.o bn_mp_set_i64.o bn_mp_set_l.o bn_mp_set_ll.o bn_mp_set_u32.o \
+bn_mp_set_u64.o bn_mp_set_ul.o bn_mp_set_ull.o bn_mp_shrink.o bn_mp_signed_rsh.o bn_mp_sqr.o \
+bn_mp_sqrmod.o bn_mp_sqrt.o bn_mp_sqrtmod_prime.o bn_mp_sub.o bn_mp_sub_d.o bn_mp_submod.o \
+bn_mp_to_radix.o bn_mp_to_sbin.o bn_mp_to_ubin.o bn_mp_ubin_size.o bn_mp_unpack.o bn_mp_xor.o bn_mp_zero.o \
+bn_prime_tab.o bn_s_mp_add.o bn_s_mp_balance_mul.o bn_s_mp_exptmod.o bn_s_mp_exptmod_fast.o \
+bn_s_mp_get_bit.o bn_s_mp_invmod_fast.o bn_s_mp_invmod_slow.o bn_s_mp_karatsuba_mul.o \
+bn_s_mp_karatsuba_sqr.o bn_s_mp_montgomery_reduce_fast.o bn_s_mp_mul_digs.o bn_s_mp_mul_digs_fast.o \
+bn_s_mp_mul_high_digs.o bn_s_mp_mul_high_digs_fast.o bn_s_mp_prime_is_divisible.o \
+bn_s_mp_rand_jenkins.o bn_s_mp_rand_platform.o bn_s_mp_reverse.o bn_s_mp_sqr.o bn_s_mp_sqr_fast.o \
+bn_s_mp_sub.o bn_s_mp_toom_mul.o bn_s_mp_toom_sqr.o
+
+#END_INS
+
+$(LIBNAME): $(OBJECTS)
+ $(AR) $(ARFLAGS) $@ $(OBJECTS)
+ $(RANLIB) $@
+
+#make a profiled library (takes a while!!!)
+#
+# This will build the library with profile generation
+# then run the test demo and rebuild the library.
+#
+# So far I've seen improvements in the MP math
+profiled:
+ make CFLAGS="$(CFLAGS) -fprofile-arcs -DTESTING" timing
+ ./timing
+ rm -f *.a *.o timing
+ make CFLAGS="$(CFLAGS) -fbranch-probabilities"
+
+#make a single object profiled library
+profiled_single:
+ perl gen.pl
+ $(CC) $(LTM_CFLAGS) -fprofile-arcs -DTESTING -c mpi.c -o mpi.o
+ $(CC) $(LTM_CFLAGS) -DTESTING -DTIMER demo/timing.c mpi.o -lgcov -o timing
+ ./timing
+ rm -f *.o timing
+ $(CC) $(LTM_CFLAGS) -fbranch-probabilities -DTESTING -c mpi.c -o mpi.o
+ $(AR) $(ARFLAGS) $(LIBNAME) mpi.o
+ ranlib $(LIBNAME)
+
+install: $(LIBNAME)
+ install -d $(DESTDIR)$(LIBPATH)
+ install -d $(DESTDIR)$(INCPATH)
+ install -m 644 $(LIBNAME) $(DESTDIR)$(LIBPATH)
+ install -m 644 $(HEADERS_PUB) $(DESTDIR)$(INCPATH)
+
+uninstall:
+ rm $(DESTDIR)$(LIBPATH)/$(LIBNAME)
+ rm $(HEADERS_PUB:%=$(DESTDIR)$(INCPATH)/%)
+
+test_standalone: test
+ @echo "test_standalone is deprecated, please use make-target 'test'"
+
+DEMOS=test mtest_opponent
+
+define DEMO_template
+$(1): demo/$(1).o demo/shared.o $$(LIBNAME)
+ $$(CC) $$(LTM_CFLAGS) $$(LTM_LFLAGS) $$^ -o $$@
+endef
+
+$(foreach demo, $(strip $(DEMOS)), $(eval $(call DEMO_template,$(demo))))
+
+.PHONY: mtest
+mtest:
+ cd mtest ; $(CC) $(LTM_CFLAGS) -O0 mtest.c $(LTM_LFLAGS) -o mtest
+
+timing: $(LIBNAME) demo/timing.c
+ $(CC) $(LTM_CFLAGS) -DTIMER demo/timing.c $(LIBNAME) $(LTM_LFLAGS) -o timing
+
+tune: $(LIBNAME)
+ $(MAKE) -C etc tune CFLAGS="$(LTM_CFLAGS)"
+ $(MAKE)
+
+# You have to create a file .coveralls.yml with the content "repo_token: "
+# in the base folder to be able to submit to coveralls
+coveralls: lcov
+ coveralls-lcov
+
+docs manual:
+ $(MAKE) -C doc/ $@ V=$(V)
+
+.PHONY: pre_gen
+pre_gen:
+ mkdir -p pre_gen
+ perl gen.pl
+ sed -e 's/[[:blank:]]*$$//' mpi.c > pre_gen/mpi.c
+ rm mpi.c
+
+zipup: clean astyle new_file docs
+ @# Update the index, so diff-index won't fail in case the pdf has been created.
+ @# As the pdf creation modifies the tex files, git sometimes detects the
+ @# modified files, but misses that it's put back to its original version.
+ @git update-index --refresh
+ @git diff-index --quiet HEAD -- || ( echo "FAILURE: uncommited changes or not a git" && exit 1 )
+ rm -rf libtommath-$(VERSION) ltm-$(VERSION).*
+ @# files/dirs excluded from "git archive" are defined in .gitattributes
+ git archive --format=tar --prefix=libtommath-$(VERSION)/ HEAD | tar x
+ @echo 'fixme check'
+ -@(find libtommath-$(VERSION)/ -type f | xargs grep 'FIXM[E]') && echo '############## BEWARE: the "fixme" marker was found !!! ##############' || true
+ mkdir -p libtommath-$(VERSION)/doc
+ cp doc/bn.pdf libtommath-$(VERSION)/doc/
+ $(MAKE) -C libtommath-$(VERSION)/ pre_gen
+ tar -c libtommath-$(VERSION)/ | xz -6e -c - > ltm-$(VERSION).tar.xz
+ zip -9rq ltm-$(VERSION).zip libtommath-$(VERSION)
+ cp doc/bn.pdf bn-$(VERSION).pdf
+ rm -rf libtommath-$(VERSION)
+ gpg -b -a ltm-$(VERSION).tar.xz
+ gpg -b -a ltm-$(VERSION).zip
+
+new_file:
+ perl helper.pl --update-files
+
+perlcritic:
+ perlcritic *.pl doc/*.pl
+
+astyle:
+ @echo " * run astyle on all sources"
+ @astyle --options=astylerc --formatted $(OBJECTS:.o=.c) tommath*.h demo/*.c etc/*.c mtest/mtest.c
ADDED libtommath/makefile.mingw
Index: libtommath/makefile.mingw
==================================================================
--- /dev/null
+++ libtommath/makefile.mingw
@@ -0,0 +1,109 @@
+# MAKEFILE for MS Windows (mingw + gcc + gmake)
+#
+# BEWARE: variable OBJECTS is updated via helper.pl
+
+### USAGE:
+# Open a command prompt with gcc + gmake in PATH and start:
+#
+# gmake -f makefile.mingw all
+# test.exe
+# gmake -f makefile.mingw PREFIX=c:\devel\libtom install
+
+#The following can be overridden from command line e.g. make -f makefile.mingw CC=gcc ARFLAGS=rcs
+PREFIX = c:\mingw
+CC = gcc
+AR = ar
+ARFLAGS = r
+RANLIB = ranlib
+STRIP = strip
+CFLAGS = -O2
+LDFLAGS =
+
+#Compilation flags
+LTM_CFLAGS = -I. $(CFLAGS)
+LTM_LDFLAGS = $(LDFLAGS) -static-libgcc
+
+#Libraries to be created
+LIBMAIN_S =libtommath.a
+LIBMAIN_I =libtommath.dll.a
+LIBMAIN_D =libtommath.dll
+
+#List of objects to compile (all goes to libtommath.a)
+OBJECTS=bn_cutoffs.o bn_deprecated.o bn_mp_2expt.o bn_mp_abs.o bn_mp_add.o bn_mp_add_d.o bn_mp_addmod.o \
+bn_mp_and.o bn_mp_clamp.o bn_mp_clear.o bn_mp_clear_multi.o bn_mp_cmp.o bn_mp_cmp_d.o bn_mp_cmp_mag.o \
+bn_mp_cnt_lsb.o bn_mp_complement.o bn_mp_copy.o bn_mp_count_bits.o bn_mp_decr.o bn_mp_div.o bn_mp_div_2.o \
+bn_mp_div_2d.o bn_mp_div_3.o bn_mp_div_d.o bn_mp_dr_is_modulus.o bn_mp_dr_reduce.o bn_mp_dr_setup.o \
+bn_mp_error_to_string.o bn_mp_exch.o bn_mp_expt_u32.o bn_mp_exptmod.o bn_mp_exteuclid.o bn_mp_fread.o \
+bn_mp_from_sbin.o bn_mp_from_ubin.o bn_mp_fwrite.o bn_mp_gcd.o bn_mp_get_double.o bn_mp_get_i32.o \
+bn_mp_get_i64.o bn_mp_get_l.o bn_mp_get_ll.o bn_mp_get_mag_u32.o bn_mp_get_mag_u64.o bn_mp_get_mag_ul.o \
+bn_mp_get_mag_ull.o bn_mp_grow.o bn_mp_incr.o bn_mp_init.o bn_mp_init_copy.o bn_mp_init_i32.o \
+bn_mp_init_i64.o bn_mp_init_l.o bn_mp_init_ll.o bn_mp_init_multi.o bn_mp_init_set.o bn_mp_init_size.o \
+bn_mp_init_u32.o bn_mp_init_u64.o bn_mp_init_ul.o bn_mp_init_ull.o bn_mp_invmod.o bn_mp_is_square.o \
+bn_mp_iseven.o bn_mp_isodd.o bn_mp_kronecker.o bn_mp_lcm.o bn_mp_log_u32.o bn_mp_lshd.o bn_mp_mod.o \
+bn_mp_mod_2d.o bn_mp_mod_d.o bn_mp_montgomery_calc_normalization.o bn_mp_montgomery_reduce.o \
+bn_mp_montgomery_setup.o bn_mp_mul.o bn_mp_mul_2.o bn_mp_mul_2d.o bn_mp_mul_d.o bn_mp_mulmod.o bn_mp_neg.o \
+bn_mp_or.o bn_mp_pack.o bn_mp_pack_count.o bn_mp_prime_fermat.o bn_mp_prime_frobenius_underwood.o \
+bn_mp_prime_is_prime.o bn_mp_prime_miller_rabin.o bn_mp_prime_next_prime.o \
+bn_mp_prime_rabin_miller_trials.o bn_mp_prime_rand.o bn_mp_prime_strong_lucas_selfridge.o \
+bn_mp_radix_size.o bn_mp_radix_smap.o bn_mp_rand.o bn_mp_read_radix.o bn_mp_reduce.o bn_mp_reduce_2k.o \
+bn_mp_reduce_2k_l.o bn_mp_reduce_2k_setup.o bn_mp_reduce_2k_setup_l.o bn_mp_reduce_is_2k.o \
+bn_mp_reduce_is_2k_l.o bn_mp_reduce_setup.o bn_mp_root_u32.o bn_mp_rshd.o bn_mp_sbin_size.o bn_mp_set.o \
+bn_mp_set_double.o bn_mp_set_i32.o bn_mp_set_i64.o bn_mp_set_l.o bn_mp_set_ll.o bn_mp_set_u32.o \
+bn_mp_set_u64.o bn_mp_set_ul.o bn_mp_set_ull.o bn_mp_shrink.o bn_mp_signed_rsh.o bn_mp_sqr.o \
+bn_mp_sqrmod.o bn_mp_sqrt.o bn_mp_sqrtmod_prime.o bn_mp_sub.o bn_mp_sub_d.o bn_mp_submod.o \
+bn_mp_to_radix.o bn_mp_to_sbin.o bn_mp_to_ubin.o bn_mp_ubin_size.o bn_mp_unpack.o bn_mp_xor.o bn_mp_zero.o \
+bn_prime_tab.o bn_s_mp_add.o bn_s_mp_balance_mul.o bn_s_mp_exptmod.o bn_s_mp_exptmod_fast.o \
+bn_s_mp_get_bit.o bn_s_mp_invmod_fast.o bn_s_mp_invmod_slow.o bn_s_mp_karatsuba_mul.o \
+bn_s_mp_karatsuba_sqr.o bn_s_mp_montgomery_reduce_fast.o bn_s_mp_mul_digs.o bn_s_mp_mul_digs_fast.o \
+bn_s_mp_mul_high_digs.o bn_s_mp_mul_high_digs_fast.o bn_s_mp_prime_is_divisible.o \
+bn_s_mp_rand_jenkins.o bn_s_mp_rand_platform.o bn_s_mp_reverse.o bn_s_mp_sqr.o bn_s_mp_sqr_fast.o \
+bn_s_mp_sub.o bn_s_mp_toom_mul.o bn_s_mp_toom_sqr.o
+
+HEADERS_PUB=tommath.h
+HEADERS=tommath_private.h tommath_class.h tommath_superclass.h tommath_cutoffs.h $(HEADERS_PUB)
+
+#The default rule for make builds the libtommath.a library (static)
+default: $(LIBMAIN_S)
+
+#Dependencies on *.h
+$(OBJECTS): $(HEADERS)
+
+.c.o:
+ $(CC) $(LTM_CFLAGS) -c $< -o $@
+
+#Create libtommath.a
+$(LIBMAIN_S): $(OBJECTS)
+ $(AR) $(ARFLAGS) $@ $(OBJECTS)
+ $(RANLIB) $@
+
+#Create DLL + import library libtommath.dll.a
+$(LIBMAIN_D) $(LIBMAIN_I): $(OBJECTS)
+ $(CC) -s -shared -o $(LIBMAIN_D) $^ -Wl,--enable-auto-import,--export-all -Wl,--out-implib=$(LIBMAIN_I) $(LTM_LDFLAGS)
+ $(STRIP) -S $(LIBMAIN_D)
+
+#Build test suite
+test.exe: demo/shared.o demo/test.o $(LIBMAIN_S)
+ $(CC) $(LTM_CFLAGS) $(LTM_LDFLAGS) $^ -o $@
+ @echo NOTICE: start the tests by launching test.exe
+
+test_standalone: test.exe
+ @echo test_standalone is deprecated, please use make-target 'test.exe'
+
+all: $(LIBMAIN_S) test.exe
+
+tune: $(LIBNAME_S)
+ $(MAKE) -C etc tune
+ $(MAKE)
+
+clean:
+ @-cmd /c del /Q /S *.o *.a *.exe *.dll 2>nul
+
+#Install the library + headers
+install: $(LIBMAIN_S) $(LIBMAIN_I) $(LIBMAIN_D)
+ cmd /c if not exist "$(PREFIX)\bin" mkdir "$(PREFIX)\bin"
+ cmd /c if not exist "$(PREFIX)\lib" mkdir "$(PREFIX)\lib"
+ cmd /c if not exist "$(PREFIX)\include" mkdir "$(PREFIX)\include"
+ copy /Y $(LIBMAIN_S) "$(PREFIX)\lib"
+ copy /Y $(LIBMAIN_I) "$(PREFIX)\lib"
+ copy /Y $(LIBMAIN_D) "$(PREFIX)\bin"
+ copy /Y tommath*.h "$(PREFIX)\include"
ADDED libtommath/makefile.msvc
Index: libtommath/makefile.msvc
==================================================================
--- /dev/null
+++ libtommath/makefile.msvc
@@ -0,0 +1,93 @@
+# MAKEFILE for MS Windows (nmake + Windows SDK)
+#
+# BEWARE: variable OBJECTS is updated via helper.pl
+
+### USAGE:
+# Open a command prompt with WinSDK variables set and start:
+#
+# nmake -f makefile.msvc all
+# test.exe
+# nmake -f makefile.msvc PREFIX=c:\devel\libtom install
+
+#The following can be overridden from command line e.g. make -f makefile.msvc CC=gcc ARFLAGS=rcs
+PREFIX = c:\devel
+CFLAGS = /Ox
+
+#Compilation flags
+LTM_CFLAGS = /nologo /I./ /D_CRT_SECURE_NO_WARNINGS /D_CRT_NONSTDC_NO_DEPRECATE /D__STDC_WANT_SECURE_LIB__=1 /D_CRT_HAS_CXX17=0 /Wall /wd4146 /wd4127 /wd4668 /wd4710 /wd4711 /wd4820 /wd5045 /WX $(CFLAGS)
+LTM_LDFLAGS = advapi32.lib
+
+#Libraries to be created (this makefile builds only static libraries)
+LIBMAIN_S =tommath.lib
+
+#List of objects to compile (all goes to tommath.lib)
+OBJECTS=bn_cutoffs.obj bn_deprecated.obj bn_mp_2expt.obj bn_mp_abs.obj bn_mp_add.obj bn_mp_add_d.obj bn_mp_addmod.obj \
+bn_mp_and.obj bn_mp_clamp.obj bn_mp_clear.obj bn_mp_clear_multi.obj bn_mp_cmp.obj bn_mp_cmp_d.obj bn_mp_cmp_mag.obj \
+bn_mp_cnt_lsb.obj bn_mp_complement.obj bn_mp_copy.obj bn_mp_count_bits.obj bn_mp_decr.obj bn_mp_div.obj bn_mp_div_2.obj \
+bn_mp_div_2d.obj bn_mp_div_3.obj bn_mp_div_d.obj bn_mp_dr_is_modulus.obj bn_mp_dr_reduce.obj bn_mp_dr_setup.obj \
+bn_mp_error_to_string.obj bn_mp_exch.obj bn_mp_expt_u32.obj bn_mp_exptmod.obj bn_mp_exteuclid.obj bn_mp_fread.obj \
+bn_mp_from_sbin.obj bn_mp_from_ubin.obj bn_mp_fwrite.obj bn_mp_gcd.obj bn_mp_get_double.obj bn_mp_get_i32.obj \
+bn_mp_get_i64.obj bn_mp_get_l.obj bn_mp_get_ll.obj bn_mp_get_mag_u32.obj bn_mp_get_mag_u64.obj bn_mp_get_mag_ul.obj \
+bn_mp_get_mag_ull.obj bn_mp_grow.obj bn_mp_incr.obj bn_mp_init.obj bn_mp_init_copy.obj bn_mp_init_i32.obj \
+bn_mp_init_i64.obj bn_mp_init_l.obj bn_mp_init_ll.obj bn_mp_init_multi.obj bn_mp_init_set.obj bn_mp_init_size.obj \
+bn_mp_init_u32.obj bn_mp_init_u64.obj bn_mp_init_ul.obj bn_mp_init_ull.obj bn_mp_invmod.obj bn_mp_is_square.obj \
+bn_mp_iseven.obj bn_mp_isodd.obj bn_mp_kronecker.obj bn_mp_lcm.obj bn_mp_log_u32.obj bn_mp_lshd.obj bn_mp_mod.obj \
+bn_mp_mod_2d.obj bn_mp_mod_d.obj bn_mp_montgomery_calc_normalization.obj bn_mp_montgomery_reduce.obj \
+bn_mp_montgomery_setup.obj bn_mp_mul.obj bn_mp_mul_2.obj bn_mp_mul_2d.obj bn_mp_mul_d.obj bn_mp_mulmod.obj bn_mp_neg.obj \
+bn_mp_or.obj bn_mp_pack.obj bn_mp_pack_count.obj bn_mp_prime_fermat.obj bn_mp_prime_frobenius_underwood.obj \
+bn_mp_prime_is_prime.obj bn_mp_prime_miller_rabin.obj bn_mp_prime_next_prime.obj \
+bn_mp_prime_rabin_miller_trials.obj bn_mp_prime_rand.obj bn_mp_prime_strong_lucas_selfridge.obj \
+bn_mp_radix_size.obj bn_mp_radix_smap.obj bn_mp_rand.obj bn_mp_read_radix.obj bn_mp_reduce.obj bn_mp_reduce_2k.obj \
+bn_mp_reduce_2k_l.obj bn_mp_reduce_2k_setup.obj bn_mp_reduce_2k_setup_l.obj bn_mp_reduce_is_2k.obj \
+bn_mp_reduce_is_2k_l.obj bn_mp_reduce_setup.obj bn_mp_root_u32.obj bn_mp_rshd.obj bn_mp_sbin_size.obj bn_mp_set.obj \
+bn_mp_set_double.obj bn_mp_set_i32.obj bn_mp_set_i64.obj bn_mp_set_l.obj bn_mp_set_ll.obj bn_mp_set_u32.obj \
+bn_mp_set_u64.obj bn_mp_set_ul.obj bn_mp_set_ull.obj bn_mp_shrink.obj bn_mp_signed_rsh.obj bn_mp_sqr.obj \
+bn_mp_sqrmod.obj bn_mp_sqrt.obj bn_mp_sqrtmod_prime.obj bn_mp_sub.obj bn_mp_sub_d.obj bn_mp_submod.obj \
+bn_mp_to_radix.obj bn_mp_to_sbin.obj bn_mp_to_ubin.obj bn_mp_ubin_size.obj bn_mp_unpack.obj bn_mp_xor.obj bn_mp_zero.obj \
+bn_prime_tab.obj bn_s_mp_add.obj bn_s_mp_balance_mul.obj bn_s_mp_exptmod.obj bn_s_mp_exptmod_fast.obj \
+bn_s_mp_get_bit.obj bn_s_mp_invmod_fast.obj bn_s_mp_invmod_slow.obj bn_s_mp_karatsuba_mul.obj \
+bn_s_mp_karatsuba_sqr.obj bn_s_mp_montgomery_reduce_fast.obj bn_s_mp_mul_digs.obj bn_s_mp_mul_digs_fast.obj \
+bn_s_mp_mul_high_digs.obj bn_s_mp_mul_high_digs_fast.obj bn_s_mp_prime_is_divisible.obj \
+bn_s_mp_rand_jenkins.obj bn_s_mp_rand_platform.obj bn_s_mp_reverse.obj bn_s_mp_sqr.obj bn_s_mp_sqr_fast.obj \
+bn_s_mp_sub.obj bn_s_mp_toom_mul.obj bn_s_mp_toom_sqr.obj
+
+HEADERS_PUB=tommath.h
+HEADERS=tommath_private.h tommath_class.h tommath_superclass.h tommath_cutoffs.h $(HEADERS_PUB)
+
+#The default rule for make builds the tommath.lib library (static)
+default: $(LIBMAIN_S)
+
+#Dependencies on *.h
+$(OBJECTS): $(HEADERS)
+
+.c.obj:
+ $(CC) $(LTM_CFLAGS) /c $< /Fo$@
+
+#Create tommath.lib
+$(LIBMAIN_S): $(OBJECTS)
+ lib /out:$(LIBMAIN_S) $(OBJECTS)
+
+#Build test suite
+test.exe: $(LIBMAIN_S) demo/shared.obj demo/test.obj
+ cl $(LTM_CFLAGS) $(TOBJECTS) $(LIBMAIN_S) $(LTM_LDFLAGS) demo/shared.c demo/test.c /Fe$@
+ @echo NOTICE: start the tests by launching test.exe
+
+test_standalone: test.exe
+ @echo test_standalone is deprecated, please use make-target 'test.exe'
+
+all: $(LIBMAIN_S) test.exe
+
+tune: $(LIBMAIN_S)
+ $(MAKE) -C etc tune
+ $(MAKE)
+
+clean:
+ @-cmd /c del /Q /S *.OBJ *.LIB *.EXE *.DLL 2>nul
+
+#Install the library + headers
+install: $(LIBMAIN_S)
+ cmd /c if not exist "$(PREFIX)\bin" mkdir "$(PREFIX)\bin"
+ cmd /c if not exist "$(PREFIX)\lib" mkdir "$(PREFIX)\lib"
+ cmd /c if not exist "$(PREFIX)\include" mkdir "$(PREFIX)\include"
+ copy /Y $(LIBMAIN_S) "$(PREFIX)\lib"
+ copy /Y tommath*.h "$(PREFIX)\include"
ADDED libtommath/makefile.shared
Index: libtommath/makefile.shared
==================================================================
--- /dev/null
+++ libtommath/makefile.shared
@@ -0,0 +1,99 @@
+#Makefile for GCC
+#
+#Tom St Denis
+
+#default files to install
+ifndef LIBNAME
+ LIBNAME=libtommath.la
+endif
+
+include makefile_include.mk
+
+
+ifndef LIBTOOL
+ ifeq ($(PLATFORM), Darwin)
+ LIBTOOL:=glibtool
+ else
+ LIBTOOL:=libtool
+ endif
+endif
+LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC)
+LTLINK = $(LIBTOOL) --mode=link --tag=CC $(CC)
+
+LCOV_ARGS=--directory .libs --directory .
+
+#START_INS
+OBJECTS=bn_cutoffs.o bn_deprecated.o bn_mp_2expt.o bn_mp_abs.o bn_mp_add.o bn_mp_add_d.o bn_mp_addmod.o \
+bn_mp_and.o bn_mp_clamp.o bn_mp_clear.o bn_mp_clear_multi.o bn_mp_cmp.o bn_mp_cmp_d.o bn_mp_cmp_mag.o \
+bn_mp_cnt_lsb.o bn_mp_complement.o bn_mp_copy.o bn_mp_count_bits.o bn_mp_decr.o bn_mp_div.o bn_mp_div_2.o \
+bn_mp_div_2d.o bn_mp_div_3.o bn_mp_div_d.o bn_mp_dr_is_modulus.o bn_mp_dr_reduce.o bn_mp_dr_setup.o \
+bn_mp_error_to_string.o bn_mp_exch.o bn_mp_expt_u32.o bn_mp_exptmod.o bn_mp_exteuclid.o bn_mp_fread.o \
+bn_mp_from_sbin.o bn_mp_from_ubin.o bn_mp_fwrite.o bn_mp_gcd.o bn_mp_get_double.o bn_mp_get_i32.o \
+bn_mp_get_i64.o bn_mp_get_l.o bn_mp_get_ll.o bn_mp_get_mag_u32.o bn_mp_get_mag_u64.o bn_mp_get_mag_ul.o \
+bn_mp_get_mag_ull.o bn_mp_grow.o bn_mp_incr.o bn_mp_init.o bn_mp_init_copy.o bn_mp_init_i32.o \
+bn_mp_init_i64.o bn_mp_init_l.o bn_mp_init_ll.o bn_mp_init_multi.o bn_mp_init_set.o bn_mp_init_size.o \
+bn_mp_init_u32.o bn_mp_init_u64.o bn_mp_init_ul.o bn_mp_init_ull.o bn_mp_invmod.o bn_mp_is_square.o \
+bn_mp_iseven.o bn_mp_isodd.o bn_mp_kronecker.o bn_mp_lcm.o bn_mp_log_u32.o bn_mp_lshd.o bn_mp_mod.o \
+bn_mp_mod_2d.o bn_mp_mod_d.o bn_mp_montgomery_calc_normalization.o bn_mp_montgomery_reduce.o \
+bn_mp_montgomery_setup.o bn_mp_mul.o bn_mp_mul_2.o bn_mp_mul_2d.o bn_mp_mul_d.o bn_mp_mulmod.o bn_mp_neg.o \
+bn_mp_or.o bn_mp_pack.o bn_mp_pack_count.o bn_mp_prime_fermat.o bn_mp_prime_frobenius_underwood.o \
+bn_mp_prime_is_prime.o bn_mp_prime_miller_rabin.o bn_mp_prime_next_prime.o \
+bn_mp_prime_rabin_miller_trials.o bn_mp_prime_rand.o bn_mp_prime_strong_lucas_selfridge.o \
+bn_mp_radix_size.o bn_mp_radix_smap.o bn_mp_rand.o bn_mp_read_radix.o bn_mp_reduce.o bn_mp_reduce_2k.o \
+bn_mp_reduce_2k_l.o bn_mp_reduce_2k_setup.o bn_mp_reduce_2k_setup_l.o bn_mp_reduce_is_2k.o \
+bn_mp_reduce_is_2k_l.o bn_mp_reduce_setup.o bn_mp_root_u32.o bn_mp_rshd.o bn_mp_sbin_size.o bn_mp_set.o \
+bn_mp_set_double.o bn_mp_set_i32.o bn_mp_set_i64.o bn_mp_set_l.o bn_mp_set_ll.o bn_mp_set_u32.o \
+bn_mp_set_u64.o bn_mp_set_ul.o bn_mp_set_ull.o bn_mp_shrink.o bn_mp_signed_rsh.o bn_mp_sqr.o \
+bn_mp_sqrmod.o bn_mp_sqrt.o bn_mp_sqrtmod_prime.o bn_mp_sub.o bn_mp_sub_d.o bn_mp_submod.o \
+bn_mp_to_radix.o bn_mp_to_sbin.o bn_mp_to_ubin.o bn_mp_ubin_size.o bn_mp_unpack.o bn_mp_xor.o bn_mp_zero.o \
+bn_prime_tab.o bn_s_mp_add.o bn_s_mp_balance_mul.o bn_s_mp_exptmod.o bn_s_mp_exptmod_fast.o \
+bn_s_mp_get_bit.o bn_s_mp_invmod_fast.o bn_s_mp_invmod_slow.o bn_s_mp_karatsuba_mul.o \
+bn_s_mp_karatsuba_sqr.o bn_s_mp_montgomery_reduce_fast.o bn_s_mp_mul_digs.o bn_s_mp_mul_digs_fast.o \
+bn_s_mp_mul_high_digs.o bn_s_mp_mul_high_digs_fast.o bn_s_mp_prime_is_divisible.o \
+bn_s_mp_rand_jenkins.o bn_s_mp_rand_platform.o bn_s_mp_reverse.o bn_s_mp_sqr.o bn_s_mp_sqr_fast.o \
+bn_s_mp_sub.o bn_s_mp_toom_mul.o bn_s_mp_toom_sqr.o
+
+#END_INS
+
+objs: $(OBJECTS)
+
+.c.o: $(HEADERS)
+ $(LTCOMPILE) $(LTM_CFLAGS) $(LTM_LDFLAGS) -o $@ -c $<
+
+LOBJECTS = $(OBJECTS:.o=.lo)
+
+$(LIBNAME): $(OBJECTS)
+ $(LTLINK) $(LTM_LDFLAGS) $(LOBJECTS) -o $(LIBNAME) -rpath $(LIBPATH) -version-info $(VERSION_SO) $(LTM_LIBTOOLFLAGS)
+
+install: $(LIBNAME)
+ install -d $(DESTDIR)$(LIBPATH)
+ install -d $(DESTDIR)$(INCPATH)
+ $(LIBTOOL) --mode=install install -m 644 $(LIBNAME) $(DESTDIR)$(LIBPATH)/$(LIBNAME)
+ install -m 644 $(HEADERS_PUB) $(DESTDIR)$(INCPATH)
+ sed -e 's,^prefix=.*,prefix=$(PREFIX),' -e 's,^Version:.*,Version: $(VERSION_PC),' libtommath.pc.in > libtommath.pc
+ install -d $(DESTDIR)$(LIBPATH)/pkgconfig
+ install -m 644 libtommath.pc $(DESTDIR)$(LIBPATH)/pkgconfig/
+
+uninstall:
+ $(LIBTOOL) --mode=uninstall rm $(DESTDIR)$(LIBPATH)/$(LIBNAME)
+ rm $(HEADERS_PUB:%=$(DESTDIR)$(INCPATH)/%)
+ rm $(DESTDIR)$(LIBPATH)/pkgconfig/libtommath.pc
+
+test_standalone: test
+ @echo "test_standalone is deprecated, please use make-target 'test'"
+
+test mtest_opponent: demo/shared.o $(LIBNAME) | demo/test.o demo/mtest_opponent.o
+ $(LTLINK) $(LTM_LDFLAGS) demo/$@.o $^ -o $@
+
+.PHONY: mtest
+mtest:
+ cd mtest ; $(CC) $(LTM_CFLAGS) -O0 mtest.c $(LTM_LDFLAGS) -o mtest
+
+timing: $(LIBNAME) demo/timing.c
+ $(LTLINK) $(LTM_CFLAGS) $(LTM_LDFLAGS) -DTIMER demo/timing.c $(LIBNAME) -o timing
+
+tune: $(LIBNAME)
+ $(LTCOMPILE) $(LTM_CFLAGS) -c etc/tune.c -o etc/tune.o
+ $(LTLINK) $(LTM_LDFLAGS) -o etc/tune etc/tune.o $(LIBNAME)
+ cd etc/; /bin/sh tune_it.sh; cd ..
+ $(MAKE) -f makefile.shared
ADDED libtommath/makefile.unix
Index: libtommath/makefile.unix
==================================================================
--- /dev/null
+++ libtommath/makefile.unix
@@ -0,0 +1,106 @@
+# MAKEFILE that is intended to be compatible with any kind of make (GNU make, BSD make, ...)
+# works on: Linux, *BSD, Cygwin, AIX, HP-UX and hopefully other UNIX systems
+#
+# Please do not use here neither any special make syntax nor any unusual tools/utilities!
+
+# using ICC compiler:
+# make -f makefile.unix CC=icc CFLAGS="-O3 -xP -ip"
+
+# using Borland C++Builder:
+# make -f makefile.unix CC=bcc32
+
+#The following can be overridden from command line e.g. "make -f makefile.unix CC=gcc ARFLAGS=rcs"
+DESTDIR =
+PREFIX = /usr/local
+LIBPATH = $(PREFIX)/lib
+INCPATH = $(PREFIX)/include
+CC = cc
+AR = ar
+ARFLAGS = r
+RANLIB = ranlib
+CFLAGS = -O2
+LDFLAGS =
+
+VERSION = 1.2.1
+
+#Compilation flags
+LTM_CFLAGS = -I. $(CFLAGS)
+LTM_LDFLAGS = $(LDFLAGS)
+
+#Library to be created (this makefile builds only static library)
+LIBMAIN_S = libtommath.a
+
+OBJECTS=bn_cutoffs.o bn_deprecated.o bn_mp_2expt.o bn_mp_abs.o bn_mp_add.o bn_mp_add_d.o bn_mp_addmod.o \
+bn_mp_and.o bn_mp_clamp.o bn_mp_clear.o bn_mp_clear_multi.o bn_mp_cmp.o bn_mp_cmp_d.o bn_mp_cmp_mag.o \
+bn_mp_cnt_lsb.o bn_mp_complement.o bn_mp_copy.o bn_mp_count_bits.o bn_mp_decr.o bn_mp_div.o bn_mp_div_2.o \
+bn_mp_div_2d.o bn_mp_div_3.o bn_mp_div_d.o bn_mp_dr_is_modulus.o bn_mp_dr_reduce.o bn_mp_dr_setup.o \
+bn_mp_error_to_string.o bn_mp_exch.o bn_mp_expt_u32.o bn_mp_exptmod.o bn_mp_exteuclid.o bn_mp_fread.o \
+bn_mp_from_sbin.o bn_mp_from_ubin.o bn_mp_fwrite.o bn_mp_gcd.o bn_mp_get_double.o bn_mp_get_i32.o \
+bn_mp_get_i64.o bn_mp_get_l.o bn_mp_get_ll.o bn_mp_get_mag_u32.o bn_mp_get_mag_u64.o bn_mp_get_mag_ul.o \
+bn_mp_get_mag_ull.o bn_mp_grow.o bn_mp_incr.o bn_mp_init.o bn_mp_init_copy.o bn_mp_init_i32.o \
+bn_mp_init_i64.o bn_mp_init_l.o bn_mp_init_ll.o bn_mp_init_multi.o bn_mp_init_set.o bn_mp_init_size.o \
+bn_mp_init_u32.o bn_mp_init_u64.o bn_mp_init_ul.o bn_mp_init_ull.o bn_mp_invmod.o bn_mp_is_square.o \
+bn_mp_iseven.o bn_mp_isodd.o bn_mp_kronecker.o bn_mp_lcm.o bn_mp_log_u32.o bn_mp_lshd.o bn_mp_mod.o \
+bn_mp_mod_2d.o bn_mp_mod_d.o bn_mp_montgomery_calc_normalization.o bn_mp_montgomery_reduce.o \
+bn_mp_montgomery_setup.o bn_mp_mul.o bn_mp_mul_2.o bn_mp_mul_2d.o bn_mp_mul_d.o bn_mp_mulmod.o bn_mp_neg.o \
+bn_mp_or.o bn_mp_pack.o bn_mp_pack_count.o bn_mp_prime_fermat.o bn_mp_prime_frobenius_underwood.o \
+bn_mp_prime_is_prime.o bn_mp_prime_miller_rabin.o bn_mp_prime_next_prime.o \
+bn_mp_prime_rabin_miller_trials.o bn_mp_prime_rand.o bn_mp_prime_strong_lucas_selfridge.o \
+bn_mp_radix_size.o bn_mp_radix_smap.o bn_mp_rand.o bn_mp_read_radix.o bn_mp_reduce.o bn_mp_reduce_2k.o \
+bn_mp_reduce_2k_l.o bn_mp_reduce_2k_setup.o bn_mp_reduce_2k_setup_l.o bn_mp_reduce_is_2k.o \
+bn_mp_reduce_is_2k_l.o bn_mp_reduce_setup.o bn_mp_root_u32.o bn_mp_rshd.o bn_mp_sbin_size.o bn_mp_set.o \
+bn_mp_set_double.o bn_mp_set_i32.o bn_mp_set_i64.o bn_mp_set_l.o bn_mp_set_ll.o bn_mp_set_u32.o \
+bn_mp_set_u64.o bn_mp_set_ul.o bn_mp_set_ull.o bn_mp_shrink.o bn_mp_signed_rsh.o bn_mp_sqr.o \
+bn_mp_sqrmod.o bn_mp_sqrt.o bn_mp_sqrtmod_prime.o bn_mp_sub.o bn_mp_sub_d.o bn_mp_submod.o \
+bn_mp_to_radix.o bn_mp_to_sbin.o bn_mp_to_ubin.o bn_mp_ubin_size.o bn_mp_unpack.o bn_mp_xor.o bn_mp_zero.o \
+bn_prime_tab.o bn_s_mp_add.o bn_s_mp_balance_mul.o bn_s_mp_exptmod.o bn_s_mp_exptmod_fast.o \
+bn_s_mp_get_bit.o bn_s_mp_invmod_fast.o bn_s_mp_invmod_slow.o bn_s_mp_karatsuba_mul.o \
+bn_s_mp_karatsuba_sqr.o bn_s_mp_montgomery_reduce_fast.o bn_s_mp_mul_digs.o bn_s_mp_mul_digs_fast.o \
+bn_s_mp_mul_high_digs.o bn_s_mp_mul_high_digs_fast.o bn_s_mp_prime_is_divisible.o \
+bn_s_mp_rand_jenkins.o bn_s_mp_rand_platform.o bn_s_mp_reverse.o bn_s_mp_sqr.o bn_s_mp_sqr_fast.o \
+bn_s_mp_sub.o bn_s_mp_toom_mul.o bn_s_mp_toom_sqr.o
+
+HEADERS_PUB=tommath.h
+HEADERS=tommath_private.h tommath_class.h tommath_superclass.h tommath_cutoffs.h $(HEADERS_PUB)
+
+#The default rule for make builds the libtommath.a library (static)
+default: $(LIBMAIN_S)
+
+#Dependencies on *.h
+$(OBJECTS): $(HEADERS)
+
+#This is necessary for compatibility with BSD make (namely on OpenBSD)
+.SUFFIXES: .o .c
+.c.o:
+ $(CC) $(LTM_CFLAGS) -c $< -o $@
+
+#Create libtommath.a
+$(LIBMAIN_S): $(OBJECTS)
+ $(AR) $(ARFLAGS) $@ $(OBJECTS)
+ $(RANLIB) $@
+
+#Build test_standalone suite
+test: demo/shared.o demo/test.o $(LIBMAIN_S)
+ $(CC) $(LTM_CFLAGS) $(LTM_LDFLAGS) $^ -o $@
+ @echo "NOTICE: start the tests by: ./test"
+
+test_standalone: test
+ @echo "test_standalone is deprecated, please use make-target 'test'"
+
+all: $(LIBMAIN_S) test
+
+tune: $(LIBMAIN_S)
+ $(MAKE) -C etc tune
+ $(MAKE)
+
+#NOTE: this makefile works also on cygwin, thus we need to delete *.exe
+clean:
+ -@rm -f $(OBJECTS) $(LIBMAIN_S)
+ -@rm -f demo/main.o demo/opponent.o demo/test.o test test.exe
+
+#Install the library + headers
+install: $(LIBMAIN_S)
+ @mkdir -p $(DESTDIR)$(INCPATH) $(DESTDIR)$(LIBPATH)/pkgconfig
+ @cp $(LIBMAIN_S) $(DESTDIR)$(LIBPATH)/
+ @cp $(HEADERS_PUB) $(DESTDIR)$(INCPATH)/
+ @sed -e 's,^prefix=.*,prefix=$(PREFIX),' -e 's,^Version:.*,Version: $(VERSION),' libtommath.pc.in > $(DESTDIR)$(LIBPATH)/pkgconfig/libtommath.pc
ADDED libtommath/makefile_include.mk
Index: libtommath/makefile_include.mk
==================================================================
--- /dev/null
+++ libtommath/makefile_include.mk
@@ -0,0 +1,166 @@
+#
+# Include makefile for libtommath
+#
+
+#version of library
+VERSION=1.2.1
+VERSION_PC=1.2.1
+VERSION_SO=3:1:2
+
+PLATFORM := $(shell uname | sed -e 's/_.*//')
+
+# default make target
+default: ${LIBNAME}
+
+# Compiler and Linker Names
+ifndef CROSS_COMPILE
+ CROSS_COMPILE=
+endif
+
+# We only need to go through this dance of determining the right compiler if we're using
+# cross compilation, otherwise $(CC) is fine as-is.
+ifneq (,$(CROSS_COMPILE))
+ifeq ($(origin CC),default)
+CSTR := "\#ifdef __clang__\nCLANG\n\#endif\n"
+ifeq ($(PLATFORM),FreeBSD)
+ # XXX: FreeBSD needs extra escaping for some reason
+ CSTR := $$$(CSTR)
+endif
+ifneq (,$(shell echo $(CSTR) | $(CC) -E - | grep CLANG))
+ CC := $(CROSS_COMPILE)clang
+else
+ CC := $(CROSS_COMPILE)gcc
+endif # Clang
+endif # cc is Make's default
+endif # CROSS_COMPILE non-empty
+
+LD=$(CROSS_COMPILE)ld
+AR=$(CROSS_COMPILE)ar
+RANLIB=$(CROSS_COMPILE)ranlib
+
+ifndef MAKE
+# BSDs refer to GNU Make as gmake
+ifneq (,$(findstring $(PLATFORM),FreeBSD OpenBSD DragonFly NetBSD))
+ MAKE=gmake
+else
+ MAKE=make
+endif
+endif
+
+LTM_CFLAGS += -I./ -Wall -Wsign-compare -Wextra -Wshadow
+
+ifdef SANITIZER
+LTM_CFLAGS += -fsanitize=undefined -fno-sanitize-recover=all -fno-sanitize=float-divide-by-zero
+endif
+
+ifndef NO_ADDTL_WARNINGS
+# additional warnings
+LTM_CFLAGS += -Wdeclaration-after-statement -Wbad-function-cast -Wcast-align
+LTM_CFLAGS += -Wstrict-prototypes -Wpointer-arith
+endif
+
+ifdef CONV_WARNINGS
+LTM_CFLAGS += -std=c89 -Wconversion -Wsign-conversion
+ifeq ($(CONV_WARNINGS), strict)
+LTM_CFLAGS += -DMP_USE_ENUMS -Wc++-compat
+endif
+else
+LTM_CFLAGS += -Wsystem-headers
+endif
+
+ifdef COMPILE_DEBUG
+#debug
+LTM_CFLAGS += -g3
+endif
+
+ifdef COMPILE_SIZE
+#for size
+LTM_CFLAGS += -Os
+else
+
+ifndef IGNORE_SPEED
+#for speed
+LTM_CFLAGS += -O3 -funroll-loops
+
+#x86 optimizations [should be valid for any GCC install though]
+LTM_CFLAGS += -fomit-frame-pointer
+endif
+
+endif # COMPILE_SIZE
+
+ifneq ($(findstring clang,$(CC)),)
+LTM_CFLAGS += -Wno-typedef-redefinition -Wno-tautological-compare -Wno-builtin-requires-header
+endif
+ifneq ($(findstring mingw,$(CC)),)
+LTM_CFLAGS += -Wno-shadow
+endif
+ifeq ($(PLATFORM), Darwin)
+LTM_CFLAGS += -Wno-nullability-completeness
+endif
+ifeq ($(PLATFORM), CYGWIN)
+LIBTOOLFLAGS += -no-undefined
+endif
+
+# add in the standard FLAGS
+LTM_CFLAGS += $(CFLAGS)
+LTM_LFLAGS += $(LFLAGS)
+LTM_LDFLAGS += $(LDFLAGS)
+LTM_LIBTOOLFLAGS += $(LIBTOOLFLAGS)
+
+
+ifeq ($(PLATFORM),FreeBSD)
+ _ARCH := $(shell sysctl -b hw.machine_arch)
+else
+ _ARCH := $(shell uname -m)
+endif
+
+# adjust coverage set
+ifneq ($(filter $(_ARCH), i386 i686 x86_64 amd64 ia64),)
+ COVERAGE = test_standalone timing
+ COVERAGE_APP = ./test && ./timing
+else
+ COVERAGE = test_standalone
+ COVERAGE_APP = ./test
+endif
+
+HEADERS_PUB=tommath.h
+HEADERS=tommath_private.h tommath_class.h tommath_superclass.h tommath_cutoffs.h $(HEADERS_PUB)
+
+#LIBPATH The directory for libtommath to be installed to.
+#INCPATH The directory to install the header files for libtommath.
+#DATAPATH The directory to install the pdf docs.
+DESTDIR ?=
+PREFIX ?= /usr/local
+LIBPATH ?= $(PREFIX)/lib
+INCPATH ?= $(PREFIX)/include
+DATAPATH ?= $(PREFIX)/share/doc/libtommath/pdf
+
+#make the code coverage of the library
+#
+coverage: LTM_CFLAGS += -fprofile-arcs -ftest-coverage -DTIMING_NO_LOGS
+coverage: LTM_LFLAGS += -lgcov
+coverage: LTM_LDFLAGS += -lgcov
+
+coverage: $(COVERAGE)
+ $(COVERAGE_APP)
+
+lcov: coverage
+ rm -f coverage.info
+ lcov --capture --no-external --no-recursion $(LCOV_ARGS) --output-file coverage.info -q
+ genhtml coverage.info --output-directory coverage -q
+
+# target that removes all coverage output
+cleancov-clean:
+ rm -f `find . -type f -name "*.info" | xargs`
+ rm -rf coverage/
+
+# cleans everything - coverage output and standard 'clean'
+cleancov: cleancov-clean clean
+
+clean:
+ rm -f *.gcda *.gcno *.gcov *.bat *.o *.a *.obj *.lib *.exe *.dll etclib/*.o \
+ demo/*.o test timing mtest_opponent mtest/mtest mtest/mtest.exe tuning_list \
+ *.s mpi.c *.da *.dyn *.dpi tommath.tex `find . -type f | grep [~] | xargs` *.lo *.la
+ rm -rf .libs/ demo/.libs
+ ${MAKE} -C etc/ clean MAKE=${MAKE}
+ ${MAKE} -C doc/ clean MAKE=${MAKE}
ADDED libtommath/testme.sh
Index: libtommath/testme.sh
==================================================================
--- /dev/null
+++ libtommath/testme.sh
@@ -0,0 +1,394 @@
+#!/bin/bash
+#
+# return values of this script are:
+# 0 success
+# 128 a test failed
+# >0 the number of timed-out tests
+# 255 parsing of parameters failed
+
+set -e
+
+if [ -f /proc/cpuinfo ]
+then
+ MAKE_JOBS=$(( ($(cat /proc/cpuinfo | grep -E '^processor[[:space:]]*:' | tail -n -1 | cut -d':' -f2) + 1) * 2 + 1 ))
+else
+ MAKE_JOBS=8
+fi
+
+ret=0
+TEST_CFLAGS=""
+
+_help()
+{
+ echo "Usage options for $(basename $0) [--with-cc=arg [other options]]"
+ echo
+ echo "Executing this script without any parameter will only run the default"
+ echo "configuration that has automatically been determined for the"
+ echo "architecture you're running."
+ echo
+ echo " --with-cc=* The compiler(s) to use for the tests"
+ echo " This is an option that will be iterated."
+ echo
+ echo " --test-vs-mtest=* Run test vs. mtest for '*' operations."
+ echo " Only the first of each options will be"
+ echo " taken into account."
+ echo
+ echo "To be able to specify options a compiler has to be given with"
+ echo "the option --with-cc=compilername"
+ echo "All other options will be tested with all MP_xBIT configurations."
+ echo
+ echo " --with-{m64,m32,mx32} The architecture(s) to build and test"
+ echo " for, e.g. --with-mx32."
+ echo " This is an option that will be iterated,"
+ echo " multiple selections are possible."
+ echo " The mx32 architecture is not supported"
+ echo " by clang and will not be executed."
+ echo
+ echo " --cflags=* Give an option to the compiler,"
+ echo " e.g. --cflags=-g"
+ echo " This is an option that will always be"
+ echo " passed as parameter to CC."
+ echo
+ echo " --make-option=* Give an option to make,"
+ echo " e.g. --make-option=\"-f makefile.shared\""
+ echo " This is an option that will always be"
+ echo " passed as parameter to make."
+ echo
+ echo " --with-low-mp Also build&run tests with -DMP_{8,16,32}BIT."
+ echo
+ echo " --mtest-real-rand Use real random data when running mtest."
+ echo
+ echo " --with-valgrind"
+ echo " --with-valgrind=* Run in valgrind (slow!)."
+ echo
+ echo " --with-travis-valgrind Run with valgrind on Travis on specific branches."
+ echo
+ echo " --valgrind-options Additional Valgrind options"
+ echo " Some of the options like e.g.:"
+ echo " --track-origins=yes add a lot of extra"
+ echo " runtime and may trigger the 30 minutes"
+ echo " timeout."
+ echo
+ echo "Godmode:"
+ echo
+ echo " --all Choose all architectures and gcc and clang"
+ echo " as compilers but does not run valgrind."
+ echo
+ echo " --format Runs the various source-code formatters"
+ echo " and generators and checks if the sources"
+ echo " are clean."
+ echo
+ echo " -h"
+ echo " --help This message"
+ echo
+ echo " -v"
+ echo " --version Prints the version. It is just the number"
+ echo " of git commits to this file, no deeper"
+ echo " meaning attached"
+ exit 0
+}
+
+_die()
+{
+ echo "error $2 while $1"
+ if [ "$2" != "124" ]
+ then
+ exit 128
+ else
+ echo "assuming timeout while running test - continue"
+ local _tail=""
+ which tail >/dev/null && _tail="tail -n 1 test_${suffix}.log" && \
+ echo "last line of test_"${suffix}".log was:" && $_tail && echo ""
+ ret=$(( $ret + 1 ))
+ fi
+}
+
+_make()
+{
+ echo -ne " Compile $1 $2"
+ suffix=$(echo ${1}${2} | tr ' ' '_')
+ CC="$1" CFLAGS="$2 $TEST_CFLAGS" make -j$MAKE_JOBS $3 $MAKE_OPTIONS > /dev/null 2>gcc_errors_${suffix}.log
+ errcnt=$(wc -l < gcc_errors_${suffix}.log)
+ if [[ ${errcnt} -gt 1 ]]; then
+ echo " failed"
+ cat gcc_errors_${suffix}.log
+ exit 128
+ fi
+}
+
+
+_runtest()
+{
+ make clean > /dev/null
+ local _timeout=""
+ which timeout >/dev/null && _timeout="timeout --foreground 90"
+ if [[ "$MAKE_OPTIONS" =~ "tune" ]]
+ then
+ # "make tune" will run "tune_it.sh" automatically, hence "autotune", but it cannot
+ # get switched off without some effort, so we just let it run twice for testing purposes
+ echo -e "\rRun autotune $1 $2"
+ _make "$1" "$2" ""
+ $_timeout $TUNE_CMD > test_${suffix}.log || _die "running autotune" $?
+ else
+ _make "$1" "$2" "test"
+ echo -e "\rRun test $1 $2"
+ $_timeout ./test > test_${suffix}.log || _die "running tests" $?
+ fi
+}
+
+# This is not much more of a C&P of _runtest with a different timeout
+# and the additional valgrind call.
+# TODO: merge
+_runvalgrind()
+{
+ make clean > /dev/null
+ local _timeout=""
+ # 30 minutes? Yes. Had it at 20 minutes and the Valgrind run needed over 25 minutes.
+ # A bit too close for comfort.
+ which timeout >/dev/null && _timeout="timeout --foreground 1800"
+echo "MAKE_OPTIONS = \"$MAKE_OPTIONS\""
+ if [[ "$MAKE_OPTIONS" =~ "tune" ]]
+ then
+echo "autotune branch"
+ _make "$1" "$2" ""
+ # The shell used for /bin/sh is DASH 0.5.7-4ubuntu1 on the author's machine which fails valgrind, so
+ # we just run on instance of etc/tune with the same options as in etc/tune_it.sh
+ echo -e "\rRun etc/tune $1 $2 once inside valgrind"
+ $_timeout $VALGRIND_BIN $VALGRIND_OPTS $TUNE_CMD > test_${suffix}.log || _die "running etc/tune" $?
+ else
+ _make "$1" "$2" "test"
+ echo -e "\rRun test $1 $2 inside valgrind"
+ $_timeout $VALGRIND_BIN $VALGRIND_OPTS ./test > test_${suffix}.log || _die "running tests" $?
+ fi
+}
+
+
+_banner()
+{
+ echo "uname="$(uname -a)
+ [[ "$#" != "0" ]] && (echo $1=$($1 -dumpversion)) || true
+}
+
+_exit()
+{
+ if [ "$ret" == "0" ]
+ then
+ echo "Tests successful"
+ else
+ echo "$ret tests timed out"
+ fi
+
+ exit $ret
+}
+
+ARCHFLAGS=""
+COMPILERS=""
+CFLAGS=""
+WITH_LOW_MP=""
+TEST_VS_MTEST=""
+MTEST_RAND=""
+# timed with an AMD A8-6600K
+# 25 minutes
+#VALGRIND_OPTS=" --track-origins=yes --leak-check=full --show-leak-kinds=all --error-exitcode=1 "
+# 9 minutes (14 minutes with --test-vs-mtest=333333 --mtest-real-rand)
+VALGRIND_OPTS=" --leak-check=full --show-leak-kinds=all --error-exitcode=1 "
+#VALGRIND_OPTS=""
+VALGRIND_BIN=""
+CHECK_FORMAT=""
+TUNE_CMD="./etc/tune -t -r 10 -L 3"
+
+alive_pid=0
+
+function kill_alive() {
+ disown $alive_pid || true
+ kill $alive_pid 2>/dev/null
+}
+
+function start_alive_printing() {
+ [ "$alive_pid" == "0" ] || return 0;
+ for i in `seq 1 10` ; do sleep 300 && echo "Tests still in Progress..."; done &
+ alive_pid=$!
+ trap kill_alive EXIT
+}
+
+while [ $# -gt 0 ];
+do
+ case $1 in
+ "--with-m64" | "--with-m32" | "--with-mx32")
+ ARCHFLAGS="$ARCHFLAGS ${1:6}"
+ ;;
+ --with-cc=*)
+ COMPILERS="$COMPILERS ${1#*=}"
+ ;;
+ --cflags=*)
+ CFLAGS="$CFLAGS ${1#*=}"
+ ;;
+ --valgrind-options=*)
+ VALGRIND_OPTS="$VALGRIND_OPTS ${1#*=}"
+ ;;
+ --with-valgrind*)
+ if [[ ${1#*d} != "" ]]
+ then
+ VALGRIND_BIN="${1#*=}"
+ else
+ VALGRIND_BIN="valgrind"
+ fi
+ start_alive_printing
+ ;;
+ --with-travis-valgrind*)
+ if [[ ("$TRAVIS_BRANCH" == "develop" && "$TRAVIS_PULL_REQUEST" == "false") || "$TRAVIS_BRANCH" == *"valgrind"* || "$TRAVIS_COMMIT_MESSAGE" == *"valgrind"* ]]
+ then
+ if [[ ${1#*d} != "" ]]
+ then
+ VALGRIND_BIN="${1#*=}"
+ else
+ VALGRIND_BIN="valgrind"
+ fi
+ start_alive_printing
+ fi
+ ;;
+ --make-option=*)
+ MAKE_OPTIONS="$MAKE_OPTIONS ${1#*=}"
+ ;;
+ --with-low-mp)
+ WITH_LOW_MP="1"
+ ;;
+ --test-vs-mtest=*)
+ TEST_VS_MTEST="${1#*=}"
+ if ! [ "$TEST_VS_MTEST" -eq "$TEST_VS_MTEST" ] 2> /dev/null
+ then
+ echo "--test-vs-mtest Parameter has to be int"
+ exit 255
+ fi
+ start_alive_printing
+ ;;
+ --mtest-real-rand)
+ MTEST_RAND="-DLTM_MTEST_REAL_RAND"
+ ;;
+ --format)
+ CHECK_FORMAT="1"
+ ;;
+ --all)
+ COMPILERS="gcc clang"
+ ARCHFLAGS="-m64 -m32 -mx32"
+ ;;
+ --help | -h)
+ _help
+ ;;
+ --version | -v)
+ echo $(git rev-list HEAD --count -- testme.sh) || echo "Unknown. Please run in original libtommath git repository."
+ exit 0
+ ;;
+ *)
+ echo "Ignoring option ${1}"
+ ;;
+ esac
+ shift
+done
+
+function _check_git() {
+ git update-index --refresh >/dev/null || true
+ git diff-index --quiet HEAD -- . || ( echo "FAILURE: $*" && exit 1 )
+}
+
+if [[ "$CHECK_FORMAT" == "1" ]]
+then
+ make astyle
+ _check_git "make astyle"
+ perl helper.pl --update-files
+ _check_git "helper.pl --update-files"
+ perl helper.pl --check-all
+ _check_git "helper.pl --check-all"
+ exit $?
+fi
+
+[[ "$VALGRIND_BIN" == "" ]] && VALGRIND_OPTS=""
+
+# default to CC environment variable if no compiler is defined but some other options
+if [[ "$COMPILERS" == "" ]] && [[ "$ARCHFLAGS$MAKE_OPTIONS$CFLAGS" != "" ]]
+then
+ COMPILERS="$CC"
+# default to CC environment variable and run only default config if no option is given
+elif [[ "$COMPILERS" == "" ]]
+then
+ _banner "$CC"
+ if [[ "$VALGRIND_BIN" != "" ]]
+ then
+ _runvalgrind "$CC" ""
+ else
+ _runtest "$CC" ""
+ fi
+ _exit
+fi
+
+
+archflags=( $ARCHFLAGS )
+compilers=( $COMPILERS )
+
+# choosing a compiler without specifying an architecture will use the default architecture
+if [ "${#archflags[@]}" == "0" ]
+then
+ archflags[0]=" "
+fi
+
+_banner
+
+if [[ "$TEST_VS_MTEST" != "" ]]
+then
+ make clean > /dev/null
+ _make "${compilers[0]} ${archflags[0]}" "$CFLAGS" "mtest_opponent"
+ echo
+ _make "gcc" "$MTEST_RAND" "mtest"
+ echo
+ echo "Run test vs. mtest for $TEST_VS_MTEST iterations"
+ _timeout=""
+ which timeout >/dev/null && _timeout="timeout --foreground 1800"
+ $_timeout ./mtest/mtest $TEST_VS_MTEST | $VALGRIND_BIN $VALGRIND_OPTS ./mtest_opponent > valgrind_test.log 2> test_vs_mtest_err.log
+ retval=$?
+ head -n 5 valgrind_test.log
+ tail -n 2 valgrind_test.log
+ exit $retval
+fi
+
+for i in "${compilers[@]}"
+do
+ if [ -z "$(which $i)" ]
+ then
+ echo "Skipped compiler $i, file not found"
+ continue
+ fi
+ compiler_version=$(echo "$i="$($i -dumpversion))
+ if [ "$compiler_version" == "clang=4.2.1" ]
+ then
+ # one of my versions of clang complains about some stuff in stdio.h and stdarg.h ...
+ TEST_CFLAGS="-Wno-typedef-redefinition"
+ else
+ TEST_CFLAGS=""
+ fi
+ echo $compiler_version
+
+ for a in "${archflags[@]}"
+ do
+ if [[ $(expr "$i" : "clang") -ne 0 && "$a" == "-mx32" ]]
+ then
+ echo "clang -mx32 tests skipped"
+ continue
+ fi
+ if [[ "$VALGRIND_BIN" != "" ]]
+ then
+ _runvalgrind "$i $a" "$CFLAGS"
+ [ "$WITH_LOW_MP" != "1" ] && continue
+ _runvalgrind "$i $a" "-DMP_8BIT $CFLAGS"
+ _runvalgrind "$i $a" "-DMP_16BIT $CFLAGS"
+ _runvalgrind "$i $a" "-DMP_32BIT $CFLAGS"
+ else
+ _runtest "$i $a" "$CFLAGS"
+ [ "$WITH_LOW_MP" != "1" ] && continue
+ _runtest "$i $a" "-DMP_8BIT $CFLAGS"
+ _runtest "$i $a" "-DMP_16BIT $CFLAGS"
+ _runtest "$i $a" "-DMP_32BIT $CFLAGS"
+ fi
+ done
+done
+
+_exit
ADDED libtommath/tommath.def
Index: libtommath/tommath.def
==================================================================
--- /dev/null
+++ libtommath/tommath.def
@@ -0,0 +1,145 @@
+; libtommath
+;
+; Use this command to produce a 32-bit .lib file, for use in any MSVC version
+; lib -machine:X86 -name:libtommath.dll -def:tommath.def -out:tommath.lib
+; Use this command to produce a 64-bit .lib file, for use in any MSVC version
+; lib -machine:X64 -name:libtommath.dll -def:tommath.def -out:tommath.lib
+;
+EXPORTS
+ mp_2expt
+ mp_abs
+ mp_add
+ mp_add_d
+ mp_addmod
+ mp_and
+ mp_clamp
+ mp_clear
+ mp_clear_multi
+ mp_cmp
+ mp_cmp_d
+ mp_cmp_mag
+ mp_cnt_lsb
+ mp_complement
+ mp_copy
+ mp_count_bits
+ mp_decr
+ mp_div
+ mp_div_2
+ mp_div_2d
+ mp_div_3
+ mp_div_d
+ mp_dr_is_modulus
+ mp_dr_reduce
+ mp_dr_setup
+ mp_error_to_string
+ mp_exch
+ mp_expt_u32
+ mp_exptmod
+ mp_exteuclid
+ mp_fread
+ mp_from_sbin
+ mp_from_ubin
+ mp_fwrite
+ mp_gcd
+ mp_get_double
+ mp_get_i32
+ mp_get_i64
+ mp_get_int
+ mp_get_l
+ mp_get_ll
+ mp_get_long
+ mp_get_long_long
+ mp_get_mag_u32
+ mp_get_mag_u64
+ mp_get_mag_ul
+ mp_get_mag_ull
+ mp_grow
+ mp_incr
+ mp_init
+ mp_init_copy
+ mp_init_i32
+ mp_init_i64
+ mp_init_l
+ mp_init_ll
+ mp_init_multi
+ mp_init_set
+ mp_init_set_int
+ mp_init_size
+ mp_init_u32
+ mp_init_u64
+ mp_init_ul
+ mp_init_ull
+ mp_invmod
+ mp_is_square
+ mp_iseven
+ mp_isodd
+ mp_kronecker
+ mp_lcm
+ mp_log_u32
+ mp_lshd
+ mp_mod
+ mp_mod_2d
+ mp_mod_d
+ mp_montgomery_calc_normalization
+ mp_montgomery_reduce
+ mp_montgomery_setup
+ mp_mul
+ mp_mul_2
+ mp_mul_2d
+ mp_mul_d
+ mp_mulmod
+ mp_neg
+ mp_or
+ mp_pack
+ mp_pack_count
+ mp_prime_fermat
+ mp_prime_frobenius_underwood
+ mp_prime_is_prime
+ mp_prime_miller_rabin
+ mp_prime_next_prime
+ mp_prime_rabin_miller_trials
+ mp_prime_rand
+ mp_prime_strong_lucas_selfridge
+ mp_radix_size
+ mp_rand
+ mp_read_radix
+ mp_reduce
+ mp_reduce_2k
+ mp_reduce_2k_l
+ mp_reduce_2k_setup
+ mp_reduce_2k_setup_l
+ mp_reduce_is_2k
+ mp_reduce_is_2k_l
+ mp_reduce_setup
+ mp_root_u32
+ mp_rshd
+ mp_sbin_size
+ mp_set
+ mp_set_double
+ mp_set_i32
+ mp_set_i64
+ mp_set_int
+ mp_set_l
+ mp_set_ll
+ mp_set_long
+ mp_set_long_long
+ mp_set_u32
+ mp_set_u64
+ mp_set_ul
+ mp_set_ull
+ mp_shrink
+ mp_signed_rsh
+ mp_sqr
+ mp_sqrmod
+ mp_sqrt
+ mp_sqrtmod_prime
+ mp_sub
+ mp_sub_d
+ mp_submod
+ mp_to_radix
+ mp_to_sbin
+ mp_to_ubin
+ mp_ubin_size
+ mp_unpack
+ mp_xor
+ mp_zero
ADDED libtommath/tommath.h
Index: libtommath/tommath.h
==================================================================
--- /dev/null
+++ libtommath/tommath.h
@@ -0,0 +1,790 @@
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#ifndef BN_H_
+#define BN_H_
+
+#include
+#include
+#include
+
+#ifdef LTM_NO_FILE
+# warning LTM_NO_FILE has been deprecated, use MP_NO_FILE.
+# define MP_NO_FILE
+#endif
+
+#ifndef MP_NO_FILE
+# include
+#endif
+
+#ifdef MP_8BIT
+# ifdef _MSC_VER
+# pragma message("8-bit (MP_8BIT) support is deprecated and will be dropped completely in the next version.")
+# else
+# warning "8-bit (MP_8BIT) support is deprecated and will be dropped completely in the next version."
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* MS Visual C++ doesn't have a 128bit type for words, so fall back to 32bit MPI's (where words are 64bit) */
+#if (defined(_MSC_VER) || defined(__LLP64__) || defined(__e2k__) || defined(__LCC__)) && !defined(MP_64BIT)
+# define MP_32BIT
+#endif
+
+/* detect 64-bit mode if possible */
+#if defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64) || \
+ defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__) || \
+ defined(__s390x__) || defined(__arch64__) || defined(__aarch64__) || \
+ defined(__sparcv9) || defined(__sparc_v9__) || defined(__sparc64__) || \
+ defined(__ia64) || defined(__ia64__) || defined(__itanium__) || defined(_M_IA64) || \
+ defined(__LP64__) || defined(_LP64) || defined(__64BIT__)
+# if !(defined(MP_64BIT) || defined(MP_32BIT) || defined(MP_16BIT) || defined(MP_8BIT))
+# if defined(__GNUC__) && !defined(__hppa)
+/* we support 128bit integers only via: __attribute__((mode(TI))) */
+# define MP_64BIT
+# else
+/* otherwise we fall back to MP_32BIT even on 64bit platforms */
+# define MP_32BIT
+# endif
+# endif
+#endif
+
+#ifdef MP_DIGIT_BIT
+# error Defining MP_DIGIT_BIT is disallowed, use MP_8/16/31/32/64BIT
+#endif
+
+/* some default configurations.
+ *
+ * A "mp_digit" must be able to hold MP_DIGIT_BIT + 1 bits
+ * A "mp_word" must be able to hold 2*MP_DIGIT_BIT + 1 bits
+ *
+ * At the very least a mp_digit must be able to hold 7 bits
+ * [any size beyond that is ok provided it doesn't overflow the data type]
+ */
+
+#ifdef MP_8BIT
+typedef uint8_t mp_digit;
+typedef uint16_t private_mp_word;
+# define MP_DIGIT_BIT 7
+#elif defined(MP_16BIT)
+typedef uint16_t mp_digit;
+typedef uint32_t private_mp_word;
+# define MP_DIGIT_BIT 15
+#elif defined(MP_64BIT)
+/* for GCC only on supported platforms */
+typedef uint64_t mp_digit;
+#if defined(__GNUC__)
+typedef unsigned long private_mp_word __attribute__((mode(TI)));
+#endif
+# define MP_DIGIT_BIT 60
+#else
+typedef uint32_t mp_digit;
+typedef uint64_t private_mp_word;
+# ifdef MP_31BIT
+/*
+ * This is an extension that uses 31-bit digits.
+ * Please be aware that not all functions support this size, especially s_mp_mul_digs_fast
+ * will be reduced to work on small numbers only:
+ * Up to 8 limbs, 248 bits instead of up to 512 limbs, 15872 bits with MP_28BIT.
+ */
+# define MP_DIGIT_BIT 31
+# else
+/* default case is 28-bit digits, defines MP_28BIT as a handy macro to test */
+# define MP_DIGIT_BIT 28
+# define MP_28BIT
+# endif
+#endif
+
+/* mp_word is a private type */
+#define mp_word MP_DEPRECATED_PRAGMA("mp_word has been made private") private_mp_word
+
+#define MP_SIZEOF_MP_DIGIT (MP_DEPRECATED_PRAGMA("MP_SIZEOF_MP_DIGIT has been deprecated, use sizeof (mp_digit)") sizeof (mp_digit))
+
+#define MP_MASK ((((mp_digit)1)<<((mp_digit)MP_DIGIT_BIT))-((mp_digit)1))
+#define MP_DIGIT_MAX MP_MASK
+
+/* Primality generation flags */
+#define MP_PRIME_BBS 0x0001 /* BBS style prime */
+#define MP_PRIME_SAFE 0x0002 /* Safe prime (p-1)/2 == prime */
+#define MP_PRIME_2MSB_ON 0x0008 /* force 2nd MSB to 1 */
+
+#define LTM_PRIME_BBS (MP_DEPRECATED_PRAGMA("LTM_PRIME_BBS has been deprecated, use MP_PRIME_BBS") MP_PRIME_BBS)
+#define LTM_PRIME_SAFE (MP_DEPRECATED_PRAGMA("LTM_PRIME_SAFE has been deprecated, use MP_PRIME_SAFE") MP_PRIME_SAFE)
+#define LTM_PRIME_2MSB_ON (MP_DEPRECATED_PRAGMA("LTM_PRIME_2MSB_ON has been deprecated, use MP_PRIME_2MSB_ON") MP_PRIME_2MSB_ON)
+
+#ifdef MP_USE_ENUMS
+typedef enum {
+ MP_ZPOS = 0, /* positive */
+ MP_NEG = 1 /* negative */
+} mp_sign;
+typedef enum {
+ MP_LT = -1, /* less than */
+ MP_EQ = 0, /* equal */
+ MP_GT = 1 /* greater than */
+} mp_ord;
+typedef enum {
+ MP_NO = 0,
+ MP_YES = 1
+} mp_bool;
+typedef enum {
+ MP_OKAY = 0, /* no error */
+ MP_ERR = -1, /* unknown error */
+ MP_MEM = -2, /* out of mem */
+ MP_VAL = -3, /* invalid input */
+ MP_ITER = -4, /* maximum iterations reached */
+ MP_BUF = -5 /* buffer overflow, supplied buffer too small */
+} mp_err;
+typedef enum {
+ MP_LSB_FIRST = -1,
+ MP_MSB_FIRST = 1
+} mp_order;
+typedef enum {
+ MP_LITTLE_ENDIAN = -1,
+ MP_NATIVE_ENDIAN = 0,
+ MP_BIG_ENDIAN = 1
+} mp_endian;
+#else
+typedef int mp_sign;
+#define MP_ZPOS 0 /* positive integer */
+#define MP_NEG 1 /* negative */
+typedef int mp_ord;
+#define MP_LT -1 /* less than */
+#define MP_EQ 0 /* equal to */
+#define MP_GT 1 /* greater than */
+typedef int mp_bool;
+#define MP_YES 1
+#define MP_NO 0
+typedef int mp_err;
+#define MP_OKAY 0 /* no error */
+#define MP_ERR -1 /* unknown error */
+#define MP_MEM -2 /* out of mem */
+#define MP_VAL -3 /* invalid input */
+#define MP_RANGE (MP_DEPRECATED_PRAGMA("MP_RANGE has been deprecated in favor of MP_VAL") MP_VAL)
+#define MP_ITER -4 /* maximum iterations reached */
+#define MP_BUF -5 /* buffer overflow, supplied buffer too small */
+typedef int mp_order;
+#define MP_LSB_FIRST -1
+#define MP_MSB_FIRST 1
+typedef int mp_endian;
+#define MP_LITTLE_ENDIAN -1
+#define MP_NATIVE_ENDIAN 0
+#define MP_BIG_ENDIAN 1
+#endif
+
+/* tunable cutoffs */
+
+#ifndef MP_FIXED_CUTOFFS
+extern int
+KARATSUBA_MUL_CUTOFF,
+KARATSUBA_SQR_CUTOFF,
+TOOM_MUL_CUTOFF,
+TOOM_SQR_CUTOFF;
+#endif
+
+/* define this to use lower memory usage routines (exptmods mostly) */
+/* #define MP_LOW_MEM */
+
+/* default precision */
+#ifndef MP_PREC
+# ifndef MP_LOW_MEM
+# define PRIVATE_MP_PREC 32 /* default digits of precision */
+# elif defined(MP_8BIT)
+# define PRIVATE_MP_PREC 16 /* default digits of precision */
+# else
+# define PRIVATE_MP_PREC 8 /* default digits of precision */
+# endif
+# define MP_PREC (MP_DEPRECATED_PRAGMA("MP_PREC is an internal macro") PRIVATE_MP_PREC)
+#endif
+
+/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */
+#define PRIVATE_MP_WARRAY (int)(1 << (((CHAR_BIT * (int)sizeof(private_mp_word)) - (2 * MP_DIGIT_BIT)) + 1))
+#define MP_WARRAY (MP_DEPRECATED_PRAGMA("MP_WARRAY is an internal macro") PRIVATE_MP_WARRAY)
+
+#if defined(__GNUC__) && __GNUC__ >= 4
+# define MP_NULL_TERMINATED __attribute__((sentinel))
+#else
+# define MP_NULL_TERMINATED
+#endif
+
+/*
+ * MP_WUR - warn unused result
+ * ---------------------------
+ *
+ * The result of functions annotated with MP_WUR must be
+ * checked and cannot be ignored.
+ *
+ * Most functions in libtommath return an error code.
+ * This error code must be checked in order to prevent crashes or invalid
+ * results.
+ *
+ * If you still want to avoid the error checks for quick and dirty programs
+ * without robustness guarantees, you can `#define MP_WUR` before including
+ * tommath.h, disabling the warnings.
+ */
+#ifndef MP_WUR
+# if defined(__GNUC__) && __GNUC__ >= 4
+# define MP_WUR __attribute__((warn_unused_result))
+# else
+# define MP_WUR
+# endif
+#endif
+
+#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 405)
+# define MP_DEPRECATED(x) __attribute__((deprecated("replaced by " #x)))
+#elif defined(_MSC_VER) && _MSC_VER >= 1500
+# define MP_DEPRECATED(x) __declspec(deprecated("replaced by " #x))
+#else
+# define MP_DEPRECATED(x)
+#endif
+
+#ifndef MP_NO_DEPRECATED_PRAGMA
+#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 301)
+# define PRIVATE_MP_DEPRECATED_PRAGMA(s) _Pragma(#s)
+# define MP_DEPRECATED_PRAGMA(s) PRIVATE_MP_DEPRECATED_PRAGMA(GCC warning s)
+#elif defined(_MSC_VER) && _MSC_VER >= 1500
+# define MP_DEPRECATED_PRAGMA(s) __pragma(message(s))
+#endif
+#endif
+
+#ifndef MP_DEPRECATED_PRAGMA
+# define MP_DEPRECATED_PRAGMA(s)
+#endif
+
+#define DIGIT_BIT (MP_DEPRECATED_PRAGMA("DIGIT_BIT macro is deprecated, MP_DIGIT_BIT instead") MP_DIGIT_BIT)
+#define USED(m) (MP_DEPRECATED_PRAGMA("USED macro is deprecated, use z->used instead") (m)->used)
+#define DIGIT(m, k) (MP_DEPRECATED_PRAGMA("DIGIT macro is deprecated, use z->dp instead") (m)->dp[(k)])
+#define SIGN(m) (MP_DEPRECATED_PRAGMA("SIGN macro is deprecated, use z->sign instead") (m)->sign)
+
+/* the infamous mp_int structure */
+typedef struct {
+ int used, alloc;
+ mp_sign sign;
+ mp_digit *dp;
+} mp_int;
+
+/* callback for mp_prime_random, should fill dst with random bytes and return how many read [upto len] */
+typedef int private_mp_prime_callback(unsigned char *dst, int len, void *dat);
+typedef private_mp_prime_callback MP_DEPRECATED(mp_rand_source) ltm_prime_callback;
+
+/* error code to char* string */
+const char *mp_error_to_string(mp_err code) MP_WUR;
+
+/* ---> init and deinit bignum functions <--- */
+/* init a bignum */
+mp_err mp_init(mp_int *a) MP_WUR;
+
+/* free a bignum */
+void mp_clear(mp_int *a);
+
+/* init a null terminated series of arguments */
+mp_err mp_init_multi(mp_int *mp, ...) MP_NULL_TERMINATED MP_WUR;
+
+/* clear a null terminated series of arguments */
+void mp_clear_multi(mp_int *mp, ...) MP_NULL_TERMINATED;
+
+/* exchange two ints */
+void mp_exch(mp_int *a, mp_int *b);
+
+/* shrink ram required for a bignum */
+mp_err mp_shrink(mp_int *a) MP_WUR;
+
+/* grow an int to a given size */
+mp_err mp_grow(mp_int *a, int size) MP_WUR;
+
+/* init to a given number of digits */
+mp_err mp_init_size(mp_int *a, int size) MP_WUR;
+
+/* ---> Basic Manipulations <--- */
+#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO)
+mp_bool mp_iseven(const mp_int *a) MP_WUR;
+mp_bool mp_isodd(const mp_int *a) MP_WUR;
+#define mp_isneg(a) (((a)->sign != MP_ZPOS) ? MP_YES : MP_NO)
+
+/* set to zero */
+void mp_zero(mp_int *a);
+
+/* get and set doubles */
+double mp_get_double(const mp_int *a) MP_WUR;
+mp_err mp_set_double(mp_int *a, double b) MP_WUR;
+
+/* get integer, set integer and init with integer (int32_t) */
+int32_t mp_get_i32(const mp_int *a) MP_WUR;
+void mp_set_i32(mp_int *a, int32_t b);
+mp_err mp_init_i32(mp_int *a, int32_t b) MP_WUR;
+
+/* get integer, set integer and init with integer, behaves like two complement for negative numbers (uint32_t) */
+#define mp_get_u32(a) ((uint32_t)mp_get_i32(a))
+void mp_set_u32(mp_int *a, uint32_t b);
+mp_err mp_init_u32(mp_int *a, uint32_t b) MP_WUR;
+
+/* get integer, set integer and init with integer (int64_t) */
+int64_t mp_get_i64(const mp_int *a) MP_WUR;
+void mp_set_i64(mp_int *a, int64_t b);
+mp_err mp_init_i64(mp_int *a, int64_t b) MP_WUR;
+
+/* get integer, set integer and init with integer, behaves like two complement for negative numbers (uint64_t) */
+#define mp_get_u64(a) ((uint64_t)mp_get_i64(a))
+void mp_set_u64(mp_int *a, uint64_t b);
+mp_err mp_init_u64(mp_int *a, uint64_t b) MP_WUR;
+
+/* get magnitude */
+uint32_t mp_get_mag_u32(const mp_int *a) MP_WUR;
+uint64_t mp_get_mag_u64(const mp_int *a) MP_WUR;
+unsigned long mp_get_mag_ul(const mp_int *a) MP_WUR;
+unsigned long long mp_get_mag_ull(const mp_int *a) MP_WUR;
+
+/* get integer, set integer (long) */
+long mp_get_l(const mp_int *a) MP_WUR;
+void mp_set_l(mp_int *a, long b);
+mp_err mp_init_l(mp_int *a, long b) MP_WUR;
+
+/* get integer, set integer (unsigned long) */
+#define mp_get_ul(a) ((unsigned long)mp_get_l(a))
+void mp_set_ul(mp_int *a, unsigned long b);
+mp_err mp_init_ul(mp_int *a, unsigned long b) MP_WUR;
+
+/* get integer, set integer (long long) */
+long long mp_get_ll(const mp_int *a) MP_WUR;
+void mp_set_ll(mp_int *a, long long b);
+mp_err mp_init_ll(mp_int *a, long long b) MP_WUR;
+
+/* get integer, set integer (unsigned long long) */
+#define mp_get_ull(a) ((unsigned long long)mp_get_ll(a))
+void mp_set_ull(mp_int *a, unsigned long long b);
+mp_err mp_init_ull(mp_int *a, unsigned long long b) MP_WUR;
+
+/* set to single unsigned digit, up to MP_DIGIT_MAX */
+void mp_set(mp_int *a, mp_digit b);
+mp_err mp_init_set(mp_int *a, mp_digit b) MP_WUR;
+
+/* get integer, set integer and init with integer (deprecated) */
+MP_DEPRECATED(mp_get_mag_u32/mp_get_u32) unsigned long mp_get_int(const mp_int *a) MP_WUR;
+MP_DEPRECATED(mp_get_mag_ul/mp_get_ul) unsigned long mp_get_long(const mp_int *a) MP_WUR;
+MP_DEPRECATED(mp_get_mag_ull/mp_get_ull) unsigned long long mp_get_long_long(const mp_int *a) MP_WUR;
+MP_DEPRECATED(mp_set_ul) mp_err mp_set_int(mp_int *a, unsigned long b);
+MP_DEPRECATED(mp_set_ul) mp_err mp_set_long(mp_int *a, unsigned long b);
+MP_DEPRECATED(mp_set_ull) mp_err mp_set_long_long(mp_int *a, unsigned long long b);
+MP_DEPRECATED(mp_init_ul) mp_err mp_init_set_int(mp_int *a, unsigned long b) MP_WUR;
+
+/* copy, b = a */
+mp_err mp_copy(const mp_int *a, mp_int *b) MP_WUR;
+
+/* inits and copies, a = b */
+mp_err mp_init_copy(mp_int *a, const mp_int *b) MP_WUR;
+
+/* trim unused digits */
+void mp_clamp(mp_int *a);
+
+
+/* export binary data */
+MP_DEPRECATED(mp_pack) mp_err mp_export(void *rop, size_t *countp, int order, size_t size,
+ int endian, size_t nails, const mp_int *op) MP_WUR;
+
+/* import binary data */
+MP_DEPRECATED(mp_unpack) mp_err mp_import(mp_int *rop, size_t count, int order,
+ size_t size, int endian, size_t nails,
+ const void *op) MP_WUR;
+
+/* unpack binary data */
+mp_err mp_unpack(mp_int *rop, size_t count, mp_order order, size_t size, mp_endian endian,
+ size_t nails, const void *op) MP_WUR;
+
+/* pack binary data */
+size_t mp_pack_count(const mp_int *a, size_t nails, size_t size) MP_WUR;
+mp_err mp_pack(void *rop, size_t maxcount, size_t *written, mp_order order, size_t size,
+ mp_endian endian, size_t nails, const mp_int *op) MP_WUR;
+
+/* ---> digit manipulation <--- */
+
+/* right shift by "b" digits */
+void mp_rshd(mp_int *a, int b);
+
+/* left shift by "b" digits */
+mp_err mp_lshd(mp_int *a, int b) MP_WUR;
+
+/* c = a / 2**b, implemented as c = a >> b */
+mp_err mp_div_2d(const mp_int *a, int b, mp_int *c, mp_int *d) MP_WUR;
+
+/* b = a/2 */
+mp_err mp_div_2(const mp_int *a, mp_int *b) MP_WUR;
+
+/* a/3 => 3c + d == a */
+mp_err mp_div_3(const mp_int *a, mp_int *c, mp_digit *d) MP_WUR;
+
+/* c = a * 2**b, implemented as c = a << b */
+mp_err mp_mul_2d(const mp_int *a, int b, mp_int *c) MP_WUR;
+
+/* b = a*2 */
+mp_err mp_mul_2(const mp_int *a, mp_int *b) MP_WUR;
+
+/* c = a mod 2**b */
+mp_err mp_mod_2d(const mp_int *a, int b, mp_int *c) MP_WUR;
+
+/* computes a = 2**b */
+mp_err mp_2expt(mp_int *a, int b) MP_WUR;
+
+/* Counts the number of lsbs which are zero before the first zero bit */
+int mp_cnt_lsb(const mp_int *a) MP_WUR;
+
+/* I Love Earth! */
+
+/* makes a pseudo-random mp_int of a given size */
+mp_err mp_rand(mp_int *a, int digits) MP_WUR;
+/* makes a pseudo-random small int of a given size */
+MP_DEPRECATED(mp_rand) mp_err mp_rand_digit(mp_digit *r) MP_WUR;
+/* use custom random data source instead of source provided the platform */
+void mp_rand_source(mp_err(*source)(void *out, size_t size));
+
+#ifdef MP_PRNG_ENABLE_LTM_RNG
+# warning MP_PRNG_ENABLE_LTM_RNG has been deprecated, use mp_rand_source instead.
+/* A last resort to provide random data on systems without any of the other
+ * implemented ways to gather entropy.
+ * It is compatible with `rng_get_bytes()` from libtomcrypt so you could
+ * provide that one and then set `ltm_rng = rng_get_bytes;` */
+extern unsigned long (*ltm_rng)(unsigned char *out, unsigned long outlen, void (*callback)(void));
+extern void (*ltm_rng_callback)(void);
+#endif
+
+/* ---> binary operations <--- */
+
+/* Checks the bit at position b and returns MP_YES
+ * if the bit is 1, MP_NO if it is 0 and MP_VAL
+ * in case of error
+ */
+MP_DEPRECATED(s_mp_get_bit) int mp_get_bit(const mp_int *a, int b) MP_WUR;
+
+/* c = a XOR b (two complement) */
+MP_DEPRECATED(mp_xor) mp_err mp_tc_xor(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+mp_err mp_xor(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+
+/* c = a OR b (two complement) */
+MP_DEPRECATED(mp_or) mp_err mp_tc_or(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+mp_err mp_or(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+
+/* c = a AND b (two complement) */
+MP_DEPRECATED(mp_and) mp_err mp_tc_and(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+mp_err mp_and(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+
+/* b = ~a (bitwise not, two complement) */
+mp_err mp_complement(const mp_int *a, mp_int *b) MP_WUR;
+
+/* right shift with sign extension */
+MP_DEPRECATED(mp_signed_rsh) mp_err mp_tc_div_2d(const mp_int *a, int b, mp_int *c) MP_WUR;
+mp_err mp_signed_rsh(const mp_int *a, int b, mp_int *c) MP_WUR;
+
+/* ---> Basic arithmetic <--- */
+
+/* b = -a */
+mp_err mp_neg(const mp_int *a, mp_int *b) MP_WUR;
+
+/* b = |a| */
+mp_err mp_abs(const mp_int *a, mp_int *b) MP_WUR;
+
+/* compare a to b */
+mp_ord mp_cmp(const mp_int *a, const mp_int *b) MP_WUR;
+
+/* compare |a| to |b| */
+mp_ord mp_cmp_mag(const mp_int *a, const mp_int *b) MP_WUR;
+
+/* c = a + b */
+mp_err mp_add(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+
+/* c = a - b */
+mp_err mp_sub(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+
+/* c = a * b */
+mp_err mp_mul(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+
+/* b = a*a */
+mp_err mp_sqr(const mp_int *a, mp_int *b) MP_WUR;
+
+/* a/b => cb + d == a */
+mp_err mp_div(const mp_int *a, const mp_int *b, mp_int *c, mp_int *d) MP_WUR;
+
+/* c = a mod b, 0 <= c < b */
+mp_err mp_mod(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+
+/* Increment "a" by one like "a++". Changes input! */
+mp_err mp_incr(mp_int *a) MP_WUR;
+
+/* Decrement "a" by one like "a--". Changes input! */
+mp_err mp_decr(mp_int *a) MP_WUR;
+
+/* ---> single digit functions <--- */
+
+/* compare against a single digit */
+mp_ord mp_cmp_d(const mp_int *a, mp_digit b) MP_WUR;
+
+/* c = a + b */
+mp_err mp_add_d(const mp_int *a, mp_digit b, mp_int *c) MP_WUR;
+
+/* c = a - b */
+mp_err mp_sub_d(const mp_int *a, mp_digit b, mp_int *c) MP_WUR;
+
+/* c = a * b */
+mp_err mp_mul_d(const mp_int *a, mp_digit b, mp_int *c) MP_WUR;
+
+/* a/b => cb + d == a */
+mp_err mp_div_d(const mp_int *a, mp_digit b, mp_int *c, mp_digit *d) MP_WUR;
+
+/* c = a mod b, 0 <= c < b */
+mp_err mp_mod_d(const mp_int *a, mp_digit b, mp_digit *c) MP_WUR;
+
+/* ---> number theory <--- */
+
+/* d = a + b (mod c) */
+mp_err mp_addmod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d) MP_WUR;
+
+/* d = a - b (mod c) */
+mp_err mp_submod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d) MP_WUR;
+
+/* d = a * b (mod c) */
+mp_err mp_mulmod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d) MP_WUR;
+
+/* c = a * a (mod b) */
+mp_err mp_sqrmod(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+
+/* c = 1/a (mod b) */
+mp_err mp_invmod(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+
+/* c = (a, b) */
+mp_err mp_gcd(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+
+/* produces value such that U1*a + U2*b = U3 */
+mp_err mp_exteuclid(const mp_int *a, const mp_int *b, mp_int *U1, mp_int *U2, mp_int *U3) MP_WUR;
+
+/* c = [a, b] or (a*b)/(a, b) */
+mp_err mp_lcm(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+
+/* finds one of the b'th root of a, such that |c|**b <= |a|
+ *
+ * returns error if a < 0 and b is even
+ */
+mp_err mp_root_u32(const mp_int *a, uint32_t b, mp_int *c) MP_WUR;
+MP_DEPRECATED(mp_root_u32) mp_err mp_n_root(const mp_int *a, mp_digit b, mp_int *c) MP_WUR;
+MP_DEPRECATED(mp_root_u32) mp_err mp_n_root_ex(const mp_int *a, mp_digit b, mp_int *c, int fast) MP_WUR;
+
+/* special sqrt algo */
+mp_err mp_sqrt(const mp_int *arg, mp_int *ret) MP_WUR;
+
+/* special sqrt (mod prime) */
+mp_err mp_sqrtmod_prime(const mp_int *n, const mp_int *prime, mp_int *ret) MP_WUR;
+
+/* is number a square? */
+mp_err mp_is_square(const mp_int *arg, mp_bool *ret) MP_WUR;
+
+/* computes the jacobi c = (a | n) (or Legendre if b is prime) */
+MP_DEPRECATED(mp_kronecker) mp_err mp_jacobi(const mp_int *a, const mp_int *n, int *c) MP_WUR;
+
+/* computes the Kronecker symbol c = (a | p) (like jacobi() but with {a,p} in Z */
+mp_err mp_kronecker(const mp_int *a, const mp_int *p, int *c) MP_WUR;
+
+/* used to setup the Barrett reduction for a given modulus b */
+mp_err mp_reduce_setup(mp_int *a, const mp_int *b) MP_WUR;
+
+/* Barrett Reduction, computes a (mod b) with a precomputed value c
+ *
+ * Assumes that 0 < x <= m*m, note if 0 > x > -(m*m) then you can merely
+ * compute the reduction as -1 * mp_reduce(mp_abs(x)) [pseudo code].
+ */
+mp_err mp_reduce(mp_int *x, const mp_int *m, const mp_int *mu) MP_WUR;
+
+/* setups the montgomery reduction */
+mp_err mp_montgomery_setup(const mp_int *n, mp_digit *rho) MP_WUR;
+
+/* computes a = B**n mod b without division or multiplication useful for
+ * normalizing numbers in a Montgomery system.
+ */
+mp_err mp_montgomery_calc_normalization(mp_int *a, const mp_int *b) MP_WUR;
+
+/* computes x/R == x (mod N) via Montgomery Reduction */
+mp_err mp_montgomery_reduce(mp_int *x, const mp_int *n, mp_digit rho) MP_WUR;
+
+/* returns 1 if a is a valid DR modulus */
+mp_bool mp_dr_is_modulus(const mp_int *a) MP_WUR;
+
+/* sets the value of "d" required for mp_dr_reduce */
+void mp_dr_setup(const mp_int *a, mp_digit *d);
+
+/* reduces a modulo n using the Diminished Radix method */
+mp_err mp_dr_reduce(mp_int *x, const mp_int *n, mp_digit k) MP_WUR;
+
+/* returns true if a can be reduced with mp_reduce_2k */
+mp_bool mp_reduce_is_2k(const mp_int *a) MP_WUR;
+
+/* determines k value for 2k reduction */
+mp_err mp_reduce_2k_setup(const mp_int *a, mp_digit *d) MP_WUR;
+
+/* reduces a modulo b where b is of the form 2**p - k [0 <= a] */
+mp_err mp_reduce_2k(mp_int *a, const mp_int *n, mp_digit d) MP_WUR;
+
+/* returns true if a can be reduced with mp_reduce_2k_l */
+mp_bool mp_reduce_is_2k_l(const mp_int *a) MP_WUR;
+
+/* determines k value for 2k reduction */
+mp_err mp_reduce_2k_setup_l(const mp_int *a, mp_int *d) MP_WUR;
+
+/* reduces a modulo b where b is of the form 2**p - k [0 <= a] */
+mp_err mp_reduce_2k_l(mp_int *a, const mp_int *n, const mp_int *d) MP_WUR;
+
+/* Y = G**X (mod P) */
+mp_err mp_exptmod(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y) MP_WUR;
+
+/* ---> Primes <--- */
+
+/* number of primes */
+#ifdef MP_8BIT
+# define PRIVATE_MP_PRIME_TAB_SIZE 31
+#else
+# define PRIVATE_MP_PRIME_TAB_SIZE 256
+#endif
+#define PRIME_SIZE (MP_DEPRECATED_PRAGMA("PRIME_SIZE has been made internal") PRIVATE_MP_PRIME_TAB_SIZE)
+
+/* table of first PRIME_SIZE primes */
+MP_DEPRECATED(internal) extern const mp_digit ltm_prime_tab[PRIVATE_MP_PRIME_TAB_SIZE];
+
+/* result=1 if a is divisible by one of the first PRIME_SIZE primes */
+MP_DEPRECATED(mp_prime_is_prime) mp_err mp_prime_is_divisible(const mp_int *a, mp_bool *result) MP_WUR;
+
+/* performs one Fermat test of "a" using base "b".
+ * Sets result to 0 if composite or 1 if probable prime
+ */
+mp_err mp_prime_fermat(const mp_int *a, const mp_int *b, mp_bool *result) MP_WUR;
+
+/* performs one Miller-Rabin test of "a" using base "b".
+ * Sets result to 0 if composite or 1 if probable prime
+ */
+mp_err mp_prime_miller_rabin(const mp_int *a, const mp_int *b, mp_bool *result) MP_WUR;
+
+/* This gives [for a given bit size] the number of trials required
+ * such that Miller-Rabin gives a prob of failure lower than 2^-96
+ */
+int mp_prime_rabin_miller_trials(int size) MP_WUR;
+
+/* performs one strong Lucas-Selfridge test of "a".
+ * Sets result to 0 if composite or 1 if probable prime
+ */
+mp_err mp_prime_strong_lucas_selfridge(const mp_int *a, mp_bool *result) MP_WUR;
+
+/* performs one Frobenius test of "a" as described by Paul Underwood.
+ * Sets result to 0 if composite or 1 if probable prime
+ */
+mp_err mp_prime_frobenius_underwood(const mp_int *N, mp_bool *result) MP_WUR;
+
+/* performs t random rounds of Miller-Rabin on "a" additional to
+ * bases 2 and 3. Also performs an initial sieve of trial
+ * division. Determines if "a" is prime with probability
+ * of error no more than (1/4)**t.
+ * Both a strong Lucas-Selfridge to complete the BPSW test
+ * and a separate Frobenius test are available at compile time.
+ * With t<0 a deterministic test is run for primes up to
+ * 318665857834031151167461. With t<13 (abs(t)-13) additional
+ * tests with sequential small primes are run starting at 43.
+ * Is Fips 186.4 compliant if called with t as computed by
+ * mp_prime_rabin_miller_trials();
+ *
+ * Sets result to 1 if probably prime, 0 otherwise
+ */
+mp_err mp_prime_is_prime(const mp_int *a, int t, mp_bool *result) MP_WUR;
+
+/* finds the next prime after the number "a" using "t" trials
+ * of Miller-Rabin.
+ *
+ * bbs_style = 1 means the prime must be congruent to 3 mod 4
+ */
+mp_err mp_prime_next_prime(mp_int *a, int t, int bbs_style) MP_WUR;
+
+/* makes a truly random prime of a given size (bytes),
+ * call with bbs = 1 if you want it to be congruent to 3 mod 4
+ *
+ * You have to supply a callback which fills in a buffer with random bytes. "dat" is a parameter you can
+ * have passed to the callback (e.g. a state or something). This function doesn't use "dat" itself
+ * so it can be NULL
+ *
+ * The prime generated will be larger than 2^(8*size).
+ */
+#define mp_prime_random(a, t, size, bbs, cb, dat) (MP_DEPRECATED_PRAGMA("mp_prime_random has been deprecated, use mp_prime_rand instead") mp_prime_random_ex(a, t, ((size) * 8) + 1, (bbs==1)?MP_PRIME_BBS:0, cb, dat))
+
+/* makes a truly random prime of a given size (bits),
+ *
+ * Flags are as follows:
+ *
+ * MP_PRIME_BBS - make prime congruent to 3 mod 4
+ * MP_PRIME_SAFE - make sure (p-1)/2 is prime as well (implies MP_PRIME_BBS)
+ * MP_PRIME_2MSB_ON - make the 2nd highest bit one
+ *
+ * You have to supply a callback which fills in a buffer with random bytes. "dat" is a parameter you can
+ * have passed to the callback (e.g. a state or something). This function doesn't use "dat" itself
+ * so it can be NULL
+ *
+ */
+MP_DEPRECATED(mp_prime_rand) mp_err mp_prime_random_ex(mp_int *a, int t, int size, int flags,
+ private_mp_prime_callback cb, void *dat) MP_WUR;
+mp_err mp_prime_rand(mp_int *a, int t, int size, int flags) MP_WUR;
+
+/* Integer logarithm to integer base */
+mp_err mp_log_u32(const mp_int *a, uint32_t base, uint32_t *c) MP_WUR;
+
+/* c = a**b */
+mp_err mp_expt_u32(const mp_int *a, uint32_t b, mp_int *c) MP_WUR;
+MP_DEPRECATED(mp_expt_u32) mp_err mp_expt_d(const mp_int *a, mp_digit b, mp_int *c) MP_WUR;
+MP_DEPRECATED(mp_expt_u32) mp_err mp_expt_d_ex(const mp_int *a, mp_digit b, mp_int *c, int fast) MP_WUR;
+
+/* ---> radix conversion <--- */
+int mp_count_bits(const mp_int *a) MP_WUR;
+
+
+MP_DEPRECATED(mp_ubin_size) int mp_unsigned_bin_size(const mp_int *a) MP_WUR;
+MP_DEPRECATED(mp_from_ubin) mp_err mp_read_unsigned_bin(mp_int *a, const unsigned char *b, int c) MP_WUR;
+MP_DEPRECATED(mp_to_ubin) mp_err mp_to_unsigned_bin(const mp_int *a, unsigned char *b) MP_WUR;
+MP_DEPRECATED(mp_to_ubin) mp_err mp_to_unsigned_bin_n(const mp_int *a, unsigned char *b, unsigned long *outlen) MP_WUR;
+
+MP_DEPRECATED(mp_sbin_size) int mp_signed_bin_size(const mp_int *a) MP_WUR;
+MP_DEPRECATED(mp_from_sbin) mp_err mp_read_signed_bin(mp_int *a, const unsigned char *b, int c) MP_WUR;
+MP_DEPRECATED(mp_to_sbin) mp_err mp_to_signed_bin(const mp_int *a, unsigned char *b) MP_WUR;
+MP_DEPRECATED(mp_to_sbin) mp_err mp_to_signed_bin_n(const mp_int *a, unsigned char *b, unsigned long *outlen) MP_WUR;
+
+size_t mp_ubin_size(const mp_int *a) MP_WUR;
+mp_err mp_from_ubin(mp_int *a, const unsigned char *buf, size_t size) MP_WUR;
+mp_err mp_to_ubin(const mp_int *a, unsigned char *buf, size_t maxlen, size_t *written) MP_WUR;
+
+size_t mp_sbin_size(const mp_int *a) MP_WUR;
+mp_err mp_from_sbin(mp_int *a, const unsigned char *buf, size_t size) MP_WUR;
+mp_err mp_to_sbin(const mp_int *a, unsigned char *buf, size_t maxlen, size_t *written) MP_WUR;
+
+mp_err mp_read_radix(mp_int *a, const char *str, int radix) MP_WUR;
+MP_DEPRECATED(mp_to_radix) mp_err mp_toradix(const mp_int *a, char *str, int radix) MP_WUR;
+MP_DEPRECATED(mp_to_radix) mp_err mp_toradix_n(const mp_int *a, char *str, int radix, int maxlen) MP_WUR;
+mp_err mp_to_radix(const mp_int *a, char *str, size_t maxlen, size_t *written, int radix) MP_WUR;
+mp_err mp_radix_size(const mp_int *a, int radix, int *size) MP_WUR;
+
+#ifndef MP_NO_FILE
+mp_err mp_fread(mp_int *a, int radix, FILE *stream) MP_WUR;
+mp_err mp_fwrite(const mp_int *a, int radix, FILE *stream) MP_WUR;
+#endif
+
+#define mp_read_raw(mp, str, len) (MP_DEPRECATED_PRAGMA("replaced by mp_read_signed_bin") mp_read_signed_bin((mp), (str), (len)))
+#define mp_raw_size(mp) (MP_DEPRECATED_PRAGMA("replaced by mp_signed_bin_size") mp_signed_bin_size(mp))
+#define mp_toraw(mp, str) (MP_DEPRECATED_PRAGMA("replaced by mp_to_signed_bin") mp_to_signed_bin((mp), (str)))
+#define mp_read_mag(mp, str, len) (MP_DEPRECATED_PRAGMA("replaced by mp_read_unsigned_bin") mp_read_unsigned_bin((mp), (str), (len))
+#define mp_mag_size(mp) (MP_DEPRECATED_PRAGMA("replaced by mp_unsigned_bin_size") mp_unsigned_bin_size(mp))
+#define mp_tomag(mp, str) (MP_DEPRECATED_PRAGMA("replaced by mp_to_unsigned_bin") mp_to_unsigned_bin((mp), (str)))
+
+#define mp_tobinary(M, S) (MP_DEPRECATED_PRAGMA("replaced by mp_to_binary") mp_toradix((M), (S), 2))
+#define mp_tooctal(M, S) (MP_DEPRECATED_PRAGMA("replaced by mp_to_octal") mp_toradix((M), (S), 8))
+#define mp_todecimal(M, S) (MP_DEPRECATED_PRAGMA("replaced by mp_to_decimal") mp_toradix((M), (S), 10))
+#define mp_tohex(M, S) (MP_DEPRECATED_PRAGMA("replaced by mp_to_hex") mp_toradix((M), (S), 16))
+
+#define mp_to_binary(M, S, N) mp_to_radix((M), (S), (N), NULL, 2)
+#define mp_to_octal(M, S, N) mp_to_radix((M), (S), (N), NULL, 8)
+#define mp_to_decimal(M, S, N) mp_to_radix((M), (S), (N), NULL, 10)
+#define mp_to_hex(M, S, N) mp_to_radix((M), (S), (N), NULL, 16)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
ADDED libtommath/tommath_class.h
Index: libtommath/tommath_class.h
==================================================================
--- /dev/null
+++ libtommath/tommath_class.h
@@ -0,0 +1,1319 @@
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#if !(defined(LTM1) && defined(LTM2) && defined(LTM3))
+#define LTM_INSIDE
+#if defined(LTM2)
+# define LTM3
+#endif
+#if defined(LTM1)
+# define LTM2
+#endif
+#define LTM1
+#if defined(LTM_ALL)
+# define BN_CUTOFFS_C
+# define BN_DEPRECATED_C
+# define BN_MP_2EXPT_C
+# define BN_MP_ABS_C
+# define BN_MP_ADD_C
+# define BN_MP_ADD_D_C
+# define BN_MP_ADDMOD_C
+# define BN_MP_AND_C
+# define BN_MP_CLAMP_C
+# define BN_MP_CLEAR_C
+# define BN_MP_CLEAR_MULTI_C
+# define BN_MP_CMP_C
+# define BN_MP_CMP_D_C
+# define BN_MP_CMP_MAG_C
+# define BN_MP_CNT_LSB_C
+# define BN_MP_COMPLEMENT_C
+# define BN_MP_COPY_C
+# define BN_MP_COUNT_BITS_C
+# define BN_MP_DECR_C
+# define BN_MP_DIV_C
+# define BN_MP_DIV_2_C
+# define BN_MP_DIV_2D_C
+# define BN_MP_DIV_3_C
+# define BN_MP_DIV_D_C
+# define BN_MP_DR_IS_MODULUS_C
+# define BN_MP_DR_REDUCE_C
+# define BN_MP_DR_SETUP_C
+# define BN_MP_ERROR_TO_STRING_C
+# define BN_MP_EXCH_C
+# define BN_MP_EXPT_U32_C
+# define BN_MP_EXPTMOD_C
+# define BN_MP_EXTEUCLID_C
+# define BN_MP_FREAD_C
+# define BN_MP_FROM_SBIN_C
+# define BN_MP_FROM_UBIN_C
+# define BN_MP_FWRITE_C
+# define BN_MP_GCD_C
+# define BN_MP_GET_DOUBLE_C
+# define BN_MP_GET_I32_C
+# define BN_MP_GET_I64_C
+# define BN_MP_GET_L_C
+# define BN_MP_GET_LL_C
+# define BN_MP_GET_MAG_U32_C
+# define BN_MP_GET_MAG_U64_C
+# define BN_MP_GET_MAG_UL_C
+# define BN_MP_GET_MAG_ULL_C
+# define BN_MP_GROW_C
+# define BN_MP_INCR_C
+# define BN_MP_INIT_C
+# define BN_MP_INIT_COPY_C
+# define BN_MP_INIT_I32_C
+# define BN_MP_INIT_I64_C
+# define BN_MP_INIT_L_C
+# define BN_MP_INIT_LL_C
+# define BN_MP_INIT_MULTI_C
+# define BN_MP_INIT_SET_C
+# define BN_MP_INIT_SIZE_C
+# define BN_MP_INIT_U32_C
+# define BN_MP_INIT_U64_C
+# define BN_MP_INIT_UL_C
+# define BN_MP_INIT_ULL_C
+# define BN_MP_INVMOD_C
+# define BN_MP_IS_SQUARE_C
+# define BN_MP_ISEVEN_C
+# define BN_MP_ISODD_C
+# define BN_MP_KRONECKER_C
+# define BN_MP_LCM_C
+# define BN_MP_LOG_U32_C
+# define BN_MP_LSHD_C
+# define BN_MP_MOD_C
+# define BN_MP_MOD_2D_C
+# define BN_MP_MOD_D_C
+# define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
+# define BN_MP_MONTGOMERY_REDUCE_C
+# define BN_MP_MONTGOMERY_SETUP_C
+# define BN_MP_MUL_C
+# define BN_MP_MUL_2_C
+# define BN_MP_MUL_2D_C
+# define BN_MP_MUL_D_C
+# define BN_MP_MULMOD_C
+# define BN_MP_NEG_C
+# define BN_MP_OR_C
+# define BN_MP_PACK_C
+# define BN_MP_PACK_COUNT_C
+# define BN_MP_PRIME_FERMAT_C
+# define BN_MP_PRIME_FROBENIUS_UNDERWOOD_C
+# define BN_MP_PRIME_IS_PRIME_C
+# define BN_MP_PRIME_MILLER_RABIN_C
+# define BN_MP_PRIME_NEXT_PRIME_C
+# define BN_MP_PRIME_RABIN_MILLER_TRIALS_C
+# define BN_MP_PRIME_RAND_C
+# define BN_MP_PRIME_STRONG_LUCAS_SELFRIDGE_C
+# define BN_MP_RADIX_SIZE_C
+# define BN_MP_RADIX_SMAP_C
+# define BN_MP_RAND_C
+# define BN_MP_READ_RADIX_C
+# define BN_MP_REDUCE_C
+# define BN_MP_REDUCE_2K_C
+# define BN_MP_REDUCE_2K_L_C
+# define BN_MP_REDUCE_2K_SETUP_C
+# define BN_MP_REDUCE_2K_SETUP_L_C
+# define BN_MP_REDUCE_IS_2K_C
+# define BN_MP_REDUCE_IS_2K_L_C
+# define BN_MP_REDUCE_SETUP_C
+# define BN_MP_ROOT_U32_C
+# define BN_MP_RSHD_C
+# define BN_MP_SBIN_SIZE_C
+# define BN_MP_SET_C
+# define BN_MP_SET_DOUBLE_C
+# define BN_MP_SET_I32_C
+# define BN_MP_SET_I64_C
+# define BN_MP_SET_L_C
+# define BN_MP_SET_LL_C
+# define BN_MP_SET_U32_C
+# define BN_MP_SET_U64_C
+# define BN_MP_SET_UL_C
+# define BN_MP_SET_ULL_C
+# define BN_MP_SHRINK_C
+# define BN_MP_SIGNED_RSH_C
+# define BN_MP_SQR_C
+# define BN_MP_SQRMOD_C
+# define BN_MP_SQRT_C
+# define BN_MP_SQRTMOD_PRIME_C
+# define BN_MP_SUB_C
+# define BN_MP_SUB_D_C
+# define BN_MP_SUBMOD_C
+# define BN_MP_TO_RADIX_C
+# define BN_MP_TO_SBIN_C
+# define BN_MP_TO_UBIN_C
+# define BN_MP_UBIN_SIZE_C
+# define BN_MP_UNPACK_C
+# define BN_MP_XOR_C
+# define BN_MP_ZERO_C
+# define BN_PRIME_TAB_C
+# define BN_S_MP_ADD_C
+# define BN_S_MP_BALANCE_MUL_C
+# define BN_S_MP_EXPTMOD_C
+# define BN_S_MP_EXPTMOD_FAST_C
+# define BN_S_MP_GET_BIT_C
+# define BN_S_MP_INVMOD_FAST_C
+# define BN_S_MP_INVMOD_SLOW_C
+# define BN_S_MP_KARATSUBA_MUL_C
+# define BN_S_MP_KARATSUBA_SQR_C
+# define BN_S_MP_MONTGOMERY_REDUCE_FAST_C
+# define BN_S_MP_MUL_DIGS_C
+# define BN_S_MP_MUL_DIGS_FAST_C
+# define BN_S_MP_MUL_HIGH_DIGS_C
+# define BN_S_MP_MUL_HIGH_DIGS_FAST_C
+# define BN_S_MP_PRIME_IS_DIVISIBLE_C
+# define BN_S_MP_RAND_JENKINS_C
+# define BN_S_MP_RAND_PLATFORM_C
+# define BN_S_MP_REVERSE_C
+# define BN_S_MP_SQR_C
+# define BN_S_MP_SQR_FAST_C
+# define BN_S_MP_SUB_C
+# define BN_S_MP_TOOM_MUL_C
+# define BN_S_MP_TOOM_SQR_C
+#endif
+#endif
+#if defined(BN_CUTOFFS_C)
+#endif
+
+#if defined(BN_DEPRECATED_C)
+# define BN_FAST_MP_INVMOD_C
+# define BN_FAST_MP_MONTGOMERY_REDUCE_C
+# define BN_FAST_S_MP_MUL_DIGS_C
+# define BN_FAST_S_MP_MUL_HIGH_DIGS_C
+# define BN_FAST_S_MP_SQR_C
+# define BN_MP_AND_C
+# define BN_MP_BALANCE_MUL_C
+# define BN_MP_CMP_D_C
+# define BN_MP_EXPORT_C
+# define BN_MP_EXPTMOD_FAST_C
+# define BN_MP_EXPT_D_C
+# define BN_MP_EXPT_D_EX_C
+# define BN_MP_EXPT_U32_C
+# define BN_MP_FROM_SBIN_C
+# define BN_MP_FROM_UBIN_C
+# define BN_MP_GET_BIT_C
+# define BN_MP_GET_INT_C
+# define BN_MP_GET_LONG_C
+# define BN_MP_GET_LONG_LONG_C
+# define BN_MP_GET_MAG_U32_C
+# define BN_MP_GET_MAG_ULL_C
+# define BN_MP_GET_MAG_UL_C
+# define BN_MP_IMPORT_C
+# define BN_MP_INIT_SET_INT_C
+# define BN_MP_INIT_U32_C
+# define BN_MP_INVMOD_SLOW_C
+# define BN_MP_JACOBI_C
+# define BN_MP_KARATSUBA_MUL_C
+# define BN_MP_KARATSUBA_SQR_C
+# define BN_MP_KRONECKER_C
+# define BN_MP_N_ROOT_C
+# define BN_MP_N_ROOT_EX_C
+# define BN_MP_OR_C
+# define BN_MP_PACK_C
+# define BN_MP_PRIME_IS_DIVISIBLE_C
+# define BN_MP_PRIME_RANDOM_EX_C
+# define BN_MP_RAND_DIGIT_C
+# define BN_MP_READ_SIGNED_BIN_C
+# define BN_MP_READ_UNSIGNED_BIN_C
+# define BN_MP_ROOT_U32_C
+# define BN_MP_SBIN_SIZE_C
+# define BN_MP_SET_INT_C
+# define BN_MP_SET_LONG_C
+# define BN_MP_SET_LONG_LONG_C
+# define BN_MP_SET_U32_C
+# define BN_MP_SET_U64_C
+# define BN_MP_SIGNED_BIN_SIZE_C
+# define BN_MP_SIGNED_RSH_C
+# define BN_MP_TC_AND_C
+# define BN_MP_TC_DIV_2D_C
+# define BN_MP_TC_OR_C
+# define BN_MP_TC_XOR_C
+# define BN_MP_TOOM_MUL_C
+# define BN_MP_TOOM_SQR_C
+# define BN_MP_TORADIX_C
+# define BN_MP_TORADIX_N_C
+# define BN_MP_TO_RADIX_C
+# define BN_MP_TO_SBIN_C
+# define BN_MP_TO_SIGNED_BIN_C
+# define BN_MP_TO_SIGNED_BIN_N_C
+# define BN_MP_TO_UBIN_C
+# define BN_MP_TO_UNSIGNED_BIN_C
+# define BN_MP_TO_UNSIGNED_BIN_N_C
+# define BN_MP_UBIN_SIZE_C
+# define BN_MP_UNPACK_C
+# define BN_MP_UNSIGNED_BIN_SIZE_C
+# define BN_MP_XOR_C
+# define BN_S_MP_BALANCE_MUL_C
+# define BN_S_MP_EXPTMOD_FAST_C
+# define BN_S_MP_GET_BIT_C
+# define BN_S_MP_INVMOD_FAST_C
+# define BN_S_MP_INVMOD_SLOW_C
+# define BN_S_MP_KARATSUBA_MUL_C
+# define BN_S_MP_KARATSUBA_SQR_C
+# define BN_S_MP_MONTGOMERY_REDUCE_FAST_C
+# define BN_S_MP_MUL_DIGS_FAST_C
+# define BN_S_MP_MUL_HIGH_DIGS_FAST_C
+# define BN_S_MP_PRIME_IS_DIVISIBLE_C
+# define BN_S_MP_PRIME_RANDOM_EX_C
+# define BN_S_MP_RAND_SOURCE_C
+# define BN_S_MP_REVERSE_C
+# define BN_S_MP_SQR_FAST_C
+# define BN_S_MP_TOOM_MUL_C
+# define BN_S_MP_TOOM_SQR_C
+#endif
+
+#if defined(BN_MP_2EXPT_C)
+# define BN_MP_GROW_C
+# define BN_MP_ZERO_C
+#endif
+
+#if defined(BN_MP_ABS_C)
+# define BN_MP_COPY_C
+#endif
+
+#if defined(BN_MP_ADD_C)
+# define BN_MP_CMP_MAG_C
+# define BN_S_MP_ADD_C
+# define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_ADD_D_C)
+# define BN_MP_CLAMP_C
+# define BN_MP_GROW_C
+# define BN_MP_SUB_D_C
+#endif
+
+#if defined(BN_MP_ADDMOD_C)
+# define BN_MP_ADD_C
+# define BN_MP_CLEAR_C
+# define BN_MP_INIT_C
+# define BN_MP_MOD_C
+#endif
+
+#if defined(BN_MP_AND_C)
+# define BN_MP_CLAMP_C
+# define BN_MP_GROW_C
+#endif
+
+#if defined(BN_MP_CLAMP_C)
+#endif
+
+#if defined(BN_MP_CLEAR_C)
+#endif
+
+#if defined(BN_MP_CLEAR_MULTI_C)
+# define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_CMP_C)
+# define BN_MP_CMP_MAG_C
+#endif
+
+#if defined(BN_MP_CMP_D_C)
+#endif
+
+#if defined(BN_MP_CMP_MAG_C)
+#endif
+
+#if defined(BN_MP_CNT_LSB_C)
+#endif
+
+#if defined(BN_MP_COMPLEMENT_C)
+# define BN_MP_NEG_C
+# define BN_MP_SUB_D_C
+#endif
+
+#if defined(BN_MP_COPY_C)
+# define BN_MP_GROW_C
+#endif
+
+#if defined(BN_MP_COUNT_BITS_C)
+#endif
+
+#if defined(BN_MP_DECR_C)
+# define BN_MP_INCR_C
+# define BN_MP_SET_C
+# define BN_MP_SUB_D_C
+# define BN_MP_ZERO_C
+#endif
+
+#if defined(BN_MP_DIV_C)
+# define BN_MP_ADD_C
+# define BN_MP_CLAMP_C
+# define BN_MP_CLEAR_C
+# define BN_MP_CMP_C
+# define BN_MP_CMP_MAG_C
+# define BN_MP_COPY_C
+# define BN_MP_COUNT_BITS_C
+# define BN_MP_DIV_2D_C
+# define BN_MP_EXCH_C
+# define BN_MP_INIT_C
+# define BN_MP_INIT_COPY_C
+# define BN_MP_INIT_SIZE_C
+# define BN_MP_LSHD_C
+# define BN_MP_MUL_2D_C
+# define BN_MP_MUL_D_C
+# define BN_MP_RSHD_C
+# define BN_MP_SUB_C
+# define BN_MP_ZERO_C
+#endif
+
+#if defined(BN_MP_DIV_2_C)
+# define BN_MP_CLAMP_C
+# define BN_MP_GROW_C
+#endif
+
+#if defined(BN_MP_DIV_2D_C)
+# define BN_MP_CLAMP_C
+# define BN_MP_COPY_C
+# define BN_MP_MOD_2D_C
+# define BN_MP_RSHD_C
+# define BN_MP_ZERO_C
+#endif
+
+#if defined(BN_MP_DIV_3_C)
+# define BN_MP_CLAMP_C
+# define BN_MP_CLEAR_C
+# define BN_MP_EXCH_C
+# define BN_MP_INIT_SIZE_C
+#endif
+
+#if defined(BN_MP_DIV_D_C)
+# define BN_MP_CLAMP_C
+# define BN_MP_CLEAR_C
+# define BN_MP_COPY_C
+# define BN_MP_DIV_2D_C
+# define BN_MP_DIV_3_C
+# define BN_MP_EXCH_C
+# define BN_MP_INIT_SIZE_C
+#endif
+
+#if defined(BN_MP_DR_IS_MODULUS_C)
+#endif
+
+#if defined(BN_MP_DR_REDUCE_C)
+# define BN_MP_CLAMP_C
+# define BN_MP_CMP_MAG_C
+# define BN_MP_GROW_C
+# define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_DR_SETUP_C)
+#endif
+
+#if defined(BN_MP_ERROR_TO_STRING_C)
+#endif
+
+#if defined(BN_MP_EXCH_C)
+#endif
+
+#if defined(BN_MP_EXPT_U32_C)
+# define BN_MP_CLEAR_C
+# define BN_MP_INIT_COPY_C
+# define BN_MP_MUL_C
+# define BN_MP_SET_C
+# define BN_MP_SQR_C
+#endif
+
+#if defined(BN_MP_EXPTMOD_C)
+# define BN_MP_ABS_C
+# define BN_MP_CLEAR_MULTI_C
+# define BN_MP_DR_IS_MODULUS_C
+# define BN_MP_INIT_MULTI_C
+# define BN_MP_INVMOD_C
+# define BN_MP_REDUCE_IS_2K_C
+# define BN_MP_REDUCE_IS_2K_L_C
+# define BN_S_MP_EXPTMOD_C
+# define BN_S_MP_EXPTMOD_FAST_C
+#endif
+
+#if defined(BN_MP_EXTEUCLID_C)
+# define BN_MP_CLEAR_MULTI_C
+# define BN_MP_COPY_C
+# define BN_MP_DIV_C
+# define BN_MP_EXCH_C
+# define BN_MP_INIT_MULTI_C
+# define BN_MP_MUL_C
+# define BN_MP_NEG_C
+# define BN_MP_SET_C
+# define BN_MP_SUB_C
+#endif
+
+#if defined(BN_MP_FREAD_C)
+# define BN_MP_ADD_D_C
+# define BN_MP_MUL_D_C
+# define BN_MP_ZERO_C
+#endif
+
+#if defined(BN_MP_FROM_SBIN_C)
+# define BN_MP_FROM_UBIN_C
+#endif
+
+#if defined(BN_MP_FROM_UBIN_C)
+# define BN_MP_CLAMP_C
+# define BN_MP_GROW_C
+# define BN_MP_MUL_2D_C
+# define BN_MP_ZERO_C
+#endif
+
+#if defined(BN_MP_FWRITE_C)
+# define BN_MP_RADIX_SIZE_C
+# define BN_MP_TO_RADIX_C
+#endif
+
+#if defined(BN_MP_GCD_C)
+# define BN_MP_ABS_C
+# define BN_MP_CLEAR_C
+# define BN_MP_CMP_MAG_C
+# define BN_MP_CNT_LSB_C
+# define BN_MP_DIV_2D_C
+# define BN_MP_EXCH_C
+# define BN_MP_INIT_COPY_C
+# define BN_MP_MUL_2D_C
+# define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_GET_DOUBLE_C)
+#endif
+
+#if defined(BN_MP_GET_I32_C)
+# define BN_MP_GET_MAG_U32_C
+#endif
+
+#if defined(BN_MP_GET_I64_C)
+# define BN_MP_GET_MAG_U64_C
+#endif
+
+#if defined(BN_MP_GET_L_C)
+# define BN_MP_GET_MAG_UL_C
+#endif
+
+#if defined(BN_MP_GET_LL_C)
+# define BN_MP_GET_MAG_ULL_C
+#endif
+
+#if defined(BN_MP_GET_MAG_U32_C)
+#endif
+
+#if defined(BN_MP_GET_MAG_U64_C)
+#endif
+
+#if defined(BN_MP_GET_MAG_UL_C)
+#endif
+
+#if defined(BN_MP_GET_MAG_ULL_C)
+#endif
+
+#if defined(BN_MP_GROW_C)
+#endif
+
+#if defined(BN_MP_INCR_C)
+# define BN_MP_ADD_D_C
+# define BN_MP_DECR_C
+# define BN_MP_SET_C
+#endif
+
+#if defined(BN_MP_INIT_C)
+#endif
+
+#if defined(BN_MP_INIT_COPY_C)
+# define BN_MP_CLEAR_C
+# define BN_MP_COPY_C
+# define BN_MP_INIT_SIZE_C
+#endif
+
+#if defined(BN_MP_INIT_I32_C)
+# define BN_MP_INIT_C
+# define BN_MP_SET_I32_C
+#endif
+
+#if defined(BN_MP_INIT_I64_C)
+# define BN_MP_INIT_C
+# define BN_MP_SET_I64_C
+#endif
+
+#if defined(BN_MP_INIT_L_C)
+# define BN_MP_INIT_C
+# define BN_MP_SET_L_C
+#endif
+
+#if defined(BN_MP_INIT_LL_C)
+# define BN_MP_INIT_C
+# define BN_MP_SET_LL_C
+#endif
+
+#if defined(BN_MP_INIT_MULTI_C)
+# define BN_MP_CLEAR_C
+# define BN_MP_INIT_C
+#endif
+
+#if defined(BN_MP_INIT_SET_C)
+# define BN_MP_INIT_C
+# define BN_MP_SET_C
+#endif
+
+#if defined(BN_MP_INIT_SIZE_C)
+#endif
+
+#if defined(BN_MP_INIT_U32_C)
+# define BN_MP_INIT_C
+# define BN_MP_SET_U32_C
+#endif
+
+#if defined(BN_MP_INIT_U64_C)
+# define BN_MP_INIT_C
+# define BN_MP_SET_U64_C
+#endif
+
+#if defined(BN_MP_INIT_UL_C)
+# define BN_MP_INIT_C
+# define BN_MP_SET_UL_C
+#endif
+
+#if defined(BN_MP_INIT_ULL_C)
+# define BN_MP_INIT_C
+# define BN_MP_SET_ULL_C
+#endif
+
+#if defined(BN_MP_INVMOD_C)
+# define BN_MP_CMP_D_C
+# define BN_S_MP_INVMOD_FAST_C
+# define BN_S_MP_INVMOD_SLOW_C
+#endif
+
+#if defined(BN_MP_IS_SQUARE_C)
+# define BN_MP_CLEAR_C
+# define BN_MP_CMP_MAG_C
+# define BN_MP_GET_I32_C
+# define BN_MP_INIT_U32_C
+# define BN_MP_MOD_C
+# define BN_MP_MOD_D_C
+# define BN_MP_SQRT_C
+# define BN_MP_SQR_C
+#endif
+
+#if defined(BN_MP_ISEVEN_C)
+#endif
+
+#if defined(BN_MP_ISODD_C)
+#endif
+
+#if defined(BN_MP_KRONECKER_C)
+# define BN_MP_CLEAR_C
+# define BN_MP_CMP_D_C
+# define BN_MP_CNT_LSB_C
+# define BN_MP_COPY_C
+# define BN_MP_DIV_2D_C
+# define BN_MP_INIT_C
+# define BN_MP_INIT_COPY_C
+# define BN_MP_MOD_C
+#endif
+
+#if defined(BN_MP_LCM_C)
+# define BN_MP_CLEAR_MULTI_C
+# define BN_MP_CMP_MAG_C
+# define BN_MP_DIV_C
+# define BN_MP_GCD_C
+# define BN_MP_INIT_MULTI_C
+# define BN_MP_MUL_C
+#endif
+
+#if defined(BN_MP_LOG_U32_C)
+# define BN_MP_CLEAR_MULTI_C
+# define BN_MP_CMP_C
+# define BN_MP_CMP_D_C
+# define BN_MP_COPY_C
+# define BN_MP_COUNT_BITS_C
+# define BN_MP_EXCH_C
+# define BN_MP_EXPT_U32_C
+# define BN_MP_INIT_MULTI_C
+# define BN_MP_MUL_C
+# define BN_MP_SET_C
+# define BN_MP_SQR_C
+#endif
+
+#if defined(BN_MP_LSHD_C)
+# define BN_MP_GROW_C
+#endif
+
+#if defined(BN_MP_MOD_C)
+# define BN_MP_ADD_C
+# define BN_MP_CLEAR_C
+# define BN_MP_DIV_C
+# define BN_MP_EXCH_C
+# define BN_MP_INIT_SIZE_C
+#endif
+
+#if defined(BN_MP_MOD_2D_C)
+# define BN_MP_CLAMP_C
+# define BN_MP_COPY_C
+# define BN_MP_ZERO_C
+#endif
+
+#if defined(BN_MP_MOD_D_C)
+# define BN_MP_DIV_D_C
+#endif
+
+#if defined(BN_MP_MONTGOMERY_CALC_NORMALIZATION_C)
+# define BN_MP_2EXPT_C
+# define BN_MP_CMP_MAG_C
+# define BN_MP_COUNT_BITS_C
+# define BN_MP_MUL_2_C
+# define BN_MP_SET_C
+# define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_MONTGOMERY_REDUCE_C)
+# define BN_MP_CLAMP_C
+# define BN_MP_CMP_MAG_C
+# define BN_MP_GROW_C
+# define BN_MP_RSHD_C
+# define BN_S_MP_MONTGOMERY_REDUCE_FAST_C
+# define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_MONTGOMERY_SETUP_C)
+#endif
+
+#if defined(BN_MP_MUL_C)
+# define BN_S_MP_BALANCE_MUL_C
+# define BN_S_MP_KARATSUBA_MUL_C
+# define BN_S_MP_MUL_DIGS_C
+# define BN_S_MP_MUL_DIGS_FAST_C
+# define BN_S_MP_TOOM_MUL_C
+#endif
+
+#if defined(BN_MP_MUL_2_C)
+# define BN_MP_GROW_C
+#endif
+
+#if defined(BN_MP_MUL_2D_C)
+# define BN_MP_CLAMP_C
+# define BN_MP_COPY_C
+# define BN_MP_GROW_C
+# define BN_MP_LSHD_C
+#endif
+
+#if defined(BN_MP_MUL_D_C)
+# define BN_MP_CLAMP_C
+# define BN_MP_GROW_C
+#endif
+
+#if defined(BN_MP_MULMOD_C)
+# define BN_MP_CLEAR_C
+# define BN_MP_INIT_SIZE_C
+# define BN_MP_MOD_C
+# define BN_MP_MUL_C
+#endif
+
+#if defined(BN_MP_NEG_C)
+# define BN_MP_COPY_C
+#endif
+
+#if defined(BN_MP_OR_C)
+# define BN_MP_CLAMP_C
+# define BN_MP_GROW_C
+#endif
+
+#if defined(BN_MP_PACK_C)
+# define BN_MP_CLEAR_C
+# define BN_MP_DIV_2D_C
+# define BN_MP_INIT_COPY_C
+# define BN_MP_PACK_COUNT_C
+#endif
+
+#if defined(BN_MP_PACK_COUNT_C)
+# define BN_MP_COUNT_BITS_C
+#endif
+
+#if defined(BN_MP_PRIME_FERMAT_C)
+# define BN_MP_CLEAR_C
+# define BN_MP_CMP_C
+# define BN_MP_CMP_D_C
+# define BN_MP_EXPTMOD_C
+# define BN_MP_INIT_C
+#endif
+
+#if defined(BN_MP_PRIME_FROBENIUS_UNDERWOOD_C)
+# define BN_MP_ADD_C
+# define BN_MP_ADD_D_C
+# define BN_MP_CLEAR_MULTI_C
+# define BN_MP_CMP_C
+# define BN_MP_COUNT_BITS_C
+# define BN_MP_EXCH_C
+# define BN_MP_GCD_C
+# define BN_MP_INIT_MULTI_C
+# define BN_MP_KRONECKER_C
+# define BN_MP_MOD_C
+# define BN_MP_MUL_2_C
+# define BN_MP_MUL_C
+# define BN_MP_MUL_D_C
+# define BN_MP_SET_C
+# define BN_MP_SET_U32_C
+# define BN_MP_SQR_C
+# define BN_MP_SUB_C
+# define BN_MP_SUB_D_C
+# define BN_S_MP_GET_BIT_C
+#endif
+
+#if defined(BN_MP_PRIME_IS_PRIME_C)
+# define BN_MP_CLEAR_C
+# define BN_MP_CMP_C
+# define BN_MP_CMP_D_C
+# define BN_MP_COUNT_BITS_C
+# define BN_MP_DIV_2D_C
+# define BN_MP_INIT_SET_C
+# define BN_MP_IS_SQUARE_C
+# define BN_MP_PRIME_MILLER_RABIN_C
+# define BN_MP_PRIME_STRONG_LUCAS_SELFRIDGE_C
+# define BN_MP_RAND_C
+# define BN_MP_READ_RADIX_C
+# define BN_MP_SET_C
+# define BN_S_MP_PRIME_IS_DIVISIBLE_C
+#endif
+
+#if defined(BN_MP_PRIME_MILLER_RABIN_C)
+# define BN_MP_CLEAR_C
+# define BN_MP_CMP_C
+# define BN_MP_CMP_D_C
+# define BN_MP_CNT_LSB_C
+# define BN_MP_DIV_2D_C
+# define BN_MP_EXPTMOD_C
+# define BN_MP_INIT_C
+# define BN_MP_INIT_COPY_C
+# define BN_MP_SQRMOD_C
+# define BN_MP_SUB_D_C
+#endif
+
+#if defined(BN_MP_PRIME_NEXT_PRIME_C)
+# define BN_MP_ADD_D_C
+# define BN_MP_CLEAR_C
+# define BN_MP_CMP_D_C
+# define BN_MP_INIT_C
+# define BN_MP_MOD_D_C
+# define BN_MP_PRIME_IS_PRIME_C
+# define BN_MP_SET_C
+# define BN_MP_SUB_D_C
+#endif
+
+#if defined(BN_MP_PRIME_RABIN_MILLER_TRIALS_C)
+#endif
+
+#if defined(BN_MP_PRIME_RAND_C)
+# define BN_MP_ADD_D_C
+# define BN_MP_DIV_2_C
+# define BN_MP_FROM_UBIN_C
+# define BN_MP_MUL_2_C
+# define BN_MP_PRIME_IS_PRIME_C
+# define BN_MP_SUB_D_C
+# define BN_S_MP_PRIME_RANDOM_EX_C
+# define BN_S_MP_RAND_CB_C
+# define BN_S_MP_RAND_SOURCE_C
+#endif
+
+#if defined(BN_MP_PRIME_STRONG_LUCAS_SELFRIDGE_C)
+# define BN_MP_ADD_C
+# define BN_MP_ADD_D_C
+# define BN_MP_CLEAR_C
+# define BN_MP_CLEAR_MULTI_C
+# define BN_MP_CMP_C
+# define BN_MP_CMP_D_C
+# define BN_MP_CNT_LSB_C
+# define BN_MP_COUNT_BITS_C
+# define BN_MP_DIV_2D_C
+# define BN_MP_DIV_2_C
+# define BN_MP_GCD_C
+# define BN_MP_INIT_C
+# define BN_MP_INIT_MULTI_C
+# define BN_MP_KRONECKER_C
+# define BN_MP_MOD_C
+# define BN_MP_MUL_2_C
+# define BN_MP_MUL_C
+# define BN_MP_SET_C
+# define BN_MP_SET_I32_C
+# define BN_MP_SET_U32_C
+# define BN_MP_SQR_C
+# define BN_MP_SUB_C
+# define BN_MP_SUB_D_C
+# define BN_S_MP_GET_BIT_C
+# define BN_S_MP_MUL_SI_C
+#endif
+
+#if defined(BN_MP_RADIX_SIZE_C)
+# define BN_MP_CLEAR_C
+# define BN_MP_COUNT_BITS_C
+# define BN_MP_DIV_D_C
+# define BN_MP_INIT_COPY_C
+#endif
+
+#if defined(BN_MP_RADIX_SMAP_C)
+#endif
+
+#if defined(BN_MP_RAND_C)
+# define BN_MP_GROW_C
+# define BN_MP_RAND_SOURCE_C
+# define BN_MP_ZERO_C
+# define BN_S_MP_RAND_PLATFORM_C
+# define BN_S_MP_RAND_SOURCE_C
+#endif
+
+#if defined(BN_MP_READ_RADIX_C)
+# define BN_MP_ADD_D_C
+# define BN_MP_MUL_D_C
+# define BN_MP_ZERO_C
+#endif
+
+#if defined(BN_MP_REDUCE_C)
+# define BN_MP_ADD_C
+# define BN_MP_CLEAR_C
+# define BN_MP_CMP_C
+# define BN_MP_CMP_D_C
+# define BN_MP_INIT_COPY_C
+# define BN_MP_LSHD_C
+# define BN_MP_MOD_2D_C
+# define BN_MP_MUL_C
+# define BN_MP_RSHD_C
+# define BN_MP_SET_C
+# define BN_MP_SUB_C
+# define BN_S_MP_MUL_DIGS_C
+# define BN_S_MP_MUL_HIGH_DIGS_C
+# define BN_S_MP_MUL_HIGH_DIGS_FAST_C
+# define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_REDUCE_2K_C)
+# define BN_MP_CLEAR_C
+# define BN_MP_CMP_MAG_C
+# define BN_MP_COUNT_BITS_C
+# define BN_MP_DIV_2D_C
+# define BN_MP_INIT_C
+# define BN_MP_MUL_D_C
+# define BN_S_MP_ADD_C
+# define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_REDUCE_2K_L_C)
+# define BN_MP_CLEAR_C
+# define BN_MP_CMP_MAG_C
+# define BN_MP_COUNT_BITS_C
+# define BN_MP_DIV_2D_C
+# define BN_MP_INIT_C
+# define BN_MP_MUL_C
+# define BN_S_MP_ADD_C
+# define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_REDUCE_2K_SETUP_C)
+# define BN_MP_2EXPT_C
+# define BN_MP_CLEAR_C
+# define BN_MP_COUNT_BITS_C
+# define BN_MP_INIT_C
+# define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_REDUCE_2K_SETUP_L_C)
+# define BN_MP_2EXPT_C
+# define BN_MP_CLEAR_C
+# define BN_MP_COUNT_BITS_C
+# define BN_MP_INIT_C
+# define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_REDUCE_IS_2K_C)
+# define BN_MP_COUNT_BITS_C
+#endif
+
+#if defined(BN_MP_REDUCE_IS_2K_L_C)
+#endif
+
+#if defined(BN_MP_REDUCE_SETUP_C)
+# define BN_MP_2EXPT_C
+# define BN_MP_DIV_C
+#endif
+
+#if defined(BN_MP_ROOT_U32_C)
+# define BN_MP_2EXPT_C
+# define BN_MP_ADD_D_C
+# define BN_MP_CLEAR_MULTI_C
+# define BN_MP_CMP_C
+# define BN_MP_COPY_C
+# define BN_MP_COUNT_BITS_C
+# define BN_MP_DIV_C
+# define BN_MP_EXCH_C
+# define BN_MP_EXPT_U32_C
+# define BN_MP_INIT_MULTI_C
+# define BN_MP_MUL_C
+# define BN_MP_MUL_D_C
+# define BN_MP_SET_C
+# define BN_MP_SUB_C
+# define BN_MP_SUB_D_C
+#endif
+
+#if defined(BN_MP_RSHD_C)
+# define BN_MP_ZERO_C
+#endif
+
+#if defined(BN_MP_SBIN_SIZE_C)
+# define BN_MP_UBIN_SIZE_C
+#endif
+
+#if defined(BN_MP_SET_C)
+#endif
+
+#if defined(BN_MP_SET_DOUBLE_C)
+# define BN_MP_DIV_2D_C
+# define BN_MP_MUL_2D_C
+# define BN_MP_SET_U64_C
+#endif
+
+#if defined(BN_MP_SET_I32_C)
+# define BN_MP_SET_U32_C
+#endif
+
+#if defined(BN_MP_SET_I64_C)
+# define BN_MP_SET_U64_C
+#endif
+
+#if defined(BN_MP_SET_L_C)
+# define BN_MP_SET_UL_C
+#endif
+
+#if defined(BN_MP_SET_LL_C)
+# define BN_MP_SET_ULL_C
+#endif
+
+#if defined(BN_MP_SET_U32_C)
+#endif
+
+#if defined(BN_MP_SET_U64_C)
+#endif
+
+#if defined(BN_MP_SET_UL_C)
+#endif
+
+#if defined(BN_MP_SET_ULL_C)
+#endif
+
+#if defined(BN_MP_SHRINK_C)
+#endif
+
+#if defined(BN_MP_SIGNED_RSH_C)
+# define BN_MP_ADD_D_C
+# define BN_MP_DIV_2D_C
+# define BN_MP_SUB_D_C
+#endif
+
+#if defined(BN_MP_SQR_C)
+# define BN_S_MP_KARATSUBA_SQR_C
+# define BN_S_MP_SQR_C
+# define BN_S_MP_SQR_FAST_C
+# define BN_S_MP_TOOM_SQR_C
+#endif
+
+#if defined(BN_MP_SQRMOD_C)
+# define BN_MP_CLEAR_C
+# define BN_MP_INIT_C
+# define BN_MP_MOD_C
+# define BN_MP_SQR_C
+#endif
+
+#if defined(BN_MP_SQRT_C)
+# define BN_MP_ADD_C
+# define BN_MP_CLEAR_C
+# define BN_MP_CMP_MAG_C
+# define BN_MP_DIV_2_C
+# define BN_MP_DIV_C
+# define BN_MP_EXCH_C
+# define BN_MP_INIT_C
+# define BN_MP_INIT_COPY_C
+# define BN_MP_RSHD_C
+# define BN_MP_ZERO_C
+#endif
+
+#if defined(BN_MP_SQRTMOD_PRIME_C)
+# define BN_MP_ADD_D_C
+# define BN_MP_CLEAR_MULTI_C
+# define BN_MP_CMP_D_C
+# define BN_MP_COPY_C
+# define BN_MP_DIV_2_C
+# define BN_MP_EXPTMOD_C
+# define BN_MP_INIT_MULTI_C
+# define BN_MP_KRONECKER_C
+# define BN_MP_MOD_D_C
+# define BN_MP_MULMOD_C
+# define BN_MP_SET_C
+# define BN_MP_SET_U32_C
+# define BN_MP_SQRMOD_C
+# define BN_MP_SUB_D_C
+# define BN_MP_ZERO_C
+#endif
+
+#if defined(BN_MP_SUB_C)
+# define BN_MP_CMP_MAG_C
+# define BN_S_MP_ADD_C
+# define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_MP_SUB_D_C)
+# define BN_MP_ADD_D_C
+# define BN_MP_CLAMP_C
+# define BN_MP_GROW_C
+#endif
+
+#if defined(BN_MP_SUBMOD_C)
+# define BN_MP_CLEAR_C
+# define BN_MP_INIT_C
+# define BN_MP_MOD_C
+# define BN_MP_SUB_C
+#endif
+
+#if defined(BN_MP_TO_RADIX_C)
+# define BN_MP_CLEAR_C
+# define BN_MP_DIV_D_C
+# define BN_MP_INIT_COPY_C
+# define BN_S_MP_REVERSE_C
+#endif
+
+#if defined(BN_MP_TO_SBIN_C)
+# define BN_MP_TO_UBIN_C
+#endif
+
+#if defined(BN_MP_TO_UBIN_C)
+# define BN_MP_CLEAR_C
+# define BN_MP_DIV_2D_C
+# define BN_MP_INIT_COPY_C
+# define BN_MP_UBIN_SIZE_C
+#endif
+
+#if defined(BN_MP_UBIN_SIZE_C)
+# define BN_MP_COUNT_BITS_C
+#endif
+
+#if defined(BN_MP_UNPACK_C)
+# define BN_MP_CLAMP_C
+# define BN_MP_MUL_2D_C
+# define BN_MP_ZERO_C
+#endif
+
+#if defined(BN_MP_XOR_C)
+# define BN_MP_CLAMP_C
+# define BN_MP_GROW_C
+#endif
+
+#if defined(BN_MP_ZERO_C)
+#endif
+
+#if defined(BN_PRIME_TAB_C)
+#endif
+
+#if defined(BN_S_MP_ADD_C)
+# define BN_MP_CLAMP_C
+# define BN_MP_GROW_C
+#endif
+
+#if defined(BN_S_MP_BALANCE_MUL_C)
+# define BN_MP_ADD_C
+# define BN_MP_CLAMP_C
+# define BN_MP_CLEAR_C
+# define BN_MP_CLEAR_MULTI_C
+# define BN_MP_EXCH_C
+# define BN_MP_INIT_MULTI_C
+# define BN_MP_INIT_SIZE_C
+# define BN_MP_LSHD_C
+# define BN_MP_MUL_C
+#endif
+
+#if defined(BN_S_MP_EXPTMOD_C)
+# define BN_MP_CLEAR_C
+# define BN_MP_COPY_C
+# define BN_MP_COUNT_BITS_C
+# define BN_MP_EXCH_C
+# define BN_MP_INIT_C
+# define BN_MP_MOD_C
+# define BN_MP_MUL_C
+# define BN_MP_REDUCE_2K_L_C
+# define BN_MP_REDUCE_2K_SETUP_L_C
+# define BN_MP_REDUCE_C
+# define BN_MP_REDUCE_SETUP_C
+# define BN_MP_SET_C
+# define BN_MP_SQR_C
+#endif
+
+#if defined(BN_S_MP_EXPTMOD_FAST_C)
+# define BN_MP_CLEAR_C
+# define BN_MP_COPY_C
+# define BN_MP_COUNT_BITS_C
+# define BN_MP_DR_REDUCE_C
+# define BN_MP_DR_SETUP_C
+# define BN_MP_EXCH_C
+# define BN_MP_INIT_SIZE_C
+# define BN_MP_MOD_C
+# define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
+# define BN_MP_MONTGOMERY_REDUCE_C
+# define BN_MP_MONTGOMERY_SETUP_C
+# define BN_MP_MULMOD_C
+# define BN_MP_MUL_C
+# define BN_MP_REDUCE_2K_C
+# define BN_MP_REDUCE_2K_SETUP_C
+# define BN_MP_SET_C
+# define BN_MP_SQR_C
+# define BN_S_MP_MONTGOMERY_REDUCE_FAST_C
+#endif
+
+#if defined(BN_S_MP_GET_BIT_C)
+#endif
+
+#if defined(BN_S_MP_INVMOD_FAST_C)
+# define BN_MP_ADD_C
+# define BN_MP_CLEAR_MULTI_C
+# define BN_MP_CMP_C
+# define BN_MP_CMP_D_C
+# define BN_MP_CMP_MAG_C
+# define BN_MP_COPY_C
+# define BN_MP_DIV_2_C
+# define BN_MP_EXCH_C
+# define BN_MP_INIT_MULTI_C
+# define BN_MP_MOD_C
+# define BN_MP_SET_C
+# define BN_MP_SUB_C
+#endif
+
+#if defined(BN_S_MP_INVMOD_SLOW_C)
+# define BN_MP_ADD_C
+# define BN_MP_CLEAR_MULTI_C
+# define BN_MP_CMP_C
+# define BN_MP_CMP_D_C
+# define BN_MP_CMP_MAG_C
+# define BN_MP_COPY_C
+# define BN_MP_DIV_2_C
+# define BN_MP_EXCH_C
+# define BN_MP_INIT_MULTI_C
+# define BN_MP_MOD_C
+# define BN_MP_SET_C
+# define BN_MP_SUB_C
+#endif
+
+#if defined(BN_S_MP_KARATSUBA_MUL_C)
+# define BN_MP_ADD_C
+# define BN_MP_CLAMP_C
+# define BN_MP_CLEAR_C
+# define BN_MP_INIT_SIZE_C
+# define BN_MP_LSHD_C
+# define BN_MP_MUL_C
+# define BN_S_MP_ADD_C
+# define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_S_MP_KARATSUBA_SQR_C)
+# define BN_MP_ADD_C
+# define BN_MP_CLAMP_C
+# define BN_MP_CLEAR_C
+# define BN_MP_INIT_SIZE_C
+# define BN_MP_LSHD_C
+# define BN_MP_SQR_C
+# define BN_S_MP_ADD_C
+# define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_S_MP_MONTGOMERY_REDUCE_FAST_C)
+# define BN_MP_CLAMP_C
+# define BN_MP_CMP_MAG_C
+# define BN_MP_GROW_C
+# define BN_S_MP_SUB_C
+#endif
+
+#if defined(BN_S_MP_MUL_DIGS_C)
+# define BN_MP_CLAMP_C
+# define BN_MP_CLEAR_C
+# define BN_MP_EXCH_C
+# define BN_MP_INIT_SIZE_C
+# define BN_S_MP_MUL_DIGS_FAST_C
+#endif
+
+#if defined(BN_S_MP_MUL_DIGS_FAST_C)
+# define BN_MP_CLAMP_C
+# define BN_MP_GROW_C
+#endif
+
+#if defined(BN_S_MP_MUL_HIGH_DIGS_C)
+# define BN_MP_CLAMP_C
+# define BN_MP_CLEAR_C
+# define BN_MP_EXCH_C
+# define BN_MP_INIT_SIZE_C
+# define BN_S_MP_MUL_HIGH_DIGS_FAST_C
+#endif
+
+#if defined(BN_S_MP_MUL_HIGH_DIGS_FAST_C)
+# define BN_MP_CLAMP_C
+# define BN_MP_GROW_C
+#endif
+
+#if defined(BN_S_MP_PRIME_IS_DIVISIBLE_C)
+# define BN_MP_MOD_D_C
+#endif
+
+#if defined(BN_S_MP_RAND_JENKINS_C)
+# define BN_S_MP_RAND_JENKINS_INIT_C
+#endif
+
+#if defined(BN_S_MP_RAND_PLATFORM_C)
+#endif
+
+#if defined(BN_S_MP_REVERSE_C)
+#endif
+
+#if defined(BN_S_MP_SQR_C)
+# define BN_MP_CLAMP_C
+# define BN_MP_CLEAR_C
+# define BN_MP_EXCH_C
+# define BN_MP_INIT_SIZE_C
+#endif
+
+#if defined(BN_S_MP_SQR_FAST_C)
+# define BN_MP_CLAMP_C
+# define BN_MP_GROW_C
+#endif
+
+#if defined(BN_S_MP_SUB_C)
+# define BN_MP_CLAMP_C
+# define BN_MP_GROW_C
+#endif
+
+#if defined(BN_S_MP_TOOM_MUL_C)
+# define BN_MP_ADD_C
+# define BN_MP_CLAMP_C
+# define BN_MP_CLEAR_C
+# define BN_MP_CLEAR_MULTI_C
+# define BN_MP_DIV_2_C
+# define BN_MP_DIV_3_C
+# define BN_MP_INIT_MULTI_C
+# define BN_MP_INIT_SIZE_C
+# define BN_MP_LSHD_C
+# define BN_MP_MUL_2_C
+# define BN_MP_MUL_C
+# define BN_MP_SUB_C
+#endif
+
+#if defined(BN_S_MP_TOOM_SQR_C)
+# define BN_MP_ADD_C
+# define BN_MP_CLAMP_C
+# define BN_MP_CLEAR_C
+# define BN_MP_DIV_2_C
+# define BN_MP_INIT_C
+# define BN_MP_INIT_SIZE_C
+# define BN_MP_LSHD_C
+# define BN_MP_MUL_2_C
+# define BN_MP_MUL_C
+# define BN_MP_SQR_C
+# define BN_MP_SUB_C
+#endif
+
+#ifdef LTM_INSIDE
+#undef LTM_INSIDE
+#ifdef LTM3
+# define LTM_LAST
+#endif
+
+#include "tommath_superclass.h"
+#include "tommath_class.h"
+#else
+# define LTM_LAST
+#endif
ADDED libtommath/tommath_cutoffs.h
Index: libtommath/tommath_cutoffs.h
==================================================================
--- /dev/null
+++ libtommath/tommath_cutoffs.h
@@ -0,0 +1,13 @@
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+/*
+ Current values evaluated on an AMD A8-6600K (64-bit).
+ Type "make tune" to optimize them for your machine but
+ be aware that it may take a long time. It took 2:30 minutes
+ on the aforementioned machine for example.
+ */
+
+#define MP_DEFAULT_KARATSUBA_MUL_CUTOFF 80
+#define MP_DEFAULT_KARATSUBA_SQR_CUTOFF 120
+#define MP_DEFAULT_TOOM_MUL_CUTOFF 350
+#define MP_DEFAULT_TOOM_SQR_CUTOFF 400
ADDED libtommath/tommath_private.h
Index: libtommath/tommath_private.h
==================================================================
--- /dev/null
+++ libtommath/tommath_private.h
@@ -0,0 +1,303 @@
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#ifndef TOMMATH_PRIV_H_
+#define TOMMATH_PRIV_H_
+
+#include "tommath.h"
+#include "tommath_class.h"
+
+/*
+ * Private symbols
+ * ---------------
+ *
+ * On Unix symbols can be marked as hidden if libtommath is compiled
+ * as a shared object. By default, symbols are visible.
+ * As of now, this feature is opt-in via the MP_PRIVATE_SYMBOLS define.
+ *
+ * On Win32 a .def file must be used to specify the exported symbols.
+ */
+#if defined (MP_PRIVATE_SYMBOLS) && defined(__GNUC__) && __GNUC__ >= 4
+# define MP_PRIVATE __attribute__ ((visibility ("hidden")))
+#else
+# define MP_PRIVATE
+#endif
+
+/* Hardening libtommath
+ * --------------------
+ *
+ * By default memory is zeroed before calling
+ * MP_FREE to avoid leaking data. This is good
+ * practice in cryptographical applications.
+ *
+ * Note however that memory allocators used
+ * in cryptographical applications can often
+ * be configured by itself to clear memory,
+ * rendering the clearing in tommath unnecessary.
+ * See for example https://github.com/GrapheneOS/hardened_malloc
+ * and the option CONFIG_ZERO_ON_FREE.
+ *
+ * Furthermore there are applications which
+ * value performance more and want this
+ * feature to be disabled. For such applications
+ * define MP_NO_ZERO_ON_FREE during compilation.
+ */
+#ifdef MP_NO_ZERO_ON_FREE
+# define MP_FREE_BUFFER(mem, size) MP_FREE((mem), (size))
+# define MP_FREE_DIGITS(mem, digits) MP_FREE((mem), sizeof (mp_digit) * (size_t)(digits))
+#else
+# define MP_FREE_BUFFER(mem, size) \
+do { \
+ size_t fs_ = (size); \
+ void* fm_ = (mem); \
+ if (fm_ != NULL) { \
+ MP_ZERO_BUFFER(fm_, fs_); \
+ MP_FREE(fm_, fs_); \
+ } \
+} while (0)
+# define MP_FREE_DIGITS(mem, digits) \
+do { \
+ int fd_ = (digits); \
+ void* fm_ = (mem); \
+ if (fm_ != NULL) { \
+ size_t fs_ = sizeof (mp_digit) * (size_t)fd_; \
+ MP_ZERO_BUFFER(fm_, fs_); \
+ MP_FREE(fm_, fs_); \
+ } \
+} while (0)
+#endif
+
+#ifdef MP_USE_MEMSET
+# include
+# define MP_ZERO_BUFFER(mem, size) memset((mem), 0, (size))
+# define MP_ZERO_DIGITS(mem, digits) \
+do { \
+ int zd_ = (digits); \
+ if (zd_ > 0) { \
+ memset((mem), 0, sizeof(mp_digit) * (size_t)zd_); \
+ } \
+} while (0)
+#else
+# define MP_ZERO_BUFFER(mem, size) \
+do { \
+ size_t zs_ = (size); \
+ char* zm_ = (char*)(mem); \
+ while (zs_-- > 0u) { \
+ *zm_++ = '\0'; \
+ } \
+} while (0)
+# define MP_ZERO_DIGITS(mem, digits) \
+do { \
+ int zd_ = (digits); \
+ mp_digit* zm_ = (mem); \
+ while (zd_-- > 0) { \
+ *zm_++ = 0; \
+ } \
+} while (0)
+#endif
+
+/* Tunable cutoffs
+ * ---------------
+ *
+ * - In the default settings, a cutoff X can be modified at runtime
+ * by adjusting the corresponding X_CUTOFF variable.
+ *
+ * - Tunability of the library can be disabled at compile time
+ * by defining the MP_FIXED_CUTOFFS macro.
+ *
+ * - There is an additional file tommath_cutoffs.h, which defines
+ * the default cutoffs. These can be adjusted manually or by the
+ * autotuner.
+ *
+ */
+
+#ifdef MP_FIXED_CUTOFFS
+# include "tommath_cutoffs.h"
+# define MP_KARATSUBA_MUL_CUTOFF MP_DEFAULT_KARATSUBA_MUL_CUTOFF
+# define MP_KARATSUBA_SQR_CUTOFF MP_DEFAULT_KARATSUBA_SQR_CUTOFF
+# define MP_TOOM_MUL_CUTOFF MP_DEFAULT_TOOM_MUL_CUTOFF
+# define MP_TOOM_SQR_CUTOFF MP_DEFAULT_TOOM_SQR_CUTOFF
+#else
+# define MP_KARATSUBA_MUL_CUTOFF KARATSUBA_MUL_CUTOFF
+# define MP_KARATSUBA_SQR_CUTOFF KARATSUBA_SQR_CUTOFF
+# define MP_TOOM_MUL_CUTOFF TOOM_MUL_CUTOFF
+# define MP_TOOM_SQR_CUTOFF TOOM_SQR_CUTOFF
+#endif
+
+/* define heap macros */
+#ifndef MP_MALLOC
+/* default to libc stuff */
+# include
+# define MP_MALLOC(size) malloc(size)
+# define MP_REALLOC(mem, oldsize, newsize) realloc((mem), (newsize))
+# define MP_CALLOC(nmemb, size) calloc((nmemb), (size))
+# define MP_FREE(mem, size) free(mem)
+#else
+/* prototypes for our heap functions */
+extern void *MP_MALLOC(size_t size);
+extern void *MP_REALLOC(void *mem, size_t oldsize, size_t newsize);
+extern void *MP_CALLOC(size_t nmemb, size_t size);
+extern void MP_FREE(void *mem, size_t size);
+#endif
+
+/* feature detection macro */
+#ifdef _MSC_VER
+/* Prevent false positive: not enough arguments for function-like macro invocation */
+#pragma warning(disable: 4003)
+#endif
+#define MP_STRINGIZE(x) MP__STRINGIZE(x)
+#define MP__STRINGIZE(x) ""#x""
+#define MP_HAS(x) (sizeof(MP_STRINGIZE(BN_##x##_C)) == 1u)
+
+/* TODO: Remove private_mp_word as soon as deprecated mp_word is removed from tommath. */
+#undef mp_word
+typedef private_mp_word mp_word;
+
+#define MP_MIN(x, y) (((x) < (y)) ? (x) : (y))
+#define MP_MAX(x, y) (((x) > (y)) ? (x) : (y))
+
+/* Static assertion */
+#define MP_STATIC_ASSERT(msg, cond) typedef char mp_static_assert_##msg[(cond) ? 1 : -1];
+
+/* ---> Basic Manipulations <--- */
+#define MP_IS_ZERO(a) ((a)->used == 0)
+#define MP_IS_EVEN(a) (((a)->used == 0) || (((a)->dp[0] & 1u) == 0u))
+#define MP_IS_ODD(a) (((a)->used > 0) && (((a)->dp[0] & 1u) == 1u))
+
+#define MP_SIZEOF_BITS(type) ((size_t)CHAR_BIT * sizeof(type))
+#define MP_MAXFAST (int)(1uL << (MP_SIZEOF_BITS(mp_word) - (2u * (size_t)MP_DIGIT_BIT)))
+
+/* TODO: Remove PRIVATE_MP_WARRAY as soon as deprecated MP_WARRAY is removed from tommath.h */
+#undef MP_WARRAY
+#define MP_WARRAY PRIVATE_MP_WARRAY
+
+/* TODO: Remove PRIVATE_MP_PREC as soon as deprecated MP_PREC is removed from tommath.h */
+#ifdef PRIVATE_MP_PREC
+# undef MP_PREC
+# define MP_PREC PRIVATE_MP_PREC
+#endif
+
+/* Minimum number of available digits in mp_int, MP_PREC >= MP_MIN_PREC */
+#define MP_MIN_PREC ((((int)MP_SIZEOF_BITS(long long) + MP_DIGIT_BIT) - 1) / MP_DIGIT_BIT)
+
+MP_STATIC_ASSERT(prec_geq_min_prec, MP_PREC >= MP_MIN_PREC)
+
+/* random number source */
+extern MP_PRIVATE mp_err(*s_mp_rand_source)(void *out, size_t size);
+
+/* lowlevel functions, do not call! */
+MP_PRIVATE mp_bool s_mp_get_bit(const mp_int *a, unsigned int b);
+MP_PRIVATE mp_err s_mp_add(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+MP_PRIVATE mp_err s_mp_sub(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+MP_PRIVATE mp_err s_mp_mul_digs_fast(const mp_int *a, const mp_int *b, mp_int *c, int digs) MP_WUR;
+MP_PRIVATE mp_err s_mp_mul_digs(const mp_int *a, const mp_int *b, mp_int *c, int digs) MP_WUR;
+MP_PRIVATE mp_err s_mp_mul_high_digs_fast(const mp_int *a, const mp_int *b, mp_int *c, int digs) MP_WUR;
+MP_PRIVATE mp_err s_mp_mul_high_digs(const mp_int *a, const mp_int *b, mp_int *c, int digs) MP_WUR;
+MP_PRIVATE mp_err s_mp_sqr_fast(const mp_int *a, mp_int *b) MP_WUR;
+MP_PRIVATE mp_err s_mp_sqr(const mp_int *a, mp_int *b) MP_WUR;
+MP_PRIVATE mp_err s_mp_balance_mul(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+MP_PRIVATE mp_err s_mp_karatsuba_mul(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+MP_PRIVATE mp_err s_mp_toom_mul(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+MP_PRIVATE mp_err s_mp_karatsuba_sqr(const mp_int *a, mp_int *b) MP_WUR;
+MP_PRIVATE mp_err s_mp_toom_sqr(const mp_int *a, mp_int *b) MP_WUR;
+MP_PRIVATE mp_err s_mp_invmod_fast(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+MP_PRIVATE mp_err s_mp_invmod_slow(const mp_int *a, const mp_int *b, mp_int *c) MP_WUR;
+MP_PRIVATE mp_err s_mp_montgomery_reduce_fast(mp_int *x, const mp_int *n, mp_digit rho) MP_WUR;
+MP_PRIVATE mp_err s_mp_exptmod_fast(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y, int redmode) MP_WUR;
+MP_PRIVATE mp_err s_mp_exptmod(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y, int redmode) MP_WUR;
+MP_PRIVATE mp_err s_mp_rand_platform(void *p, size_t n) MP_WUR;
+MP_PRIVATE mp_err s_mp_prime_random_ex(mp_int *a, int t, int size, int flags, private_mp_prime_callback cb, void *dat);
+MP_PRIVATE void s_mp_reverse(unsigned char *s, size_t len);
+MP_PRIVATE mp_err s_mp_prime_is_divisible(const mp_int *a, mp_bool *result);
+
+/* TODO: jenkins prng is not thread safe as of now */
+MP_PRIVATE mp_err s_mp_rand_jenkins(void *p, size_t n) MP_WUR;
+MP_PRIVATE void s_mp_rand_jenkins_init(uint64_t seed);
+
+extern MP_PRIVATE const char *const mp_s_rmap;
+extern MP_PRIVATE const uint8_t mp_s_rmap_reverse[];
+extern MP_PRIVATE const size_t mp_s_rmap_reverse_sz;
+extern MP_PRIVATE const mp_digit *s_mp_prime_tab;
+
+/* deprecated functions */
+MP_DEPRECATED(s_mp_invmod_fast) mp_err fast_mp_invmod(const mp_int *a, const mp_int *b, mp_int *c);
+MP_DEPRECATED(s_mp_montgomery_reduce_fast) mp_err fast_mp_montgomery_reduce(mp_int *x, const mp_int *n,
+ mp_digit rho);
+MP_DEPRECATED(s_mp_mul_digs_fast) mp_err fast_s_mp_mul_digs(const mp_int *a, const mp_int *b, mp_int *c,
+ int digs);
+MP_DEPRECATED(s_mp_mul_high_digs_fast) mp_err fast_s_mp_mul_high_digs(const mp_int *a, const mp_int *b,
+ mp_int *c,
+ int digs);
+MP_DEPRECATED(s_mp_sqr_fast) mp_err fast_s_mp_sqr(const mp_int *a, mp_int *b);
+MP_DEPRECATED(s_mp_balance_mul) mp_err mp_balance_mul(const mp_int *a, const mp_int *b, mp_int *c);
+MP_DEPRECATED(s_mp_exptmod_fast) mp_err mp_exptmod_fast(const mp_int *G, const mp_int *X, const mp_int *P,
+ mp_int *Y,
+ int redmode);
+MP_DEPRECATED(s_mp_invmod_slow) mp_err mp_invmod_slow(const mp_int *a, const mp_int *b, mp_int *c);
+MP_DEPRECATED(s_mp_karatsuba_mul) mp_err mp_karatsuba_mul(const mp_int *a, const mp_int *b, mp_int *c);
+MP_DEPRECATED(s_mp_karatsuba_sqr) mp_err mp_karatsuba_sqr(const mp_int *a, mp_int *b);
+MP_DEPRECATED(s_mp_toom_mul) mp_err mp_toom_mul(const mp_int *a, const mp_int *b, mp_int *c);
+MP_DEPRECATED(s_mp_toom_sqr) mp_err mp_toom_sqr(const mp_int *a, mp_int *b);
+MP_DEPRECATED(s_mp_reverse) void bn_reverse(unsigned char *s, int len);
+
+#define MP_GET_ENDIANNESS(x) \
+ do{\
+ int16_t n = 0x1; \
+ char *p = (char *)&n; \
+ x = (p[0] == '\x01') ? MP_LITTLE_ENDIAN : MP_BIG_ENDIAN; \
+ } while (0)
+
+/* code-generating macros */
+#define MP_SET_UNSIGNED(name, type) \
+ void name(mp_int * a, type b) \
+ { \
+ int i = 0; \
+ while (b != 0u) { \
+ a->dp[i++] = ((mp_digit)b & MP_MASK); \
+ if (MP_SIZEOF_BITS(type) <= MP_DIGIT_BIT) { break; } \
+ b >>= ((MP_SIZEOF_BITS(type) <= MP_DIGIT_BIT) ? 0 : MP_DIGIT_BIT); \
+ } \
+ a->used = i; \
+ a->sign = MP_ZPOS; \
+ MP_ZERO_DIGITS(a->dp + a->used, a->alloc - a->used); \
+ }
+
+#define MP_SET_SIGNED(name, uname, type, utype) \
+ void name(mp_int * a, type b) \
+ { \
+ uname(a, (b < 0) ? -(utype)b : (utype)b); \
+ if (b < 0) { a->sign = MP_NEG; } \
+ }
+
+#define MP_INIT_INT(name , set, type) \
+ mp_err name(mp_int * a, type b) \
+ { \
+ mp_err err; \
+ if ((err = mp_init(a)) != MP_OKAY) { \
+ return err; \
+ } \
+ set(a, b); \
+ return MP_OKAY; \
+ }
+
+#define MP_GET_MAG(name, type) \
+ type name(const mp_int* a) \
+ { \
+ unsigned i = MP_MIN((unsigned)a->used, (unsigned)((MP_SIZEOF_BITS(type) + MP_DIGIT_BIT - 1) / MP_DIGIT_BIT)); \
+ type res = 0u; \
+ while (i --> 0u) { \
+ res <<= ((MP_SIZEOF_BITS(type) <= MP_DIGIT_BIT) ? 0 : MP_DIGIT_BIT); \
+ res |= (type)a->dp[i]; \
+ if (MP_SIZEOF_BITS(type) <= MP_DIGIT_BIT) { break; } \
+ } \
+ return res; \
+ }
+
+#define MP_GET_SIGNED(name, mag, type, utype) \
+ type name(const mp_int* a) \
+ { \
+ utype res = mag(a); \
+ return (a->sign == MP_NEG) ? (type)-res : (type)res; \
+ }
+
+#endif
ADDED libtommath/tommath_superclass.h
Index: libtommath/tommath_superclass.h
==================================================================
--- /dev/null
+++ libtommath/tommath_superclass.h
@@ -0,0 +1,110 @@
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* super class file for PK algos */
+
+/* default ... include all MPI */
+#ifndef LTM_NOTHING
+#define LTM_ALL
+#endif
+
+/* RSA only (does not support DH/DSA/ECC) */
+/* #define SC_RSA_1 */
+/* #define SC_RSA_1_WITH_TESTS */
+
+/* For reference.... On an Athlon64 optimizing for speed...
+
+ LTM's mpi.o with all functions [striped] is 142KiB in size.
+
+*/
+
+#ifdef SC_RSA_1_WITH_TESTS
+# define BN_MP_ERROR_TO_STRING_C
+# define BN_MP_FREAD_C
+# define BN_MP_FWRITE_C
+# define BN_MP_INCR_C
+# define BN_MP_ISEVEN_C
+# define BN_MP_ISODD_C
+# define BN_MP_NEG_C
+# define BN_MP_PRIME_FROBENIUS_UNDERWOOD_C
+# define BN_MP_RADIX_SIZE_C
+# define BN_MP_RAND_C
+# define BN_MP_REDUCE_C
+# define BN_MP_REDUCE_2K_L_C
+# define BN_MP_FROM_SBIN_C
+# define BN_MP_ROOT_U32_C
+# define BN_MP_SET_L_C
+# define BN_MP_SET_UL_C
+# define BN_MP_SBIN_SIZE_C
+# define BN_MP_TO_RADIX_C
+# define BN_MP_TO_SBIN_C
+# define BN_S_MP_RAND_JENKINS_C
+# define BN_S_MP_RAND_PLATFORM_C
+#endif
+
+/* Works for RSA only, mpi.o is 68KiB */
+#if defined(SC_RSA_1) || defined (SC_RSA_1_WITH_TESTS)
+# define BN_CUTOFFS_C
+# define BN_MP_ADDMOD_C
+# define BN_MP_CLEAR_MULTI_C
+# define BN_MP_EXPTMOD_C
+# define BN_MP_GCD_C
+# define BN_MP_INIT_MULTI_C
+# define BN_MP_INVMOD_C
+# define BN_MP_LCM_C
+# define BN_MP_MOD_C
+# define BN_MP_MOD_D_C
+# define BN_MP_MULMOD_C
+# define BN_MP_PRIME_IS_PRIME_C
+# define BN_MP_PRIME_RABIN_MILLER_TRIALS_C
+# define BN_MP_PRIME_RAND_C
+# define BN_MP_RADIX_SMAP_C
+# define BN_MP_SET_INT_C
+# define BN_MP_SHRINK_C
+# define BN_MP_TO_UNSIGNED_BIN_C
+# define BN_MP_UNSIGNED_BIN_SIZE_C
+# define BN_PRIME_TAB_C
+# define BN_S_MP_REVERSE_C
+
+/* other modifiers */
+# define BN_MP_DIV_SMALL /* Slower division, not critical */
+
+
+/* here we are on the last pass so we turn things off. The functions classes are still there
+ * but we remove them specifically from the build. This also invokes tweaks in functions
+ * like removing support for even moduli, etc...
+ */
+# ifdef LTM_LAST
+# undef BN_MP_DR_IS_MODULUS_C
+# undef BN_MP_DR_SETUP_C
+# undef BN_MP_DR_REDUCE_C
+# undef BN_MP_DIV_3_C
+# undef BN_MP_REDUCE_2K_SETUP_C
+# undef BN_MP_REDUCE_2K_C
+# undef BN_MP_REDUCE_IS_2K_C
+# undef BN_MP_REDUCE_SETUP_C
+# undef BN_S_MP_BALANCE_MUL_C
+# undef BN_S_MP_EXPTMOD_C
+# undef BN_S_MP_INVMOD_FAST_C
+# undef BN_S_MP_KARATSUBA_MUL_C
+# undef BN_S_MP_KARATSUBA_SQR_C
+# undef BN_S_MP_MUL_HIGH_DIGS_C
+# undef BN_S_MP_MUL_HIGH_DIGS_FAST_C
+# undef BN_S_MP_TOOM_MUL_C
+# undef BN_S_MP_TOOM_SQR_C
+
+# ifndef SC_RSA_1_WITH_TESTS
+# undef BN_MP_REDUCE_C
+# endif
+
+/* To safely undefine these you have to make sure your RSA key won't exceed the Comba threshold
+ * which is roughly 255 digits [7140 bits for 32-bit machines, 15300 bits for 64-bit machines]
+ * which means roughly speaking you can handle upto 2536-bit RSA keys with these defined without
+ * trouble.
+ */
+# undef BN_MP_MONTGOMERY_REDUCE_C
+# undef BN_S_MP_MUL_DIGS_C
+# undef BN_S_MP_SQR_C
+# endif
+
+#endif