Coder Social home page Coder Social logo

libtom / libtommath Goto Github PK

View Code? Open in Web Editor NEW
632.0 49.0 191.0 21.27 MB

LibTomMath is a free open source portable number theoretic multiple-precision integer library written entirely in C.

Home Page: https://www.libtom.net

License: Other

C 87.09% Perl 3.31% Makefile 2.92% Assembly 0.09% Shell 3.35% HTML 0.15% Roff 0.06% Swift 0.29% CMake 2.74%
mpi libtommath c math multi-precision

libtommath's Introduction

libtommath

This is the git repository for LibTomMath, a free open source portable number theoretic multiple-precision integer (MPI) library written entirely in C.

Build Status

Travis CI

master: Build Status

develop: Build Status

AppVeyor

master: Build status

develop: Build status

ABI Laboratory

API/ABI changes: check here

Pre-built packages

We sometimes upload deb packages of the latest state from the develop branch to packagecloud.io.

Use those packages with caution and at your own discretion.

Summary

The develop branch contains the in-development version. Stable releases are tagged.

Documentation is built from the LaTeX file doc/bn.tex and available as PDF for each release. This PDF is also created as build artifact on each CI run.

There is also limited documentation in tommath.h.

Originally the library contained a document, tommath.pdf, which describes the goals of the project and many of the algorithms used at the time. This document has been removed since it can't be built anymore and nobody spent the time to fix and update it. The latest valid update to that document was done in version 0.39 of the library and it is contained within that tarball.

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.

CMake support

The project provides support for the CMake build system.

git clone https://github.com/libtom/libtommath.git
mkdir -p libtommath/build
cd libtommath/build
cmake ..
make -j$(nproc)

A shared library build can be done by setting -DBUILD_SHARED_LIBS=On when invoking the cmake command.

libtommath's People

Contributors

abokth avatar arnout avatar cntrump avatar czurnieden avatar dbussink avatar dfateyev avatar dmitry-lipetsk avatar fperrad avatar j08ny avatar karel-m avatar kennykb avatar lomereiter avatar madebr avatar magicaltux avatar masterduke17 avatar mikhailnov avatar minad avatar mkj avatar moritz avatar mrpelotazo avatar nijtmans avatar prince213 avatar ramkumarkoppu avatar samcv avatar serval2412 avatar sjaeckel avatar timgates42 avatar tomstdenis avatar usafchn avatar vonbrand avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

libtommath's Issues

Potential problem with mp_add_d('0',...)

Hello

I offer to rewrite the next part of mp_add_d

     /* add digit, after this we're propagating
      * the carry.
      */
     *tmpc   = *tmpa++ + b;
     mu      = *tmpc >> DIGIT_BIT;
     *tmpc++ &= MP_MASK;

     /* now handle rest of the digits */
     for (ix = 1; ix < a->used; ix++) {
        *tmpc   = *tmpa++ + mu;
        mu      = *tmpc >> DIGIT_BIT;
        *tmpc++ &= MP_MASK;
     }

to

     /* add digit, after this we're propagating
      * the carry.
      */
     mu      = b;

     /* now handle rest of the digits */
     for (ix = 0; ix < a->used; ix++) {
        *tmpc   = *tmpa++ + mu;
        mu      = *tmpc >> DIGIT_BIT;
        *tmpc++ &= MP_MASK;
     }

It will allow to correctly work with zero value in 'a' (when a->used == 0)


Please review...

improve mp_lshd

I offer add to 'mp_lshd' function the special support for zero value of 'a':

 if(mp_iszero(a)==MP_YES)
 {
  return MP_OKAY;
 }

It can help to avoid an creation of 'unnormalized' result in 'b'.


Or add call of 'mp_clamp(b)' before exit from mp_lshd.

stdint.h and portability troubles

The commit 7ab90a4 introduced #include <stdint.h> which makes troubles (= build failures) with some compilers/platforms.

I have experienced build failure due to non-existing stdint.h at couple of MSVC compiler + a bit older HP ANSI C compiler at HP-UX 11.11 / PA-RISC2.

I am also afraid that some older 32bit MS Visual Studio compilers will not accept long long (we should rather use __int64).

Before I start preparing a pull request I want to ask whether we want to support these cases because the patch should have return back some parts that were removed by the commit mentioned at the beginning.

Cosmetic change: warnings in test suite

Some new warnings are expected to be fixed in the future:

libtool: link: gcc -I./ -Wall -Wsign-compare -Wextra -Wshadow -Wsystem-headers -Wdeclaration-after-statement -Wbad-function-cast -Wcast-align -Wstrict-prototypes -Wpointer-arith -fprofile-arcs -ftest-coverage -DTIMING_NO_LOGS -DTIMER demo/timing.c -o .libs/ltmtest  -lgcov ./.libs/libtommath.so
demo/timing.c: In function 'main':
demo/timing.c:125:11: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 2 has type 'uint64_t {aka long unsigned int}' [-Wformat=]
    printf("CLK_PER_SEC == %llu\n", CLK_PER_SEC);
           ^
demo/timing.c:140:14: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 3 has type 'uint64_t {aka long unsigned int}' [-Wformat=]
       printf("Adding\t\t%4d-bit => %9llu/sec, %9llu cycles\n",
              ^
demo/timing.c:140:14: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 4 has type 'uint64_t {aka long unsigned int}' [-Wformat=]
demo/timing.c:162:14: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 3 has type 'uint64_t {aka long unsigned int}' [-Wformat=]
       printf("Subtracting\t\t%4d-bit => %9llu/sec, %9llu cycles\n",
              ^
demo/timing.c:162:14: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 4 has type 'uint64_t {aka long unsigned int}' [-Wformat=]
demo/timing.c:197:10: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 3 has type 'uint64_t {aka long unsigned int}' [-Wformat=]
   printf("Multiplying\t%4d-bit => %9llu/sec, %9llu cycles\n",
          ^
demo/timing.c:197:10: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 4 has type 'uint64_t {aka long unsigned int}' [-Wformat=]
demo/timing.c:217:10: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 3 has type 'uint64_t {aka long unsigned int}' [-Wformat=]
   printf("Squaring\t%4d-bit => %9llu/sec, %9llu cycles\n",
          ^
demo/timing.c:217:10: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 4 has type 'uint64_t {aka long unsigned int}' [-Wformat=]
demo/timing.c:293:10: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 3 has type 'uint64_t {aka long unsigned int}' [-Wformat=]
   printf("Exponentiating\t%4d-bit => %9llu/sec, %9llu cycles\n",
          ^
demo/timing.c:293:10: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 4 has type 'uint64_t {aka long unsigned int}' [-Wformat=]
demo/timing.c:329:14: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 3 has type 'uint64_t {aka long unsigned int}' [-Wformat=]
       printf("Inverting mod\t%4d-bit => %9llu/sec, %9llu cycles\n",
              ^
demo/timing.c:329:14: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 4 has type 'uint64_t {aka long unsigned int}' [-Wformat=]

libtommath-1.0.1-rc1 -- not /usr/local

sudo make -j5 -f makefile.shared LT=glibtool install causes the libtommath libs to be installed in /lib, not /usr/local/lib. Attempts to set PREFIX crashed the make.

memory leaks in mp_init_copy

  int     res;

  if ((res = mp_init_size (a, b->used)) != MP_OKAY) {
    return res;
  }

  if((res = mp_copy (b, a)) != MP_OKAY) {
    mp_clear(a); //<-------- NEW CODE
  }

  return res;

libtomath build broken on win32, due to the use of uint8_t

When importing the "develop" branch of libtom/libtommath into Tcl, it broke the win32 build. The reason is that no header file is used which defines uint8_t, still this symbol is used in tommath_private.h and bn_mp_radix_smap.c. (the use in tommath.h is harmless, since Tcl doesn't use MP_8BIT)

Feature request: conversion from mp_int to float or double precision

It would be nice if I could convert a mp_int into a float or double, preserving the magnitude and some of the first digits, though of course the general case will be lossy. If the mp_int is too large, it could return Inf or -Inf.

We use mp_int for storing big integers in a Perl 6 compiler, and it we'll need to offer such functionality to our uses eventually.

Time for a new release ?

Hello

Moarvm (Rakudo/Perl6 VM) is using libtommath from April 2018 (https://github.com/MoarVM/libtommath/tree/289e346bb9b968377ffbbbe6876342fedda4e072).

As Debian packager, I'm building MoarVM with the last version of libtommath (1.0.1) which was released in August 2017.

I've currently have not seen a problem using Rakudo with this old version of libtommath. But, the increasing gap of libtommath version between Rakudo development and Debian build is making me nervous.

Since libtommath was last released a year ago and the development is quite active (119 commits since 1.0.1), it may be time to cut a new release...

Thoughts ?

Please create a new release

Hello

Latest version of Rakudo Perl6 (actually moarvm) does not compile on Debian with libtommath 1.0:

src/math/bigintops.c:950:13: error: โ€˜MP_GEN_RANDOM_MAXโ€™ undeclared (first use in this function); did you mean โ€˜MP_GEN_RANDOMโ€™?
         if (MP_GEN_RANDOM_MAX >= abs(smallint_max)) {
             ^~~~~~~~~~~~~~~~~
             MP_GEN_RANDOM

Moarvm is now using libtommath from March 2017 (i.e. commit 8ae5ddf ) as a git submodule. The MP_GEN_RANDOM_MAX macro was added to

As a Debian packager, I can only use a released version of libtommath. Could you please create a new release so I can package it and fix moarvm build in Debian ?

All the best

Error compilation with makefile.msvc under VS 2017

When using the commandile nmake -f makefile.msvc to compile the library I get:

CFLAGS = /I. /Ox /DWIN32 /W3  /Fo$@

macro '$@' is illegal in the context of batch rule 'rule'

The quick fix is to remove /Fo$@.

tommath_class.h includes itself

I got a bit lost among all the #ifdef, #else and #endif but, if I am not wrong, tommaath_class.h includes itself here.

Is it a human error or it is done on purpose?

new function mp_sqrtmod_prime

Hi,

it would be nice to have mp_sqrtmod_prime function - it is necessary for handling compressed ECC keys as mentioned in this issue libtom/libtomcrypt#34

here is my suggestion (I'll send it as pull request if you find it worth considering):

diff --git a/src/ltm/bn_mp_sqrtmod_prime.c b/src/ltm/bn_mp_sqrtmod_prime.c
--- /dev/null
+++ b/src/ltm/bn_mp_sqrtmod_prime.c
@@ -0,0 +1,122 @@
+#include <tommath.h>
+#ifdef BN_MP_SQRTMOD_PRIME_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis
+ *
+ * LibTomMath is a library that provides multiple-precision
+ * integer arithmetic as well as number theoretic functionality.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* Tonelliโ€“Shanks algorithm
+ * https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm
+ * https://gmplib.org/list-archives/gmp-discuss/2013-April/005300.html
+ *
+ */
+
+int mp_sqrtmod_prime(mp_int *n, mp_int *prime, mp_int *ret)
+{
+  int res, legendre;
+  mp_int t1, C, Q, S, Z, M, T, R, two;
+  unsigned long i;
+
+  /* first handle the simple cases */
+  if (mp_cmp_d(n, 0) == MP_EQ) {
+    mp_zero(ret);
+    return MP_OKAY;
+  }
+  if (mp_cmp_d(prime, 2) == MP_EQ)                              return MP_VAL; /* prime must be odd */
+  if ((res = mp_jacobi(n, prime, &legendre)) != MP_OKAY)        return res;
+  if (legendre == -1)                                           return MP_VAL; /* quadratic non-residue mod prime */
+
+  mp_init_multi(&t1, &C, &Q, &S, &Z, &M, &T, &R, &two, NULL);
+
+  /* SPECIAL CASE: if prime mod 4 == 3
+   * compute directly: res = n^(prime+1)/4 mod prime
+   * Handbook of Applied Cryptography algorithm 3.36
+   */
+  if ((res = mp_mod_d(prime, 4, &i)) != MP_OKAY)                goto cleanup;
+  if (i == 3) {
+    if ((res = mp_add_d(prime, 1, &t1)) != MP_OKAY)             goto cleanup;
+    if ((res = mp_div_2(&t1, &t1)) != MP_OKAY)                  goto cleanup;
+    if ((res = mp_div_2(&t1, &t1)) != MP_OKAY)                  goto cleanup;
+    if ((res = mp_exptmod(n, &t1, prime, ret)) != MP_OKAY)      goto cleanup;
+    res = 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 ((res = mp_copy(prime, &Q)) != MP_OKAY)                    goto cleanup;
+  if ((res = mp_sub_d(&Q, 1, &Q)) != MP_OKAY)                   goto cleanup;
+  /* Q = prime - 1 */
+  mp_zero(&S);
+  /* S = 0 */
+  while (mp_iseven(&Q)) {
+    if ((res = mp_div_2(&Q, &Q)) != MP_OKAY)                    goto cleanup;
+    /* Q = Q / 2 */
+    if ((res = mp_add_d(&S, 1, &S)) != MP_OKAY)                 goto cleanup;
+    /* S = S + 1 */
+  }
+
+  /* find a Z such that the Legendre symbol (Z|prime) == -1 */
+  mp_set_int(&Z, 2);
+  /* Z = 2 */
+  while(1) {
+    if ((res = mp_jacobi(&Z, prime, &legendre)) != MP_OKAY)     goto cleanup;
+    if (legendre == -1) break;
+    if ((res = mp_add_d(&Z, 1, &Z)) != MP_OKAY)                 goto cleanup;
+    /* Z = Z + 1 */
+  }
+
+  if ((res = mp_exptmod(&Z, &Q, prime, &C)) != MP_OKAY)         goto cleanup;
+  /* C = Z ^ Q mod prime */
+  if ((res = mp_add_d(&Q, 1, &t1)) != MP_OKAY)                  goto cleanup;
+  if ((res = mp_div_2(&t1, &t1)) != MP_OKAY)                    goto cleanup;
+  /* t1 = (Q + 1) / 2 */
+  if ((res = mp_exptmod(n, &t1, prime, &R)) != MP_OKAY)         goto cleanup;
+  /* R = n ^ ((Q + 1) / 2) mod prime */
+  if ((res = mp_exptmod(n, &Q, prime, &T)) != MP_OKAY)          goto cleanup;
+  /* T = n ^ Q mod prime */
+  if ((res = mp_copy(&S, &M)) != MP_OKAY)                       goto cleanup;
+  /* M = S */
+  if ((res = mp_set_int(&two, 2)) != MP_OKAY)                   goto cleanup;
+
+  while (1) {
+    if ((res = mp_copy(&T, &t1)) != MP_OKAY)                    goto cleanup;
+    i = 0;
+    while (1) {
+      if (mp_cmp_d(&t1, 1) == MP_EQ) break;
+      if ((res = mp_exptmod(&t1, &two, prime, &t1)) != MP_OKAY) goto cleanup;
+      i++;
+    }
+    if (i == 0) {
+      mp_copy(&R, ret);
+      res = MP_OKAY;
+      goto cleanup;
+    }
+    if ((res = mp_sub_d(&M, i, &t1)) != MP_OKAY)                goto cleanup;
+    if ((res = mp_sub_d(&t1, 1, &t1)) != MP_OKAY)               goto cleanup;
+    if ((res = mp_exptmod(&two, &t1, prime, &t1)) != MP_OKAY)   goto cleanup;
+    /* t1 = 2 ^ (M - i - 1) */
+    if ((res = mp_exptmod(&C, &t1, prime, &t1)) != MP_OKAY)     goto cleanup;
+    /* t1 = C ^ (2 ^ (M - i - 1)) mod prime */
+    if ((res = mp_sqrmod(&t1, prime, &C)) != MP_OKAY)           goto cleanup;
+    /* C = (t1 * t1) mod prime */
+    if ((res = mp_mulmod(&R, &t1, prime, &R)) != MP_OKAY)       goto cleanup;
+    /* R = (R * t1) mod prime */
+    if ((res = mp_mulmod(&T, &C, prime, &T)) != MP_OKAY)        goto cleanup;
+    /* T = (T * C) mod prime */
+    mp_set(&M, i);
+    /* M = i */
+  }
+
+  res = MP_VAL;
+cleanup:
+  mp_clear_multi(&t1, &C, &Q, &S, &Z, &M, &T, &R, &two, NULL);
+  return res;
+}
+
+#endif
diff --git a/src/ltm/tommath.h b/src/ltm/tommath.h
index 58a26c8..14da465 100644
--- a/src/ltm/tommath.h
+++ b/src/ltm/tommath.h
@@ -394,6 +394,9 @@ int mp_n_root(mp_int *a, mp_digit b, mp_int *c);
 /* special sqrt algo */
 int mp_sqrt(mp_int *arg, mp_int *ret);

+/* special sqrt (mod prime) */
+int mp_sqrtmod_prime(mp_int *arg, mp_int *prime, mp_int *ret);
+
 /* is number a square? */
 int mp_is_square(mp_int *arg, int *ret);

diff --git a/src/ltm/tommath_class.h b/src/ltm/tommath_class.h
index 68b88b9..a82fa44 100644
--- a/src/ltm/tommath_class.h
+++ b/src/ltm/tommath_class.h
@@ -104,6 +104,7 @@
 #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
@@ -823,6 +824,18 @@
    #define BN_MP_CLEAR_C
 #endif

+#if defined(BN_MP_SQRTMOD_PRIME_C)
+   #define BN_MP_JACOBI_C
+   #define BN_MP_ZERO_C
+   #define BN_MP_SET_INT_C
+   #define BN_MP_COPY_C
+   #define BN_MP_SUB_C
+   #define BN_MP_SUB_D_C
+   #define BN_MP_DIV_2_C
+   #define BN_MP_ADD_D_C
+   #define BN_MP_EXPTMOD_C
+#endif
+
 #if defined(BN_MP_SUB_C)
    #define BN_S_MP_ADD_C
    #define BN_MP_CMP_MAG_C

mistake in mp_div

In code:

  /* step 3. for i from n down to (t + 1) */
  for (i = n; i >= (t + 1); i--) {
    if (i > x.used) {
      continue;
    }

I think, should be:

   if (i >= x.used) {

Decimal numbers (radix==10) for test operation (a / b):

a=3067161331641079976151533586319557730249073818741761610008250427475901610199879968766329531563687043693402621268943124868381696242108642234231961730721843589353846747206472781244530543373423697860384124350169319274508178224664556550535653424037901850281783620936151120511351560268242242944861690615059558257179150439309203196444289158574162364448252611588808917477886531318273928442271549262235942891697671710701430134360572789944439609882091248919666254084798263561644567930542524789226705258184111355143245563109214371174898026588545768462834262830136558105821577991371394478637020935897350920595595149428868836454

b=161854874649776085868045952190159031555772097014435707776279513538616175047026058065927714606879676219064271341818754038806823814541886861147177045257236811627035155212310813305487929926508522581710604504792711726648563877865328333166885998671854094528177699206377434633696300213499023964016345755132798642663

The problem occurred at line

  /* 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])  //<---------------------- HERE. i==52, x.used==52

Incorrect work of mp_add_d(a=-1, b=4, a)

Hello

Seems, mp_add_d works incorrectly when pointers 'a' and 'c' are equal and (*a)=="-1", b=="4"

I think,
/*line 53*/ c->sign = MP_ZPOS;

should be after

/*line 62*/ if (a->sign == MP_ZPOS) {...} else {...}

libtommath-1.0.1-rc1 -- macOS glibtool

compiling on macOS (darwin) with make -j5 -f makefile.shared and ran into the libtool vs glibtool issue

libtool --mode=compile --tag=CC gcc -I./ -Wall -Wsign-compare -Wextra -Wshadow -Wsystem-headers -Wdeclaration-after-statement -Wbad-function-cast -Wcast-align -Wstrict-prototypes -Wpointer-arith -O3 -funroll-loops -fomit-frame-pointer  -o bn_fast_s_mp_mul_digs.o -c bn_fast_s_mp_mul_digs.c
error: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool: unknown option character `-' in: --mode=compile

By itself, make worked.

PS: adding LT=glibtool worked but for the uninitiated I would prefer seeing

ifndef LT
  ifeq ($(PLATFORM), Darwin)
    LT:=glibtool
  else
    LT:=libtool
  endif
endif

incosistent MP_32BIT vs. MP_31BIT in tommath.h

In tommath.h we have:

...
#if !(defined(MP_32BIT) || defined(MP_16BIT) || defined(MP_8BIT))
...

and couple of lines after that:

...
#ifdef MP_31BIT
...

IMO both MP_31BIT and MP_32BIT should be consistent

DER should check EOL

der_decode_sequence_ex currently does a break, when it sees a LTC_ASN1_EOL.
But shouldn't it check if the input data is really at its end?

I came to this over dsa_verify_hash. This function accepts signatures that are too long.
If you are using documents with inline signatures the signature has to be stripped out
before calculating the hash. But if the signature is not stripped out while processing the file means that it is possible to modify the file content by appending to the signature.

Licensing, Public Domain issues

I see that libtommath is "dual licensed" under "Public Domain" and "WTFPL".

"WTFPL" may not be legally viable and "Public Domain" is not a license because it is dependent on the country of the software's use. I think the creator may be located in Canada? So here are the Canadian rules on Public Domain:

If it was created in Canada, treat it under Canadian law
If it wasn't created in Canada (Berne Convention Country), treat it as if it were created in Canada

It is not to my knowledge allowable to give up your copyright and put it into Public Domain yourself, you must wait 50 years after death, and that is different on different countries. I could be wrong about not being able to give it up under Canadian law, but even so users of the software are still at the mercy of their countries laws regarding Public Domain and Copyright.

May I suggest you choose CC-0 which puts your work into the public domain but also has provisions which take effect if the persons country does not recognize a work as being in public domain. Thereby achieving the desired goal of public domain, but also making users confident that they are able to use the software worldwide without having to do extensive research on Public Domain for their country.

Given that software and the Internet is Global it would be awesome if this work could be licensed under CC-0. Thank you all for developing this great software. I ask this only in the hope that a change such as this will allow more usage of this software in the spirit of your intention, of putting it into the Public Domain regardless of a persons country.

From the CC site:

Dedicating works to the public domain is difficult if not impossible for those wanting to contribute 
their works for public use before applicable copyright or database protection terms expire. Few if any 
jurisdictions have a process for doing so easily and reliably. Laws vary from jurisdiction to jurisdiction 
as to what rights are automatically granted and how and when they expire or may be voluntarily 
relinquished. More challenging yet, many legal systems effectively prohibit any attempt by these 
owners to surrender rights automatically conferred by law, particularly moral rights, even when the 
author wishing to do so is well informed and resolute about doing so and contributing their work to 
the public domain.

Improve mp_init_copy()

In mp_init_copy(), mp_init() is used to assign the memory with default block size, mp_copy() is used to grow the target mp_int size if it is required and copy the content.

My suggestion is to use mp_init_size() instead of mp_init() inside the mp_init_copy to assign required memory depending on the source mp_int size and then use mp_copy to copy the content. This will avoid the subsequent mp_grow() inside the mp_copy(). The changes code would look like this:

int mp_init_copy (mp_int * a, mp_int * b)
{
int res;

if ((res = mp_init_size (a, b->used)) != MP_OKAY) {
return res;
}
return mp_copy (b, a);
}

mp_invmod() returns an incorrect result

a = "47182BB8DF0FFE9F61B1F269BACC066B48BA145D35137D426328DC3F88A5EA44";
b = "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF";

the correct result is:

a^-1(mod b) =  "0521A82E10376F8E4FDEF9A32A427AC2A0FFF686E00290D39E3E4B5522409596"

but mp_invmod() returns

"10521A82D10376F8E4FDEF9A32A427AC2A0FFF685E00290D49E3E4B5522409595"	

I called the function like this:

    uint8_t a[32] = {0x47,0x18,0x2B,0xB8,0xDF,0x0F,0xFE,0x9F,0x61,0xB1,0xF2,0x69,0xBA,0xCC,0x06,0x6B,0x48,0xBA,0x14,0x5D,0x35,0x13,0x7D,0x42,0x63,0x28,0xDC,0x3F,0x88,0xA5,0xEA,0x44};
    uint8_t b[32] = {0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
    uint8_t ret[32] = {0};
    mp_int mp_a,mp_b,mp_ret;
    mp_init_multi(&mp_a, &mp_b, &mp_ret, NULL);
    
    mp_read_unsigned_bin(&mp_a, a, 32);
    mp_read_unsigned_bin(&mp_b, b, 32);
    
    mp_invmod(&mp_a, &mp_b, &mp_ret);
    
    mp_to_unsigned_bin(&mp_ret, ret);

the function doesn't always return incorrect values.

Redefinition of macro MIN / MAX

HP ANSI C compiler (HP-UX PARISC)

cpp: "src/ltm/tommath_private.h", line 21: warning 2001: Redefinition of macro MIN.
cpp: "src/ltm/tommath_private.h", line 23: warning 2001: Redefinition of macro MAX.

Not a big deal, I am posting this just in case we want to keep "no compiler warnings during build" strategy

Need help with mp_exptmod and BigInts

I would like to calculate the following in C ++ with libtommath:
x ^ (2 ^ level) % n

So I try it ...

        char buff[4096];
        mp_int x, level, n, X, e;

        mp_init(&x);
        mp_init(&level);
        mp_init(&n);
        mp_init(&X);
        mp_init(&e);

        // Calculate RSA  x ^ (2 ^ level) % n

        mp_set(&x, 32878006774570359216307190512414453734815024711845858985814302013359906676224571864057517441898232179839316906470039235887748992902358250854400787652810336070530280967470770997285440429053186803879037);
        mp_set(&level, 10000);
        mp_set(&n, 77898130960070341501772069500669364440519531421534783575397763758775619778096560479521554583192022357575799725548012588149166448319424189949242058358050730052508358466295626425829884371399991831978634);
        mp_set(&e, 2);

        mp_sqr(&e, &level);
        mp_toint(&level, buff);
        printf("LVL = %s\n", buff );  // 4
        mp_exptmod(&x, &level, &n, &X);

        mp_toint(&X, buff);
        printf("X :: %s\n", buff); // 346751013179386221

//Warning: integer constant is too large for its type mp_set(&n, ...);
//Warning: integer constant is too large for its type mp_set(&x, ...);

It just doesn't calculate the big numbers correct ... or I'm doing something wrong ...

error in fast_s_mp_mul_digs

  c->used = pa;

  {
    mp_digit *tmpc;
    tmpc = c->dp;
    for (ix = 0; ix < (pa + 1); ix++) {
      /* now extract the previous digit [below the carry] */
      *tmpc++ = W[ix];
    }

Should be:
for (ix = 0; ix < pa ; ix++) {

Feature request: Addition of an arithmetic right shift function that emulates 2's complement

See this "bug": #29

Also see this wikipedia article: https://en.wikipedia.org/wiki/Arithmetic_shift

LibTomMath's right shift function does a logical right shift. However, if you want to match what processors do (necessary for my use case which is transparently using mp_int behind-the-scenes for integers too big to represent with a long), you want an arithmetic right shift that acts as if it's 2's complement - we want to act as if there's a sign bit and preserve it, even though we don't actually have one.

Not sure what to call it.

conversion from 'size_t' to 'int' (warning)

I have experienced the following:

bn_mp_export.c(68) : warning C4267: 'function' : conversion from 'size_t' to 'int', possible loss of data
bn_mp_import.c(55) : warning C4267: 'function' : conversion from 'size_t' to 'int', possible loss of data

Possible (untested) fix:

## bn_mp_import.c 
- (result = mp_mul_2d(rop, ((j == 0) ? (8 - odd_nails) : 8), rop)) != MP_OKAY) {
+ (result = mp_mul_2d(rop, (int)((j == 0) ? (8 - odd_nails) : 8), rop)) != MP_OKAY) {


## bn_mp_export.c
- if ((result = mp_div_2d(&t, ((j == ((size - nail_bytes) - 1)) ? (8 - odd_nails) : 8), &t, NULL)) != MP_OKAY) {
+ if ((result = mp_div_2d(&t, (int)((j == ((size - nail_bytes) - 1)) ? (8 - odd_nails) : 8), &t, NULL)) != MP_OKAY) {

build libtommath before libtomcrypt on win10-64bit + mingw-gcc

in order to build libtomcrypt on win10-64bit + mingw-gcc there is a need
to build libtommath before.

the command: mingw32-make -f makefile.mingw inside C:\libtomcrypt-develop can not work.
the solution in: C:\libtommath-develop is:

C:\libtommath-develop> gcc -I. -c *.c
C:\libtommath-develop> ar -r libtommath.a *.o
C:\libtommath-develop> ranlib libtommath.a

and after that: rename C:\libtommath-develop to: C:\libtommath
then the command:
mingw32-make -f makefile.mingw inside C:\libtomcrypt-develop works.

there is a need to create makefile.mingw in C:\libtommath-develop for this commands:
and maybe a C:\libtommath-develop rename is needed.

C:\libtommath-develop> gcc -I. -c *.c
C:\libtommath-develop> ar -r libtommath.a *.o
C:\libtommath-develop> ranlib libtommath.a

Please confirm the result of mp_exptmod

Hello.

Could anybody confirm the following result of mp_exptmod(G,X,P):

[decimal numbers]
G: 134579305646567588532446688779867257713771275107057684621479634689650080773159393062143615968462797569598762456137907426092218976711352664901100324510362588000972245190812583367951716257843798290510401392628339635570171029437522098146169720032322549061259568330770328939946360070887343808349359575738583288513

X: 59621918710175437070932497031782508368941263753349421666170603004927957539961933633126185597358384597639320471341244211399512691371990377023221395581281196351551942288799914425527074844447065151470655714679461853044096538898382911610773551224067179736028363490008331414981702505494439632826269013715639300607

P: 161854874649776085868045952190159031555772097014435707776279513538616175047026058065927714606879676219064271341818754038806823814541886861147177045257236811627035155212310813305487929926508522581710604504792711726648563877865328333166885998671854094528177699206377434633696300213499023964016345755132798642663

Result:
101301173055927651077022731855711438828812096932633287901900987654023094677508334006010080425994011956816952131806632586952937438745717497636453981418484521946523641731799712935430148584311675467744159957145015439883211966248185614742819253200041306084133542299253931058698197750953799169870496336490295415615


If result is correct - how I can to check this result through other libtommath functions?

Thanks.

Redefinition of macro MIN|MAX

Compiler warning:

cpp: "ltm/tommath_private.h", line 21: warning 2001: Redefinition of macro MIN.
cpp: "ltm/tommath_private.h", line 23: warning 2001: Redefinition of macro MAX.

Possible patch:

+ #ifndef MIN
  #define MIN(x,y) (((x) < (y)) ? (x) : (y))
+ #endif

+ #ifndef MAX
  #define MAX(x,y) (((x) > (y)) ? (x) : (y)) 
+ #endif

Please create a new release to help packaging in distros

Hello

I'm trying to create a Debian package for Perl6. This packaging is currently blocked by a test failure. The root cause of this failure is fixed in libtommath by commit 6907f6c (merged).

To provide a proper Perl6 package, this library must be provided by libtommath Debian package which is at version 0.42.0 (4 years old).

I'd like to create a new version of libtommath package so that the above fix is available for Debian users (and Perl6 package).

To make this work much easier, could you create a new release of libtommath ?

All the best

bn_mp_read_radix.c bug with radix 36

Comment and code says:
/* 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]
*/

This is wrong. It has to be radix <= 36... so the correct code would be

ch = (char) ((radix <= 36) ? toupper (*str) : *str);

instead

ch = (char) ((radix < 36) ? toupper (*str) : *str);

Best,
Sascha

Inconsistent right shift (`mp_div_2d`) results near 64-bit integer boundary

I have no idea why this is happening, nor does @sjaeckel, but I should make an issue at some point, right?

I'm currently trying to integrate LibTomMath, specifically version v0.42.0, into PHP to provide bigint support. However, it's producing incorrect results for right shifts (mp_div_2d) near the 64-bit integer boundary.

The expected output of a portion of PHP's right-shift test script for bigints looks like this:

--- testing: -9223372036854775807 >> 0 ---
int(-9223372036854775807)
--- testing: -9223372036854775807 >> 1 ---
int(-4611686018427387904)
--- testing: -9223372036854775807 >> 7 ---
int(-72057594037927936)
--- testing: -9223372036854775807 >> 9 ---
int(-18014398509481984)
--- testing: -9223372036854775807 >> 65 ---
int(-1)
--- testing: -9223372036854775809 >> 0 ---
int(-9223372036854775809)
--- testing: -9223372036854775809 >> 1 ---
int(-4611686018427387905)
--- testing: -9223372036854775809 >> 7 ---
int(-72057594037927937)
--- testing: -9223372036854775809 >> 9 ---
int(-18014398509481985)
--- testing: -9223372036854775809 >> 65 ---
int(-1)

This is what GMP (GNU Multiple Precision) produces for right shifts, and is also what Python produces. (@sjaeckel likes Wolfram|Alpha for some reason, which produces different results, but LibTomMath isn't consistent with Wolfram|Alpha either actually, they're consistent for the 32-bit results)~~ so that's not an excuse ;)~~

However, a generated single-file version of LibTomMath compiled as part of PHP, on my machine (OS X Yosemite on 2013 13" MacBook Air base configuration), produces different output from expected:

--- testing: -9223372036854775807 >> 0 ---
int(-9223372036854775807)
--- testing: -9223372036854775807 >> 1 ---
int(-4611686018427387904)
--- testing: -9223372036854775807 >> 7 ---
int(-72057594037927936)
--- testing: -9223372036854775807 >> 9 ---
int(-18014398509481984)
--- testing: -9223372036854775807 >> 65 ---
int(-1)
--- testing: -9223372036854775809 >> 0 ---
int(-9223372036854775809)
--- testing: -9223372036854775809 >> 1 ---
int(-4611686018427387904)
--- testing: -9223372036854775809 >> 7 ---
int(-72057594037927936)
--- testing: -9223372036854775809 >> 9 ---
int(-18014398509481984)
--- testing: -9223372036854775809 >> 65 ---
int(0)

Note the last 5 results are odd in the actual output, yet they're even in the expected output.

The clang -v output:
Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin14.0.0
Thread model: posix

It gets stranger, however, in that if compiled targeting 32-bit (clang -m32), we get a different set of results!

--- testing: -9223372036854775807 >> 0 ---
int(-9223372036854775807)
--- testing: -9223372036854775807 >> 1 ---
int(-4611686018427387903)
--- testing: -9223372036854775807 >> 7 ---
int(-72057594037927935)
--- testing: -9223372036854775807 >> 9 ---
int(-18014398509481983)
--- testing: -9223372036854775807 >> 65 ---
int(0)
--- testing: -9223372036854775809 >> 0 ---
int(-9223372036854775809)
--- testing: -9223372036854775809 >> 1 ---
int(-4611686018427387904)
--- testing: -9223372036854775809 >> 7 ---
int(-72057594037927936)
--- testing: -9223372036854775809 >> 9 ---
int(-18014398509481984)
--- testing: -9223372036854775809 >> 65 ---
int(0)

This set of results doesn't match either the expected output, nor the output on 64-bit.

The clang -m32 -v output:
Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn)
Target: i386-apple-darwin14.0.0
Thread model: posix

As you can see, for right shifts, LibTomMath is not only producing incorrect results, but it is not even producing the same results consistently across platforms, which is pretty concerning.

One thing to note: the result for -9223372036854775809 >> 65 being 0 and not -1 are arguably not a bug and can be forgiven, if LibTomMath policy is not to do sign extension. However, the other results are most definitely wrong.

The incorrect range in fast_mp_montgomery_reduce

  /* 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) DIGIT_BIT);
    }

I think, in this code should be used

    for (; ix < ((n->used * 2) + 1); ix++) {
  1. The result from last cycle not used
  2. In last cycle " *_W++ += " works with uninitialized element from " W "

In general, this part of code can be reduced / simplified

mp_exptmod_fast

/*LINE 147*/
  if (redmode == 0) {
#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
     /* now we need R mod m */
     if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) {
       goto LBL_RES;
     }
#else 
     err = MP_VAL;
     goto LBL_RES;
#endif

     /* PROBLEM: unreachable code if BN_MP_MONTGOMERY_CALC_NORMALIZATION_C not defined */

     /* now set M[1] to G * R mod m */
     if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) {
       goto LBL_RES;
     }
  }

Jacobi symbol incomplete

The the algorithm to compute the Jacobi is incomplete: the domain of the numerator of the Jacobi symbol is the whole Z. Negative numerators can be computed with the help of quadratic reciprocity, that is: (n/m) = (-1/n)(n/m). The value of (-1/n) comes from the Legendre symbol (1) and is (-1)^((n-1)/2). The lowest two bits of n are enough to compute this factor but working with the whole lowest limb might be more legible.

A rough sketch using the whole lowest limb:

 /* at the end */
 tmp = p->dp[0] - 1;
 tmp >>= 1;
/* change sign if "tmp" is odd */
 tmp = (tmp & 1) ? 1 : -1;
 /* if "a" is unity "tmp" is already the correct result */
 /* use "tmp" to define the sign of the result before returning */

(1) from the congruence a^((p-1)/2) = (a/p) mod p
see for example: Henri Cohen "A Course in Computational Algebraic Number Theory" of which you might find a copy on the internet.

typedefs for long64 and ulong64 in tommath.h

In tommath.h we have

/* this is to make porting into LibTomCrypt easier :-) */
#ifndef CRYPT
   typedef unsigned long long   ulong64;
   typedef signed long long     long64;
#endif

plus 1 more occurrence of a similar block

I think that this is kind of a legacy stuff that can be removed, or not?

Buffer overflow in fast_mp_montgomery_reduce

fast_mp_montgomery_reduce contains the next code:

  /* 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++;
    }

I not found the any check/protection for case " x->used > MP_WARRAY "

Please review this code.

Request: Two's complement math functions

These are useful since modern CPUs use two's complement integers, so they could be used as drop-in arbitrary-precision replacements for native integer operations. Python's bitwise operators behave like this on bignums.

In particular, the useful functions:

  • Ones' complement - trivial to implement, this is just (-n - 1), has the same result as bitwise NOT on two's complement system
  • Arithmetic right shift with sign extension - also trivial to implement: if op1 is negative, get its one's complement, do your usual logical right shift of that (LibTomMath's right shifts are logical right shifts), then get the one's complement of the result of that shift.
  • Two's complement OR, XOR, AND - trickier to implement. If both inputs are positive, do your usual <bitwise op>. If one or both inputs is negative, you must convert the negative ones to their two's complement representation (if both are negative, they must be two's complement representations for the same power of two/width in bits). Then, you must do <bitwise op> on the two values. Then, do a <bitwise op> on the fake sign bits (1 is negative, 0 is non-negative), and if it results in 1, get the two's complement of the result of the earlier bitwise op.

If you want an idea of implementation:

For test cases:

This is the successor issue to the previous one about just right shifts: #30

Also, before this is implemented, and even if this isn't implemented, we should probably note explicitly that we don't do two's complement operations for right shifts, AND, OR and XOR, to avoid user confusion.

:)

Not supported __int128 MSVC 2015 x64

Hi,

i want to compile libtommath with my MSVC 2015 x64 compiler and this error message comes up:

"libtommath\tommath.h(67): error C4235: nonstandard extension used: '__int128' keyword not supported on this architecture"

Do you know any workaround/fix for that problem? Thank you very much!

Regards,
atvise

mp_invmod(a,b,c) fails for a=1, b=1

And it seems to be due to the fact that optimised fast_mp_invmod is not able to handle this case.

A possible fix for bn_mp_invmod.c might look like this:

-  if (mp_isodd (b) == MP_YES) {
+  if ((mp_isodd (b) == MP_YES) && (mp_cmp_d (b, 1) != MP_EQ)) {
     return fast_mp_invmod (a, b, c);
   }

Originally reported by @pjacklam as a bug in Math::BigInt::LTM (perl bindings for libtommath).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.