diff options
Diffstat (limited to 'libtommath')
191 files changed, 31595 insertions, 0 deletions
diff --git a/libtommath/LICENSE b/libtommath/LICENSE new file mode 100644 index 0000000..5baa792 --- /dev/null +++ b/libtommath/LICENSE @@ -0,0 +1,4 @@ +LibTomMath is hereby released into the Public Domain. + +-- Tom St Denis + diff --git a/libtommath/Makefile.in b/libtommath/Makefile.in new file mode 100644 index 0000000..21dda19 --- /dev/null +++ b/libtommath/Makefile.in @@ -0,0 +1,186 @@ +#Makefile for GCC +# +#Tom St Denis + +#version of library +VERSION=0.40 + +VPATH=@srcdir@ +srcdir=@srcdir@ + +# Dropbear takes flags from the toplevel makefile +CFLAGS += -I$(srcdir) + +#CFLAGS += -I./ -Wall -W -Wshadow -Wsign-compare + +ifndef IGNORE_SPEED + +#for speed +#CFLAGS += -O3 -funroll-all-loops + +#for size +#CFLAGS += -Os + +#x86 optimizations [should be valid for any GCC install though] +#CFLAGS += -fomit-frame-pointer + +#debug +#CFLAGS += -g3 + +#install as this user +ifndef INSTALL_GROUP + GROUP=wheel +else + GROUP=$(INSTALL_GROUP) +endif + +ifndef INSTALL_USER + USER=root +else + USER=$(INSTALL_USER) +endif + +#default files to install +ifndef LIBNAME + LIBNAME=libtommath.a +endif + +default: ${LIBNAME} + +HEADERS=tommath.h tommath_class.h tommath_superclass.h + +#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= +LIBPATH=/usr/lib +INCPATH=/usr/include +DATAPATH=/usr/share/doc/libtommath/pdf + +OBJECTS=bncore.o bn_mp_init.o bn_mp_clear.o bn_mp_exch.o bn_mp_grow.o bn_mp_shrink.o \ +bn_mp_clamp.o bn_mp_zero.o bn_mp_set.o bn_mp_set_int.o bn_mp_init_size.o bn_mp_copy.o \ +bn_mp_init_copy.o bn_mp_abs.o bn_mp_neg.o bn_mp_cmp_mag.o bn_mp_cmp.o bn_mp_cmp_d.o \ +bn_mp_rshd.o bn_mp_lshd.o bn_mp_mod_2d.o bn_mp_div_2d.o bn_mp_mul_2d.o bn_mp_div_2.o \ +bn_mp_mul_2.o bn_s_mp_add.o bn_s_mp_sub.o bn_fast_s_mp_mul_digs.o bn_s_mp_mul_digs.o \ +bn_fast_s_mp_mul_high_digs.o bn_s_mp_mul_high_digs.o bn_fast_s_mp_sqr.o bn_s_mp_sqr.o \ +bn_mp_add.o bn_mp_sub.o bn_mp_karatsuba_mul.o bn_mp_mul.o bn_mp_karatsuba_sqr.o \ +bn_mp_sqr.o bn_mp_div.o bn_mp_mod.o bn_mp_add_d.o bn_mp_sub_d.o bn_mp_mul_d.o \ +bn_mp_div_d.o bn_mp_mod_d.o bn_mp_expt_d.o bn_mp_addmod.o bn_mp_submod.o \ +bn_mp_mulmod.o bn_mp_sqrmod.o bn_mp_gcd.o bn_mp_lcm.o bn_fast_mp_invmod.o bn_mp_invmod.o \ +bn_mp_reduce.o bn_mp_montgomery_setup.o bn_fast_mp_montgomery_reduce.o bn_mp_montgomery_reduce.o \ +bn_mp_exptmod_fast.o bn_mp_exptmod.o bn_mp_2expt.o bn_mp_n_root.o bn_mp_jacobi.o bn_reverse.o \ +bn_mp_count_bits.o bn_mp_read_unsigned_bin.o bn_mp_read_signed_bin.o bn_mp_to_unsigned_bin.o \ +bn_mp_to_signed_bin.o bn_mp_unsigned_bin_size.o bn_mp_signed_bin_size.o \ +bn_mp_xor.o bn_mp_and.o bn_mp_or.o bn_mp_rand.o bn_mp_montgomery_calc_normalization.o \ +bn_mp_prime_is_divisible.o bn_prime_tab.o bn_mp_prime_fermat.o bn_mp_prime_miller_rabin.o \ +bn_mp_prime_is_prime.o bn_mp_prime_next_prime.o bn_mp_dr_reduce.o \ +bn_mp_dr_is_modulus.o bn_mp_dr_setup.o bn_mp_reduce_setup.o \ +bn_mp_toom_mul.o bn_mp_toom_sqr.o bn_mp_div_3.o bn_s_mp_exptmod.o \ +bn_mp_reduce_2k.o bn_mp_reduce_is_2k.o bn_mp_reduce_2k_setup.o \ +bn_mp_reduce_2k_l.o bn_mp_reduce_is_2k_l.o bn_mp_reduce_2k_setup_l.o \ +bn_mp_radix_smap.o bn_mp_read_radix.o bn_mp_toradix.o bn_mp_radix_size.o \ +bn_mp_fread.o bn_mp_fwrite.o bn_mp_cnt_lsb.o bn_error.o \ +bn_mp_init_multi.o bn_mp_clear_multi.o bn_mp_exteuclid.o bn_mp_toradix_n.o \ +bn_mp_prime_random_ex.o bn_mp_get_int.o bn_mp_sqrt.o bn_mp_is_square.o bn_mp_init_set.o \ +bn_mp_init_set_int.o bn_mp_invmod_slow.o bn_mp_prime_rabin_miller_trials.o \ +bn_mp_to_signed_bin_n.o bn_mp_to_unsigned_bin_n.o + +$(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 + ./ltmtest + rm -f *.a *.o ltmtest + make CFLAGS="$(CFLAGS) -fbranch-probabilities" + +#make a single object profiled library +profiled_single: + perl gen.pl + $(CC) $(CFLAGS) -fprofile-arcs -DTESTING -c mpi.c -o mpi.o + $(CC) $(CFLAGS) -DTESTING -DTIMER demo/timing.c mpi.o -o ltmtest + ./ltmtest + rm -f *.o ltmtest + $(CC) $(CFLAGS) -fbranch-probabilities -DTESTING -c mpi.c -o mpi.o + $(AR) $(ARFLAGS) $(LIBNAME) mpi.o + $(RANLIB) $(LIBNAME) + +install: $(LIBNAME) + install -d -g $(GROUP) -o $(USER) $(DESTDIR)$(LIBPATH) + install -d -g $(GROUP) -o $(USER) $(DESTDIR)$(INCPATH) + install -g $(GROUP) -o $(USER) $(LIBNAME) $(DESTDIR)$(LIBPATH) + install -g $(GROUP) -o $(USER) $(HEADERS) $(DESTDIR)$(INCPATH) + +test: $(LIBNAME) demo/demo.o + $(CC) $(CFLAGS) demo/demo.o $(LIBNAME) -o test + +mtest: test + cd mtest ; $(CC) $(CFLAGS) mtest.c -o mtest + +timing: $(LIBNAME) + $(CC) $(CFLAGS) -DTIMER demo/timing.c $(LIBNAME) -o ltmtest + +# makes the LTM book DVI file, requires tetex, perl and makeindex [part of tetex I think] +docdvi: tommath.src + cd pics ; MAKE=${MAKE} ${MAKE} + echo "hello" > tommath.ind + perl booker.pl + latex tommath > /dev/null + latex tommath > /dev/null + makeindex tommath + latex tommath > /dev/null + +# poster, makes the single page PDF poster +poster: poster.tex + pdflatex poster + rm -f poster.aux poster.log + +# makes the LTM book PDF file, requires tetex, cleans up the LaTeX temp files +docs: docdvi + dvipdf tommath + rm -f tommath.log tommath.aux tommath.dvi tommath.idx tommath.toc tommath.lof tommath.ind tommath.ilg + cd pics ; MAKE=${MAKE} ${MAKE} clean + +#LTM user manual +mandvi: bn.tex + echo "hello" > bn.ind + latex bn > /dev/null + latex bn > /dev/null + makeindex bn + latex bn > /dev/null + +#LTM user manual [pdf] +manual: mandvi + pdflatex bn >/dev/null + rm -f bn.aux bn.dvi bn.log bn.idx bn.lof bn.out bn.toc + +pretty: + perl pretty.build + +clean: + rm -f *.bat *.pdf *.o *.a *.obj *.lib *.exe *.dll etclib/*.o demo/demo.o test ltmtest mpitest mtest/mtest mtest/mtest.exe \ + *.idx *.toc *.log *.aux *.dvi *.lof *.ind *.ilg *.ps *.log *.s mpi.c *.da *.dyn *.dpi tommath.tex `find . -type f | grep [~] | xargs` *.lo *.la + rm -rf .libs + cd etc ; MAKE=${MAKE} ${MAKE} clean + cd pics ; MAKE=${MAKE} ${MAKE} clean + +#zipup the project (take that!) +no_oops: clean + cd .. ; cvs commit + echo Scanning for scratch/dirty files + find . -type f | grep -v CVS | xargs -n 1 bash mess.sh + +zipup: clean manual poster docs + perl gen.pl ; mv mpi.c pre_gen/ ; \ + cd .. ; rm -rf ltm* libtommath-$(VERSION) ; mkdir libtommath-$(VERSION) ; \ + cp -R ./libtommath/* ./libtommath-$(VERSION)/ ; \ + tar -c libtommath-$(VERSION)/* | bzip2 -9vvc > ltm-$(VERSION).tar.bz2 ; \ + zip -9 -r ltm-$(VERSION).zip libtommath-$(VERSION)/* ; \ + mv -f ltm* ~ ; rm -rf libtommath-$(VERSION) diff --git a/libtommath/bn.tex b/libtommath/bn.tex new file mode 100644 index 0000000..38ece04 --- /dev/null +++ b/libtommath/bn.tex @@ -0,0 +1,1835 @@ +\documentclass[synpaper]{book} +\usepackage{hyperref} +\usepackage{makeidx} +\usepackage{amssymb} +\usepackage{color} +\usepackage{alltt} +\usepackage{graphicx} +\usepackage{layout} +\def\union{\cup} +\def\intersect{\cap} +\def\getsrandom{\stackrel{\rm R}{\gets}} +\def\cross{\times} +\def\cat{\hspace{0.5em} \| \hspace{0.5em}} +\def\catn{$\|$} +\def\divides{\hspace{0.3em} | \hspace{0.3em}} +\def\nequiv{\not\equiv} +\def\approx{\raisebox{0.2ex}{\mbox{\small $\sim$}}} +\def\lcm{{\rm lcm}} +\def\gcd{{\rm gcd}} +\def\log{{\rm log}} +\def\ord{{\rm ord}} +\def\abs{{\mathit abs}} +\def\rep{{\mathit rep}} +\def\mod{{\mathit\ mod\ }} +\renewcommand{\pmod}[1]{\ ({\rm mod\ }{#1})} +\newcommand{\floor}[1]{\left\lfloor{#1}\right\rfloor} +\newcommand{\ceil}[1]{\left\lceil{#1}\right\rceil} +\def\Or{{\rm\ or\ }} +\def\And{{\rm\ and\ }} +\def\iff{\hspace{1em}\Longleftrightarrow\hspace{1em}} +\def\implies{\Rightarrow} +\def\undefined{{\rm ``undefined"}} +\def\Proof{\vspace{1ex}\noindent {\bf Proof:}\hspace{1em}} +\let\oldphi\phi +\def\phi{\varphi} +\def\Pr{{\rm Pr}} +\newcommand{\str}[1]{{\mathbf{#1}}} +\def\F{{\mathbb F}} +\def\N{{\mathbb N}} +\def\Z{{\mathbb Z}} +\def\R{{\mathbb R}} +\def\C{{\mathbb C}} +\def\Q{{\mathbb Q}} +\definecolor{DGray}{gray}{0.5} +\newcommand{\emailaddr}[1]{\mbox{$<${#1}$>$}} +\def\twiddle{\raisebox{0.3ex}{\mbox{\tiny $\sim$}}} +\def\gap{\vspace{0.5ex}} +\makeindex +\begin{document} +\frontmatter +\pagestyle{empty} +\title{LibTomMath User Manual \\ v0.40} +\author{Tom St Denis \\ tomstdenis@gmail.com} +\maketitle +This text, the library and the accompanying textbook are all hereby placed in the public domain. This book has been +formatted for B5 [176x250] paper using the \LaTeX{} {\em book} macro package. + +\vspace{10cm} + +\begin{flushright}Open Source. Open Academia. Open Minds. + +\mbox{ } + +Tom St Denis, + +Ontario, Canada +\end{flushright} + +\tableofcontents +\listoffigures +\mainmatter +\pagestyle{headings} +\chapter{Introduction} +\section{What is LibTomMath?} +LibTomMath is a library of source code which provides a series of efficient and carefully written functions for manipulating +large integer numbers. It was written in portable ISO C source code so that it will build on any platform with a conforming +C compiler. + +In a nutshell the library was written from scratch with verbose comments to help instruct computer science students how +to implement ``bignum'' math. However, the resulting code has proven to be very useful. It has been used by numerous +universities, commercial and open source software developers. It has been used on a variety of platforms ranging from +Linux and Windows based x86 to ARM based Gameboys and PPC based MacOS machines. + +\section{License} +As of the v0.25 the library source code has been placed in the public domain with every new release. As of the v0.28 +release the textbook ``Implementing Multiple Precision Arithmetic'' has been placed in the public domain with every new +release as well. This textbook is meant to compliment the project by providing a more solid walkthrough of the development +algorithms used in the library. + +Since both\footnote{Note that the MPI files under mtest/ are copyrighted by Michael Fromberger. They are not required to use LibTomMath.} are in the +public domain everyone is entitled to do with them as they see fit. + +\section{Building LibTomMath} + +LibTomMath is meant to be very ``GCC friendly'' as it comes with a makefile well suited for GCC. However, the library will +also build in MSVC, Borland C out of the box. For any other ISO C compiler a makefile will have to be made by the end +developer. + +\subsection{Static Libraries} +To build as a static library for GCC issue the following +\begin{alltt} +make +\end{alltt} + +command. This will build the library and archive the object files in ``libtommath.a''. Now you link against +that and include ``tommath.h'' within your programs. Alternatively to build with MSVC issue the following +\begin{alltt} +nmake -f makefile.msvc +\end{alltt} + +This will build the library and archive the object files in ``tommath.lib''. This has been tested with MSVC +version 6.00 with service pack 5. + +\subsection{Shared Libraries} +To build as a shared library for GCC issue the following +\begin{alltt} +make -f makefile.shared +\end{alltt} +This requires the ``libtool'' package (common on most Linux/BSD systems). It will build LibTomMath as both shared +and static then install (by default) into /usr/lib as well as install the header files in /usr/include. The shared +library (resource) will be called ``libtommath.la'' while the static library called ``libtommath.a''. Generally +you use libtool to link your application against the shared object. + +There is limited support for making a ``DLL'' in windows via the ``makefile.cygwin\_dll'' makefile. It requires +Cygwin to work with since it requires the auto-export/import functionality. The resulting DLL and import library +``libtommath.dll.a'' can be used to link LibTomMath dynamically to any Windows program using Cygwin. + +\subsection{Testing} +To build the library and the test harness type + +\begin{alltt} +make test +\end{alltt} + +This will build the library, ``test'' and ``mtest/mtest''. The ``test'' program will accept test vectors and verify the +results. ``mtest/mtest'' will generate test vectors using the MPI library by Michael Fromberger\footnote{A copy of MPI +is included in the package}. Simply pipe mtest into test using + +\begin{alltt} +mtest/mtest | test +\end{alltt} + +If you do not have a ``/dev/urandom'' style RNG source you will have to write your own PRNG and simply pipe that into +mtest. For example, if your PRNG program is called ``myprng'' simply invoke + +\begin{alltt} +myprng | mtest/mtest | test +\end{alltt} + +This will output a row of numbers that are increasing. Each column is a different test (such as addition, multiplication, etc) +that is being performed. The numbers represent how many times the test was invoked. If an error is detected the program +will exit with a dump of the relevent numbers it was working with. + +\section{Build Configuration} +LibTomMath can configured at build time in three phases we shall call ``depends'', ``tweaks'' and ``trims''. +Each phase changes how the library is built and they are applied one after another respectively. + +To make the system more powerful you can tweak the build process. Classes are defined in the file +``tommath\_superclass.h''. By default, the symbol ``LTM\_ALL'' shall be defined which simply +instructs the system to build all of the functions. This is how LibTomMath used to be packaged. This will give you +access to every function LibTomMath offers. + +However, there are cases where such a build is not optional. For instance, you want to perform RSA operations. You +don't need the vast majority of the library to perform these operations. Aside from LTM\_ALL there is +another pre--defined class ``SC\_RSA\_1'' which works in conjunction with the RSA from LibTomCrypt. Additional +classes can be defined base on the need of the user. + +\subsection{Build Depends} +In the file tommath\_class.h you will see a large list of C ``defines'' followed by a series of ``ifdefs'' +which further define symbols. All of the symbols (technically they're macros $\ldots$) represent a given C source +file. For instance, BN\_MP\_ADD\_C represents the file ``bn\_mp\_add.c''. When a define has been enabled the +function in the respective file will be compiled and linked into the library. Accordingly when the define +is absent the file will not be compiled and not contribute any size to the library. + +You will also note that the header tommath\_class.h is actually recursively included (it includes itself twice). +This is to help resolve as many dependencies as possible. In the last pass the symbol LTM\_LAST will be defined. +This is useful for ``trims''. + +\subsection{Build Tweaks} +A tweak is an algorithm ``alternative''. For example, to provide tradeoffs (usually between size and space). +They can be enabled at any pass of the configuration phase. + +\begin{small} +\begin{center} +\begin{tabular}{|l|l|} +\hline \textbf{Define} & \textbf{Purpose} \\ +\hline BN\_MP\_DIV\_SMALL & Enables a slower, smaller and equally \\ + & functional mp\_div() function \\ +\hline +\end{tabular} +\end{center} +\end{small} + +\subsection{Build Trims} +A trim is a manner of removing functionality from a function that is not required. For instance, to perform +RSA cryptography you only require exponentiation with odd moduli so even moduli support can be safely removed. +Build trims are meant to be defined on the last pass of the configuration which means they are to be defined +only if LTM\_LAST has been defined. + +\subsubsection{Moduli Related} +\begin{small} +\begin{center} +\begin{tabular}{|l|l|} +\hline \textbf{Restriction} & \textbf{Undefine} \\ +\hline Exponentiation with odd moduli only & BN\_S\_MP\_EXPTMOD\_C \\ + & BN\_MP\_REDUCE\_C \\ + & BN\_MP\_REDUCE\_SETUP\_C \\ + & BN\_S\_MP\_MUL\_HIGH\_DIGS\_C \\ + & BN\_FAST\_S\_MP\_MUL\_HIGH\_DIGS\_C \\ +\hline Exponentiation with random odd moduli & (The above plus the following) \\ + & BN\_MP\_REDUCE\_2K\_C \\ + & BN\_MP\_REDUCE\_2K\_SETUP\_C \\ + & BN\_MP\_REDUCE\_IS\_2K\_C \\ + & BN\_MP\_DR\_IS\_MODULUS\_C \\ + & BN\_MP\_DR\_REDUCE\_C \\ + & BN\_MP\_DR\_SETUP\_C \\ +\hline Modular inverse odd moduli only & BN\_MP\_INVMOD\_SLOW\_C \\ +\hline Modular inverse (both, smaller/slower) & BN\_FAST\_MP\_INVMOD\_C \\ +\hline +\end{tabular} +\end{center} +\end{small} + +\subsubsection{Operand Size Related} +\begin{small} +\begin{center} +\begin{tabular}{|l|l|} +\hline \textbf{Restriction} & \textbf{Undefine} \\ +\hline Moduli $\le 2560$ bits & BN\_MP\_MONTGOMERY\_REDUCE\_C \\ + & BN\_S\_MP\_MUL\_DIGS\_C \\ + & BN\_S\_MP\_MUL\_HIGH\_DIGS\_C \\ + & BN\_S\_MP\_SQR\_C \\ +\hline Polynomial Schmolynomial & BN\_MP\_KARATSUBA\_MUL\_C \\ + & BN\_MP\_KARATSUBA\_SQR\_C \\ + & BN\_MP\_TOOM\_MUL\_C \\ + & BN\_MP\_TOOM\_SQR\_C \\ + +\hline +\end{tabular} +\end{center} +\end{small} + + +\section{Purpose of LibTomMath} +Unlike GNU MP (GMP) Library, LIP, OpenSSL or various other commercial kits (Miracl), LibTomMath was not written with +bleeding edge performance in mind. First and foremost LibTomMath was written to be entirely open. Not only is the +source code public domain (unlike various other GPL/etc licensed code), not only is the code freely downloadable but the +source code is also accessible for computer science students attempting to learn ``BigNum'' or multiple precision +arithmetic techniques. + +LibTomMath was written to be an instructive collection of source code. This is why there are many comments, only one +function per source file and often I use a ``middle-road'' approach where I don't cut corners for an extra 2\% speed +increase. + +Source code alone cannot really teach how the algorithms work which is why I also wrote a textbook that accompanies +the library (beat that!). + +So you may be thinking ``should I use LibTomMath?'' and the answer is a definite maybe. Let me tabulate what I think +are the pros and cons of LibTomMath by comparing it to the math routines from GnuPG\footnote{GnuPG v1.2.3 versus LibTomMath v0.28}. + +\newpage\begin{figure}[here] +\begin{small} +\begin{center} +\begin{tabular}{|l|c|c|l|} +\hline \textbf{Criteria} & \textbf{Pro} & \textbf{Con} & \textbf{Notes} \\ +\hline Few lines of code per file & X & & GnuPG $ = 300.9$, LibTomMath $ = 71.97$ \\ +\hline Commented function prototypes & X && GnuPG function names are cryptic. \\ +\hline Speed && X & LibTomMath is slower. \\ +\hline Totally free & X & & GPL has unfavourable restrictions.\\ +\hline Large function base & X & & GnuPG is barebones. \\ +\hline Five modular reduction algorithms & X & & Faster modular exponentiation for a variety of moduli. \\ +\hline Portable & X & & GnuPG requires configuration to build. \\ +\hline +\end{tabular} +\end{center} +\end{small} +\caption{LibTomMath Valuation} +\end{figure} + +It may seem odd to compare LibTomMath to GnuPG since the math in GnuPG is only a small portion of the entire application. +However, LibTomMath was written with cryptography in mind. It provides essentially all of the functions a cryptosystem +would require when working with large integers. + +So it may feel tempting to just rip the math code out of GnuPG (or GnuMP where it was taken from originally) in your +own application but I think there are reasons not to. While LibTomMath is slower than libraries such as GnuMP it is +not normally significantly slower. On x86 machines the difference is normally a factor of two when performing modular +exponentiations. It depends largely on the processor, compiler and the moduli being used. + +Essentially the only time you wouldn't use LibTomMath is when blazing speed is the primary concern. However, +on the other side of the coin LibTomMath offers you a totally free (public domain) well structured math library +that is very flexible, complete and performs well in resource contrained environments. Fast RSA for example can +be performed with as little as 8KB of ram for data (again depending on build options). + +\chapter{Getting Started with LibTomMath} +\section{Building Programs} +In order to use LibTomMath you must include ``tommath.h'' and link against the appropriate library file (typically +libtommath.a). There is no library initialization required and the entire library is thread safe. + +\section{Return Codes} +There are three possible return codes a function may return. + +\index{MP\_OKAY}\index{MP\_YES}\index{MP\_NO}\index{MP\_VAL}\index{MP\_MEM} +\begin{figure}[here!] +\begin{center} +\begin{small} +\begin{tabular}{|l|l|} +\hline \textbf{Code} & \textbf{Meaning} \\ +\hline MP\_OKAY & The function succeeded. \\ +\hline MP\_VAL & The function input was invalid. \\ +\hline MP\_MEM & Heap memory exhausted. \\ +\hline &\\ +\hline MP\_YES & Response is yes. \\ +\hline MP\_NO & Response is no. \\ +\hline +\end{tabular} +\end{small} +\end{center} +\caption{Return Codes} +\end{figure} + +The last two codes listed are not actually ``return'ed'' by a function. They are placed in an integer (the caller must +provide the address of an integer it can store to) which the caller can access. To convert one of the three return codes +to a string use the following function. + +\index{mp\_error\_to\_string} +\begin{alltt} +char *mp_error_to_string(int code); +\end{alltt} + +This will return a pointer to a string which describes the given error code. It will not work for the return codes +MP\_YES and MP\_NO. + +\section{Data Types} +The basic ``multiple precision integer'' type is known as the ``mp\_int'' within LibTomMath. This data type is used to +organize all of the data required to manipulate the integer it represents. Within LibTomMath it has been prototyped +as the following. + +\index{mp\_int} +\begin{alltt} +typedef struct \{ + int used, alloc, sign; + mp_digit *dp; +\} mp_int; +\end{alltt} + +Where ``mp\_digit'' is a data type that represents individual digits of the integer. By default, an mp\_digit is the +ISO C ``unsigned long'' data type and each digit is $28-$bits long. The mp\_digit type can be configured to suit other +platforms by defining the appropriate macros. + +All LTM functions that use the mp\_int type will expect a pointer to mp\_int structure. You must allocate memory to +hold the structure itself by yourself (whether off stack or heap it doesn't matter). The very first thing that must be +done to use an mp\_int is that it must be initialized. + +\section{Function Organization} + +The arithmetic functions of the library are all organized to have the same style prototype. That is source operands +are passed on the left and the destination is on the right. For instance, + +\begin{alltt} +mp_add(&a, &b, &c); /* c = a + b */ +mp_mul(&a, &a, &c); /* c = a * a */ +mp_div(&a, &b, &c, &d); /* c = [a/b], d = a mod b */ +\end{alltt} + +Another feature of the way the functions have been implemented is that source operands can be destination operands as well. +For instance, + +\begin{alltt} +mp_add(&a, &b, &b); /* b = a + b */ +mp_div(&a, &b, &a, &c); /* a = [a/b], c = a mod b */ +\end{alltt} + +This allows operands to be re-used which can make programming simpler. + +\section{Initialization} +\subsection{Single Initialization} +A single mp\_int can be initialized with the ``mp\_init'' function. + +\index{mp\_init} +\begin{alltt} +int mp_init (mp_int * a); +\end{alltt} + +This function expects a pointer to an mp\_int structure and will initialize the members of the structure so the mp\_int +represents the default integer which is zero. If the functions returns MP\_OKAY then the mp\_int is ready to be used +by the other LibTomMath functions. + +\begin{small} \begin{alltt} +int main(void) +\{ + mp_int number; + int result; + + if ((result = mp_init(&number)) != MP_OKAY) \{ + printf("Error initializing the number. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* use the number */ + + return EXIT_SUCCESS; +\} +\end{alltt} \end{small} + +\subsection{Single Free} +When you are finished with an mp\_int it is ideal to return the heap it used back to the system. The following function +provides this functionality. + +\index{mp\_clear} +\begin{alltt} +void mp_clear (mp_int * a); +\end{alltt} + +The function expects a pointer to a previously initialized mp\_int structure and frees the heap it uses. It sets the +pointer\footnote{The ``dp'' member.} within the mp\_int to \textbf{NULL} which is used to prevent double free situations. +Is is legal to call mp\_clear() twice on the same mp\_int in a row. + +\begin{small} \begin{alltt} +int main(void) +\{ + mp_int number; + int result; + + if ((result = mp_init(&number)) != MP_OKAY) \{ + printf("Error initializing the number. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* use the number */ + + /* We're done with it. */ + mp_clear(&number); + + return EXIT_SUCCESS; +\} +\end{alltt} \end{small} + +\subsection{Multiple Initializations} +Certain algorithms require more than one large integer. In these instances it is ideal to initialize all of the mp\_int +variables in an ``all or nothing'' fashion. That is, they are either all initialized successfully or they are all +not initialized. + +The mp\_init\_multi() function provides this functionality. + +\index{mp\_init\_multi} \index{mp\_clear\_multi} +\begin{alltt} +int mp_init_multi(mp_int *mp, ...); +\end{alltt} + +It accepts a \textbf{NULL} terminated list of pointers to mp\_int structures. It will attempt to initialize them all +at once. If the function returns MP\_OKAY then all of the mp\_int variables are ready to use, otherwise none of them +are available for use. A complementary mp\_clear\_multi() function allows multiple mp\_int variables to be free'd +from the heap at the same time. + +\begin{small} \begin{alltt} +int main(void) +\{ + mp_int num1, num2, num3; + int result; + + if ((result = mp_init_multi(&num1, + &num2, + &num3, NULL)) != MP\_OKAY) \{ + printf("Error initializing the numbers. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* use the numbers */ + + /* We're done with them. */ + mp_clear_multi(&num1, &num2, &num3, NULL); + + return EXIT_SUCCESS; +\} +\end{alltt} \end{small} + +\subsection{Other Initializers} +To initialized and make a copy of an mp\_int the mp\_init\_copy() function has been provided. + +\index{mp\_init\_copy} +\begin{alltt} +int mp_init_copy (mp_int * a, mp_int * b); +\end{alltt} + +This function will initialize $a$ and make it a copy of $b$ if all goes well. + +\begin{small} \begin{alltt} +int main(void) +\{ + mp_int num1, num2; + int result; + + /* initialize and do work on num1 ... */ + + /* We want a copy of num1 in num2 now */ + if ((result = mp_init_copy(&num2, &num1)) != MP_OKAY) \{ + printf("Error initializing the copy. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* now num2 is ready and contains a copy of num1 */ + + /* We're done with them. */ + mp_clear_multi(&num1, &num2, NULL); + + return EXIT_SUCCESS; +\} +\end{alltt} \end{small} + +Another less common initializer is mp\_init\_size() which allows the user to initialize an mp\_int with a given +default number of digits. By default, all initializers allocate \textbf{MP\_PREC} digits. This function lets +you override this behaviour. + +\index{mp\_init\_size} +\begin{alltt} +int mp_init_size (mp_int * a, int size); +\end{alltt} + +The $size$ parameter must be greater than zero. If the function succeeds the mp\_int $a$ will be initialized +to have $size$ digits (which are all initially zero). + +\begin{small} \begin{alltt} +int main(void) +\{ + mp_int number; + int result; + + /* we need a 60-digit number */ + if ((result = mp_init_size(&number, 60)) != MP_OKAY) \{ + printf("Error initializing the number. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* use the number */ + + return EXIT_SUCCESS; +\} +\end{alltt} \end{small} + +\section{Maintenance Functions} + +\subsection{Reducing Memory Usage} +When an mp\_int is in a state where it won't be changed again\footnote{A Diffie-Hellman modulus for instance.} excess +digits can be removed to return memory to the heap with the mp\_shrink() function. + +\index{mp\_shrink} +\begin{alltt} +int mp_shrink (mp_int * a); +\end{alltt} + +This will remove excess digits of the mp\_int $a$. If the operation fails the mp\_int should be intact without the +excess digits being removed. Note that you can use a shrunk mp\_int in further computations, however, such operations +will require heap operations which can be slow. It is not ideal to shrink mp\_int variables that you will further +modify in the system (unless you are seriously low on memory). + +\begin{small} \begin{alltt} +int main(void) +\{ + mp_int number; + int result; + + if ((result = mp_init(&number)) != MP_OKAY) \{ + printf("Error initializing the number. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* use the number [e.g. pre-computation] */ + + /* We're done with it for now. */ + if ((result = mp_shrink(&number)) != MP_OKAY) \{ + printf("Error shrinking the number. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* use it .... */ + + + /* we're done with it. */ + mp_clear(&number); + + return EXIT_SUCCESS; +\} +\end{alltt} \end{small} + +\subsection{Adding additional digits} + +Within the mp\_int structure are two parameters which control the limitations of the array of digits that represent +the integer the mp\_int is meant to equal. The \textit{used} parameter dictates how many digits are significant, that is, +contribute to the value of the mp\_int. The \textit{alloc} parameter dictates how many digits are currently available in +the array. If you need to perform an operation that requires more digits you will have to mp\_grow() the mp\_int to +your desired size. + +\index{mp\_grow} +\begin{alltt} +int mp_grow (mp_int * a, int size); +\end{alltt} + +This will grow the array of digits of $a$ to $size$. If the \textit{alloc} parameter is already bigger than +$size$ the function will not do anything. + +\begin{small} \begin{alltt} +int main(void) +\{ + mp_int number; + int result; + + if ((result = mp_init(&number)) != MP_OKAY) \{ + printf("Error initializing the number. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* use the number */ + + /* We need to add 20 digits to the number */ + if ((result = mp_grow(&number, number.alloc + 20)) != MP_OKAY) \{ + printf("Error growing the number. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + + /* use the number */ + + /* we're done with it. */ + mp_clear(&number); + + return EXIT_SUCCESS; +\} +\end{alltt} \end{small} + +\chapter{Basic Operations} +\section{Small Constants} +Setting mp\_ints to small constants is a relatively common operation. To accomodate these instances there are two +small constant assignment functions. The first function is used to set a single digit constant while the second sets +an ISO C style ``unsigned long'' constant. The reason for both functions is efficiency. Setting a single digit is quick but the +domain of a digit can change (it's always at least $0 \ldots 127$). + +\subsection{Single Digit} + +Setting a single digit can be accomplished with the following function. + +\index{mp\_set} +\begin{alltt} +void mp_set (mp_int * a, mp_digit b); +\end{alltt} + +This will zero the contents of $a$ and make it represent an integer equal to the value of $b$. Note that this +function has a return type of \textbf{void}. It cannot cause an error so it is safe to assume the function +succeeded. + +\begin{small} \begin{alltt} +int main(void) +\{ + mp_int number; + int result; + + if ((result = mp_init(&number)) != MP_OKAY) \{ + printf("Error initializing the number. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* set the number to 5 */ + mp_set(&number, 5); + + /* we're done with it. */ + mp_clear(&number); + + return EXIT_SUCCESS; +\} +\end{alltt} \end{small} + +\subsection{Long Constants} + +To set a constant that is the size of an ISO C ``unsigned long'' and larger than a single digit the following function +can be used. + +\index{mp\_set\_int} +\begin{alltt} +int mp_set_int (mp_int * a, unsigned long b); +\end{alltt} + +This will assign the value of the 32-bit variable $b$ to the mp\_int $a$. Unlike mp\_set() this function will always +accept a 32-bit input regardless of the size of a single digit. However, since the value may span several digits +this function can fail if it runs out of heap memory. + +To get the ``unsigned long'' copy of an mp\_int the following function can be used. + +\index{mp\_get\_int} +\begin{alltt} +unsigned long mp_get_int (mp_int * a); +\end{alltt} + +This will return the 32 least significant bits of the mp\_int $a$. + +\begin{small} \begin{alltt} +int main(void) +\{ + mp_int number; + int result; + + if ((result = mp_init(&number)) != MP_OKAY) \{ + printf("Error initializing the number. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* set the number to 654321 (note this is bigger than 127) */ + if ((result = mp_set_int(&number, 654321)) != MP_OKAY) \{ + printf("Error setting the value of the number. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + printf("number == \%lu", mp_get_int(&number)); + + /* we're done with it. */ + mp_clear(&number); + + return EXIT_SUCCESS; +\} +\end{alltt} \end{small} + +This should output the following if the program succeeds. + +\begin{alltt} +number == 654321 +\end{alltt} + +\subsection{Initialize and Setting Constants} +To both initialize and set small constants the following two functions are available. +\index{mp\_init\_set} \index{mp\_init\_set\_int} +\begin{alltt} +int mp_init_set (mp_int * a, mp_digit b); +int mp_init_set_int (mp_int * a, unsigned long b); +\end{alltt} + +Both functions work like the previous counterparts except they first mp\_init $a$ before setting the values. + +\begin{alltt} +int main(void) +\{ + mp_int number1, number2; + int result; + + /* initialize and set a single digit */ + if ((result = mp_init_set(&number1, 100)) != MP_OKAY) \{ + printf("Error setting number1: \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* initialize and set a long */ + if ((result = mp_init_set_int(&number2, 1023)) != MP_OKAY) \{ + printf("Error setting number2: \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* display */ + printf("Number1, Number2 == \%lu, \%lu", + mp_get_int(&number1), mp_get_int(&number2)); + + /* clear */ + mp_clear_multi(&number1, &number2, NULL); + + return EXIT_SUCCESS; +\} +\end{alltt} + +If this program succeeds it shall output. +\begin{alltt} +Number1, Number2 == 100, 1023 +\end{alltt} + +\section{Comparisons} + +Comparisons in LibTomMath are always performed in a ``left to right'' fashion. There are three possible return codes +for any comparison. + +\index{MP\_GT} \index{MP\_EQ} \index{MP\_LT} +\begin{figure}[here] +\begin{center} +\begin{tabular}{|c|c|} +\hline \textbf{Result Code} & \textbf{Meaning} \\ +\hline MP\_GT & $a > b$ \\ +\hline MP\_EQ & $a = b$ \\ +\hline MP\_LT & $a < b$ \\ +\hline +\end{tabular} +\end{center} +\caption{Comparison Codes for $a, b$} +\label{fig:CMP} +\end{figure} + +In figure \ref{fig:CMP} two integers $a$ and $b$ are being compared. In this case $a$ is said to be ``to the left'' of +$b$. + +\subsection{Unsigned comparison} + +An unsigned comparison considers only the digits themselves and not the associated \textit{sign} flag of the +mp\_int structures. This is analogous to an absolute comparison. The function mp\_cmp\_mag() will compare two +mp\_int variables based on their digits only. + +\index{mp\_cmp\_mag} +\begin{alltt} +int mp_cmp_mag(mp_int * a, mp_int * b); +\end{alltt} +This will compare $a$ to $b$ placing $a$ to the left of $b$. This function cannot fail and will return one of the +three compare codes listed in figure \ref{fig:CMP}. + +\begin{small} \begin{alltt} +int main(void) +\{ + mp_int number1, number2; + int result; + + if ((result = mp_init_multi(&number1, &number2, NULL)) != MP_OKAY) \{ + printf("Error initializing the numbers. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* set the number1 to 5 */ + mp_set(&number1, 5); + + /* set the number2 to -6 */ + mp_set(&number2, 6); + if ((result = mp_neg(&number2, &number2)) != MP_OKAY) \{ + printf("Error negating number2. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + switch(mp_cmp_mag(&number1, &number2)) \{ + case MP_GT: printf("|number1| > |number2|"); break; + case MP_EQ: printf("|number1| = |number2|"); break; + case MP_LT: printf("|number1| < |number2|"); break; + \} + + /* we're done with it. */ + mp_clear_multi(&number1, &number2, NULL); + + return EXIT_SUCCESS; +\} +\end{alltt} \end{small} + +If this program\footnote{This function uses the mp\_neg() function which is discussed in section \ref{sec:NEG}.} completes +successfully it should print the following. + +\begin{alltt} +|number1| < |number2| +\end{alltt} + +This is because $\vert -6 \vert = 6$ and obviously $5 < 6$. + +\subsection{Signed comparison} + +To compare two mp\_int variables based on their signed value the mp\_cmp() function is provided. + +\index{mp\_cmp} +\begin{alltt} +int mp_cmp(mp_int * a, mp_int * b); +\end{alltt} + +This will compare $a$ to the left of $b$. It will first compare the signs of the two mp\_int variables. If they +differ it will return immediately based on their signs. If the signs are equal then it will compare the digits +individually. This function will return one of the compare conditions codes listed in figure \ref{fig:CMP}. + +\begin{small} \begin{alltt} +int main(void) +\{ + mp_int number1, number2; + int result; + + if ((result = mp_init_multi(&number1, &number2, NULL)) != MP_OKAY) \{ + printf("Error initializing the numbers. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* set the number1 to 5 */ + mp_set(&number1, 5); + + /* set the number2 to -6 */ + mp_set(&number2, 6); + if ((result = mp_neg(&number2, &number2)) != MP_OKAY) \{ + printf("Error negating number2. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + switch(mp_cmp(&number1, &number2)) \{ + case MP_GT: printf("number1 > number2"); break; + case MP_EQ: printf("number1 = number2"); break; + case MP_LT: printf("number1 < number2"); break; + \} + + /* we're done with it. */ + mp_clear_multi(&number1, &number2, NULL); + + return EXIT_SUCCESS; +\} +\end{alltt} \end{small} + +If this program\footnote{This function uses the mp\_neg() function which is discussed in section \ref{sec:NEG}.} completes +successfully it should print the following. + +\begin{alltt} +number1 > number2 +\end{alltt} + +\subsection{Single Digit} + +To compare a single digit against an mp\_int the following function has been provided. + +\index{mp\_cmp\_d} +\begin{alltt} +int mp_cmp_d(mp_int * a, mp_digit b); +\end{alltt} + +This will compare $a$ to the left of $b$ using a signed comparison. Note that it will always treat $b$ as +positive. This function is rather handy when you have to compare against small values such as $1$ (which often +comes up in cryptography). The function cannot fail and will return one of the tree compare condition codes +listed in figure \ref{fig:CMP}. + + +\begin{small} \begin{alltt} +int main(void) +\{ + mp_int number; + int result; + + if ((result = mp_init(&number)) != MP_OKAY) \{ + printf("Error initializing the number. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* set the number to 5 */ + mp_set(&number, 5); + + switch(mp_cmp_d(&number, 7)) \{ + case MP_GT: printf("number > 7"); break; + case MP_EQ: printf("number = 7"); break; + case MP_LT: printf("number < 7"); break; + \} + + /* we're done with it. */ + mp_clear(&number); + + return EXIT_SUCCESS; +\} +\end{alltt} \end{small} + +If this program functions properly it will print out the following. + +\begin{alltt} +number < 7 +\end{alltt} + +\section{Logical Operations} + +Logical operations are operations that can be performed either with simple shifts or boolean operators such as +AND, XOR and OR directly. These operations are very quick. + +\subsection{Multiplication by two} + +Multiplications and divisions by any power of two can be performed with quick logical shifts either left or +right depending on the operation. + +When multiplying or dividing by two a special case routine can be used which are as follows. +\index{mp\_mul\_2} \index{mp\_div\_2} +\begin{alltt} +int mp_mul_2(mp_int * a, mp_int * b); +int mp_div_2(mp_int * a, mp_int * b); +\end{alltt} + +The former will assign twice $a$ to $b$ while the latter will assign half $a$ to $b$. These functions are fast +since the shift counts and maskes are hardcoded into the routines. + +\begin{small} \begin{alltt} +int main(void) +\{ + mp_int number; + int result; + + if ((result = mp_init(&number)) != MP_OKAY) \{ + printf("Error initializing the number. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* set the number to 5 */ + mp_set(&number, 5); + + /* multiply by two */ + if ((result = mp\_mul\_2(&number, &number)) != MP_OKAY) \{ + printf("Error multiplying the number. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + switch(mp_cmp_d(&number, 7)) \{ + case MP_GT: printf("2*number > 7"); break; + case MP_EQ: printf("2*number = 7"); break; + case MP_LT: printf("2*number < 7"); break; + \} + + /* now divide by two */ + if ((result = mp\_div\_2(&number, &number)) != MP_OKAY) \{ + printf("Error dividing the number. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + switch(mp_cmp_d(&number, 7)) \{ + case MP_GT: printf("2*number/2 > 7"); break; + case MP_EQ: printf("2*number/2 = 7"); break; + case MP_LT: printf("2*number/2 < 7"); break; + \} + + /* we're done with it. */ + mp_clear(&number); + + return EXIT_SUCCESS; +\} +\end{alltt} \end{small} + +If this program is successful it will print out the following text. + +\begin{alltt} +2*number > 7 +2*number/2 < 7 +\end{alltt} + +Since $10 > 7$ and $5 < 7$. To multiply by a power of two the following function can be used. + +\index{mp\_mul\_2d} +\begin{alltt} +int mp_mul_2d(mp_int * a, int b, mp_int * c); +\end{alltt} + +This will multiply $a$ by $2^b$ and store the result in ``c''. If the value of $b$ is less than or equal to +zero the function will copy $a$ to ``c'' without performing any further actions. + +To divide by a power of two use the following. + +\index{mp\_div\_2d} +\begin{alltt} +int mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d); +\end{alltt} +Which will divide $a$ by $2^b$, store the quotient in ``c'' and the remainder in ``d'. If $b \le 0$ then the +function simply copies $a$ over to ``c'' and zeroes $d$. The variable $d$ may be passed as a \textbf{NULL} +value to signal that the remainder is not desired. + +\subsection{Polynomial Basis Operations} + +Strictly speaking the organization of the integers within the mp\_int structures is what is known as a +``polynomial basis''. This simply means a field element is stored by divisions of a radix. For example, if +$f(x) = \sum_{i=0}^{k} y_ix^k$ for any vector $\vec y$ then the array of digits in $\vec y$ are said to be +the polynomial basis representation of $z$ if $f(\beta) = z$ for a given radix $\beta$. + +To multiply by the polynomial $g(x) = x$ all you have todo is shift the digits of the basis left one place. The +following function provides this operation. + +\index{mp\_lshd} +\begin{alltt} +int mp_lshd (mp_int * a, int b); +\end{alltt} + +This will multiply $a$ in place by $x^b$ which is equivalent to shifting the digits left $b$ places and inserting zeroes +in the least significant digits. Similarly to divide by a power of $x$ the following function is provided. + +\index{mp\_rshd} +\begin{alltt} +void mp_rshd (mp_int * a, int b) +\end{alltt} +This will divide $a$ in place by $x^b$ and discard the remainder. This function cannot fail as it performs the operations +in place and no new digits are required to complete it. + +\subsection{AND, OR and XOR Operations} + +While AND, OR and XOR operations are not typical ``bignum functions'' they can be useful in several instances. The +three functions are prototyped as follows. + +\index{mp\_or} \index{mp\_and} \index{mp\_xor} +\begin{alltt} +int mp_or (mp_int * a, mp_int * b, mp_int * c); +int mp_and (mp_int * a, mp_int * b, mp_int * c); +int mp_xor (mp_int * a, mp_int * b, mp_int * c); +\end{alltt} + +Which compute $c = a \odot b$ where $\odot$ is one of OR, AND or XOR. + +\section{Addition and Subtraction} + +To compute an addition or subtraction the following two functions can be used. + +\index{mp\_add} \index{mp\_sub} +\begin{alltt} +int mp_add (mp_int * a, mp_int * b, mp_int * c); +int mp_sub (mp_int * a, mp_int * b, mp_int * c) +\end{alltt} + +Which perform $c = a \odot b$ where $\odot$ is one of signed addition or subtraction. The operations are fully sign +aware. + +\section{Sign Manipulation} +\subsection{Negation} +\label{sec:NEG} +Simple integer negation can be performed with the following. + +\index{mp\_neg} +\begin{alltt} +int mp_neg (mp_int * a, mp_int * b); +\end{alltt} + +Which assigns $-a$ to $b$. + +\subsection{Absolute} +Simple integer absolutes can be performed with the following. + +\index{mp\_neg} +\begin{alltt} +int mp_abs (mp_int * a, mp_int * b); +\end{alltt} + +Which assigns $\vert a \vert$ to $b$. + +\section{Integer Division and Remainder} +To perform a complete and general integer division with remainder use the following function. + +\index{mp\_div} +\begin{alltt} +int mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d); +\end{alltt} + +This divides $a$ by $b$ and stores the quotient in $c$ and $d$. The signed quotient is computed such that +$bc + d = a$. Note that either of $c$ or $d$ can be set to \textbf{NULL} if their value is not required. If +$b$ is zero the function returns \textbf{MP\_VAL}. + + +\chapter{Multiplication and Squaring} +\section{Multiplication} +A full signed integer multiplication can be performed with the following. +\index{mp\_mul} +\begin{alltt} +int mp_mul (mp_int * a, mp_int * b, mp_int * c); +\end{alltt} +Which assigns the full signed product $ab$ to $c$. This function actually breaks into one of four cases which are +specific multiplication routines optimized for given parameters. First there are the Toom-Cook multiplications which +should only be used with very large inputs. This is followed by the Karatsuba multiplications which are for moderate +sized inputs. Then followed by the Comba and baseline multipliers. + +Fortunately for the developer you don't really need to know this unless you really want to fine tune the system. mp\_mul() +will determine on its own\footnote{Some tweaking may be required.} what routine to use automatically when it is called. + +\begin{alltt} +int main(void) +\{ + mp_int number1, number2; + int result; + + /* Initialize the numbers */ + if ((result = mp_init_multi(&number1, + &number2, NULL)) != MP_OKAY) \{ + printf("Error initializing the numbers. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* set the terms */ + if ((result = mp_set_int(&number, 257)) != MP_OKAY) \{ + printf("Error setting number1. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + if ((result = mp_set_int(&number2, 1023)) != MP_OKAY) \{ + printf("Error setting number2. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* multiply them */ + if ((result = mp_mul(&number1, &number2, + &number1)) != MP_OKAY) \{ + printf("Error multiplying terms. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* display */ + printf("number1 * number2 == \%lu", mp_get_int(&number1)); + + /* free terms and return */ + mp_clear_multi(&number1, &number2, NULL); + + return EXIT_SUCCESS; +\} +\end{alltt} + +If this program succeeds it shall output the following. + +\begin{alltt} +number1 * number2 == 262911 +\end{alltt} + +\section{Squaring} +Since squaring can be performed faster than multiplication it is performed it's own function instead of just using +mp\_mul(). + +\index{mp\_sqr} +\begin{alltt} +int mp_sqr (mp_int * a, mp_int * b); +\end{alltt} + +Will square $a$ and store it in $b$. Like the case of multiplication there are four different squaring +algorithms all which can be called from mp\_sqr(). It is ideal to use mp\_sqr over mp\_mul when squaring terms because +of the speed difference. + +\section{Tuning Polynomial Basis Routines} + +Both of the Toom-Cook and Karatsuba multiplication algorithms are faster than the traditional $O(n^2)$ approach that +the Comba and baseline algorithms use. At $O(n^{1.464973})$ and $O(n^{1.584962})$ running times respectively they require +considerably less work. For example, a 10000-digit multiplication would take roughly 724,000 single precision +multiplications with Toom-Cook or 100,000,000 single precision multiplications with the standard Comba (a factor +of 138). + +So why not always use Karatsuba or Toom-Cook? The simple answer is that they have so much overhead that they're not +actually faster than Comba until you hit distinct ``cutoff'' points. For Karatsuba with the default configuration, +GCC 3.3.1 and an Athlon XP processor the cutoff point is roughly 110 digits (about 70 for the Intel P4). That is, at +110 digits Karatsuba and Comba multiplications just about break even and for 110+ digits Karatsuba is faster. + +Toom-Cook has incredible overhead and is probably only useful for very large inputs. So far no known cutoff points +exist and for the most part I just set the cutoff points very high to make sure they're not called. + +A demo program in the ``etc/'' directory of the project called ``tune.c'' can be used to find the cutoff points. This +can be built with GCC as follows + +\begin{alltt} +make XXX +\end{alltt} +Where ``XXX'' is one of the following entries from the table \ref{fig:tuning}. + +\begin{figure}[here] +\begin{center} +\begin{small} +\begin{tabular}{|l|l|} +\hline \textbf{Value of XXX} & \textbf{Meaning} \\ +\hline tune & Builds portable tuning application \\ +\hline tune86 & Builds x86 (pentium and up) program for COFF \\ +\hline tune86c & Builds x86 program for Cygwin \\ +\hline tune86l & Builds x86 program for Linux (ELF format) \\ +\hline +\end{tabular} +\end{small} +\end{center} +\caption{Build Names for Tuning Programs} +\label{fig:tuning} +\end{figure} + +When the program is running it will output a series of measurements for different cutoff points. It will first find +good Karatsuba squaring and multiplication points. Then it proceeds to find Toom-Cook points. Note that the Toom-Cook +tuning takes a very long time as the cutoff points are likely to be very high. + +\chapter{Modular Reduction} + +Modular reduction is process of taking the remainder of one quantity divided by another. Expressed +as (\ref{eqn:mod}) the modular reduction is equivalent to the remainder of $b$ divided by $c$. + +\begin{equation} +a \equiv b \mbox{ (mod }c\mbox{)} +\label{eqn:mod} +\end{equation} + +Of particular interest to cryptography are reductions where $b$ is limited to the range $0 \le b < c^2$ since particularly +fast reduction algorithms can be written for the limited range. + +Note that one of the four optimized reduction algorithms are automatically chosen in the modular exponentiation +algorithm mp\_exptmod when an appropriate modulus is detected. + +\section{Straight Division} +In order to effect an arbitrary modular reduction the following algorithm is provided. + +\index{mp\_mod} +\begin{alltt} +int mp_mod(mp_int *a, mp_int *b, mp_int *c); +\end{alltt} + +This reduces $a$ modulo $b$ and stores the result in $c$. The sign of $c$ shall agree with the sign +of $b$. This algorithm accepts an input $a$ of any range and is not limited by $0 \le a < b^2$. + +\section{Barrett Reduction} + +Barrett reduction is a generic optimized reduction algorithm that requires pre--computation to achieve +a decent speedup over straight division. First a $\mu$ value must be precomputed with the following function. + +\index{mp\_reduce\_setup} +\begin{alltt} +int mp_reduce_setup(mp_int *a, mp_int *b); +\end{alltt} + +Given a modulus in $b$ this produces the required $\mu$ value in $a$. For any given modulus this only has to +be computed once. Modular reduction can now be performed with the following. + +\index{mp\_reduce} +\begin{alltt} +int mp_reduce(mp_int *a, mp_int *b, mp_int *c); +\end{alltt} + +This will reduce $a$ in place modulo $b$ with the precomputed $\mu$ value in $c$. $a$ must be in the range +$0 \le a < b^2$. + +\begin{alltt} +int main(void) +\{ + mp_int a, b, c, mu; + int result; + + /* initialize a,b to desired values, mp_init mu, + * c and set c to 1...we want to compute a^3 mod b + */ + + /* get mu value */ + if ((result = mp_reduce_setup(&mu, b)) != MP_OKAY) \{ + printf("Error getting mu. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* square a to get c = a^2 */ + if ((result = mp_sqr(&a, &c)) != MP_OKAY) \{ + printf("Error squaring. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* now reduce `c' modulo b */ + if ((result = mp_reduce(&c, &b, &mu)) != MP_OKAY) \{ + printf("Error reducing. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* multiply a to get c = a^3 */ + if ((result = mp_mul(&a, &c, &c)) != MP_OKAY) \{ + printf("Error reducing. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* now reduce `c' modulo b */ + if ((result = mp_reduce(&c, &b, &mu)) != MP_OKAY) \{ + printf("Error reducing. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* c now equals a^3 mod b */ + + return EXIT_SUCCESS; +\} +\end{alltt} + +This program will calculate $a^3 \mbox{ mod }b$ if all the functions succeed. + +\section{Montgomery Reduction} + +Montgomery is a specialized reduction algorithm for any odd moduli. Like Barrett reduction a pre--computation +step is required. This is accomplished with the following. + +\index{mp\_montgomery\_setup} +\begin{alltt} +int mp_montgomery_setup(mp_int *a, mp_digit *mp); +\end{alltt} + +For the given odd moduli $a$ the precomputation value is placed in $mp$. The reduction is computed with the +following. + +\index{mp\_montgomery\_reduce} +\begin{alltt} +int mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp); +\end{alltt} +This reduces $a$ in place modulo $m$ with the pre--computed value $mp$. $a$ must be in the range +$0 \le a < b^2$. + +Montgomery reduction is faster than Barrett reduction for moduli smaller than the ``comba'' limit. With the default +setup for instance, the limit is $127$ digits ($3556$--bits). Note that this function is not limited to +$127$ digits just that it falls back to a baseline algorithm after that point. + +An important observation is that this reduction does not return $a \mbox{ mod }m$ but $aR^{-1} \mbox{ mod }m$ +where $R = \beta^n$, $n$ is the n number of digits in $m$ and $\beta$ is radix used (default is $2^{28}$). + +To quickly calculate $R$ the following function was provided. + +\index{mp\_montgomery\_calc\_normalization} +\begin{alltt} +int mp_montgomery_calc_normalization(mp_int *a, mp_int *b); +\end{alltt} +Which calculates $a = R$ for the odd moduli $b$ without using multiplication or division. + +The normal modus operandi for Montgomery reductions is to normalize the integers before entering the system. For +example, to calculate $a^3 \mbox { mod }b$ using Montgomery reduction the value of $a$ can be normalized by +multiplying it by $R$. Consider the following code snippet. + +\begin{alltt} +int main(void) +\{ + mp_int a, b, c, R; + mp_digit mp; + int result; + + /* initialize a,b to desired values, + * mp_init R, c and set c to 1.... + */ + + /* get normalization */ + if ((result = mp_montgomery_calc_normalization(&R, b)) != MP_OKAY) \{ + printf("Error getting norm. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* get mp value */ + if ((result = mp_montgomery_setup(&c, &mp)) != MP_OKAY) \{ + printf("Error setting up montgomery. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* normalize `a' so now a is equal to aR */ + if ((result = mp_mulmod(&a, &R, &b, &a)) != MP_OKAY) \{ + printf("Error computing aR. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* square a to get c = a^2R^2 */ + if ((result = mp_sqr(&a, &c)) != MP_OKAY) \{ + printf("Error squaring. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* now reduce `c' back down to c = a^2R^2 * R^-1 == a^2R */ + if ((result = mp_montgomery_reduce(&c, &b, mp)) != MP_OKAY) \{ + printf("Error reducing. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* multiply a to get c = a^3R^2 */ + if ((result = mp_mul(&a, &c, &c)) != MP_OKAY) \{ + printf("Error reducing. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* now reduce `c' back down to c = a^3R^2 * R^-1 == a^3R */ + if ((result = mp_montgomery_reduce(&c, &b, mp)) != MP_OKAY) \{ + printf("Error reducing. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* now reduce (again) `c' back down to c = a^3R * R^-1 == a^3 */ + if ((result = mp_montgomery_reduce(&c, &b, mp)) != MP_OKAY) \{ + printf("Error reducing. \%s", + mp_error_to_string(result)); + return EXIT_FAILURE; + \} + + /* c now equals a^3 mod b */ + + return EXIT_SUCCESS; +\} +\end{alltt} + +This particular example does not look too efficient but it demonstrates the point of the algorithm. By +normalizing the inputs the reduced results are always of the form $aR$ for some variable $a$. This allows +a single final reduction to correct for the normalization and the fast reduction used within the algorithm. + +For more details consider examining the file \textit{bn\_mp\_exptmod\_fast.c}. + +\section{Restricted Dimminished Radix} + +``Dimminished Radix'' reduction refers to reduction with respect to moduli that are ameniable to simple +digit shifting and small multiplications. In this case the ``restricted'' variant refers to moduli of the +form $\beta^k - p$ for some $k \ge 0$ and $0 < p < \beta$ where $\beta$ is the radix (default to $2^{28}$). + +As in the case of Montgomery reduction there is a pre--computation phase required for a given modulus. + +\index{mp\_dr\_setup} +\begin{alltt} +void mp_dr_setup(mp_int *a, mp_digit *d); +\end{alltt} + +This computes the value required for the modulus $a$ and stores it in $d$. This function cannot fail +and does not return any error codes. After the pre--computation a reduction can be performed with the +following. + +\index{mp\_dr\_reduce} +\begin{alltt} +int mp_dr_reduce(mp_int *a, mp_int *b, mp_digit mp); +\end{alltt} + +This reduces $a$ in place modulo $b$ with the pre--computed value $mp$. $b$ must be of a restricted +dimminished radix form and $a$ must be in the range $0 \le a < b^2$. Dimminished radix reductions are +much faster than both Barrett and Montgomery reductions as they have a much lower asymtotic running time. + +Since the moduli are restricted this algorithm is not particularly useful for something like Rabin, RSA or +BBS cryptographic purposes. This reduction algorithm is useful for Diffie-Hellman and ECC where fixed +primes are acceptable. + +Note that unlike Montgomery reduction there is no normalization process. The result of this function is +equal to the correct residue. + +\section{Unrestricted Dimminshed Radix} + +Unrestricted reductions work much like the restricted counterparts except in this case the moduli is of the +form $2^k - p$ for $0 < p < \beta$. In this sense the unrestricted reductions are more flexible as they +can be applied to a wider range of numbers. + +\index{mp\_reduce\_2k\_setup} +\begin{alltt} +int mp_reduce_2k_setup(mp_int *a, mp_digit *d); +\end{alltt} + +This will compute the required $d$ value for the given moduli $a$. + +\index{mp\_reduce\_2k} +\begin{alltt} +int mp_reduce_2k(mp_int *a, mp_int *n, mp_digit d); +\end{alltt} + +This will reduce $a$ in place modulo $n$ with the pre--computed value $d$. From my experience this routine is +slower than mp\_dr\_reduce but faster for most moduli sizes than the Montgomery reduction. + +\chapter{Exponentiation} +\section{Single Digit Exponentiation} +\index{mp\_expt\_d} +\begin{alltt} +int mp_expt_d (mp_int * a, mp_digit b, mp_int * c) +\end{alltt} +This computes $c = a^b$ using a simple binary left-to-right algorithm. It is faster than repeated multiplications by +$a$ for all values of $b$ greater than three. + +\section{Modular Exponentiation} +\index{mp\_exptmod} +\begin{alltt} +int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) +\end{alltt} +This computes $Y \equiv G^X \mbox{ (mod }P\mbox{)}$ using a variable width sliding window algorithm. This function +will automatically detect the fastest modular reduction technique to use during the operation. For negative values of +$X$ the operation is performed as $Y \equiv (G^{-1} \mbox{ mod }P)^{\vert X \vert} \mbox{ (mod }P\mbox{)}$ provided that +$gcd(G, P) = 1$. + +This function is actually a shell around the two internal exponentiation functions. This routine will automatically +detect when Barrett, Montgomery, Restricted and Unrestricted Dimminished Radix based exponentiation can be used. Generally +moduli of the a ``restricted dimminished radix'' form lead to the fastest modular exponentiations. Followed by Montgomery +and the other two algorithms. + +\section{Root Finding} +\index{mp\_n\_root} +\begin{alltt} +int mp_n_root (mp_int * a, mp_digit b, mp_int * c) +\end{alltt} +This computes $c = a^{1/b}$ such that $c^b \le a$ and $(c+1)^b > a$. The implementation of this function is not +ideal for values of $b$ greater than three. It will work but become very slow. So unless you are working with very small +numbers (less than 1000 bits) I'd avoid $b > 3$ situations. Will return a positive root only for even roots and return +a root with the sign of the input for odd roots. For example, performing $4^{1/2}$ will return $2$ whereas $(-8)^{1/3}$ +will return $-2$. + +This algorithm uses the ``Newton Approximation'' method and will converge on the correct root fairly quickly. Since +the algorithm requires raising $a$ to the power of $b$ it is not ideal to attempt to find roots for large +values of $b$. If particularly large roots are required then a factor method could be used instead. For example, +$a^{1/16}$ is equivalent to $\left (a^{1/4} \right)^{1/4}$ or simply +$\left ( \left ( \left ( a^{1/2} \right )^{1/2} \right )^{1/2} \right )^{1/2}$ + +\chapter{Prime Numbers} +\section{Trial Division} +\index{mp\_prime\_is\_divisible} +\begin{alltt} +int mp_prime_is_divisible (mp_int * a, int *result) +\end{alltt} +This will attempt to evenly divide $a$ by a list of primes\footnote{Default is the first 256 primes.} and store the +outcome in ``result''. That is if $result = 0$ then $a$ is not divisible by the primes, otherwise it is. Note that +if the function does not return \textbf{MP\_OKAY} the value in ``result'' should be considered undefined\footnote{Currently +the default is to set it to zero first.}. + +\section{Fermat Test} +\index{mp\_prime\_fermat} +\begin{alltt} +int mp_prime_fermat (mp_int * a, mp_int * b, int *result) +\end{alltt} +Performs a Fermat primality test to the base $b$. That is it computes $b^a \mbox{ mod }a$ and tests whether the value is +equal to $b$ or not. If the values are equal then $a$ is probably prime and $result$ is set to one. Otherwise $result$ +is set to zero. + +\section{Miller-Rabin Test} +\index{mp\_prime\_miller\_rabin} +\begin{alltt} +int mp_prime_miller_rabin (mp_int * a, mp_int * b, int *result) +\end{alltt} +Performs a Miller-Rabin test to the base $b$ of $a$. This test is much stronger than the Fermat test and is very hard to +fool (besides with Carmichael numbers). If $a$ passes the test (therefore is probably prime) $result$ is set to one. +Otherwise $result$ is set to zero. + +Note that is suggested that you use the Miller-Rabin test instead of the Fermat test since all of the failures of +Miller-Rabin are a subset of the failures of the Fermat test. + +\subsection{Required Number of Tests} +Generally to ensure a number is very likely to be prime you have to perform the Miller-Rabin with at least a half-dozen +or so unique bases. However, it has been proven that the probability of failure goes down as the size of the input goes up. +This is why a simple function has been provided to help out. + +\index{mp\_prime\_rabin\_miller\_trials} +\begin{alltt} +int mp_prime_rabin_miller_trials(int size) +\end{alltt} +This returns the number of trials required for a $2^{-96}$ (or lower) probability of failure for a given ``size'' expressed +in bits. This comes in handy specially since larger numbers are slower to test. For example, a 512-bit number would +require ten tests whereas a 1024-bit number would only require four tests. + +You should always still perform a trial division before a Miller-Rabin test though. + +\section{Primality Testing} +\index{mp\_prime\_is\_prime} +\begin{alltt} +int mp_prime_is_prime (mp_int * a, int t, int *result) +\end{alltt} +This will perform a trial division followed by $t$ rounds of Miller-Rabin tests on $a$ and store the result in $result$. +If $a$ passes all of the tests $result$ is set to one, otherwise it is set to zero. Note that $t$ is bounded by +$1 \le t < PRIME\_SIZE$ where $PRIME\_SIZE$ is the number of primes in the prime number table (by default this is $256$). + +\section{Next Prime} +\index{mp\_prime\_next\_prime} +\begin{alltt} +int mp_prime_next_prime(mp_int *a, int t, int bbs_style) +\end{alltt} +This finds the next prime after $a$ that passes mp\_prime\_is\_prime() with $t$ tests. Set $bbs\_style$ to one if you +want only the next prime congruent to $3 \mbox{ mod } 4$, otherwise set it to zero to find any next prime. + +\section{Random Primes} +\index{mp\_prime\_random} +\begin{alltt} +int mp_prime_random(mp_int *a, int t, int size, int bbs, + ltm_prime_callback cb, void *dat) +\end{alltt} +This will find a prime greater than $256^{size}$ which can be ``bbs\_style'' or not depending on $bbs$ and must pass +$t$ rounds of tests. The ``ltm\_prime\_callback'' is a typedef for + +\begin{alltt} +typedef int ltm_prime_callback(unsigned char *dst, int len, void *dat); +\end{alltt} + +Which is a function that must read $len$ bytes (and return the amount stored) into $dst$. The $dat$ variable is simply +copied from the original input. It can be used to pass RNG context data to the callback. The function +mp\_prime\_random() is more suitable for generating primes which must be secret (as in the case of RSA) since there +is no skew on the least significant bits. + +\textit{Note:} As of v0.30 of the LibTomMath library this function has been deprecated. It is still available +but users are encouraged to use the new mp\_prime\_random\_ex() function instead. + +\subsection{Extended Generation} +\index{mp\_prime\_random\_ex} +\begin{alltt} +int mp_prime_random_ex(mp_int *a, int t, + int size, int flags, + ltm_prime_callback cb, void *dat); +\end{alltt} +This will generate a prime in $a$ using $t$ tests of the primality testing algorithms. The variable $size$ +specifies the bit length of the prime desired. The variable $flags$ specifies one of several options available +(see fig. \ref{fig:primeopts}) which can be OR'ed together. The callback parameters are used as in +mp\_prime\_random(). + +\begin{figure}[here] +\begin{center} +\begin{small} +\begin{tabular}{|r|l|} +\hline \textbf{Flag} & \textbf{Meaning} \\ +\hline LTM\_PRIME\_BBS & Make the prime congruent to $3$ modulo $4$ \\ +\hline LTM\_PRIME\_SAFE & Make a prime $p$ such that $(p - 1)/2$ is also prime. \\ + & This option implies LTM\_PRIME\_BBS as well. \\ +\hline LTM\_PRIME\_2MSB\_OFF & Makes sure that the bit adjacent to the most significant bit \\ + & Is forced to zero. \\ +\hline LTM\_PRIME\_2MSB\_ON & Makes sure that the bit adjacent to the most significant bit \\ + & Is forced to one. \\ +\hline +\end{tabular} +\end{small} +\end{center} +\caption{Primality Generation Options} +\label{fig:primeopts} +\end{figure} + +\chapter{Input and Output} +\section{ASCII Conversions} +\subsection{To ASCII} +\index{mp\_toradix} +\begin{alltt} +int mp_toradix (mp_int * a, char *str, int radix); +\end{alltt} +This still store $a$ in ``str'' as a base-``radix'' string of ASCII chars. This function appends a NUL character +to terminate the string. Valid values of ``radix'' line in the range $[2, 64]$. To determine the size (exact) required +by the conversion before storing any data use the following function. + +\index{mp\_radix\_size} +\begin{alltt} +int mp_radix_size (mp_int * a, int radix, int *size) +\end{alltt} +This stores in ``size'' the number of characters (including space for the NUL terminator) required. Upon error this +function returns an error code and ``size'' will be zero. + +\subsection{From ASCII} +\index{mp\_read\_radix} +\begin{alltt} +int mp_read_radix (mp_int * a, char *str, int radix); +\end{alltt} +This will read the base-``radix'' NUL terminated string from ``str'' into $a$. It will stop reading when it reads a +character it does not recognize (which happens to include th NUL char... imagine that...). A single leading $-$ sign +can be used to denote a negative number. + +\section{Binary Conversions} + +Converting an mp\_int to and from binary is another keen idea. + +\index{mp\_unsigned\_bin\_size} +\begin{alltt} +int mp_unsigned_bin_size(mp_int *a); +\end{alltt} + +This will return the number of bytes (octets) required to store the unsigned copy of the integer $a$. + +\index{mp\_to\_unsigned\_bin} +\begin{alltt} +int mp_to_unsigned_bin(mp_int *a, unsigned char *b); +\end{alltt} +This will store $a$ into the buffer $b$ in big--endian format. Fortunately this is exactly what DER (or is it ASN?) +requires. It does not store the sign of the integer. + +\index{mp\_read\_unsigned\_bin} +\begin{alltt} +int mp_read_unsigned_bin(mp_int *a, unsigned char *b, int c); +\end{alltt} +This will read in an unsigned big--endian array of bytes (octets) from $b$ of length $c$ into $a$. The resulting +integer $a$ will always be positive. + +For those who acknowledge the existence of negative numbers (heretic!) there are ``signed'' versions of the +previous functions. + +\begin{alltt} +int mp_signed_bin_size(mp_int *a); +int mp_read_signed_bin(mp_int *a, unsigned char *b, int c); +int mp_to_signed_bin(mp_int *a, unsigned char *b); +\end{alltt} +They operate essentially the same as the unsigned copies except they prefix the data with zero or non--zero +byte depending on the sign. If the sign is zpos (e.g. not negative) the prefix is zero, otherwise the prefix +is non--zero. + +\chapter{Algebraic Functions} +\section{Extended Euclidean Algorithm} +\index{mp\_exteuclid} +\begin{alltt} +int mp_exteuclid(mp_int *a, mp_int *b, + mp_int *U1, mp_int *U2, mp_int *U3); +\end{alltt} + +This finds the triple U1/U2/U3 using the Extended Euclidean algorithm such that the following equation holds. + +\begin{equation} +a \cdot U1 + b \cdot U2 = U3 +\end{equation} + +Any of the U1/U2/U3 paramters can be set to \textbf{NULL} if they are not desired. + +\section{Greatest Common Divisor} +\index{mp\_gcd} +\begin{alltt} +int mp_gcd (mp_int * a, mp_int * b, mp_int * c) +\end{alltt} +This will compute the greatest common divisor of $a$ and $b$ and store it in $c$. + +\section{Least Common Multiple} +\index{mp\_lcm} +\begin{alltt} +int mp_lcm (mp_int * a, mp_int * b, mp_int * c) +\end{alltt} +This will compute the least common multiple of $a$ and $b$ and store it in $c$. + +\section{Jacobi Symbol} +\index{mp\_jacobi} +\begin{alltt} +int mp_jacobi (mp_int * a, mp_int * p, int *c) +\end{alltt} +This will compute the Jacobi symbol for $a$ with respect to $p$. If $p$ is prime this essentially computes the Legendre +symbol. The result is stored in $c$ and can take on one of three values $\lbrace -1, 0, 1 \rbrace$. If $p$ is prime +then the result will be $-1$ when $a$ is not a quadratic residue modulo $p$. The result will be $0$ if $a$ divides $p$ +and the result will be $1$ if $a$ is a quadratic residue modulo $p$. + +\section{Modular Inverse} +\index{mp\_invmod} +\begin{alltt} +int mp_invmod (mp_int * a, mp_int * b, mp_int * c) +\end{alltt} +Computes the multiplicative inverse of $a$ modulo $b$ and stores the result in $c$ such that $ac \equiv 1 \mbox{ (mod }b\mbox{)}$. + +\section{Single Digit Functions} + +For those using small numbers (\textit{snicker snicker}) there are several ``helper'' functions + +\index{mp\_add\_d} \index{mp\_sub\_d} \index{mp\_mul\_d} \index{mp\_div\_d} \index{mp\_mod\_d} +\begin{alltt} +int mp_add_d(mp_int *a, mp_digit b, mp_int *c); +int mp_sub_d(mp_int *a, mp_digit b, mp_int *c); +int mp_mul_d(mp_int *a, mp_digit b, mp_int *c); +int mp_div_d(mp_int *a, mp_digit b, mp_int *c, mp_digit *d); +int mp_mod_d(mp_int *a, mp_digit b, mp_digit *c); +\end{alltt} + +These work like the full mp\_int capable variants except the second parameter $b$ is a mp\_digit. These +functions fairly handy if you have to work with relatively small numbers since you will not have to allocate +an entire mp\_int to store a number like $1$ or $2$. + +\input{bn.ind} + +\end{document} diff --git a/libtommath/bn_error.c b/libtommath/bn_error.c new file mode 100644 index 0000000..1ae6430 --- /dev/null +++ b/libtommath/bn_error.c @@ -0,0 +1,47 @@ +#include <tommath.h> +#ifdef BN_ERROR_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +static const struct { + int code; + char *msg; +} msgs[] = { + { MP_OKAY, "Successful" }, + { MP_MEM, "Out of heap" }, + { MP_VAL, "Value out of range" } +}; + +/* return a char * string for a given code */ +char *mp_error_to_string(int code) +{ + int x; + + /* scan the lookup table for the given message */ + for (x = 0; x < (int)(sizeof(msgs) / sizeof(msgs[0])); x++) { + if (msgs[x].code == code) { + return msgs[x].msg; + } + } + + /* generic reply for invalid code */ + return "Invalid error code"; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_error.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_fast_mp_invmod.c b/libtommath/bn_fast_mp_invmod.c new file mode 100644 index 0000000..1974145 --- /dev/null +++ b/libtommath/bn_fast_mp_invmod.c @@ -0,0 +1,148 @@ +#include <tommath.h> +#ifdef BN_FAST_MP_INVMOD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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 + */ +int fast_mp_invmod (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int x, y, u, v, B, D; + int res, neg; + + /* 2. [modified] b must be odd */ + if (mp_iseven (b) == 1) { + return MP_VAL; + } + + /* init all our temps */ + if ((res = mp_init_multi(&x, &y, &u, &v, &B, &D, NULL)) != MP_OKAY) { + return res; + } + + /* x == modulus, y == value to invert */ + if ((res = mp_copy (b, &x)) != MP_OKAY) { + goto LBL_ERR; + } + + /* we need y = |a| */ + if ((res = mp_mod (a, b, &y)) != MP_OKAY) { + goto LBL_ERR; + } + + /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ + if ((res = mp_copy (&x, &u)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_copy (&y, &v)) != MP_OKAY) { + goto LBL_ERR; + } + mp_set (&D, 1); + +top: + /* 4. while u is even do */ + while (mp_iseven (&u) == 1) { + /* 4.1 u = u/2 */ + if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { + goto LBL_ERR; + } + /* 4.2 if B is odd then */ + if (mp_isodd (&B) == 1) { + if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } + /* B = B/2 */ + if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* 5. while v is even do */ + while (mp_iseven (&v) == 1) { + /* 5.1 v = v/2 */ + if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { + goto LBL_ERR; + } + /* 5.2 if D is odd then */ + if (mp_isodd (&D) == 1) { + /* D = (D-x)/2 */ + if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + /* D = D/2 */ + if ((res = 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 ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } else { + /* v - v - u, D = D - B */ + if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* if not zero goto step 4 */ + if (mp_iszero (&u) == 0) { + goto top; + } + + /* now a = C, b = D, gcd == g*v */ + + /* if v != 1 then there is no inverse */ + if (mp_cmp_d (&v, 1) != MP_EQ) { + res = MP_VAL; + goto LBL_ERR; + } + + /* b is now the inverse */ + neg = a->sign; + while (D.sign == MP_NEG) { + if ((res = mp_add (&D, b, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + mp_exch (&D, c); + c->sign = neg; + res = MP_OKAY; + +LBL_ERR:mp_clear_multi (&x, &y, &u, &v, &B, &D, NULL); + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_fast_mp_invmod.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_fast_mp_montgomery_reduce.c b/libtommath/bn_fast_mp_montgomery_reduce.c new file mode 100644 index 0000000..13538c8 --- /dev/null +++ b/libtommath/bn_fast_mp_montgomery_reduce.c @@ -0,0 +1,172 @@ +#include <tommath.h> +#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* computes xR**-1 == x (mod N) via Montgomery Reduction + * + * This is an optimized implementation of montgomery_reduce + * which uses the comba method to quickly calculate the columns of the + * reduction. + * + * Based on Algorithm 14.32 on pp.601 of HAC. +*/ +int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho) +{ + int ix, res, olduse; + mp_word W[MP_WARRAY]; + + /* get old used count */ + olduse = x->used; + + /* grow a as required */ + if (x->alloc < n->used + 1) { + if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) { + return res; + } + } + + /* first we have to get the digits of the input into + * an array of double precision words W[...] + */ + { + register mp_word *_W; + register 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] */ + for (; ix < n->used * 2 + 1; ix++) { + *_W++ = 0; + } + } + + /* 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) + */ + register mp_digit mu; + mu = (mp_digit) (((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 + */ + { + register int iy; + register mp_digit *tmpn; + register 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) DIGIT_BIT); + } + + /* now we have to propagate the carries and + * shift the words downward [all those least + * significant digits we zeroed]. + */ + { + register mp_digit *tmpx; + register 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); + } + + /* 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++ = (mp_digit)(*_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 + */ + for (; ix < olduse; ix++) { + *tmpx++ = 0; + } + } + + /* 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 + +/* $Source: /cvs/libtom/libtommath/bn_fast_mp_montgomery_reduce.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_fast_s_mp_mul_digs.c b/libtommath/bn_fast_s_mp_mul_digs.c new file mode 100644 index 0000000..8e2e069 --- /dev/null +++ b/libtommath/bn_fast_s_mp_mul_digs.c @@ -0,0 +1,107 @@ +#include <tommath.h> +#ifdef BN_FAST_S_MP_MUL_DIGS_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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. + * + */ +int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + int olduse, res, pa, ix, iz; + mp_digit W[MP_WARRAY]; + register mp_word _W; + + /* grow the destination as required */ + if (c->alloc < digs) { + if ((res = mp_grow (c, digs)) != MP_OKAY) { + return res; + } + } + + /* number of output digits to produce */ + pa = 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 = 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 = 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)DIGIT_BIT); + } + + /* setup dest */ + olduse = c->used; + c->used = pa; + + { + register mp_digit *tmpc; + tmpc = c->dp; + for (ix = 0; ix < pa+1; ix++) { + /* now extract the previous digit [below the carry] */ + *tmpc++ = W[ix]; + } + + /* clear unused digits [that existed in the old copy of c] */ + for (; ix < olduse; ix++) { + *tmpc++ = 0; + } + } + mp_clamp (c); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_fast_s_mp_mul_digs.c,v $ */ +/* $Revision: 1.7 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_fast_s_mp_mul_high_digs.c b/libtommath/bn_fast_s_mp_mul_high_digs.c new file mode 100644 index 0000000..4778b2f --- /dev/null +++ b/libtommath/bn_fast_s_mp_mul_high_digs.c @@ -0,0 +1,98 @@ +#include <tommath.h> +#ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* this is a modified version of fast_s_mul_digs that only produces + * output digits *above* digs. See the comments for fast_s_mul_digs + * 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. + */ +int fast_s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + int olduse, res, pa, ix, iz; + mp_digit W[MP_WARRAY]; + mp_word _W; + + /* grow the destination as required */ + pa = a->used + b->used; + if (c->alloc < pa) { + if ((res = mp_grow (c, pa)) != MP_OKAY) { + return res; + } + } + + /* 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 = 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 = 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)DIGIT_BIT); + } + + /* setup dest */ + olduse = c->used; + c->used = pa; + + { + register 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] */ + for (; ix < olduse; ix++) { + *tmpc++ = 0; + } + } + mp_clamp (c); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_fast_s_mp_mul_high_digs.c,v $ */ +/* $Revision: 1.5 $ */ +/* $Date: 2006/11/14 03:46:25 $ */ diff --git a/libtommath/bn_fast_s_mp_sqr.c b/libtommath/bn_fast_s_mp_sqr.c new file mode 100644 index 0000000..bb5974c --- /dev/null +++ b/libtommath/bn_fast_s_mp_sqr.c @@ -0,0 +1,114 @@ +#include <tommath.h> +#ifdef BN_FAST_S_MP_SQR_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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. +*/ + +int fast_s_mp_sqr (mp_int * a, mp_int * b) +{ + int olduse, res, pa, ix, iz; + mp_digit W[MP_WARRAY], *tmpx; + mp_word W1; + + /* grow the destination as required */ + pa = a->used + a->used; + if (b->alloc < pa) { + if ((res = mp_grow (b, pa)) != MP_OKAY) { + return res; + } + } + + /* 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 = 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 = 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 = 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 ((ix&1) == 0) { + _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)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] */ + for (; ix < olduse; ix++) { + *tmpb++ = 0; + } + } + mp_clamp (b); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_fast_s_mp_sqr.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_2expt.c b/libtommath/bn_mp_2expt.c new file mode 100644 index 0000000..9e5f32e --- /dev/null +++ b/libtommath/bn_mp_2expt.c @@ -0,0 +1,48 @@ +#include <tommath.h> +#ifdef BN_MP_2EXPT_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* computes a = 2**b + * + * Simple algorithm which zeroes the int, grows it then just sets one bit + * as required. + */ +int +mp_2expt (mp_int * a, int b) +{ + int res; + + /* zero a as per default */ + mp_zero (a); + + /* grow a to accomodate the single bit */ + if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) { + return res; + } + + /* set the used count of where the bit will go */ + a->used = b / DIGIT_BIT + 1; + + /* put the single bit in its place */ + a->dp[b / DIGIT_BIT] = ((mp_digit)1) << (b % DIGIT_BIT); + + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_2expt.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_abs.c b/libtommath/bn_mp_abs.c new file mode 100644 index 0000000..9643c5e --- /dev/null +++ b/libtommath/bn_mp_abs.c @@ -0,0 +1,43 @@ +#include <tommath.h> +#ifdef BN_MP_ABS_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* b = |a| + * + * Simple function copies the input and fixes the sign to positive + */ +int +mp_abs (mp_int * a, mp_int * b) +{ + int res; + + /* copy a to b */ + if (a != b) { + if ((res = mp_copy (a, b)) != MP_OKAY) { + return res; + } + } + + /* force the sign of b to positive */ + b->sign = MP_ZPOS; + + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_abs.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_add.c b/libtommath/bn_mp_add.c new file mode 100644 index 0000000..a90eef6 --- /dev/null +++ b/libtommath/bn_mp_add.c @@ -0,0 +1,53 @@ +#include <tommath.h> +#ifdef BN_MP_ADD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* high level addition (handles signs) */ +int mp_add (mp_int * a, mp_int * b, mp_int * c) +{ + int sa, sb, res; + + /* 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; + res = 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; + res = s_mp_sub (b, a, c); + } else { + c->sign = sa; + res = s_mp_sub (a, b, c); + } + } + return res; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_add.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_add_d.c b/libtommath/bn_mp_add_d.c new file mode 100644 index 0000000..5af5aa9 --- /dev/null +++ b/libtommath/bn_mp_add_d.c @@ -0,0 +1,112 @@ +#include <tommath.h> +#ifdef BN_MP_ADD_D_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* single digit addition */ +int +mp_add_d (mp_int * a, mp_digit b, mp_int * c) +{ + int res, ix, oldused; + mp_digit *tmpa, *tmpc, mu; + + /* grow c as required */ + if (c->alloc < a->used + 1) { + if ((res = mp_grow(c, a->used + 1)) != MP_OKAY) { + return res; + } + } + + /* if a is negative and |a| >= b, call c = |a| - b */ + if (a->sign == MP_NEG && (a->used > 1 || a->dp[0] >= b)) { + /* temporarily fix sign of a */ + a->sign = MP_ZPOS; + + /* c = |a| - b */ + res = mp_sub_d(a, b, c); + + /* fix sign */ + a->sign = c->sign = MP_NEG; + + /* clamp */ + mp_clamp(c); + + return res; + } + + /* old number of used digits in c */ + oldused = c->used; + + /* sign always positive */ + c->sign = MP_ZPOS; + + /* source alias */ + tmpa = a->dp; + + /* destination alias */ + tmpc = c->dp; + + /* if a is positive */ + if (a->sign == MP_ZPOS) { + /* 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; + } + /* 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; + } + + /* now zero to oldused */ + while (ix++ < oldused) { + *tmpc++ = 0; + } + mp_clamp(c); + + return MP_OKAY; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_add_d.c,v $ */ +/* $Revision: 1.4 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_addmod.c b/libtommath/bn_mp_addmod.c new file mode 100644 index 0000000..d3b3ac4 --- /dev/null +++ b/libtommath/bn_mp_addmod.c @@ -0,0 +1,41 @@ +#include <tommath.h> +#ifdef BN_MP_ADDMOD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* d = a + b (mod c) */ +int +mp_addmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + int res; + mp_int t; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_add (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, c, d); + mp_clear (&t); + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_addmod.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_and.c b/libtommath/bn_mp_and.c new file mode 100644 index 0000000..9a2c0ee --- /dev/null +++ b/libtommath/bn_mp_and.c @@ -0,0 +1,57 @@ +#include <tommath.h> +#ifdef BN_MP_AND_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* AND two ints together */ +int +mp_and (mp_int * a, mp_int * b, mp_int * c) +{ + int res, ix, px; + mp_int t, *x; + + if (a->used > b->used) { + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + px = b->used; + x = b; + } else { + if ((res = mp_init_copy (&t, b)) != MP_OKAY) { + return res; + } + px = a->used; + x = a; + } + + for (ix = 0; ix < px; ix++) { + t.dp[ix] &= x->dp[ix]; + } + + /* zero digits above the last from the smallest mp_int */ + for (; ix < t.used; ix++) { + t.dp[ix] = 0; + } + + mp_clamp (&t); + mp_exch (c, &t); + mp_clear (&t); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_and.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_clamp.c b/libtommath/bn_mp_clamp.c new file mode 100644 index 0000000..da4e1ef --- /dev/null +++ b/libtommath/bn_mp_clamp.c @@ -0,0 +1,44 @@ +#include <tommath.h> +#ifdef BN_MP_CLAMP_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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] == 0) { + --(a->used); + } + + /* reset the sign flag if used == 0 */ + if (a->used == 0) { + a->sign = MP_ZPOS; + } +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_clamp.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_clear.c b/libtommath/bn_mp_clear.c new file mode 100644 index 0000000..000bd06 --- /dev/null +++ b/libtommath/bn_mp_clear.c @@ -0,0 +1,47 @@ +#include <tommath.h> +#ifdef BN_MP_CLEAR_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* clear one (frees) */ +void +mp_clear (mp_int * a) +{ + volatile mp_digit *p; + int len; + + /* only do anything if a hasn't been freed previously */ + if (a->dp != NULL) { + /* first zero the digits */ + len = a->alloc; + p = a->dp; + while (len--) { + *p++ = 0; + } + + /* free ram */ + XFREE(a->dp); + + /* reset members to make debugging easier */ + a->dp = NULL; + a->alloc = a->used = 0; + a->sign = MP_ZPOS; + } +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_clear.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_clear_multi.c b/libtommath/bn_mp_clear_multi.c new file mode 100644 index 0000000..e1859be --- /dev/null +++ b/libtommath/bn_mp_clear_multi.c @@ -0,0 +1,34 @@ +#include <tommath.h> +#ifdef BN_MP_CLEAR_MULTI_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ +#include <stdarg.h> + +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 + +/* $Source: /cvs/libtom/libtommath/bn_mp_clear_multi.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_cmp.c b/libtommath/bn_mp_cmp.c new file mode 100644 index 0000000..f4e2af7 --- /dev/null +++ b/libtommath/bn_mp_cmp.c @@ -0,0 +1,43 @@ +#include <tommath.h> +#ifdef BN_MP_CMP_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* compare two ints (signed)*/ +int +mp_cmp (mp_int * a, 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 + +/* $Source: /cvs/libtom/libtommath/bn_mp_cmp.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_cmp_d.c b/libtommath/bn_mp_cmp_d.c new file mode 100644 index 0000000..20a19bc --- /dev/null +++ b/libtommath/bn_mp_cmp_d.c @@ -0,0 +1,44 @@ +#include <tommath.h> +#ifdef BN_MP_CMP_D_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* compare a digit */ +int mp_cmp_d(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 + +/* $Source: /cvs/libtom/libtommath/bn_mp_cmp_d.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_cmp_mag.c b/libtommath/bn_mp_cmp_mag.c new file mode 100644 index 0000000..5dc7a3f --- /dev/null +++ b/libtommath/bn_mp_cmp_mag.c @@ -0,0 +1,55 @@ +#include <tommath.h> +#ifdef BN_MP_CMP_MAG_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* compare maginitude of two ints (unsigned) */ +int mp_cmp_mag (mp_int * a, mp_int * b) +{ + int n; + 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 + +/* $Source: /cvs/libtom/libtommath/bn_mp_cmp_mag.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_cnt_lsb.c b/libtommath/bn_mp_cnt_lsb.c new file mode 100644 index 0000000..017b990 --- /dev/null +++ b/libtommath/bn_mp_cnt_lsb.c @@ -0,0 +1,53 @@ +#include <tommath.h> +#ifdef BN_MP_CNT_LSB_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +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(mp_int *a) +{ + int x; + mp_digit q, qq; + + /* easy out */ + if (mp_iszero(a) == 1) { + return 0; + } + + /* scan lower digits until non-zero */ + for (x = 0; x < a->used && a->dp[x] == 0; x++); + q = a->dp[x]; + x *= DIGIT_BIT; + + /* now scan this digit until a 1 is found */ + if ((q & 1) == 0) { + do { + qq = q & 15; + x += lnz[qq]; + q >>= 4; + } while (qq == 0); + } + return x; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_cnt_lsb.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_copy.c b/libtommath/bn_mp_copy.c new file mode 100644 index 0000000..d820397 --- /dev/null +++ b/libtommath/bn_mp_copy.c @@ -0,0 +1,68 @@ +#include <tommath.h> +#ifdef BN_MP_COPY_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* copy, b = a */ +int +mp_copy (mp_int * a, mp_int * b) +{ + int res, n; + + /* if dst == src do nothing */ + if (a == b) { + return MP_OKAY; + } + + /* grow dest */ + if (b->alloc < a->used) { + if ((res = mp_grow (b, a->used)) != MP_OKAY) { + return res; + } + } + + /* zero b and copy the parameters over */ + { + register mp_digit *tmpa, *tmpb; + + /* 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 */ + for (; n < b->used; n++) { + *tmpb++ = 0; + } + } + + /* copy used count and sign */ + b->used = a->used; + b->sign = a->sign; + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_copy.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_count_bits.c b/libtommath/bn_mp_count_bits.c new file mode 100644 index 0000000..ff4db22 --- /dev/null +++ b/libtommath/bn_mp_count_bits.c @@ -0,0 +1,45 @@ +#include <tommath.h> +#ifdef BN_MP_COUNT_BITS_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* returns the number of bits in an int */ +int +mp_count_bits (mp_int * a) +{ + int r; + mp_digit q; + + /* shortcut */ + if (a->used == 0) { + return 0; + } + + /* get number of digits and add that */ + r = (a->used - 1) * DIGIT_BIT; + + /* take the last digit and count the bits in it */ + q = a->dp[a->used - 1]; + while (q > ((mp_digit) 0)) { + ++r; + q >>= ((mp_digit) 1); + } + return r; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_count_bits.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_div.c b/libtommath/bn_mp_div.c new file mode 100644 index 0000000..f4aa1aa --- /dev/null +++ b/libtommath/bn_mp_div.c @@ -0,0 +1,294 @@ +#include <tommath.h> +#ifdef BN_MP_DIV_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +#ifdef BN_MP_DIV_SMALL + +/* slower bit-bang division... also smaller */ +int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + mp_int ta, tb, tq, q; + int res, n, n2; + + /* is divisor zero ? */ + if (mp_iszero (b) == 1) { + return MP_VAL; + } + + /* if a < b then q=0, r = a */ + if (mp_cmp_mag (a, b) == MP_LT) { + if (d != NULL) { + res = mp_copy (a, d); + } else { + res = MP_OKAY; + } + if (c != NULL) { + mp_zero (c); + } + return res; + } + + /* init our temps */ + if ((res = mp_init_multi(&ta, &tb, &tq, &q, NULL) != MP_OKAY)) { + return res; + } + + + mp_set(&tq, 1); + n = mp_count_bits(a) - mp_count_bits(b); + if (((res = mp_abs(a, &ta)) != MP_OKAY) || + ((res = mp_abs(b, &tb)) != MP_OKAY) || + ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) || + ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) { + goto LBL_ERR; + } + + while (n-- >= 0) { + if (mp_cmp(&tb, &ta) != MP_GT) { + if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) || + ((res = mp_add(&q, &tq, &q)) != MP_OKAY)) { + goto LBL_ERR; + } + } + if (((res = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) || + ((res = 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_iszero(c) == MP_YES) ? MP_ZPOS : n2; + } + if (d != NULL) { + mp_exch(d, &ta); + d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n; + } +LBL_ERR: + mp_clear_multi(&ta, &tb, &tq, &q, NULL); + return res; +} + +#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. +*/ +int mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + mp_int q, x, y, t1, t2; + int res, n, t, i, norm, neg; + + /* is divisor zero ? */ + if (mp_iszero (b) == 1) { + return MP_VAL; + } + + /* if a < b then q=0, r = a */ + if (mp_cmp_mag (a, b) == MP_LT) { + if (d != NULL) { + res = mp_copy (a, d); + } else { + res = MP_OKAY; + } + if (c != NULL) { + mp_zero (c); + } + return res; + } + + if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) { + return res; + } + q.used = a->used + 2; + + if ((res = mp_init (&t1)) != MP_OKAY) { + goto LBL_Q; + } + + if ((res = mp_init (&t2)) != MP_OKAY) { + goto LBL_T1; + } + + if ((res = mp_init_copy (&x, a)) != MP_OKAY) { + goto LBL_T2; + } + + if ((res = 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**DIGIT_BIT] */ + norm = mp_count_bits(&y) % DIGIT_BIT; + if (norm < (int)(DIGIT_BIT-1)) { + norm = (DIGIT_BIT-1) - norm; + if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) { + goto LBL_Y; + } + if ((res = 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} } */ + if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b**{n-t} */ + goto LBL_Y; + } + + while (mp_cmp (&x, &y) != MP_LT) { + ++(q.dp[n - t]); + if ((res = 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) << DIGIT_BIT) - 1); + } else { + mp_word tmp; + tmp = ((mp_word) x.dp[i]) << ((mp_word) 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] + 1) & MP_MASK; + do { + q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK; + + /* find left hand */ + mp_zero (&t1); + t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1]; + t1.dp[1] = y.dp[t]; + t1.used = 2; + if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) { + goto LBL_Y; + } + + /* find right hand */ + t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2]; + t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1]; + 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 ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) { + goto LBL_Y; + } + + if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { + goto LBL_Y; + } + + if ((res = 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 ((res = mp_copy (&y, &t1)) != MP_OKAY) { + goto LBL_Y; + } + if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { + goto LBL_Y; + } + if ((res = 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 ((res = mp_div_2d (&x, norm, &x, NULL)) != MP_OKAY) { + goto LBL_Y; + } + mp_exch (&x, d); + } + + res = 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 res; +} + +#endif + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_div.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_div_2.c b/libtommath/bn_mp_div_2.c new file mode 100644 index 0000000..0035e56 --- /dev/null +++ b/libtommath/bn_mp_div_2.c @@ -0,0 +1,68 @@ +#include <tommath.h> +#ifdef BN_MP_DIV_2_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* b = a/2 */ +int mp_div_2(mp_int * a, mp_int * b) +{ + int x, res, oldused; + + /* copy */ + if (b->alloc < a->used) { + if ((res = mp_grow (b, a->used)) != MP_OKAY) { + return res; + } + } + + oldused = b->used; + b->used = a->used; + { + register mp_digit r, rr, *tmpa, *tmpb; + + /* 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 & 1; + + /* shift the current digit, add in carry and store */ + *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1)); + + /* forward carry to next iteration */ + r = rr; + } + + /* zero excess digits */ + tmpb = b->dp + b->used; + for (x = b->used; x < oldused; x++) { + *tmpb++ = 0; + } + } + b->sign = a->sign; + mp_clamp (b); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_div_2.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_div_2d.c b/libtommath/bn_mp_div_2d.c new file mode 100644 index 0000000..6c18d80 --- /dev/null +++ b/libtommath/bn_mp_div_2d.c @@ -0,0 +1,97 @@ +#include <tommath.h> +#ifdef BN_MP_DIV_2D_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* shift right by a certain bit count (store quotient in c, optional remainder in d) */ +int mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d) +{ + mp_digit D, r, rr; + int x, res; + mp_int t; + + + /* if the shift count is <= 0 then we do no work */ + if (b <= 0) { + res = mp_copy (a, c); + if (d != NULL) { + mp_zero (d); + } + return res; + } + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + /* get the remainder */ + if (d != NULL) { + if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + } + + /* copy */ + if ((res = mp_copy (a, c)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + /* shift by as many digits in the bit count */ + if (b >= (int)DIGIT_BIT) { + mp_rshd (c, b / DIGIT_BIT); + } + + /* shift any bit count < DIGIT_BIT */ + D = (mp_digit) (b % DIGIT_BIT); + if (D != 0) { + register mp_digit *tmpc, mask, shift; + + /* mask */ + mask = (((mp_digit)1) << D) - 1; + + /* shift for lsb */ + shift = 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); + if (d != NULL) { + mp_exch (&t, d); + } + mp_clear (&t); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_div_2d.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_div_3.c b/libtommath/bn_mp_div_3.c new file mode 100644 index 0000000..c6090f4 --- /dev/null +++ b/libtommath/bn_mp_div_3.c @@ -0,0 +1,79 @@ +#include <tommath.h> +#ifdef BN_MP_DIV_3_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* divide by three (based on routine from MPI and the GMP manual) */ +int +mp_div_3 (mp_int * a, mp_int *c, mp_digit * d) +{ + mp_int q; + mp_word w, t; + mp_digit b; + int res, ix; + + /* b = 2**DIGIT_BIT / 3 */ + b = (((mp_word)1) << ((mp_word)DIGIT_BIT)) / ((mp_word)3); + + if ((res = mp_init_size(&q, a->used)) != MP_OKAY) { + return res; + } + + q.used = a->used; + q.sign = a->sign; + w = 0; + for (ix = a->used - 1; ix >= 0; ix--) { + w = (w << ((mp_word)DIGIT_BIT)) | ((mp_word)a->dp[ix]); + + if (w >= 3) { + /* multiply w by [1/3] */ + t = (w * ((mp_word)b)) >> ((mp_word)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 >= 3) { + t += 1; + w -= 3; + } + } 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 res; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_div_3.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_div_d.c b/libtommath/bn_mp_div_d.c new file mode 100644 index 0000000..771aa6a --- /dev/null +++ b/libtommath/bn_mp_div_d.c @@ -0,0 +1,110 @@ +#include <tommath.h> +#ifdef BN_MP_DIV_D_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +static int s_is_power_of_two(mp_digit b, int *p) +{ + int x; + + for (x = 1; x < DIGIT_BIT; x++) { + if (b == (((mp_digit)1)<<x)) { + *p = x; + return 1; + } + } + return 0; +} + +/* single digit division (based on routine from MPI) */ +int mp_div_d (mp_int * a, mp_digit b, mp_int * c, mp_digit * d) +{ + mp_int q; + mp_word w; + mp_digit t; + int res, ix; + + /* cannot divide by zero */ + if (b == 0) { + return MP_VAL; + } + + /* quick outs */ + if (b == 1 || mp_iszero(a) == 1) { + if (d != NULL) { + *d = 0; + } + if (c != NULL) { + return mp_copy(a, c); + } + return MP_OKAY; + } + + /* power of two ? */ + if (s_is_power_of_two(b, &ix) == 1) { + if (d != NULL) { + *d = a->dp[0] & ((((mp_digit)1)<<ix) - 1); + } + if (c != NULL) { + return mp_div_2d(a, ix, c, NULL); + } + return MP_OKAY; + } + +#ifdef BN_MP_DIV_3_C + /* three? */ + if (b == 3) { + return mp_div_3(a, c, d); + } +#endif + + /* no easy answer [c'est la vie]. Just division */ + if ((res = mp_init_size(&q, a->used)) != MP_OKAY) { + return res; + } + + q.used = a->used; + q.sign = a->sign; + w = 0; + for (ix = a->used - 1; ix >= 0; ix--) { + w = (w << ((mp_word)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] = (mp_digit)t; + } + + if (d != NULL) { + *d = (mp_digit)w; + } + + if (c != NULL) { + mp_clamp(&q); + mp_exch(&q, c); + } + mp_clear(&q); + + return res; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_div_d.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_dr_is_modulus.c b/libtommath/bn_mp_dr_is_modulus.c new file mode 100644 index 0000000..e9223f3 --- /dev/null +++ b/libtommath/bn_mp_dr_is_modulus.c @@ -0,0 +1,43 @@ +#include <tommath.h> +#ifdef BN_MP_DR_IS_MODULUS_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* determines if a number is a valid DR modulus */ +int mp_dr_is_modulus(mp_int *a) +{ + int ix; + + /* must be at least two digits */ + if (a->used < 2) { + return 0; + } + + /* 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 0; + } + } + return 1; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_dr_is_modulus.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_dr_reduce.c b/libtommath/bn_mp_dr_reduce.c new file mode 100644 index 0000000..d2ef18f --- /dev/null +++ b/libtommath/bn_mp_dr_reduce.c @@ -0,0 +1,94 @@ +#include <tommath.h> +#ifdef BN_MP_DR_REDUCE_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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 + */ +int +mp_dr_reduce (mp_int * x, mp_int * n, mp_digit k) +{ + int err, 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)DIGIT_BIT)); + } + + /* set final carry */ + *tmpx1++ = mu; + + /* zero words above m */ + for (i = m + 1; i < x->used; i++) { + *tmpx1++ = 0; + } + + /* 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) { + s_mp_sub(x, n, x); + goto top; + } + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_dr_reduce.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_dr_setup.c b/libtommath/bn_mp_dr_setup.c new file mode 100644 index 0000000..3e82c9b --- /dev/null +++ b/libtommath/bn_mp_dr_setup.c @@ -0,0 +1,32 @@ +#include <tommath.h> +#ifdef BN_MP_DR_SETUP_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* determines the setup value */ +void mp_dr_setup(mp_int *a, mp_digit *d) +{ + /* the casts are required if DIGIT_BIT is one less than + * the number of bits in a mp_digit [e.g. DIGIT_BIT==31] + */ + *d = (mp_digit)((((mp_word)1) << ((mp_word)DIGIT_BIT)) - + ((mp_word)a->dp[0])); +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_dr_setup.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_exch.c b/libtommath/bn_mp_exch.c new file mode 100644 index 0000000..81a42ac --- /dev/null +++ b/libtommath/bn_mp_exch.c @@ -0,0 +1,34 @@ +#include <tommath.h> +#ifdef BN_MP_EXCH_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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 + +/* $Source: /cvs/libtom/libtommath/bn_mp_exch.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_expt_d.c b/libtommath/bn_mp_expt_d.c new file mode 100644 index 0000000..656cf68 --- /dev/null +++ b/libtommath/bn_mp_expt_d.c @@ -0,0 +1,57 @@ +#include <tommath.h> +#ifdef BN_MP_EXPT_D_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* calculate c = a**b using a square-multiply algorithm */ +int mp_expt_d (mp_int * a, mp_digit b, mp_int * c) +{ + int res, x; + mp_int g; + + if ((res = mp_init_copy (&g, a)) != MP_OKAY) { + return res; + } + + /* set initial result */ + mp_set (c, 1); + + for (x = 0; x < (int) DIGIT_BIT; x++) { + /* square */ + if ((res = mp_sqr (c, c)) != MP_OKAY) { + mp_clear (&g); + return res; + } + + /* if the bit is set multiply */ + if ((b & (mp_digit) (((mp_digit)1) << (DIGIT_BIT - 1))) != 0) { + if ((res = mp_mul (c, &g, c)) != MP_OKAY) { + mp_clear (&g); + return res; + } + } + + /* shift to next bit */ + b <<= 1; + } + + mp_clear (&g); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_expt_d.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_exptmod.c b/libtommath/bn_mp_exptmod.c new file mode 100644 index 0000000..d72ab20 --- /dev/null +++ b/libtommath/bn_mp_exptmod.c @@ -0,0 +1,112 @@ +#include <tommath.h> +#ifdef BN_MP_EXPTMOD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + + +/* 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) + */ +int mp_exptmod (mp_int * G, mp_int * X, 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) { +#ifdef BN_MP_INVMOD_C + mp_int tmpG, tmpX; + int err; + + /* first compute 1/G mod P */ + if ((err = mp_init(&tmpG)) != MP_OKAY) { + return err; + } + if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) { + mp_clear(&tmpG); + return err; + } + + /* now get |X| */ + if ((err = mp_init(&tmpX)) != MP_OKAY) { + mp_clear(&tmpG); + return err; + } + if ((err = mp_abs(X, &tmpX)) != MP_OKAY) { + mp_clear_multi(&tmpG, &tmpX, NULL); + return err; + } + + /* and now compute (1/G)**|X| instead of G**X [X < 0] */ + err = mp_exptmod(&tmpG, &tmpX, P, Y); + mp_clear_multi(&tmpG, &tmpX, NULL); + return err; +#else + /* no invmod */ + return MP_VAL; +#endif + } + +/* modified diminished radix reduction */ +#if defined(BN_MP_REDUCE_IS_2K_L_C) && defined(BN_MP_REDUCE_2K_L_C) && defined(BN_S_MP_EXPTMOD_C) + if (mp_reduce_is_2k_l(P) == MP_YES) { + return s_mp_exptmod(G, X, P, Y, 1); + } +#endif + +#ifdef BN_MP_DR_IS_MODULUS_C + /* is it a DR modulus? */ + dr = mp_dr_is_modulus(P); +#else + /* default to no */ + dr = 0; +#endif + +#ifdef BN_MP_REDUCE_IS_2K_C + /* if not, is it a unrestricted DR modulus? */ + if (dr == 0) { + dr = mp_reduce_is_2k(P) << 1; + } +#endif + + /* if the modulus is odd or dr != 0 use the montgomery method */ +#ifdef BN_MP_EXPTMOD_FAST_C + if (mp_isodd (P) == 1 || dr != 0) { + return mp_exptmod_fast (G, X, P, Y, dr); + } else { +#endif +#ifdef BN_S_MP_EXPTMOD_C + /* 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 +#ifdef BN_MP_EXPTMOD_FAST_C + } +#endif +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_exptmod.c,v $ */ +/* $Revision: 1.4 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_exptmod_fast.c b/libtommath/bn_mp_exptmod_fast.c new file mode 100644 index 0000000..32f8f16 --- /dev/null +++ b/libtommath/bn_mp_exptmod_fast.c @@ -0,0 +1,321 @@ +#include <tommath.h> +#ifdef BN_MP_EXPTMOD_FAST_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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 +#else + #define TAB_SIZE 256 +#endif + +int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) +{ + mp_int M[TAB_SIZE], res; + mp_digit buf, mp; + int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + + /* 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. + */ + int (*redux)(mp_int*,mp_int*,mp_digit); + + /* 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; + } + +#ifdef MP_LOW_MEM + if (winsize > 5) { + winsize = 5; + } +#endif + + /* 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; + } + } + + /* determine and setup reduction code */ + if (redmode == 0) { +#ifdef BN_MP_MONTGOMERY_SETUP_C + /* now setup montgomery */ + if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) { + goto LBL_M; + } +#else + err = MP_VAL; + goto LBL_M; +#endif + + /* automatically pick the comba one if available (saves quite a few calls/ifs) */ +#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C + if (((P->used * 2 + 1) < MP_WARRAY) && + P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + redux = fast_mp_montgomery_reduce; + } else +#endif + { +#ifdef BN_MP_MONTGOMERY_REDUCE_C + /* use slower baseline Montgomery method */ + redux = mp_montgomery_reduce; +#else + err = MP_VAL; + goto LBL_M; +#endif + } + } else if (redmode == 1) { +#if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C) + /* 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; +#endif + } else { +#if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C) + /* 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; +#endif + } + + /* setup result */ + if ((err = mp_init (&res)) != 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) { +#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 + + /* now set M[1] to G * R mod m */ + if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) { + goto LBL_RES; + } + } else { + mp_set(&res, 1); + 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[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_RES; + } + + for (x = 0; x < (winsize - 1); x++) { + if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&M[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)DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1; + 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 + + +/* $Source: /cvs/libtom/libtommath/bn_mp_exptmod_fast.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_exteuclid.c b/libtommath/bn_mp_exteuclid.c new file mode 100644 index 0000000..25ccba9 --- /dev/null +++ b/libtommath/bn_mp_exteuclid.c @@ -0,0 +1,82 @@ +#include <tommath.h> +#ifdef BN_MP_EXTEUCLID_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* Extended euclidean algorithm of (a, b) produces + a*u1 + b*u2 = u3 + */ +int mp_exteuclid(mp_int *a, 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; + int 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, 1); + if ((err = mp_copy(a, &u3)) != MP_OKAY) { goto _ERR; } + + /* initialize, (v1,v2,v3) = (0,1,b) */ + mp_set(&v2, 1); + if ((err = mp_copy(b, &v3)) != MP_OKAY) { goto _ERR; } + + /* loop while v3 != 0 */ + while (mp_iszero(&v3) == MP_NO) { + /* q = u3/v3 */ + if ((err = mp_div(&u3, &v3, &q, NULL)) != MP_OKAY) { goto _ERR; } + + /* (t1,t2,t3) = (u1,u2,u3) - (v1,v2,v3)q */ + if ((err = mp_mul(&v1, &q, &tmp)) != MP_OKAY) { goto _ERR; } + if ((err = mp_sub(&u1, &tmp, &t1)) != MP_OKAY) { goto _ERR; } + if ((err = mp_mul(&v2, &q, &tmp)) != MP_OKAY) { goto _ERR; } + if ((err = mp_sub(&u2, &tmp, &t2)) != MP_OKAY) { goto _ERR; } + if ((err = mp_mul(&v3, &q, &tmp)) != MP_OKAY) { goto _ERR; } + if ((err = mp_sub(&u3, &tmp, &t3)) != MP_OKAY) { goto _ERR; } + + /* (u1,u2,u3) = (v1,v2,v3) */ + if ((err = mp_copy(&v1, &u1)) != MP_OKAY) { goto _ERR; } + if ((err = mp_copy(&v2, &u2)) != MP_OKAY) { goto _ERR; } + if ((err = mp_copy(&v3, &u3)) != MP_OKAY) { goto _ERR; } + + /* (v1,v2,v3) = (t1,t2,t3) */ + if ((err = mp_copy(&t1, &v1)) != MP_OKAY) { goto _ERR; } + if ((err = mp_copy(&t2, &v2)) != MP_OKAY) { goto _ERR; } + if ((err = mp_copy(&t3, &v3)) != MP_OKAY) { goto _ERR; } + } + + /* make sure U3 >= 0 */ + if (u3.sign == MP_NEG) { + mp_neg(&u1, &u1); + mp_neg(&u2, &u2); + mp_neg(&u3, &u3); + } + + /* 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; +_ERR: mp_clear_multi(&u1, &u2, &u3, &v1, &v2, &v3, &t1, &t2, &t3, &q, &tmp, NULL); + return err; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_exteuclid.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_fread.c b/libtommath/bn_mp_fread.c new file mode 100644 index 0000000..c3bd08d --- /dev/null +++ b/libtommath/bn_mp_fread.c @@ -0,0 +1,67 @@ +#include <tommath.h> +#ifdef BN_MP_FREAD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* read a bigint from a file stream in ASCII */ +int mp_fread(mp_int *a, int radix, FILE *stream) +{ + int err, ch, neg, y; + + /* clear a */ + mp_zero(a); + + /* if first digit is - then set negative */ + ch = fgetc(stream); + if (ch == '-') { + neg = MP_NEG; + ch = fgetc(stream); + } else { + neg = MP_ZPOS; + } + + for (;;) { + /* find y in the radix map */ + for (y = 0; y < radix; y++) { + if (mp_s_rmap[y] == ch) { + break; + } + } + if (y == radix) { + break; + } + + /* shift up and add */ + if ((err = mp_mul_d(a, radix, a)) != MP_OKAY) { + return err; + } + if ((err = mp_add_d(a, y, a)) != MP_OKAY) { + return err; + } + + ch = fgetc(stream); + } + if (mp_cmp_d(a, 0) != MP_EQ) { + a->sign = neg; + } + + return MP_OKAY; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_fread.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_fwrite.c b/libtommath/bn_mp_fwrite.c new file mode 100644 index 0000000..006f923 --- /dev/null +++ b/libtommath/bn_mp_fwrite.c @@ -0,0 +1,52 @@ +#include <tommath.h> +#ifdef BN_MP_FWRITE_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +int mp_fwrite(mp_int *a, int radix, FILE *stream) +{ + char *buf; + int err, len, x; + + if ((err = mp_radix_size(a, radix, &len)) != MP_OKAY) { + return err; + } + + buf = OPT_CAST(char) XMALLOC (len); + if (buf == NULL) { + return MP_MEM; + } + + if ((err = mp_toradix(a, buf, radix)) != MP_OKAY) { + XFREE (buf); + return err; + } + + for (x = 0; x < len; x++) { + if (fputc(buf[x], stream) == EOF) { + XFREE (buf); + return MP_VAL; + } + } + + XFREE (buf); + return MP_OKAY; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_fwrite.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_gcd.c b/libtommath/bn_mp_gcd.c new file mode 100644 index 0000000..23f6b02 --- /dev/null +++ b/libtommath/bn_mp_gcd.c @@ -0,0 +1,105 @@ +#include <tommath.h> +#ifdef BN_MP_GCD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* Greatest Common Divisor using the binary method */ +int mp_gcd (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int u, v; + int k, u_lsb, v_lsb, res; + + /* either zero than gcd is the largest */ + if (mp_iszero (a) == MP_YES) { + return mp_abs (b, c); + } + if (mp_iszero (b) == MP_YES) { + return mp_abs (a, c); + } + + /* get copies of a and b we can modify */ + if ((res = mp_init_copy (&u, a)) != MP_OKAY) { + return res; + } + + if ((res = 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 = MIN(u_lsb, v_lsb); + + if (k > 0) { + /* divide the power of two out */ + if ((res = mp_div_2d(&u, k, &u, NULL)) != MP_OKAY) { + goto LBL_V; + } + + if ((res = mp_div_2d(&v, k, &v, NULL)) != MP_OKAY) { + goto LBL_V; + } + } + + /* divide any remaining factors of two out */ + if (u_lsb != k) { + if ((res = mp_div_2d(&u, u_lsb - k, &u, NULL)) != MP_OKAY) { + goto LBL_V; + } + } + + if (v_lsb != k) { + if ((res = mp_div_2d(&v, v_lsb - k, &v, NULL)) != MP_OKAY) { + goto LBL_V; + } + } + + while (mp_iszero(&v) == 0) { + /* 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 ((res = s_mp_sub(&v, &u, &v)) != MP_OKAY) { + goto LBL_V; + } + + /* Divide out all factors of two */ + if ((res = 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 ((res = mp_mul_2d (&u, k, c)) != MP_OKAY) { + goto LBL_V; + } + c->sign = MP_ZPOS; + res = MP_OKAY; +LBL_V:mp_clear (&u); +LBL_U:mp_clear (&v); + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_gcd.c,v $ */ +/* $Revision: 1.4 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_get_int.c b/libtommath/bn_mp_get_int.c new file mode 100644 index 0000000..7948d46 --- /dev/null +++ b/libtommath/bn_mp_get_int.c @@ -0,0 +1,45 @@ +#include <tommath.h> +#ifdef BN_MP_GET_INT_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* get the lower 32-bits of an mp_int */ +unsigned long mp_get_int(mp_int * a) +{ + int i; + unsigned long res; + + if (a->used == 0) { + return 0; + } + + /* get number of digits of the lsb we have to read */ + i = MIN(a->used,(int)((sizeof(unsigned long)*CHAR_BIT+DIGIT_BIT-1)/DIGIT_BIT))-1; + + /* get most significant digit of result */ + res = DIGIT(a,i); + + while (--i >= 0) { + res = (res << DIGIT_BIT) | DIGIT(a,i); + } + + /* force result to 32-bits always so it is consistent on non 32-bit platforms */ + return res & 0xFFFFFFFFUL; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_get_int.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_grow.c b/libtommath/bn_mp_grow.c new file mode 100644 index 0000000..2d50058 --- /dev/null +++ b/libtommath/bn_mp_grow.c @@ -0,0 +1,57 @@ +#include <tommath.h> +#ifdef BN_MP_GROW_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* grow as required */ +int mp_grow (mp_int * a, int size) +{ + int i; + mp_digit *tmp; + + /* if the alloc size is smaller alloc more ram */ + if (a->alloc < size) { + /* ensure there are always at least MP_PREC digits extra on top */ + size += (MP_PREC * 2) - (size % MP_PREC); + + /* 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 = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * size); + 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; + for (; i < a->alloc; i++) { + a->dp[i] = 0; + } + } + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_grow.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_init.c b/libtommath/bn_mp_init.c new file mode 100644 index 0000000..565ea47 --- /dev/null +++ b/libtommath/bn_mp_init.c @@ -0,0 +1,46 @@ +#include <tommath.h> +#ifdef BN_MP_INIT_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* init a new mp_int */ +int mp_init (mp_int * a) +{ + int i; + + /* allocate memory required and clear it */ + a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * MP_PREC); + if (a->dp == NULL) { + return MP_MEM; + } + + /* set the digits to zero */ + for (i = 0; i < MP_PREC; i++) { + a->dp[i] = 0; + } + + /* 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 + +/* $Source: /cvs/libtom/libtommath/bn_mp_init.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_init_copy.c b/libtommath/bn_mp_init_copy.c new file mode 100644 index 0000000..8e7329c --- /dev/null +++ b/libtommath/bn_mp_init_copy.c @@ -0,0 +1,32 @@ +#include <tommath.h> +#ifdef BN_MP_INIT_COPY_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* creates "a" then copies b into it */ +int mp_init_copy (mp_int * a, mp_int * b) +{ + int res; + + if ((res = mp_init (a)) != MP_OKAY) { + return res; + } + return mp_copy (b, a); +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_init_copy.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_init_multi.c b/libtommath/bn_mp_init_multi.c new file mode 100644 index 0000000..d592f43 --- /dev/null +++ b/libtommath/bn_mp_init_multi.c @@ -0,0 +1,59 @@ +#include <tommath.h> +#ifdef BN_MP_INIT_MULTI_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ +#include <stdarg.h> + +int mp_init_multi(mp_int *mp, ...) +{ + mp_err res = 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; + + /* end the current list */ + va_end(args); + + /* now start cleaning up */ + cur_arg = mp; + va_start(clean_args, mp); + while (n--) { + mp_clear(cur_arg); + cur_arg = va_arg(clean_args, mp_int*); + } + va_end(clean_args); + res = MP_MEM; + break; + } + n++; + cur_arg = va_arg(args, mp_int*); + } + va_end(args); + return res; /* Assumed ok, if error flagged above. */ +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_init_multi.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_init_set.c b/libtommath/bn_mp_init_set.c new file mode 100644 index 0000000..a7ee8f7 --- /dev/null +++ b/libtommath/bn_mp_init_set.c @@ -0,0 +1,32 @@ +#include <tommath.h> +#ifdef BN_MP_INIT_SET_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* initialize and set a digit */ +int mp_init_set (mp_int * a, mp_digit b) +{ + int err; + if ((err = mp_init(a)) != MP_OKAY) { + return err; + } + mp_set(a, b); + return err; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_init_set.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_init_set_int.c b/libtommath/bn_mp_init_set_int.c new file mode 100644 index 0000000..7c9dd46 --- /dev/null +++ b/libtommath/bn_mp_init_set_int.c @@ -0,0 +1,31 @@ +#include <tommath.h> +#ifdef BN_MP_INIT_SET_INT_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* initialize and set a digit */ +int mp_init_set_int (mp_int * a, unsigned long b) +{ + int err; + if ((err = mp_init(a)) != MP_OKAY) { + return err; + } + return mp_set_int(a, b); +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_init_set_int.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_init_size.c b/libtommath/bn_mp_init_size.c new file mode 100644 index 0000000..4aebd1f --- /dev/null +++ b/libtommath/bn_mp_init_size.c @@ -0,0 +1,48 @@ +#include <tommath.h> +#ifdef BN_MP_INIT_SIZE_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* init an mp_init for a given size */ +int mp_init_size (mp_int * a, int size) +{ + int x; + + /* pad size so there are always extra digits */ + size += (MP_PREC * 2) - (size % MP_PREC); + + /* alloc mem */ + a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * size); + if (a->dp == NULL) { + return MP_MEM; + } + + /* set the members */ + a->used = 0; + a->alloc = size; + a->sign = MP_ZPOS; + + /* zero the digits */ + for (x = 0; x < size; x++) { + a->dp[x] = 0; + } + + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_init_size.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_invmod.c b/libtommath/bn_mp_invmod.c new file mode 100644 index 0000000..3f5791f --- /dev/null +++ b/libtommath/bn_mp_invmod.c @@ -0,0 +1,43 @@ +#include <tommath.h> +#ifdef BN_MP_INVMOD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* hac 14.61, pp608 */ +int mp_invmod (mp_int * a, mp_int * b, mp_int * c) +{ + /* b cannot be negative */ + if (b->sign == MP_NEG || mp_iszero(b) == 1) { + return MP_VAL; + } + +#ifdef BN_FAST_MP_INVMOD_C + /* if the modulus is odd we can use a faster routine instead */ + if (mp_isodd (b) == 1) { + return fast_mp_invmod (a, b, c); + } +#endif + +#ifdef BN_MP_INVMOD_SLOW_C + return mp_invmod_slow(a, b, c); +#endif + + return MP_VAL; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_invmod.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_invmod_slow.c b/libtommath/bn_mp_invmod_slow.c new file mode 100644 index 0000000..a4e4fbc --- /dev/null +++ b/libtommath/bn_mp_invmod_slow.c @@ -0,0 +1,175 @@ +#include <tommath.h> +#ifdef BN_MP_INVMOD_SLOW_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* hac 14.61, pp608 */ +int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int x, y, u, v, A, B, C, D; + int res; + + /* b cannot be negative */ + if (b->sign == MP_NEG || mp_iszero(b) == 1) { + return MP_VAL; + } + + /* init temps */ + if ((res = mp_init_multi(&x, &y, &u, &v, + &A, &B, &C, &D, NULL)) != MP_OKAY) { + return res; + } + + /* x = a, y = b */ + if ((res = mp_mod(a, b, &x)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_copy (b, &y)) != MP_OKAY) { + goto LBL_ERR; + } + + /* 2. [modified] if x,y are both even then return an error! */ + if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) { + res = MP_VAL; + goto LBL_ERR; + } + + /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ + if ((res = mp_copy (&x, &u)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_copy (&y, &v)) != MP_OKAY) { + goto LBL_ERR; + } + mp_set (&A, 1); + mp_set (&D, 1); + +top: + /* 4. while u is even do */ + while (mp_iseven (&u) == 1) { + /* 4.1 u = u/2 */ + if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { + goto LBL_ERR; + } + /* 4.2 if A or B is odd then */ + if (mp_isodd (&A) == 1 || mp_isodd (&B) == 1) { + /* A = (A+y)/2, B = (B-x)/2 */ + if ((res = mp_add (&A, &y, &A)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } + /* A = A/2, B = B/2 */ + if ((res = mp_div_2 (&A, &A)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* 5. while v is even do */ + while (mp_iseven (&v) == 1) { + /* 5.1 v = v/2 */ + if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { + goto LBL_ERR; + } + /* 5.2 if C or D is odd then */ + if (mp_isodd (&C) == 1 || mp_isodd (&D) == 1) { + /* C = (C+y)/2, D = (D-x)/2 */ + if ((res = mp_add (&C, &y, &C)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + /* C = C/2, D = D/2 */ + if ((res = mp_div_2 (&C, &C)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = 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 ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } else { + /* v - v - u, C = C - A, D = D - B */ + if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* if not zero goto step 4 */ + if (mp_iszero (&u) == 0) + goto top; + + /* now a = C, b = D, gcd == g*v */ + + /* if v != 1 then there is no inverse */ + if (mp_cmp_d (&v, 1) != MP_EQ) { + res = MP_VAL; + goto LBL_ERR; + } + + /* if its too low */ + while (mp_cmp_d(&C, 0) == MP_LT) { + if ((res = mp_add(&C, b, &C)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* too big */ + while (mp_cmp_mag(&C, b) != MP_LT) { + if ((res = mp_sub(&C, b, &C)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* C is now the inverse */ + mp_exch (&C, c); + res = MP_OKAY; +LBL_ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL); + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_invmod_slow.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_is_square.c b/libtommath/bn_mp_is_square.c new file mode 100644 index 0000000..a235d97 --- /dev/null +++ b/libtommath/bn_mp_is_square.c @@ -0,0 +1,109 @@ +#include <tommath.h> +#ifdef BN_MP_IS_SQUARE_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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 */ +int mp_is_square(mp_int *arg,int *ret) +{ + int res; + mp_digit c; + mp_int t; + unsigned long r; + + /* Default to Non-square :) */ + *ret = MP_NO; + + if (arg->sign == MP_NEG) { + return MP_VAL; + } + + /* digits used? (TSD) */ + if (arg->used == 0) { + return MP_OKAY; + } + + /* First check mod 128 (suppose that DIGIT_BIT is at least 7) */ + if (rem_128[127 & DIGIT(arg,0)] == 1) { + return MP_OKAY; + } + + /* Next check mod 105 (3*5*7) */ + if ((res = mp_mod_d(arg,105,&c)) != MP_OKAY) { + return res; + } + if (rem_105[c] == 1) { + return MP_OKAY; + } + + + if ((res = mp_init_set_int(&t,11L*13L*17L*19L*23L*29L*31L)) != MP_OKAY) { + return res; + } + if ((res = mp_mod(arg,&t,&t)) != MP_OKAY) { + goto ERR; + } + r = mp_get_int(&t); + /* Check for other prime modules, note it's not an ERROR but we must + * free "t" so the easiest way is to goto ERR. We know that res + * is already equal to MP_OKAY from the mp_mod call + */ + if ( (1L<<(r%11)) & 0x5C4L ) goto ERR; + if ( (1L<<(r%13)) & 0x9E4L ) goto ERR; + if ( (1L<<(r%17)) & 0x5CE8L ) goto ERR; + if ( (1L<<(r%19)) & 0x4F50CL ) goto ERR; + if ( (1L<<(r%23)) & 0x7ACCA0L ) goto ERR; + if ( (1L<<(r%29)) & 0xC2EDD0CL ) goto ERR; + if ( (1L<<(r%31)) & 0x6DE2B848L ) goto ERR; + + /* Final check - is sqr(sqrt(arg)) == arg ? */ + if ((res = mp_sqrt(arg,&t)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sqr(&t,&t)) != MP_OKAY) { + goto ERR; + } + + *ret = (mp_cmp_mag(&t,arg) == MP_EQ) ? MP_YES : MP_NO; +ERR:mp_clear(&t); + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_is_square.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_jacobi.c b/libtommath/bn_mp_jacobi.c new file mode 100644 index 0000000..2e88fd4 --- /dev/null +++ b/libtommath/bn_mp_jacobi.c @@ -0,0 +1,105 @@ +#include <tommath.h> +#ifdef BN_MP_JACOBI_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* computes the jacobi c = (a | n) (or Legendre if n is prime) + * HAC pp. 73 Algorithm 2.149 + */ +int mp_jacobi (mp_int * a, mp_int * p, int *c) +{ + mp_int a1, p1; + int k, s, r, res; + mp_digit residue; + + /* if p <= 0 return MP_VAL */ + if (mp_cmp_d(p, 0) != MP_GT) { + return MP_VAL; + } + + /* step 1. if a == 0, return 0 */ + if (mp_iszero (a) == 1) { + *c = 0; + return MP_OKAY; + } + + /* step 2. if a == 1, return 1 */ + if (mp_cmp_d (a, 1) == MP_EQ) { + *c = 1; + return MP_OKAY; + } + + /* default */ + s = 0; + + /* step 3. write a = a1 * 2**k */ + if ((res = mp_init_copy (&a1, a)) != MP_OKAY) { + return res; + } + + if ((res = mp_init (&p1)) != MP_OKAY) { + goto LBL_A1; + } + + /* divide out larger power of two */ + k = mp_cnt_lsb(&a1); + if ((res = mp_div_2d(&a1, k, &a1, NULL)) != MP_OKAY) { + goto LBL_P1; + } + + /* step 4. if e is even set s=1 */ + if ((k & 1) == 0) { + s = 1; + } else { + /* else set s=1 if p = 1/7 (mod 8) or s=-1 if p = 3/5 (mod 8) */ + residue = p->dp[0] & 7; + + if (residue == 1 || residue == 7) { + s = 1; + } else if (residue == 3 || residue == 5) { + s = -1; + } + } + + /* step 5. if p == 3 (mod 4) *and* a1 == 3 (mod 4) then s = -s */ + if ( ((p->dp[0] & 3) == 3) && ((a1.dp[0] & 3) == 3)) { + s = -s; + } + + /* if a1 == 1 we're done */ + if (mp_cmp_d (&a1, 1) == MP_EQ) { + *c = s; + } else { + /* n1 = n mod a1 */ + if ((res = mp_mod (p, &a1, &p1)) != MP_OKAY) { + goto LBL_P1; + } + if ((res = mp_jacobi (&p1, &a1, &r)) != MP_OKAY) { + goto LBL_P1; + } + *c = s * r; + } + + /* done */ + res = MP_OKAY; +LBL_P1:mp_clear (&p1); +LBL_A1:mp_clear (&a1); + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_jacobi.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_karatsuba_mul.c b/libtommath/bn_mp_karatsuba_mul.c new file mode 100644 index 0000000..35dc9a4 --- /dev/null +++ b/libtommath/bn_mp_karatsuba_mul.c @@ -0,0 +1,167 @@ +#include <tommath.h> +#ifdef BN_MP_KARATSUBA_MUL_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* c = |a| * |b| using Karatsuba Multiplication using + * three half size multiplications + * + * Let B represent the radix [e.g. 2**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. + */ +int mp_karatsuba_mul (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int x0, x1, y0, y1, t1, x0y0, x1y1; + int B, err; + + /* default the return code to an error */ + err = MP_MEM; + + /* min # of digits */ + B = 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 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; + + { + register int x; + register 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))<<B */ + if (mp_lshd (&x1y1, B * 2) != MP_OKAY) + goto X1Y1; /* x1y1 = x1y1 << 2*B */ + + if (mp_add (&x0y0, &t1, &t1) != MP_OKAY) + goto X1Y1; /* t1 = x0y0 + t1 */ + if (mp_add (&t1, &x1y1, c) != MP_OKAY) + goto X1Y1; /* t1 = x0y0 + t1 + x1y1 */ + + /* Algorithm succeeded set the return code to MP_OKAY */ + err = MP_OKAY; + +X1Y1:mp_clear (&x1y1); +X0Y0:mp_clear (&x0y0); +T1:mp_clear (&t1); +Y1:mp_clear (&y1); +Y0:mp_clear (&y0); +X1:mp_clear (&x1); +X0:mp_clear (&x0); +ERR: + return err; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_karatsuba_mul.c,v $ */ +/* $Revision: 1.5 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_karatsuba_sqr.c b/libtommath/bn_mp_karatsuba_sqr.c new file mode 100644 index 0000000..6d8ad6e --- /dev/null +++ b/libtommath/bn_mp_karatsuba_sqr.c @@ -0,0 +1,121 @@ +#include <tommath.h> +#ifdef BN_MP_KARATSUBA_SQR_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* Karatsuba squaring, computes b = a*a using three + * half size squarings + * + * See comments of karatsuba_mul for details. It + * is essentially the same algorithm but merely + * tuned to perform recursive squarings. + */ +int mp_karatsuba_sqr (mp_int * a, mp_int * b) +{ + mp_int x0, x1, t1, t2, x0x0, x1x1; + int B, err; + + err = MP_MEM; + + /* min # of digits */ + B = a->used; + + /* now divide in two */ + B = B >> 1; + + /* init copy all the temps */ + if (mp_init_size (&x0, B) != MP_OKAY) + goto 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; + + { + register int x; + register 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))<<B */ + if (mp_lshd (&x1x1, B * 2) != MP_OKAY) + goto X1X1; /* x1x1 = x1x1 << 2*B */ + + if (mp_add (&x0x0, &t1, &t1) != MP_OKAY) + goto X1X1; /* t1 = x0x0 + t1 */ + if (mp_add (&t1, &x1x1, b) != MP_OKAY) + goto X1X1; /* t1 = x0x0 + t1 + x1x1 */ + + err = MP_OKAY; + +X1X1:mp_clear (&x1x1); +X0X0:mp_clear (&x0x0); +T2:mp_clear (&t2); +T1:mp_clear (&t1); +X1:mp_clear (&x1); +X0:mp_clear (&x0); +ERR: + return err; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_karatsuba_sqr.c,v $ */ +/* $Revision: 1.5 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_lcm.c b/libtommath/bn_mp_lcm.c new file mode 100644 index 0000000..48b2b63 --- /dev/null +++ b/libtommath/bn_mp_lcm.c @@ -0,0 +1,60 @@ +#include <tommath.h> +#ifdef BN_MP_LCM_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* computes least common multiple as |a*b|/(a, b) */ +int mp_lcm (mp_int * a, mp_int * b, mp_int * c) +{ + int res; + mp_int t1, t2; + + + if ((res = mp_init_multi (&t1, &t2, NULL)) != MP_OKAY) { + return res; + } + + /* t1 = get the GCD of the two inputs */ + if ((res = 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 ((res = mp_div(a, &t1, &t2, NULL)) != MP_OKAY) { + goto LBL_T; + } + res = mp_mul(b, &t2, c); + } else { + /* store quotient in t2 such that t2 * a is the LCM */ + if ((res = mp_div(b, &t1, &t2, NULL)) != MP_OKAY) { + goto LBL_T; + } + res = mp_mul(a, &t2, c); + } + + /* fix the sign to positive */ + c->sign = MP_ZPOS; + +LBL_T: + mp_clear_multi (&t1, &t2, NULL); + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_lcm.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_lshd.c b/libtommath/bn_mp_lshd.c new file mode 100644 index 0000000..ca9b853 --- /dev/null +++ b/libtommath/bn_mp_lshd.c @@ -0,0 +1,67 @@ +#include <tommath.h> +#ifdef BN_MP_LSHD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* shift left a certain amount of digits */ +int mp_lshd (mp_int * a, int b) +{ + int x, res; + + /* if its less than zero return */ + if (b <= 0) { + return MP_OKAY; + } + + /* grow to fit the new digits */ + if (a->alloc < a->used + b) { + if ((res = mp_grow (a, a->used + b)) != MP_OKAY) { + return res; + } + } + + { + register mp_digit *top, *bottom; + + /* 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 */ + top = a->dp; + for (x = 0; x < b; x++) { + *top++ = 0; + } + } + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_lshd.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_mod.c b/libtommath/bn_mp_mod.c new file mode 100644 index 0000000..be1f36d --- /dev/null +++ b/libtommath/bn_mp_mod.c @@ -0,0 +1,48 @@ +#include <tommath.h> +#ifdef BN_MP_MOD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* c = a mod b, 0 <= c < b */ +int +mp_mod (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int t; + int res; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + if (t.sign != b->sign) { + res = mp_add (b, &t, c); + } else { + res = MP_OKAY; + mp_exch (&t, c); + } + + mp_clear (&t); + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_mod.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_mod_2d.c b/libtommath/bn_mp_mod_2d.c new file mode 100644 index 0000000..461b1b2 --- /dev/null +++ b/libtommath/bn_mp_mod_2d.c @@ -0,0 +1,55 @@ +#include <tommath.h> +#ifdef BN_MP_MOD_2D_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* calc a value mod 2**b */ +int +mp_mod_2d (mp_int * a, int b, mp_int * c) +{ + int x, res; + + /* 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 >= (int) (a->used * DIGIT_BIT)) { + res = mp_copy (a, c); + return res; + } + + /* copy */ + if ((res = mp_copy (a, c)) != MP_OKAY) { + return res; + } + + /* zero digits above the last digit of the modulus */ + for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) { + c->dp[x] = 0; + } + /* clear the digit that is not completely outside/inside the modulus */ + c->dp[b / DIGIT_BIT] &= + (mp_digit) ((((mp_digit) 1) << (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1)); + mp_clamp (c); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_mod_2d.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_mod_d.c b/libtommath/bn_mp_mod_d.c new file mode 100644 index 0000000..8bc499b --- /dev/null +++ b/libtommath/bn_mp_mod_d.c @@ -0,0 +1,27 @@ +#include <tommath.h> +#ifdef BN_MP_MOD_D_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +int +mp_mod_d (mp_int * a, mp_digit b, mp_digit * c) +{ + return mp_div_d(a, b, NULL, c); +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_mod_d.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_montgomery_calc_normalization.c b/libtommath/bn_mp_montgomery_calc_normalization.c new file mode 100644 index 0000000..91eb5fe --- /dev/null +++ b/libtommath/bn_mp_montgomery_calc_normalization.c @@ -0,0 +1,59 @@ +#include <tommath.h> +#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* + * 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. + */ +int mp_montgomery_calc_normalization (mp_int * a, mp_int * b) +{ + int x, bits, res; + + /* how many bits of last digit does b use */ + bits = mp_count_bits (b) % DIGIT_BIT; + + if (b->used > 1) { + if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) { + return res; + } + } else { + mp_set(a, 1); + bits = 1; + } + + + /* now compute C = A * B mod b */ + for (x = bits - 1; x < (int)DIGIT_BIT; x++) { + if ((res = mp_mul_2 (a, a)) != MP_OKAY) { + return res; + } + if (mp_cmp_mag (a, b) != MP_LT) { + if ((res = s_mp_sub (a, b, a)) != MP_OKAY) { + return res; + } + } + } + + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_montgomery_calc_normalization.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_montgomery_reduce.c b/libtommath/bn_mp_montgomery_reduce.c new file mode 100644 index 0000000..a121d2a --- /dev/null +++ b/libtommath/bn_mp_montgomery_reduce.c @@ -0,0 +1,118 @@ +#include <tommath.h> +#ifdef BN_MP_MONTGOMERY_REDUCE_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* computes xR**-1 == x (mod N) via Montgomery Reduction */ +int +mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho) +{ + int ix, res, digs; + 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) && + n->used < + (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_mp_montgomery_reduce (x, n, rho); + } + + /* grow the input as required */ + if (x->alloc < digs) { + if ((res = mp_grow (x, digs)) != MP_OKAY) { + return res; + } + } + 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 */ + { + register int iy; + register mp_digit *tmpn, *tmpx, u; + register 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) 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) { + *tmpx += u; + u = *tmpx >> 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 + +/* $Source: /cvs/libtom/libtommath/bn_mp_montgomery_reduce.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_montgomery_setup.c b/libtommath/bn_mp_montgomery_setup.c new file mode 100644 index 0000000..0dc800e --- /dev/null +++ b/libtommath/bn_mp_montgomery_setup.c @@ -0,0 +1,59 @@ +#include <tommath.h> +#ifdef BN_MP_MONTGOMERY_SETUP_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* setups the montgomery reduction stuff */ +int +mp_montgomery_setup (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 & 1) == 0) { + return MP_VAL; + } + + x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */ + x *= 2 - b * x; /* here x*a==1 mod 2**8 */ +#if !defined(MP_8BIT) + x *= 2 - b * x; /* here x*a==1 mod 2**16 */ +#endif +#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT)) + x *= 2 - b * x; /* here x*a==1 mod 2**32 */ +#endif +#ifdef MP_64BIT + x *= 2 - b * x; /* here x*a==1 mod 2**64 */ +#endif + + /* rho = -1/m mod b */ + *rho = (unsigned long)(((mp_word)1 << ((mp_word) DIGIT_BIT)) - x) & MP_MASK; + + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_montgomery_setup.c,v $ */ +/* $Revision: 1.4 $ */ +/* $Date: 2006/12/04 21:34:03 $ */ diff --git a/libtommath/bn_mp_mul.c b/libtommath/bn_mp_mul.c new file mode 100644 index 0000000..f941a1a --- /dev/null +++ b/libtommath/bn_mp_mul.c @@ -0,0 +1,66 @@ +#include <tommath.h> +#ifdef BN_MP_MUL_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* high level multiplication (handles sign) */ +int mp_mul (mp_int * a, mp_int * b, mp_int * c) +{ + int res, neg; + neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; + + /* use Toom-Cook? */ +#ifdef BN_MP_TOOM_MUL_C + if (MIN (a->used, b->used) >= TOOM_MUL_CUTOFF) { + res = mp_toom_mul(a, b, c); + } else +#endif +#ifdef BN_MP_KARATSUBA_MUL_C + /* use Karatsuba? */ + if (MIN (a->used, b->used) >= KARATSUBA_MUL_CUTOFF) { + res = mp_karatsuba_mul (a, b, c); + } else +#endif + { + /* 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 + */ + int digs = a->used + b->used + 1; + +#ifdef BN_FAST_S_MP_MUL_DIGS_C + if ((digs < MP_WARRAY) && + MIN(a->used, b->used) <= + (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + res = fast_s_mp_mul_digs (a, b, c, digs); + } else +#endif +#ifdef BN_S_MP_MUL_DIGS_C + res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */ +#else + res = MP_VAL; +#endif + + } + c->sign = (c->used > 0) ? neg : MP_ZPOS; + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_mul.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_mul_2.c b/libtommath/bn_mp_mul_2.c new file mode 100644 index 0000000..0d27a9d --- /dev/null +++ b/libtommath/bn_mp_mul_2.c @@ -0,0 +1,82 @@ +#include <tommath.h> +#ifdef BN_MP_MUL_2_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* b = a*2 */ +int mp_mul_2(mp_int * a, mp_int * b) +{ + int x, res, oldused; + + /* grow to accomodate result */ + if (b->alloc < a->used + 1) { + if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) { + return res; + } + } + + oldused = b->used; + b->used = a->used; + + { + register 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)(DIGIT_BIT - 1)); + + /* now shift up this digit, add in the carry [from the previous] */ + *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK; + + /* copy the carry that would be from the source + * digit into the next iteration + */ + r = rr; + } + + /* new leading digit? */ + if (r != 0) { + /* 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 + */ + tmpb = b->dp + b->used; + for (x = b->used; x < oldused; x++) { + *tmpb++ = 0; + } + } + b->sign = a->sign; + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_mul_2.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_mul_2d.c b/libtommath/bn_mp_mul_2d.c new file mode 100644 index 0000000..d803bf4 --- /dev/null +++ b/libtommath/bn_mp_mul_2d.c @@ -0,0 +1,85 @@ +#include <tommath.h> +#ifdef BN_MP_MUL_2D_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* shift left by a certain bit count */ +int mp_mul_2d (mp_int * a, int b, mp_int * c) +{ + mp_digit d; + int res; + + /* copy */ + if (a != c) { + if ((res = mp_copy (a, c)) != MP_OKAY) { + return res; + } + } + + if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) { + if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) { + return res; + } + } + + /* shift by as many digits in the bit count */ + if (b >= (int)DIGIT_BIT) { + if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) { + return res; + } + } + + /* shift any bit count < DIGIT_BIT */ + d = (mp_digit) (b % DIGIT_BIT); + if (d != 0) { + register mp_digit *tmpc, shift, mask, r, rr; + register int x; + + /* bitmask for carries */ + mask = (((mp_digit)1) << d) - 1; + + /* shift for msbs */ + shift = 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 != 0) { + c->dp[(c->used)++] = r; + } + } + mp_clamp (c); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_mul_2d.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_mul_d.c b/libtommath/bn_mp_mul_d.c new file mode 100644 index 0000000..a6324aa --- /dev/null +++ b/libtommath/bn_mp_mul_d.c @@ -0,0 +1,79 @@ +#include <tommath.h> +#ifdef BN_MP_MUL_D_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* multiply by a digit */ +int +mp_mul_d (mp_int * a, mp_digit b, mp_int * c) +{ + mp_digit u, *tmpa, *tmpc; + mp_word r; + int ix, res, olduse; + + /* make sure c is big enough to hold a*b */ + if (c->alloc < a->used + 1) { + if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) { + return res; + } + } + + /* 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) DIGIT_BIT)); + } + + /* store final carry [if any] and increment ix offset */ + *tmpc++ = u; + ++ix; + + /* now zero digits above the top */ + while (ix++ < olduse) { + *tmpc++ = 0; + } + + /* set used count */ + c->used = a->used + 1; + mp_clamp(c); + + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_mul_d.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_mulmod.c b/libtommath/bn_mp_mulmod.c new file mode 100644 index 0000000..46818b6 --- /dev/null +++ b/libtommath/bn_mp_mulmod.c @@ -0,0 +1,40 @@ +#include <tommath.h> +#ifdef BN_MP_MULMOD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* d = a * b (mod c) */ +int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + int res; + mp_int t; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_mul (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, c, d); + mp_clear (&t); + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_mulmod.c,v $ */ +/* $Revision: 1.4 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_n_root.c b/libtommath/bn_mp_n_root.c new file mode 100644 index 0000000..c154016 --- /dev/null +++ b/libtommath/bn_mp_n_root.c @@ -0,0 +1,132 @@ +#include <tommath.h> +#ifdef BN_MP_N_ROOT_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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. This is not meant to + * find huge roots [square and cube, etc]. + */ +int mp_n_root (mp_int * a, mp_digit b, mp_int * c) +{ + mp_int t1, t2, t3; + int res, neg; + + /* input must be positive if b is even */ + if ((b & 1) == 0 && a->sign == MP_NEG) { + return MP_VAL; + } + + if ((res = mp_init (&t1)) != MP_OKAY) { + return res; + } + + if ((res = mp_init (&t2)) != MP_OKAY) { + goto LBL_T1; + } + + if ((res = mp_init (&t3)) != MP_OKAY) { + goto LBL_T2; + } + + /* if a is negative fudge the sign but keep track */ + neg = a->sign; + a->sign = MP_ZPOS; + + /* t2 = 2 */ + mp_set (&t2, 2); + + do { + /* t1 = t2 */ + if ((res = mp_copy (&t2, &t1)) != MP_OKAY) { + goto LBL_T3; + } + + /* t2 = t1 - ((t1**b - a) / (b * t1**(b-1))) */ + + /* t3 = t1**(b-1) */ + if ((res = mp_expt_d (&t1, b - 1, &t3)) != MP_OKAY) { + goto LBL_T3; + } + + /* numerator */ + /* t2 = t1**b */ + if ((res = mp_mul (&t3, &t1, &t2)) != MP_OKAY) { + goto LBL_T3; + } + + /* t2 = t1**b - a */ + if ((res = mp_sub (&t2, a, &t2)) != MP_OKAY) { + goto LBL_T3; + } + + /* denominator */ + /* t3 = t1**(b-1) * b */ + if ((res = mp_mul_d (&t3, b, &t3)) != MP_OKAY) { + goto LBL_T3; + } + + /* t3 = (t1**b - a)/(b * t1**(b-1)) */ + if ((res = mp_div (&t2, &t3, &t3, NULL)) != MP_OKAY) { + goto LBL_T3; + } + + if ((res = mp_sub (&t1, &t3, &t2)) != MP_OKAY) { + goto LBL_T3; + } + } while (mp_cmp (&t1, &t2) != MP_EQ); + + /* result can be off by a few so check */ + for (;;) { + if ((res = mp_expt_d (&t1, b, &t2)) != MP_OKAY) { + goto LBL_T3; + } + + if (mp_cmp (&t2, a) == MP_GT) { + if ((res = mp_sub_d (&t1, 1, &t1)) != MP_OKAY) { + goto LBL_T3; + } + } else { + break; + } + } + + /* reset the sign of a first */ + a->sign = neg; + + /* set the result */ + mp_exch (&t1, c); + + /* set the sign of the result */ + c->sign = neg; + + res = MP_OKAY; + +LBL_T3:mp_clear (&t3); +LBL_T2:mp_clear (&t2); +LBL_T1:mp_clear (&t1); + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_n_root.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_neg.c b/libtommath/bn_mp_neg.c new file mode 100644 index 0000000..0db9b40 --- /dev/null +++ b/libtommath/bn_mp_neg.c @@ -0,0 +1,40 @@ +#include <tommath.h> +#ifdef BN_MP_NEG_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* b = -a */ +int mp_neg (mp_int * a, mp_int * b) +{ + int res; + if (a != b) { + if ((res = mp_copy (a, b)) != MP_OKAY) { + return res; + } + } + + if (mp_iszero(b) != MP_YES) { + b->sign = (a->sign == MP_ZPOS) ? MP_NEG : MP_ZPOS; + } else { + b->sign = MP_ZPOS; + } + + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_neg.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_or.c b/libtommath/bn_mp_or.c new file mode 100644 index 0000000..a9fc74a --- /dev/null +++ b/libtommath/bn_mp_or.c @@ -0,0 +1,50 @@ +#include <tommath.h> +#ifdef BN_MP_OR_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* OR two ints together */ +int mp_or (mp_int * a, mp_int * b, mp_int * c) +{ + int res, ix, px; + mp_int t, *x; + + if (a->used > b->used) { + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + px = b->used; + x = b; + } else { + if ((res = mp_init_copy (&t, b)) != MP_OKAY) { + return res; + } + px = a->used; + x = a; + } + + for (ix = 0; ix < px; ix++) { + t.dp[ix] |= x->dp[ix]; + } + mp_clamp (&t); + mp_exch (c, &t); + mp_clear (&t); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_or.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_prime_fermat.c b/libtommath/bn_mp_prime_fermat.c new file mode 100644 index 0000000..1869867 --- /dev/null +++ b/libtommath/bn_mp_prime_fermat.c @@ -0,0 +1,62 @@ +#include <tommath.h> +#ifdef BN_MP_PRIME_FERMAT_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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. + */ +int mp_prime_fermat (mp_int * a, mp_int * b, int *result) +{ + mp_int t; + int err; + + /* default to composite */ + *result = MP_NO; + + /* ensure b > 1 */ + if (mp_cmp_d(b, 1) != 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 + +/* $Source: /cvs/libtom/libtommath/bn_mp_prime_fermat.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_prime_is_divisible.c b/libtommath/bn_mp_prime_is_divisible.c new file mode 100644 index 0000000..d065451 --- /dev/null +++ b/libtommath/bn_mp_prime_is_divisible.c @@ -0,0 +1,50 @@ +#include <tommath.h> +#ifdef BN_MP_PRIME_IS_DIVISIBLE_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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 + */ +int mp_prime_is_divisible (mp_int * a, int *result) +{ + int err, ix; + mp_digit res; + + /* default to not */ + *result = MP_NO; + + for (ix = 0; ix < PRIME_SIZE; ix++) { + /* what is a mod LBL_prime_tab[ix] */ + if ((err = mp_mod_d (a, ltm_prime_tab[ix], &res)) != MP_OKAY) { + return err; + } + + /* is the residue zero? */ + if (res == 0) { + *result = MP_YES; + return MP_OKAY; + } + } + + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_prime_is_divisible.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_prime_is_prime.c b/libtommath/bn_mp_prime_is_prime.c new file mode 100644 index 0000000..d93d46a --- /dev/null +++ b/libtommath/bn_mp_prime_is_prime.c @@ -0,0 +1,83 @@ +#include <tommath.h> +#ifdef BN_MP_PRIME_IS_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* performs a variable number of rounds of Miller-Rabin + * + * Probability of error after t rounds is no more than + + * + * Sets result to 1 if probably prime, 0 otherwise + */ +int mp_prime_is_prime (mp_int * a, int t, int *result) +{ + mp_int b; + int ix, err, res; + + /* default to no */ + *result = MP_NO; + + /* valid value of t? */ + if (t <= 0 || t > PRIME_SIZE) { + return MP_VAL; + } + + /* is the input equal to one of the primes in the table? */ + for (ix = 0; ix < PRIME_SIZE; ix++) { + if (mp_cmp_d(a, ltm_prime_tab[ix]) == MP_EQ) { + *result = 1; + return MP_OKAY; + } + } + + /* first perform trial division */ + if ((err = mp_prime_is_divisible (a, &res)) != MP_OKAY) { + return err; + } + + /* return if it was trivially divisible */ + if (res == MP_YES) { + return MP_OKAY; + } + + /* now perform the miller-rabin rounds */ + if ((err = mp_init (&b)) != MP_OKAY) { + return err; + } + + for (ix = 0; ix < t; ix++) { + /* set the prime */ + mp_set (&b, ltm_prime_tab[ix]); + + 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 + +/* $Source: /cvs/libtom/libtommath/bn_mp_prime_is_prime.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_prime_miller_rabin.c b/libtommath/bn_mp_prime_miller_rabin.c new file mode 100644 index 0000000..9bd6ba1 --- /dev/null +++ b/libtommath/bn_mp_prime_miller_rabin.c @@ -0,0 +1,103 @@ +#include <tommath.h> +#ifdef BN_MP_PRIME_MILLER_RABIN_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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. + */ +int mp_prime_miller_rabin (mp_int * a, mp_int * b, int *result) +{ + mp_int n1, y, r; + int s, j, err; + + /* default */ + *result = MP_NO; + + /* ensure b > 1 */ + if (mp_cmp_d(b, 1) != 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, 1, &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, 1) != 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, 1) == 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 + +/* $Source: /cvs/libtom/libtommath/bn_mp_prime_miller_rabin.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_prime_next_prime.c b/libtommath/bn_mp_prime_next_prime.c new file mode 100644 index 0000000..a2da345 --- /dev/null +++ b/libtommath/bn_mp_prime_next_prime.c @@ -0,0 +1,170 @@ +#include <tommath.h> +#ifdef BN_MP_PRIME_NEXT_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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 + */ +int mp_prime_next_prime(mp_int *a, int t, int bbs_style) +{ + int err, res, x, y; + mp_digit res_tab[PRIME_SIZE], step, kstep; + mp_int b; + + /* ensure t is valid */ + if (t <= 0 || t > PRIME_SIZE) { + return MP_VAL; + } + + /* force positive */ + a->sign = MP_ZPOS; + + /* simple algo if a is less than the largest prime in the table */ + if (mp_cmp_d(a, ltm_prime_tab[PRIME_SIZE-1]) == MP_LT) { + /* find which prime it is bigger than */ + for (x = PRIME_SIZE - 2; x >= 0; x--) { + if (mp_cmp_d(a, ltm_prime_tab[x]) != MP_LT) { + if (bbs_style == 1) { + /* ok we found a prime smaller or + * equal [so the next is larger] + * + * however, the prime must be + * congruent to 3 mod 4 + */ + if ((ltm_prime_tab[x + 1] & 3) != 3) { + /* scan upwards for a prime congruent to 3 mod 4 */ + for (y = x + 1; y < PRIME_SIZE; y++) { + if ((ltm_prime_tab[y] & 3) == 3) { + mp_set(a, ltm_prime_tab[y]); + return MP_OKAY; + } + } + } + } else { + mp_set(a, ltm_prime_tab[x + 1]); + return MP_OKAY; + } + } + } + /* at this point a maybe 1 */ + if (mp_cmp_d(a, 1) == MP_EQ) { + mp_set(a, 2); + 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] & 3) != 3) { + if ((err = mp_sub_d(a, (a->dp[0] & 3) + 1, a)) != MP_OKAY) { return err; }; + } + } else { + if (mp_iseven(a) == 1) { + /* force odd */ + if ((err = mp_sub_d(a, 1, a)) != MP_OKAY) { + return err; + } + } + } + + /* generate the restable */ + for (x = 1; x < PRIME_SIZE; x++) { + if ((err = mp_mod_d(a, ltm_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 < PRIME_SIZE; x++) { + /* add the step to each residue */ + res_tab[x] += kstep; + + /* subtract the modulus [instead of using division] */ + if (res_tab[x] >= ltm_prime_tab[x]) { + res_tab[x] -= ltm_prime_tab[x]; + } + + /* set flag if zero */ + if (res_tab[x] == 0) { + y = 1; + } + } + } while (y == 1 && step < ((((mp_digit)1)<<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 == MAX then skip test */ + if (y == 1 && step >= ((((mp_digit)1)<<DIGIT_BIT) - kstep)) { + continue; + } + + /* is this prime? */ + for (x = 0; x < t; x++) { + mp_set(&b, ltm_prime_tab[t]); + if ((err = mp_prime_miller_rabin(a, &b, &res)) != MP_OKAY) { + goto LBL_ERR; + } + if (res == MP_NO) { + break; + } + } + + if (res == MP_YES) { + break; + } + } + + err = MP_OKAY; +LBL_ERR: + mp_clear(&b); + return err; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_prime_next_prime.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_prime_rabin_miller_trials.c b/libtommath/bn_mp_prime_rabin_miller_trials.c new file mode 100644 index 0000000..140b254 --- /dev/null +++ b/libtommath/bn_mp_prime_rabin_miller_trials.c @@ -0,0 +1,52 @@ +#include <tommath.h> +#ifdef BN_MP_PRIME_RABIN_MILLER_TRIALS_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + + +static const struct { + int k, t; +} sizes[] = { +{ 128, 28 }, +{ 256, 16 }, +{ 384, 10 }, +{ 512, 7 }, +{ 640, 6 }, +{ 768, 5 }, +{ 896, 4 }, +{ 1024, 4 } +}; + +/* 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 + 1; +} + + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_prime_rabin_miller_trials.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_prime_random_ex.c b/libtommath/bn_mp_prime_random_ex.c new file mode 100644 index 0000000..cde7a38 --- /dev/null +++ b/libtommath/bn_mp_prime_random_ex.c @@ -0,0 +1,125 @@ +#include <tommath.h> +#ifdef BN_MP_PRIME_RANDOM_EX_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* makes a truly random prime of a given size (bits), + * + * Flags are as follows: + * + * LTM_PRIME_BBS - make prime congruent to 3 mod 4 + * LTM_PRIME_SAFE - make sure (p-1)/2 is prime as well (implies LTM_PRIME_BBS) + * LTM_PRIME_2MSB_OFF - make the 2nd highest bit zero + * LTM_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! */ +int mp_prime_random_ex(mp_int *a, int t, int size, int flags, ltm_prime_callback cb, void *dat) +{ + unsigned char *tmp, maskAND, maskOR_msb, maskOR_lsb; + int res, err, bsize, maskOR_msb_offset; + + /* sanity check the input */ + if (size <= 1 || t <= 0) { + return MP_VAL; + } + + /* LTM_PRIME_SAFE implies LTM_PRIME_BBS */ + if (flags & LTM_PRIME_SAFE) { + flags |= LTM_PRIME_BBS; + } + + /* calc the byte size */ + bsize = (size>>3) + ((size&7)?1:0); + + /* we need a buffer of bsize bytes */ + tmp = OPT_CAST(unsigned char) XMALLOC(bsize); + if (tmp == NULL) { + return MP_MEM; + } + + /* calc the maskAND value for the MSbyte*/ + maskAND = ((size&7) == 0) ? 0xFF : (0xFF >> (8 - (size & 7))); + + /* calc the maskOR_msb */ + maskOR_msb = 0; + maskOR_msb_offset = ((size & 7) == 1) ? 1 : 0; + if (flags & LTM_PRIME_2MSB_ON) { + maskOR_msb |= 0x80 >> ((9 - size) & 7); + } + + /* get the maskOR_lsb */ + maskOR_lsb = 1; + if (flags & LTM_PRIME_BBS) { + maskOR_lsb |= 3; + } + + do { + /* read the bytes */ + if (cb(tmp, bsize, dat) != bsize) { + err = MP_VAL; + goto error; + } + + /* work over the MSbyte */ + tmp[0] &= maskAND; + tmp[0] |= 1 << ((size - 1) & 7); + + /* mix in the maskORs */ + tmp[maskOR_msb_offset] |= maskOR_msb; + tmp[bsize-1] |= maskOR_lsb; + + /* read it in */ + if ((err = mp_read_unsigned_bin(a, tmp, 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 & LTM_PRIME_SAFE) { + /* see if (a-1)/2 is prime */ + if ((err = mp_sub_d(a, 1, 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 & LTM_PRIME_SAFE) { + /* restore a to the original value */ + if ((err = mp_mul_2(a, a)) != MP_OKAY) { goto error; } + if ((err = mp_add_d(a, 1, a)) != MP_OKAY) { goto error; } + } + + err = MP_OKAY; +error: + XFREE(tmp); + return err; +} + + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_prime_random_ex.c,v $ */ +/* $Revision: 1.4 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_radix_size.c b/libtommath/bn_mp_radix_size.c new file mode 100644 index 0000000..c9e8822 --- /dev/null +++ b/libtommath/bn_mp_radix_size.c @@ -0,0 +1,78 @@ +#include <tommath.h> +#ifdef BN_MP_RADIX_SIZE_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* returns size of ASCII reprensentation */ +int mp_radix_size (mp_int * a, int radix, int *size) +{ + int res, digs; + mp_int t; + mp_digit d; + + *size = 0; + + /* special case for binary */ + if (radix == 2) { + *size = mp_count_bits (a) + (a->sign == MP_NEG ? 1 : 0) + 1; + return MP_OKAY; + } + + /* make sure the radix is in range */ + if (radix < 2 || radix > 64) { + return MP_VAL; + } + + if (mp_iszero(a) == MP_YES) { + *size = 2; + 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 ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + + /* force temp to positive */ + t.sign = MP_ZPOS; + + /* fetch out all of the digits */ + 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); + + /* return digs + 1, the 1 is for the NULL byte that would be required. */ + *size = digs + 1; + return MP_OKAY; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_radix_size.c,v $ */ +/* $Revision: 1.4 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_radix_smap.c b/libtommath/bn_mp_radix_smap.c new file mode 100644 index 0000000..58c3a5e --- /dev/null +++ b/libtommath/bn_mp_radix_smap.c @@ -0,0 +1,24 @@ +#include <tommath.h> +#ifdef BN_MP_RADIX_SMAP_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* chars used in radix conversions */ +const char *mp_s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_radix_smap.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_rand.c b/libtommath/bn_mp_rand.c new file mode 100644 index 0000000..6c8f3b3 --- /dev/null +++ b/libtommath/bn_mp_rand.c @@ -0,0 +1,55 @@ +#include <tommath.h> +#ifdef BN_MP_RAND_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* makes a pseudo-random int of a given size */ +int +mp_rand (mp_int * a, int digits) +{ + int res; + mp_digit d; + + mp_zero (a); + if (digits <= 0) { + return MP_OKAY; + } + + /* first place a random non-zero digit */ + do { + d = ((mp_digit) abs (rand ())) & MP_MASK; + } while (d == 0); + + if ((res = mp_add_d (a, d, a)) != MP_OKAY) { + return res; + } + + while (--digits > 0) { + if ((res = mp_lshd (a, 1)) != MP_OKAY) { + return res; + } + + if ((res = mp_add_d (a, ((mp_digit) abs (rand ())), a)) != MP_OKAY) { + return res; + } + } + + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_rand.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_read_radix.c b/libtommath/bn_mp_read_radix.c new file mode 100644 index 0000000..d2119c1 --- /dev/null +++ b/libtommath/bn_mp_read_radix.c @@ -0,0 +1,85 @@ +#include <tommath.h> +#ifdef BN_MP_READ_RADIX_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* read a string [ASCII] in a given radix */ +int mp_read_radix (mp_int * a, const char *str, int radix) +{ + int y, res, neg; + 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) { + /* 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 = (char) ((radix < 36) ? toupper (*str) : *str); + for (y = 0; y < 64; y++) { + if (ch == mp_s_rmap[y]) { + break; + } + } + + /* 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 < radix) { + if ((res = mp_mul_d (a, (mp_digit) radix, a)) != MP_OKAY) { + return res; + } + if ((res = mp_add_d (a, (mp_digit) y, a)) != MP_OKAY) { + return res; + } + } else { + break; + } + ++str; + } + + /* set the sign only if a != 0 */ + if (mp_iszero(a) != 1) { + a->sign = neg; + } + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_read_radix.c,v $ */ +/* $Revision: 1.4 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_read_signed_bin.c b/libtommath/bn_mp_read_signed_bin.c new file mode 100644 index 0000000..e3df3c3 --- /dev/null +++ b/libtommath/bn_mp_read_signed_bin.c @@ -0,0 +1,41 @@ +#include <tommath.h> +#ifdef BN_MP_READ_SIGNED_BIN_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* read signed bin, big endian, first byte is 0==positive or 1==negative */ +int mp_read_signed_bin (mp_int * a, const unsigned char *b, int c) +{ + int res; + + /* read magnitude */ + if ((res = mp_read_unsigned_bin (a, b + 1, c - 1)) != MP_OKAY) { + return res; + } + + /* first byte is 0 for positive, non-zero for negative */ + if (b[0] == 0) { + a->sign = MP_ZPOS; + } else { + a->sign = MP_NEG; + } + + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_read_signed_bin.c,v $ */ +/* $Revision: 1.4 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_read_unsigned_bin.c b/libtommath/bn_mp_read_unsigned_bin.c new file mode 100644 index 0000000..0c471ed --- /dev/null +++ b/libtommath/bn_mp_read_unsigned_bin.c @@ -0,0 +1,55 @@ +#include <tommath.h> +#ifdef BN_MP_READ_UNSIGNED_BIN_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* reads a unsigned char array, assumes the msb is stored first [big endian] */ +int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c) +{ + int res; + + /* make sure there are at least two digits */ + if (a->alloc < 2) { + if ((res = mp_grow(a, 2)) != MP_OKAY) { + return res; + } + } + + /* zero the int */ + mp_zero (a); + + /* read the bytes in */ + while (c-- > 0) { + if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) { + return res; + } + +#ifndef MP_8BIT + a->dp[0] |= *b++; + a->used += 1; +#else + a->dp[0] = (*b & MP_MASK); + a->dp[1] |= ((*b++ >> 7U) & 1); + a->used += 2; +#endif + } + mp_clamp (a); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_read_unsigned_bin.c,v $ */ +/* $Revision: 1.4 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_reduce.c b/libtommath/bn_mp_reduce.c new file mode 100644 index 0000000..3f7284a --- /dev/null +++ b/libtommath/bn_mp_reduce.c @@ -0,0 +1,100 @@ +#include <tommath.h> +#ifdef BN_MP_REDUCE_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* reduces x mod m, assumes 0 < x < m**2, mu is + * precomputed via mp_reduce_setup. + * From HAC pp.604 Algorithm 14.42 + */ +int mp_reduce (mp_int * x, mp_int * m, mp_int * mu) +{ + mp_int q; + int res, um = m->used; + + /* q = x */ + if ((res = mp_init_copy (&q, x)) != MP_OKAY) { + return res; + } + + /* q1 = x / b**(k-1) */ + mp_rshd (&q, um - 1); + + /* according to HAC this optimization is ok */ + if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) { + if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) { + goto CLEANUP; + } + } else { +#ifdef BN_S_MP_MUL_HIGH_DIGS_C + if ((res = s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) { + goto CLEANUP; + } +#elif defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C) + if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) { + goto CLEANUP; + } +#else + { + res = MP_VAL; + goto CLEANUP; + } +#endif + } + + /* q3 = q2 / b**(k+1) */ + mp_rshd (&q, um + 1); + + /* x = x mod b**(k+1), quick (no division) */ + if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) { + goto CLEANUP; + } + + /* q = q * m mod b**(k+1), quick (no division) */ + if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) { + goto CLEANUP; + } + + /* x = x - q */ + if ((res = mp_sub (x, &q, x)) != MP_OKAY) { + goto CLEANUP; + } + + /* If x < 0, add b**(k+1) to it */ + if (mp_cmp_d (x, 0) == MP_LT) { + mp_set (&q, 1); + if ((res = mp_lshd (&q, um + 1)) != MP_OKAY) + goto CLEANUP; + if ((res = mp_add (x, &q, x)) != MP_OKAY) + goto CLEANUP; + } + + /* Back off if it's too big */ + while (mp_cmp (x, m) != MP_LT) { + if ((res = s_mp_sub (x, m, x)) != MP_OKAY) { + goto CLEANUP; + } + } + +CLEANUP: + mp_clear (&q); + + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_reduce.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_reduce_2k.c b/libtommath/bn_mp_reduce_2k.c new file mode 100644 index 0000000..5810696 --- /dev/null +++ b/libtommath/bn_mp_reduce_2k.c @@ -0,0 +1,61 @@ +#include <tommath.h> +#ifdef BN_MP_REDUCE_2K_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* reduces a modulo n where n is of the form 2**p - d */ +int mp_reduce_2k(mp_int *a, mp_int *n, mp_digit d) +{ + mp_int q; + int p, res; + + if ((res = mp_init(&q)) != MP_OKAY) { + return res; + } + + p = mp_count_bits(n); +top: + /* q = a/2**p, a = a mod 2**p */ + if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) { + goto ERR; + } + + if (d != 1) { + /* q = q * d */ + if ((res = mp_mul_d(&q, d, &q)) != MP_OKAY) { + goto ERR; + } + } + + /* a = a + q */ + if ((res = s_mp_add(a, &q, a)) != MP_OKAY) { + goto ERR; + } + + if (mp_cmp_mag(a, n) != MP_LT) { + s_mp_sub(a, n, a); + goto top; + } + +ERR: + mp_clear(&q); + return res; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_reduce_2k.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_reduce_2k_l.c b/libtommath/bn_mp_reduce_2k_l.c new file mode 100644 index 0000000..53b435f --- /dev/null +++ b/libtommath/bn_mp_reduce_2k_l.c @@ -0,0 +1,62 @@ +#include <tommath.h> +#ifdef BN_MP_REDUCE_2K_L_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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. +*/ +int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d) +{ + mp_int q; + int p, res; + + if ((res = mp_init(&q)) != MP_OKAY) { + return res; + } + + p = mp_count_bits(n); +top: + /* q = a/2**p, a = a mod 2**p */ + if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) { + goto ERR; + } + + /* q = q * d */ + if ((res = mp_mul(&q, d, &q)) != MP_OKAY) { + goto ERR; + } + + /* a = a + q */ + if ((res = s_mp_add(a, &q, a)) != MP_OKAY) { + goto ERR; + } + + if (mp_cmp_mag(a, n) != MP_LT) { + s_mp_sub(a, n, a); + goto top; + } + +ERR: + mp_clear(&q); + return res; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_reduce_2k_l.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_reduce_2k_setup.c b/libtommath/bn_mp_reduce_2k_setup.c new file mode 100644 index 0000000..07de0ec --- /dev/null +++ b/libtommath/bn_mp_reduce_2k_setup.c @@ -0,0 +1,47 @@ +#include <tommath.h> +#ifdef BN_MP_REDUCE_2K_SETUP_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* determines the setup value */ +int mp_reduce_2k_setup(mp_int *a, mp_digit *d) +{ + int res, p; + mp_int tmp; + + if ((res = mp_init(&tmp)) != MP_OKAY) { + return res; + } + + p = mp_count_bits(a); + if ((res = mp_2expt(&tmp, p)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + + if ((res = s_mp_sub(&tmp, a, &tmp)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + + *d = tmp.dp[0]; + mp_clear(&tmp); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_reduce_2k_setup.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_reduce_2k_setup_l.c b/libtommath/bn_mp_reduce_2k_setup_l.c new file mode 100644 index 0000000..05f0385 --- /dev/null +++ b/libtommath/bn_mp_reduce_2k_setup_l.c @@ -0,0 +1,44 @@ +#include <tommath.h> +#ifdef BN_MP_REDUCE_2K_SETUP_L_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* determines the setup value */ +int mp_reduce_2k_setup_l(mp_int *a, mp_int *d) +{ + int res; + mp_int tmp; + + if ((res = mp_init(&tmp)) != MP_OKAY) { + return res; + } + + if ((res = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) { + goto ERR; + } + + if ((res = s_mp_sub(&tmp, a, d)) != MP_OKAY) { + goto ERR; + } + +ERR: + mp_clear(&tmp); + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_reduce_2k_setup_l.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_reduce_is_2k.c b/libtommath/bn_mp_reduce_is_2k.c new file mode 100644 index 0000000..0897b0a --- /dev/null +++ b/libtommath/bn_mp_reduce_is_2k.c @@ -0,0 +1,52 @@ +#include <tommath.h> +#ifdef BN_MP_REDUCE_IS_2K_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* determines if mp_reduce_2k can be used */ +int mp_reduce_is_2k(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 = DIGIT_BIT; ix < iy; ix++) { + if ((a->dp[iw] & iz) == 0) { + return MP_NO; + } + iz <<= 1; + if (iz > (mp_digit)MP_MASK) { + ++iw; + iz = 1; + } + } + } + return MP_YES; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_reduce_is_2k.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_reduce_is_2k_l.c b/libtommath/bn_mp_reduce_is_2k_l.c new file mode 100644 index 0000000..c4b42c9 --- /dev/null +++ b/libtommath/bn_mp_reduce_is_2k_l.c @@ -0,0 +1,44 @@ +#include <tommath.h> +#ifdef BN_MP_REDUCE_IS_2K_L_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* determines if reduce_2k_l can be used */ +int mp_reduce_is_2k_l(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_MASK) { + ++iy; + } + } + return (iy >= (a->used/2)) ? MP_YES : MP_NO; + + } + return MP_NO; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_reduce_is_2k_l.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_reduce_setup.c b/libtommath/bn_mp_reduce_setup.c new file mode 100644 index 0000000..5085af0 --- /dev/null +++ b/libtommath/bn_mp_reduce_setup.c @@ -0,0 +1,34 @@ +#include <tommath.h> +#ifdef BN_MP_REDUCE_SETUP_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* pre-calculate the value required for Barrett reduction + * For a given modulus "b" it calulates the value required in "a" + */ +int mp_reduce_setup (mp_int * a, mp_int * b) +{ + int res; + + if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) { + return res; + } + return mp_div (a, b, a, NULL); +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_reduce_setup.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_rshd.c b/libtommath/bn_mp_rshd.c new file mode 100644 index 0000000..534bd4d --- /dev/null +++ b/libtommath/bn_mp_rshd.c @@ -0,0 +1,72 @@ +#include <tommath.h> +#ifdef BN_MP_RSHD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* shift right a certain amount of digits */ +void mp_rshd (mp_int * a, int b) +{ + int x; + + /* 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; + } + + { + register mp_digit *bottom, *top; + + /* 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 */ + for (; x < a->used; x++) { + *bottom++ = 0; + } + } + + /* remove excess digits */ + a->used -= b; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_rshd.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_set.c b/libtommath/bn_mp_set.c new file mode 100644 index 0000000..a1ebadb --- /dev/null +++ b/libtommath/bn_mp_set.c @@ -0,0 +1,29 @@ +#include <tommath.h> +#ifdef BN_MP_SET_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* set to a digit */ +void mp_set (mp_int * a, mp_digit b) +{ + mp_zero (a); + a->dp[0] = b & MP_MASK; + a->used = (a->dp[0] != 0) ? 1 : 0; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_set.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_set_int.c b/libtommath/bn_mp_set_int.c new file mode 100644 index 0000000..35e844f --- /dev/null +++ b/libtommath/bn_mp_set_int.c @@ -0,0 +1,48 @@ +#include <tommath.h> +#ifdef BN_MP_SET_INT_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* set a 32-bit const */ +int mp_set_int (mp_int * a, unsigned long b) +{ + int x, res; + + mp_zero (a); + + /* set four bits at a time */ + for (x = 0; x < 8; x++) { + /* shift the number up four bits */ + if ((res = mp_mul_2d (a, 4, a)) != MP_OKAY) { + return res; + } + + /* OR in the top four bits of the source */ + a->dp[0] |= (b >> 28) & 15; + + /* shift the source up to the next four bits */ + b <<= 4; + + /* ensure that digits are not clamped off */ + a->used += 1; + } + mp_clamp (a); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_set_int.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_shrink.c b/libtommath/bn_mp_shrink.c new file mode 100644 index 0000000..e676068 --- /dev/null +++ b/libtommath/bn_mp_shrink.c @@ -0,0 +1,35 @@ +#include <tommath.h> +#ifdef BN_MP_SHRINK_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* shrink a bignum */ +int mp_shrink (mp_int * a) +{ + mp_digit *tmp; + if (a->alloc != a->used && a->used > 0) { + if ((tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * a->used)) == NULL) { + return MP_MEM; + } + a->dp = tmp; + a->alloc = a->used; + } + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_shrink.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_signed_bin_size.c b/libtommath/bn_mp_signed_bin_size.c new file mode 100644 index 0000000..8df0b78 --- /dev/null +++ b/libtommath/bn_mp_signed_bin_size.c @@ -0,0 +1,27 @@ +#include <tommath.h> +#ifdef BN_MP_SIGNED_BIN_SIZE_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* get the size for an signed equivalent */ +int mp_signed_bin_size (mp_int * a) +{ + return 1 + mp_unsigned_bin_size (a); +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_signed_bin_size.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_sqr.c b/libtommath/bn_mp_sqr.c new file mode 100644 index 0000000..bff8a7d --- /dev/null +++ b/libtommath/bn_mp_sqr.c @@ -0,0 +1,58 @@ +#include <tommath.h> +#ifdef BN_MP_SQR_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* computes b = a*a */ +int +mp_sqr (mp_int * a, mp_int * b) +{ + int res; + +#ifdef BN_MP_TOOM_SQR_C + /* use Toom-Cook? */ + if (a->used >= TOOM_SQR_CUTOFF) { + res = mp_toom_sqr(a, b); + /* Karatsuba? */ + } else +#endif +#ifdef BN_MP_KARATSUBA_SQR_C +if (a->used >= KARATSUBA_SQR_CUTOFF) { + res = mp_karatsuba_sqr (a, b); + } else +#endif + { +#ifdef BN_FAST_S_MP_SQR_C + /* can we use the fast comba multiplier? */ + if ((a->used * 2 + 1) < MP_WARRAY && + a->used < + (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) { + res = fast_s_mp_sqr (a, b); + } else +#endif +#ifdef BN_S_MP_SQR_C + res = s_mp_sqr (a, b); +#else + res = MP_VAL; +#endif + } + b->sign = MP_ZPOS; + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_sqr.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_sqrmod.c b/libtommath/bn_mp_sqrmod.c new file mode 100644 index 0000000..38cbc92 --- /dev/null +++ b/libtommath/bn_mp_sqrmod.c @@ -0,0 +1,41 @@ +#include <tommath.h> +#ifdef BN_MP_SQRMOD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* c = a * a (mod b) */ +int +mp_sqrmod (mp_int * a, mp_int * b, mp_int * c) +{ + int res; + mp_int t; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_sqr (a, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, b, c); + mp_clear (&t); + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_sqrmod.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_sqrt.c b/libtommath/bn_mp_sqrt.c new file mode 100644 index 0000000..4449625 --- /dev/null +++ b/libtommath/bn_mp_sqrt.c @@ -0,0 +1,81 @@ +#include <tommath.h> +#ifdef BN_MP_SQRT_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* this function is less generic than mp_n_root, simpler and faster */ +int mp_sqrt(mp_int *arg, mp_int *ret) +{ + int res; + mp_int t1,t2; + + /* must be positive */ + if (arg->sign == MP_NEG) { + return MP_VAL; + } + + /* easy out */ + if (mp_iszero(arg) == MP_YES) { + mp_zero(ret); + return MP_OKAY; + } + + if ((res = mp_init_copy(&t1, arg)) != MP_OKAY) { + return res; + } + + if ((res = mp_init(&t2)) != MP_OKAY) { + goto E2; + } + + /* First approx. (not very bad for large arg) */ + mp_rshd (&t1,t1.used/2); + + /* t1 > 0 */ + if ((res = mp_div(arg,&t1,&t2,NULL)) != MP_OKAY) { + goto E1; + } + if ((res = mp_add(&t1,&t2,&t1)) != MP_OKAY) { + goto E1; + } + if ((res = mp_div_2(&t1,&t1)) != MP_OKAY) { + goto E1; + } + /* And now t1 > sqrt(arg) */ + do { + if ((res = mp_div(arg,&t1,&t2,NULL)) != MP_OKAY) { + goto E1; + } + if ((res = mp_add(&t1,&t2,&t1)) != MP_OKAY) { + goto E1; + } + if ((res = 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 res; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_sqrt.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_sub.c b/libtommath/bn_mp_sub.c new file mode 100644 index 0000000..a69d032 --- /dev/null +++ b/libtommath/bn_mp_sub.c @@ -0,0 +1,59 @@ +#include <tommath.h> +#ifdef BN_MP_SUB_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* high level subtraction (handles signs) */ +int +mp_sub (mp_int * a, mp_int * b, mp_int * c) +{ + int sa, sb, res; + + sa = a->sign; + sb = b->sign; + + 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; + res = 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 */ + res = 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 */ + res = s_mp_sub (b, a, c); + } + } + return res; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_sub.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_sub_d.c b/libtommath/bn_mp_sub_d.c new file mode 100644 index 0000000..ee77a5a --- /dev/null +++ b/libtommath/bn_mp_sub_d.c @@ -0,0 +1,93 @@ +#include <tommath.h> +#ifdef BN_MP_SUB_D_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* single digit subtraction */ +int +mp_sub_d (mp_int * a, mp_digit b, mp_int * c) +{ + mp_digit *tmpa, *tmpc, mu; + int res, ix, oldused; + + /* grow c as required */ + if (c->alloc < a->used + 1) { + if ((res = mp_grow(c, a->used + 1)) != MP_OKAY) { + return res; + } + } + + /* if a is negative just do an unsigned + * addition [with fudged signs] + */ + if (a->sign == MP_NEG) { + a->sign = MP_ZPOS; + res = mp_add_d(a, b, c); + a->sign = c->sign = MP_NEG; + + /* clamp */ + mp_clamp(c); + + return res; + } + + /* 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 { + /* positive/size */ + c->sign = MP_ZPOS; + c->used = a->used; + + /* subtract first digit */ + *tmpc = *tmpa++ - b; + mu = *tmpc >> (sizeof(mp_digit) * CHAR_BIT - 1); + *tmpc++ &= MP_MASK; + + /* handle rest of the digits */ + for (ix = 1; ix < a->used; ix++) { + *tmpc = *tmpa++ - mu; + mu = *tmpc >> (sizeof(mp_digit) * CHAR_BIT - 1); + *tmpc++ &= MP_MASK; + } + } + + /* zero excess digits */ + while (ix++ < oldused) { + *tmpc++ = 0; + } + mp_clamp(c); + return MP_OKAY; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_sub_d.c,v $ */ +/* $Revision: 1.5 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_submod.c b/libtommath/bn_mp_submod.c new file mode 100644 index 0000000..bd24f25 --- /dev/null +++ b/libtommath/bn_mp_submod.c @@ -0,0 +1,42 @@ +#include <tommath.h> +#ifdef BN_MP_SUBMOD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* d = a - b (mod c) */ +int +mp_submod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + int res; + mp_int t; + + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_sub (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, c, d); + mp_clear (&t); + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_submod.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_to_signed_bin.c b/libtommath/bn_mp_to_signed_bin.c new file mode 100644 index 0000000..9125d07 --- /dev/null +++ b/libtommath/bn_mp_to_signed_bin.c @@ -0,0 +1,33 @@ +#include <tommath.h> +#ifdef BN_MP_TO_SIGNED_BIN_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* store in signed [big endian] format */ +int mp_to_signed_bin (mp_int * a, unsigned char *b) +{ + int res; + + if ((res = mp_to_unsigned_bin (a, b + 1)) != MP_OKAY) { + return res; + } + b[0] = (unsigned char) ((a->sign == MP_ZPOS) ? 0 : 1); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_to_signed_bin.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_to_signed_bin_n.c b/libtommath/bn_mp_to_signed_bin_n.c new file mode 100644 index 0000000..4e9d217 --- /dev/null +++ b/libtommath/bn_mp_to_signed_bin_n.c @@ -0,0 +1,31 @@ +#include <tommath.h> +#ifdef BN_MP_TO_SIGNED_BIN_N_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* store in signed [big endian] format */ +int mp_to_signed_bin_n (mp_int * a, unsigned char *b, unsigned long *outlen) +{ + if (*outlen < (unsigned long)mp_signed_bin_size(a)) { + return MP_VAL; + } + *outlen = mp_signed_bin_size(a); + return mp_to_signed_bin(a, b); +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_to_signed_bin_n.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_to_unsigned_bin.c b/libtommath/bn_mp_to_unsigned_bin.c new file mode 100644 index 0000000..b25935d --- /dev/null +++ b/libtommath/bn_mp_to_unsigned_bin.c @@ -0,0 +1,48 @@ +#include <tommath.h> +#ifdef BN_MP_TO_UNSIGNED_BIN_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* store in unsigned [big endian] format */ +int mp_to_unsigned_bin (mp_int * a, unsigned char *b) +{ + int x, res; + mp_int t; + + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + + x = 0; + while (mp_iszero (&t) == 0) { +#ifndef MP_8BIT + b[x++] = (unsigned char) (t.dp[0] & 255); +#else + b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7)); +#endif + if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) { + mp_clear (&t); + return res; + } + } + bn_reverse (b, x); + mp_clear (&t); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_to_unsigned_bin.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_to_unsigned_bin_n.c b/libtommath/bn_mp_to_unsigned_bin_n.c new file mode 100644 index 0000000..4abf4e1 --- /dev/null +++ b/libtommath/bn_mp_to_unsigned_bin_n.c @@ -0,0 +1,31 @@ +#include <tommath.h> +#ifdef BN_MP_TO_UNSIGNED_BIN_N_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* store in unsigned [big endian] format */ +int mp_to_unsigned_bin_n (mp_int * a, unsigned char *b, unsigned long *outlen) +{ + if (*outlen < (unsigned long)mp_unsigned_bin_size(a)) { + return MP_VAL; + } + *outlen = mp_unsigned_bin_size(a); + return mp_to_unsigned_bin(a, b); +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_to_unsigned_bin_n.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_toom_mul.c b/libtommath/bn_mp_toom_mul.c new file mode 100644 index 0000000..fa29078 --- /dev/null +++ b/libtommath/bn_mp_toom_mul.c @@ -0,0 +1,284 @@ +#include <tommath.h> +#ifdef BN_MP_TOOM_MUL_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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...). +*/ +int mp_toom_mul(mp_int *a, mp_int *b, mp_int *c) +{ + mp_int w0, w1, w2, w3, w4, tmp1, tmp2, a0, a1, a2, b0, b1, b2; + int res, B; + + /* init temps */ + if ((res = mp_init_multi(&w0, &w1, &w2, &w3, &w4, + &a0, &a1, &a2, &b0, &b1, + &b2, &tmp1, &tmp2, NULL)) != MP_OKAY) { + return res; + } + + /* B */ + B = MIN(a->used, b->used) / 3; + + /* a = a2 * B**2 + a1 * B + a0 */ + if ((res = mp_mod_2d(a, DIGIT_BIT * B, &a0)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_copy(a, &a1)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&a1, B); + mp_mod_2d(&a1, DIGIT_BIT * B, &a1); + + if ((res = mp_copy(a, &a2)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&a2, B*2); + + /* b = b2 * B**2 + b1 * B + b0 */ + if ((res = mp_mod_2d(b, DIGIT_BIT * B, &b0)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_copy(b, &b1)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&b1, B); + mp_mod_2d(&b1, DIGIT_BIT * B, &b1); + + if ((res = mp_copy(b, &b2)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&b2, B*2); + + /* w0 = a0*b0 */ + if ((res = mp_mul(&a0, &b0, &w0)) != MP_OKAY) { + goto ERR; + } + + /* w4 = a2 * b2 */ + if ((res = mp_mul(&a2, &b2, &w4)) != MP_OKAY) { + goto ERR; + } + + /* w1 = (a2 + 2(a1 + 2a0))(b2 + 2(b1 + 2b0)) */ + if ((res = mp_mul_2(&a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a2, &tmp1)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_mul_2(&b0, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b1, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp2, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b2, &tmp2)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_mul(&tmp1, &tmp2, &w1)) != MP_OKAY) { + goto ERR; + } + + /* w3 = (a0 + 2(a1 + 2a2))(b0 + 2(b1 + 2b2)) */ + if ((res = mp_mul_2(&a2, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_mul_2(&b2, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b1, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp2, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b0, &tmp2)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_mul(&tmp1, &tmp2, &w3)) != MP_OKAY) { + goto ERR; + } + + + /* w2 = (a2 + a1 + a0)(b2 + b1 + b0) */ + if ((res = mp_add(&a2, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&b2, &b1, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b0, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul(&tmp1, &tmp2, &w2)) != MP_OKAY) { + goto ERR; + } + + /* now solve the matrix + + 0 0 0 0 1 + 1 2 4 8 16 + 1 1 1 1 1 + 16 8 4 2 1 + 1 0 0 0 0 + + using 12 subtractions, 4 shifts, + 2 small divisions and 1 small multiplication + */ + + /* r1 - r4 */ + if ((res = mp_sub(&w1, &w4, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r0 */ + if ((res = mp_sub(&w3, &w0, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1/2 */ + if ((res = mp_div_2(&w1, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3/2 */ + if ((res = mp_div_2(&w3, &w3)) != MP_OKAY) { + goto ERR; + } + /* r2 - r0 - r4 */ + if ((res = mp_sub(&w2, &w0, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w4, &w2)) != MP_OKAY) { + goto ERR; + } + /* r1 - r2 */ + if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r2 */ + if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1 - 8r0 */ + if ((res = mp_mul_2d(&w0, 3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w1, &tmp1, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - 8r4 */ + if ((res = mp_mul_2d(&w4, 3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w3, &tmp1, &w3)) != MP_OKAY) { + goto ERR; + } + /* 3r2 - r1 - r3 */ + if ((res = mp_mul_d(&w2, 3, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w1, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w3, &w2)) != MP_OKAY) { + goto ERR; + } + /* r1 - r2 */ + if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r2 */ + if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1/3 */ + if ((res = mp_div_3(&w1, &w1, NULL)) != MP_OKAY) { + goto ERR; + } + /* r3/3 */ + if ((res = mp_div_3(&w3, &w3, NULL)) != MP_OKAY) { + goto ERR; + } + + /* at this point shift W[n] by B*n */ + if ((res = mp_lshd(&w1, 1*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w2, 2*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w3, 3*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w4, 4*B)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_add(&w0, &w1, c)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&w2, &w3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&w4, &tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, c, c)) != MP_OKAY) { + goto ERR; + } + +ERR: + mp_clear_multi(&w0, &w1, &w2, &w3, &w4, + &a0, &a1, &a2, &b0, &b1, + &b2, &tmp1, &tmp2, NULL); + return res; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_toom_mul.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_toom_sqr.c b/libtommath/bn_mp_toom_sqr.c new file mode 100644 index 0000000..093181a --- /dev/null +++ b/libtommath/bn_mp_toom_sqr.c @@ -0,0 +1,226 @@ +#include <tommath.h> +#ifdef BN_MP_TOOM_SQR_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* squaring using Toom-Cook 3-way algorithm */ +int +mp_toom_sqr(mp_int *a, mp_int *b) +{ + mp_int w0, w1, w2, w3, w4, tmp1, a0, a1, a2; + int res, B; + + /* init temps */ + if ((res = mp_init_multi(&w0, &w1, &w2, &w3, &w4, &a0, &a1, &a2, &tmp1, NULL)) != MP_OKAY) { + return res; + } + + /* B */ + B = a->used / 3; + + /* a = a2 * B**2 + a1 * B + a0 */ + if ((res = mp_mod_2d(a, DIGIT_BIT * B, &a0)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_copy(a, &a1)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&a1, B); + mp_mod_2d(&a1, DIGIT_BIT * B, &a1); + + if ((res = mp_copy(a, &a2)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&a2, B*2); + + /* w0 = a0*a0 */ + if ((res = mp_sqr(&a0, &w0)) != MP_OKAY) { + goto ERR; + } + + /* w4 = a2 * a2 */ + if ((res = mp_sqr(&a2, &w4)) != MP_OKAY) { + goto ERR; + } + + /* w1 = (a2 + 2(a1 + 2a0))**2 */ + if ((res = mp_mul_2(&a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a2, &tmp1)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_sqr(&tmp1, &w1)) != MP_OKAY) { + goto ERR; + } + + /* w3 = (a0 + 2(a1 + 2a2))**2 */ + if ((res = mp_mul_2(&a2, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_sqr(&tmp1, &w3)) != MP_OKAY) { + goto ERR; + } + + + /* w2 = (a2 + a1 + a0)**2 */ + if ((res = mp_add(&a2, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sqr(&tmp1, &w2)) != MP_OKAY) { + goto ERR; + } + + /* now solve the matrix + + 0 0 0 0 1 + 1 2 4 8 16 + 1 1 1 1 1 + 16 8 4 2 1 + 1 0 0 0 0 + + using 12 subtractions, 4 shifts, 2 small divisions and 1 small multiplication. + */ + + /* r1 - r4 */ + if ((res = mp_sub(&w1, &w4, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r0 */ + if ((res = mp_sub(&w3, &w0, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1/2 */ + if ((res = mp_div_2(&w1, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3/2 */ + if ((res = mp_div_2(&w3, &w3)) != MP_OKAY) { + goto ERR; + } + /* r2 - r0 - r4 */ + if ((res = mp_sub(&w2, &w0, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w4, &w2)) != MP_OKAY) { + goto ERR; + } + /* r1 - r2 */ + if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r2 */ + if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1 - 8r0 */ + if ((res = mp_mul_2d(&w0, 3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w1, &tmp1, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - 8r4 */ + if ((res = mp_mul_2d(&w4, 3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w3, &tmp1, &w3)) != MP_OKAY) { + goto ERR; + } + /* 3r2 - r1 - r3 */ + if ((res = mp_mul_d(&w2, 3, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w1, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w3, &w2)) != MP_OKAY) { + goto ERR; + } + /* r1 - r2 */ + if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r2 */ + if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1/3 */ + if ((res = mp_div_3(&w1, &w1, NULL)) != MP_OKAY) { + goto ERR; + } + /* r3/3 */ + if ((res = mp_div_3(&w3, &w3, NULL)) != MP_OKAY) { + goto ERR; + } + + /* at this point shift W[n] by B*n */ + if ((res = mp_lshd(&w1, 1*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w2, 2*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w3, 3*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w4, 4*B)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_add(&w0, &w1, b)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&w2, &w3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&w4, &tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, b, b)) != MP_OKAY) { + goto ERR; + } + +ERR: + mp_clear_multi(&w0, &w1, &w2, &w3, &w4, &a0, &a1, &a2, &tmp1, NULL); + return res; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_toom_sqr.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_toradix.c b/libtommath/bn_mp_toradix.c new file mode 100644 index 0000000..c500832 --- /dev/null +++ b/libtommath/bn_mp_toradix.c @@ -0,0 +1,75 @@ +#include <tommath.h> +#ifdef BN_MP_TORADIX_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* stores a bignum as a ASCII string in a given radix (2..64) */ +int mp_toradix (mp_int * a, char *str, int radix) +{ + int res, digs; + mp_int t; + mp_digit d; + char *_s = str; + + /* check range of the radix */ + if (radix < 2 || radix > 64) { + return MP_VAL; + } + + /* quick out if its zero */ + if (mp_iszero(a) == 1) { + *str++ = '0'; + *str = '\0'; + return MP_OKAY; + } + + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + + /* if it is negative output a - */ + if (t.sign == MP_NEG) { + ++_s; + *str++ = '-'; + t.sign = MP_ZPOS; + } + + digs = 0; + while (mp_iszero (&t) == 0) { + if ((res = mp_div_d (&t, (mp_digit) radix, &t, &d)) != MP_OKAY) { + mp_clear (&t); + return res; + } + *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] + */ + bn_reverse ((unsigned char *)_s, digs); + + /* append a NULL so the string is properly terminated */ + *str = '\0'; + + mp_clear (&t); + return MP_OKAY; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_toradix.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_toradix_n.c b/libtommath/bn_mp_toradix_n.c new file mode 100644 index 0000000..7c0f3bc --- /dev/null +++ b/libtommath/bn_mp_toradix_n.c @@ -0,0 +1,88 @@ +#include <tommath.h> +#ifdef BN_MP_TORADIX_N_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* stores a bignum as a ASCII string in a given radix (2..64) + * + * Stores upto maxlen-1 chars and always a NULL byte + */ +int mp_toradix_n(mp_int * a, char *str, int radix, int maxlen) +{ + int res, digs; + mp_int t; + mp_digit d; + char *_s = str; + + /* check range of the maxlen, radix */ + if (maxlen < 2 || radix < 2 || radix > 64) { + return MP_VAL; + } + + /* quick out if its zero */ + if (mp_iszero(a) == MP_YES) { + *str++ = '0'; + *str = '\0'; + return MP_OKAY; + } + + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + + /* 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 = 0; + while (mp_iszero (&t) == 0) { + if (--maxlen < 1) { + /* no more room */ + break; + } + if ((res = mp_div_d (&t, (mp_digit) radix, &t, &d)) != MP_OKAY) { + mp_clear (&t); + return res; + } + *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 + */ + bn_reverse ((unsigned char *)_s, digs); + + /* append a NULL so the string is properly terminated */ + *str = '\0'; + + mp_clear (&t); + return MP_OKAY; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_toradix_n.c,v $ */ +/* $Revision: 1.4 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_unsigned_bin_size.c b/libtommath/bn_mp_unsigned_bin_size.c new file mode 100644 index 0000000..00d6aa0 --- /dev/null +++ b/libtommath/bn_mp_unsigned_bin_size.c @@ -0,0 +1,28 @@ +#include <tommath.h> +#ifdef BN_MP_UNSIGNED_BIN_SIZE_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* get the size for an unsigned equivalent */ +int mp_unsigned_bin_size (mp_int * a) +{ + int size = mp_count_bits (a); + return (size / 8 + ((size & 7) != 0 ? 1 : 0)); +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_unsigned_bin_size.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_xor.c b/libtommath/bn_mp_xor.c new file mode 100644 index 0000000..508c1a0 --- /dev/null +++ b/libtommath/bn_mp_xor.c @@ -0,0 +1,51 @@ +#include <tommath.h> +#ifdef BN_MP_XOR_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* XOR two ints together */ +int +mp_xor (mp_int * a, mp_int * b, mp_int * c) +{ + int res, ix, px; + mp_int t, *x; + + if (a->used > b->used) { + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + px = b->used; + x = b; + } else { + if ((res = mp_init_copy (&t, b)) != MP_OKAY) { + return res; + } + px = a->used; + x = a; + } + + for (ix = 0; ix < px; ix++) { + t.dp[ix] ^= x->dp[ix]; + } + mp_clamp (&t); + mp_exch (c, &t); + mp_clear (&t); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_xor.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_mp_zero.c b/libtommath/bn_mp_zero.c new file mode 100644 index 0000000..d8fd536 --- /dev/null +++ b/libtommath/bn_mp_zero.c @@ -0,0 +1,36 @@ +#include <tommath.h> +#ifdef BN_MP_ZERO_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* set to zero */ +void mp_zero (mp_int * a) +{ + int n; + mp_digit *tmp; + + a->sign = MP_ZPOS; + a->used = 0; + + tmp = a->dp; + for (n = 0; n < a->alloc; n++) { + *tmp++ = 0; + } +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_zero.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_prime_tab.c b/libtommath/bn_prime_tab.c new file mode 100644 index 0000000..522d428 --- /dev/null +++ b/libtommath/bn_prime_tab.c @@ -0,0 +1,61 @@ +#include <tommath.h> +#ifdef BN_PRIME_TAB_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ +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 +}; +#endif + +/* $Source: /cvs/libtom/libtommath/bn_prime_tab.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_reverse.c b/libtommath/bn_reverse.c new file mode 100644 index 0000000..ed19627 --- /dev/null +++ b/libtommath/bn_reverse.c @@ -0,0 +1,39 @@ +#include <tommath.h> +#ifdef BN_REVERSE_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* reverse an array, used for radix code */ +void +bn_reverse (unsigned char *s, int len) +{ + int ix, iy; + unsigned char t; + + ix = 0; + iy = len - 1; + while (ix < iy) { + t = s[ix]; + s[ix] = s[iy]; + s[iy] = t; + ++ix; + --iy; + } +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_reverse.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_s_mp_add.c b/libtommath/bn_s_mp_add.c new file mode 100644 index 0000000..5d17f12 --- /dev/null +++ b/libtommath/bn_s_mp_add.c @@ -0,0 +1,109 @@ +#include <tommath.h> +#ifdef BN_S_MP_ADD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* low level addition, based on HAC pp.594, Algorithm 14.7 */ +int +s_mp_add (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int *x; + int olduse, res, 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 ((res = mp_grow (c, max + 1)) != MP_OKAY) { + return res; + } + } + + /* get old used digit count and set new one */ + olduse = c->used; + c->used = max + 1; + + { + register mp_digit u, *tmpa, *tmpb, *tmpc; + register 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)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)DIGIT_BIT); + + /* take away carry bit from T[i] */ + *tmpc++ &= MP_MASK; + } + } + + /* add carry */ + *tmpc++ = u; + + /* clear digits above oldused */ + for (i = c->used; i < olduse; i++) { + *tmpc++ = 0; + } + } + + mp_clamp (c); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_s_mp_add.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_s_mp_exptmod.c b/libtommath/bn_s_mp_exptmod.c new file mode 100644 index 0000000..189197c --- /dev/null +++ b/libtommath/bn_s_mp_exptmod.c @@ -0,0 +1,252 @@ +#include <tommath.h> +#ifdef BN_S_MP_EXPTMOD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ +#ifdef MP_LOW_MEM + #define TAB_SIZE 32 +#else + #define TAB_SIZE 256 +#endif + +int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) +{ + mp_int M[TAB_SIZE], res, mu; + mp_digit buf; + int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + int (*redux)(mp_int*,mp_int*,mp_int*); + + /* 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; + } + +#ifdef MP_LOW_MEM + if (winsize > 5) { + winsize = 5; + } +#endif + + /* 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[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_MU; + } + + for (x = 0; x < (winsize - 1); x++) { + /* square it */ + if ((err = mp_sqr (&M[1 << (winsize - 1)], + &M[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_MU; + } + + /* reduce modulo P */ + if ((err = redux (&M[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, 1); + + /* 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) DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1; + 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 + +/* $Source: /cvs/libtom/libtommath/bn_s_mp_exptmod.c,v $ */ +/* $Revision: 1.4 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_s_mp_mul_digs.c b/libtommath/bn_s_mp_mul_digs.c new file mode 100644 index 0000000..7d55b81 --- /dev/null +++ b/libtommath/bn_s_mp_mul_digs.c @@ -0,0 +1,90 @@ +#include <tommath.h> +#ifdef BN_S_MP_MUL_DIGS_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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. + */ +int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + mp_int t; + int res, pa, pb, ix, iy; + mp_digit u; + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + + /* can we use the fast multiplier? */ + if (((digs) < MP_WARRAY) && + MIN (a->used, b->used) < + (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_s_mp_mul_digs (a, b, c, digs); + } + + if ((res = mp_init_size (&t, digs)) != MP_OKAY) { + return res; + } + 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 = 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) 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 + +/* $Source: /cvs/libtom/libtommath/bn_s_mp_mul_digs.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_s_mp_mul_high_digs.c b/libtommath/bn_s_mp_mul_high_digs.c new file mode 100644 index 0000000..1c0aae4 --- /dev/null +++ b/libtommath/bn_s_mp_mul_high_digs.c @@ -0,0 +1,81 @@ +#include <tommath.h> +#ifdef BN_S_MP_MUL_HIGH_DIGS_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* multiplies |a| * |b| and does not compute the lower digs digits + * [meant to get the higher part of the product] + */ +int +s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + mp_int t; + int res, pa, pb, ix, iy; + mp_digit u; + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + + /* can we use the fast multiplier? */ +#ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C + if (((a->used + b->used + 1) < MP_WARRAY) + && MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_s_mp_mul_high_digs (a, b, c, digs); + } +#endif + + if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) { + return res; + } + 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) DIGIT_BIT)); + } + *tmpt = u; + } + mp_clamp (&t); + mp_exch (&t, c); + mp_clear (&t); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_s_mp_mul_high_digs.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_s_mp_sqr.c b/libtommath/bn_s_mp_sqr.c new file mode 100644 index 0000000..b0063bc --- /dev/null +++ b/libtommath/bn_s_mp_sqr.c @@ -0,0 +1,84 @@ +#include <tommath.h> +#ifdef BN_S_MP_SQR_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */ +int s_mp_sqr (mp_int * a, mp_int * b) +{ + mp_int t; + int res, ix, iy, pa; + mp_word r; + mp_digit u, tmpx, *tmpt; + + pa = a->used; + if ((res = mp_init_size (&t, 2*pa + 1)) != MP_OKAY) { + return res; + } + + /* 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) 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) DIGIT_BIT)); + } + /* propagate upwards */ + while (u != ((mp_digit) 0)) { + r = ((mp_word) *tmpt) + ((mp_word) u); + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + } + } + + mp_clamp (&t); + mp_exch (&t, b); + mp_clear (&t); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_s_mp_sqr.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bn_s_mp_sub.c b/libtommath/bn_s_mp_sub.c new file mode 100644 index 0000000..f5949f5 --- /dev/null +++ b/libtommath/bn_s_mp_sub.c @@ -0,0 +1,89 @@ +#include <tommath.h> +#ifdef BN_S_MP_SUB_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */ +int +s_mp_sub (mp_int * a, mp_int * b, mp_int * c) +{ + int olduse, res, min, max; + + /* find sizes */ + min = b->used; + max = a->used; + + /* init result */ + if (c->alloc < max) { + if ((res = mp_grow (c, max)) != MP_OKAY) { + return res; + } + } + olduse = c->used; + c->used = max; + + { + register mp_digit u, *tmpa, *tmpb, *tmpc; + register 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_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); + + /* 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_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); + + /* Clear carry from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* clear digits above used (since we may not have grown result above) */ + for (i = c->used; i < olduse; i++) { + *tmpc++ = 0; + } + } + + mp_clamp (c); + return MP_OKAY; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_s_mp_sub.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/bncore.c b/libtommath/bncore.c new file mode 100644 index 0000000..989a1dd --- /dev/null +++ b/libtommath/bncore.c @@ -0,0 +1,36 @@ +#include <tommath.h> +#ifdef BNCORE_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* Known optimal configurations + + CPU /Compiler /MUL CUTOFF/SQR CUTOFF +------------------------------------------------------------- + Intel P4 Northwood /GCC v3.4.1 / 88/ 128/LTM 0.32 ;-) + AMD Athlon64 /GCC v3.4.4 / 80/ 120/LTM 0.35 + +*/ + +int KARATSUBA_MUL_CUTOFF = 80, /* Min. number of digits before Karatsuba multiplication is used. */ + KARATSUBA_SQR_CUTOFF = 120, /* Min. number of digits before Karatsuba squaring is used. */ + + TOOM_MUL_CUTOFF = 350, /* no optimal values of these are known yet so set em high */ + TOOM_SQR_CUTOFF = 400; +#endif + +/* $Source: /cvs/libtom/libtommath/bncore.c,v $ */ +/* $Revision: 1.4 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/booker.pl b/libtommath/booker.pl new file mode 100644 index 0000000..49f1889 --- /dev/null +++ b/libtommath/booker.pl @@ -0,0 +1,265 @@ +#!/bin/perl +# +#Used to prepare the book "tommath.src" for LaTeX by pre-processing it into a .tex file +# +#Essentially you write the "tommath.src" as normal LaTex except where you want code snippets you put +# +#EXAM,file +# +#This preprocessor will then open "file" and insert it as a verbatim copy. +# +#Tom St Denis + +#get graphics type +if (shift =~ /PDF/) { + $graph = ""; +} else { + $graph = ".ps"; +} + +open(IN,"<tommath.src") or die "Can't open source file"; +open(OUT,">tommath.tex") or die "Can't open destination file"; + +print "Scanning for sections\n"; +$chapter = $section = $subsection = 0; +$x = 0; +while (<IN>) { + print "."; + if (!(++$x % 80)) { print "\n"; } + #update the headings + if (~($_ =~ /\*/)) { + if ($_ =~ /\\chapter{.+}/) { + ++$chapter; + $section = $subsection = 0; + } elsif ($_ =~ /\\section{.+}/) { + ++$section; + $subsection = 0; + } elsif ($_ =~ /\\subsection{.+}/) { + ++$subsection; + } + } + + if ($_ =~ m/MARK/) { + @m = split(",",$_); + chomp(@m[1]); + $index1{@m[1]} = $chapter; + $index2{@m[1]} = $section; + $index3{@m[1]} = $subsection; + } +} +close(IN); + +open(IN,"<tommath.src") or die "Can't open source file"; +$readline = $wroteline = 0; +$srcline = 0; + +while (<IN>) { + ++$readline; + ++$srcline; + + if ($_ =~ m/MARK/) { + } elsif ($_ =~ m/EXAM/ || $_ =~ m/LIST/) { + if ($_ =~ m/EXAM/) { + $skipheader = 1; + } else { + $skipheader = 0; + } + + # EXAM,file + chomp($_); + @m = split(",",$_); + open(SRC,"<$m[1]") or die "Error:$srcline:Can't open source file $m[1]"; + + print "$srcline:Inserting $m[1]:"; + + $line = 0; + $tmp = $m[1]; + $tmp =~ s/_/"\\_"/ge; + print OUT "\\vspace{+3mm}\\begin{small}\n\\hspace{-5.1mm}{\\bf File}: $tmp\n\\vspace{-3mm}\n\\begin{alltt}\n"; + $wroteline += 5; + + if ($skipheader == 1) { + # scan till next end of comment, e.g. skip license + while (<SRC>) { + $text[$line++] = $_; + last if ($_ =~ /math\.libtomcrypt\.com/); + } + <SRC>; + } + + $inline = 0; + while (<SRC>) { + next if ($_ =~ /\$Source/); + next if ($_ =~ /\$Revision/); + next if ($_ =~ /\$Date/); + $text[$line++] = $_; + ++$inline; + chomp($_); + $_ =~ s/\t/" "/ge; + $_ =~ s/{/"^{"/ge; + $_ =~ s/}/"^}"/ge; + $_ =~ s/\\/'\symbol{92}'/ge; + $_ =~ s/\^/"\\"/ge; + + printf OUT ("%03d ", $line); + for ($x = 0; $x < length($_); $x++) { + print OUT chr(vec($_, $x, 8)); + if ($x == 75) { + print OUT "\n "; + ++$wroteline; + } + } + print OUT "\n"; + ++$wroteline; + } + $totlines = $line; + print OUT "\\end{alltt}\n\\end{small}\n"; + close(SRC); + print "$inline lines\n"; + $wroteline += 2; + } elsif ($_ =~ m/@\d+,.+@/) { + # line contains [number,text] + # e.g. @14,for (ix = 0)@ + $txt = $_; + while ($txt =~ m/@\d+,.+@/) { + @m = split("@",$txt); # splits into text, one, two + @parms = split(",",$m[1]); # splits one,two into two elements + + # now search from $parms[0] down for $parms[1] + $found1 = 0; + $found2 = 0; + for ($i = $parms[0]; $i < $totlines && $found1 == 0; $i++) { + if ($text[$i] =~ m/\Q$parms[1]\E/) { + $foundline1 = $i + 1; + $found1 = 1; + } + } + + # now search backwards + for ($i = $parms[0] - 1; $i >= 0 && $found2 == 0; $i--) { + if ($text[$i] =~ m/\Q$parms[1]\E/) { + $foundline2 = $i + 1; + $found2 = 1; + } + } + + # now use the closest match or the first if tied + if ($found1 == 1 && $found2 == 0) { + $found = 1; + $foundline = $foundline1; + } elsif ($found1 == 0 && $found2 == 1) { + $found = 1; + $foundline = $foundline2; + } elsif ($found1 == 1 && $found2 == 1) { + $found = 1; + if (($foundline1 - $parms[0]) <= ($parms[0] - $foundline2)) { + $foundline = $foundline1; + } else { + $foundline = $foundline2; + } + } else { + $found = 0; + } + + # if found replace + if ($found == 1) { + $delta = $parms[0] - $foundline; + print "Found replacement tag for \"$parms[1]\" on line $srcline which refers to line $foundline (delta $delta)\n"; + $_ =~ s/@\Q$m[1]\E@/$foundline/; + } else { + print "ERROR: The tag \"$parms[1]\" on line $srcline was not found in the most recently parsed source!\n"; + } + + # remake the rest of the line + $cnt = @m; + $txt = ""; + for ($i = 2; $i < $cnt; $i++) { + $txt = $txt . $m[$i] . "@"; + } + } + print OUT $_; + ++$wroteline; + } elsif ($_ =~ /~.+~/) { + # line contains a ~text~ pair used to refer to indexing :-) + $txt = $_; + while ($txt =~ /~.+~/) { + @m = split("~", $txt); + + # word is the second position + $word = @m[1]; + $a = $index1{$word}; + $b = $index2{$word}; + $c = $index3{$word}; + + # if chapter (a) is zero it wasn't found + if ($a == 0) { + print "ERROR: the tag \"$word\" on line $srcline was not found previously marked.\n"; + } else { + # format the tag as x, x.y or x.y.z depending on the values + $str = $a; + $str = $str . ".$b" if ($b != 0); + $str = $str . ".$c" if ($c != 0); + + if ($b == 0 && $c == 0) { + # its a chapter + if ($a <= 10) { + if ($a == 1) { + $str = "chapter one"; + } elsif ($a == 2) { + $str = "chapter two"; + } elsif ($a == 3) { + $str = "chapter three"; + } elsif ($a == 4) { + $str = "chapter four"; + } elsif ($a == 5) { + $str = "chapter five"; + } elsif ($a == 6) { + $str = "chapter six"; + } elsif ($a == 7) { + $str = "chapter seven"; + } elsif ($a == 8) { + $str = "chapter eight"; + } elsif ($a == 9) { + $str = "chapter nine"; + } elsif ($a == 10) { + $str = "chapter ten"; + } + } else { + $str = "chapter " . $str; + } + } else { + $str = "section " . $str if ($b != 0 && $c == 0); + $str = "sub-section " . $str if ($b != 0 && $c != 0); + } + + #substitute + $_ =~ s/~\Q$word\E~/$str/; + + print "Found replacement tag for marker \"$word\" on line $srcline which refers to $str\n"; + } + + # remake rest of the line + $cnt = @m; + $txt = ""; + for ($i = 2; $i < $cnt; $i++) { + $txt = $txt . $m[$i] . "~"; + } + } + print OUT $_; + ++$wroteline; + } elsif ($_ =~ m/FIGU/) { + # FIGU,file,caption + chomp($_); + @m = split(",", $_); + print OUT "\\begin{center}\n\\begin{figure}[here]\n\\includegraphics{pics/$m[1]$graph}\n"; + print OUT "\\caption{$m[2]}\n\\label{pic:$m[1]}\n\\end{figure}\n\\end{center}\n"; + $wroteline += 4; + } else { + print OUT $_; + ++$wroteline; + } +} +print "Read $readline lines, wrote $wroteline lines\n"; + +close (OUT); +close (IN); diff --git a/libtommath/changes.txt b/libtommath/changes.txt new file mode 100644 index 0000000..aaaf69f --- /dev/null +++ b/libtommath/changes.txt @@ -0,0 +1,393 @@ +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" <Wolfgang.Ehrhardt@munich.netsurf.de> 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 diff --git a/libtommath/demo/demo.c b/libtommath/demo/demo.c new file mode 100644 index 0000000..bb5eb44 --- /dev/null +++ b/libtommath/demo/demo.c @@ -0,0 +1,740 @@ +#include <time.h> + +#ifdef IOWNANATHLON +#include <unistd.h> +#define SLEEP sleep(4) +#else +#define SLEEP +#endif + +#include "tommath.h" + +void ndraw(mp_int * a, char *name) +{ + char buf[16000]; + + printf("%s: ", name); + mp_toradix(a, buf, 10); + printf("%s\n", buf); +} + +static void draw(mp_int * a) +{ + ndraw(a, ""); +} + + +unsigned long lfsr = 0xAAAAAAAAUL; + +int lbit(void) +{ + if (lfsr & 0x80000000UL) { + lfsr = ((lfsr << 1) ^ 0x8000001BUL) & 0xFFFFFFFFUL; + return 1; + } else { + lfsr <<= 1; + return 0; + } +} + +int myrng(unsigned char *dst, int len, void *dat) +{ + int x; + + for (x = 0; x < len; x++) + dst[x] = rand() & 0xFF; + return len; +} + + + +char cmd[4096], buf[4096]; +int main(void) +{ + mp_int a, b, c, d, e, f; + unsigned long expt_n, add_n, sub_n, mul_n, div_n, sqr_n, mul2d_n, div2d_n, + gcd_n, lcm_n, inv_n, div2_n, mul2_n, add_d_n, sub_d_n, t; + unsigned rr; + int i, n, err, cnt, ix, old_kara_m, old_kara_s; + mp_digit mp; + + + mp_init(&a); + mp_init(&b); + mp_init(&c); + mp_init(&d); + mp_init(&e); + mp_init(&f); + + srand(time(NULL)); + +#if 0 + // test montgomery + printf("Testing montgomery...\n"); + for (i = 1; i < 10; i++) { + printf("Testing digit size: %d\n", i); + 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()) % (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) { +printf("d = e mod a, c = e MOD a\n"); +mp_todecimal(&a, buf); printf("a = %s\n", buf); +mp_todecimal(&e, buf); printf("e = %s\n", buf); +mp_todecimal(&d, buf); printf("d = %s\n", buf); +mp_todecimal(&c, buf); printf("c = %s\n", buf); +printf("compare no compare!\n"); exit(EXIT_FAILURE); } + } + } + } + printf("done\n"); + + // test mp_get_int + printf("Testing: mp_get_int\n"); + for (i = 0; i < 1000; ++i) { + t = ((unsigned long) rand() * rand() + 1) & 0xFFFFFFFF; + mp_set_int(&a, t); + if (t != mp_get_int(&a)) { + printf("mp_get_int() bad result!\n"); + return 1; + } + } + mp_set_int(&a, 0); + if (mp_get_int(&a) != 0) { + printf("mp_get_int() bad result!\n"); + return 1; + } + mp_set_int(&a, 0xffffffff); + if (mp_get_int(&a) != 0xffffffff) { + printf("mp_get_int() bad result!\n"); + return 1; + } + // test mp_sqrt + printf("Testing: mp_sqrt\n"); + for (i = 0; i < 1000; ++i) { + printf("%6d\r", i); + fflush(stdout); + n = (rand() & 15) + 1; + mp_rand(&a, n); + if (mp_sqrt(&a, &b) != MP_OKAY) { + printf("mp_sqrt() error!\n"); + return 1; + } + mp_n_root(&a, 2, &a); + if (mp_cmp_mag(&b, &a) != MP_EQ) { + printf("mp_sqrt() bad result!\n"); + return 1; + } + } + + printf("\nTesting: mp_is_square\n"); + for (i = 0; i < 1000; ++i) { + printf("%6d\r", i); + fflush(stdout); + + /* test mp_is_square false negatives */ + n = (rand() & 7) + 1; + mp_rand(&a, n); + mp_sqr(&a, &a); + if (mp_is_square(&a, &n) != MP_OKAY) { + printf("fn:mp_is_square() error!\n"); + return 1; + } + if (n == 0) { + printf("fn:mp_is_square() bad result!\n"); + return 1; + } + + /* test for false positives */ + mp_add_d(&a, 1, &a); + if (mp_is_square(&a, &n) != MP_OKAY) { + printf("fp:mp_is_square() error!\n"); + return 1; + } + if (n == 1) { + printf("fp:mp_is_square() bad result!\n"); + return 1; + } + + } + printf("\n\n"); + + /* test for size */ + for (ix = 10; ix < 128; ix++) { + printf("Testing (not safe-prime): %9d bits \r", ix); + fflush(stdout); + err = + mp_prime_random_ex(&a, 8, ix, + (rand() & 1) ? LTM_PRIME_2MSB_OFF : + LTM_PRIME_2MSB_ON, myrng, NULL); + if (err != MP_OKAY) { + printf("failed with err code %d\n", err); + return EXIT_FAILURE; + } + if (mp_count_bits(&a) != ix) { + printf("Prime is %d not %d bits!!!\n", mp_count_bits(&a), ix); + return EXIT_FAILURE; + } + } + + for (ix = 16; ix < 128; ix++) { + printf("Testing ( safe-prime): %9d bits \r", ix); + fflush(stdout); + err = + mp_prime_random_ex(&a, 8, ix, + ((rand() & 1) ? LTM_PRIME_2MSB_OFF : + LTM_PRIME_2MSB_ON) | LTM_PRIME_SAFE, myrng, + NULL); + if (err != MP_OKAY) { + printf("failed with err code %d\n", err); + return EXIT_FAILURE; + } + if (mp_count_bits(&a) != ix) { + printf("Prime is %d not %d bits!!!\n", mp_count_bits(&a), ix); + return EXIT_FAILURE; + } + /* let's see if it's really a safe prime */ + mp_sub_d(&a, 1, &a); + mp_div_2(&a, &a); + mp_prime_is_prime(&a, 8, &cnt); + if (cnt != MP_YES) { + printf("sub is not prime!\n"); + return EXIT_FAILURE; + } + } + + printf("\n\n"); + + mp_read_radix(&a, "123456", 10); + mp_toradix_n(&a, buf, 10, 3); + printf("a == %s\n", buf); + mp_toradix_n(&a, buf, 10, 4); + printf("a == %s\n", buf); + mp_toradix_n(&a, buf, 10, 30); + printf("a == %s\n", buf); + + +#if 0 + for (;;) { + fgets(buf, sizeof(buf), stdin); + mp_read_radix(&a, buf, 10); + mp_prime_next_prime(&a, 5, 1); + mp_toradix(&a, buf, 10); + printf("%s, %lu\n", buf, a.dp[0] & 3); + } +#endif + + /* test mp_cnt_lsb */ + printf("testing mp_cnt_lsb...\n"); + mp_set(&a, 1); + for (ix = 0; ix < 1024; ix++) { + if (mp_cnt_lsb(&a) != ix) { + printf("Failed at %d, %d\n", ix, mp_cnt_lsb(&a)); + return 0; + } + mp_mul_2(&a, &a); + } + +/* test mp_reduce_2k */ + printf("Testing mp_reduce_2k...\n"); + for (cnt = 3; cnt <= 128; ++cnt) { + mp_digit tmp; + + mp_2expt(&a, cnt); + mp_sub_d(&a, 2, &a); /* a = 2**cnt - 2 */ + + + printf("\nTesting %4d bits", cnt); + printf("(%d)", mp_reduce_is_2k(&a)); + mp_reduce_2k_setup(&a, &tmp); + printf("(%d)", tmp); + for (ix = 0; ix < 1000; ix++) { + if (!(ix & 127)) { + printf("."); + fflush(stdout); + } + mp_rand(&b, (cnt / DIGIT_BIT + 1) * 2); + mp_copy(&c, &b); + mp_mod(&c, &a, &c); + mp_reduce_2k(&b, &a, 2); + if (mp_cmp(&c, &b)) { + printf("FAILED\n"); + exit(0); + } + } + } + +/* test mp_div_3 */ + printf("Testing mp_div_3...\n"); + mp_set(&d, 3); + for (cnt = 0; cnt < 10000;) { + mp_digit r1, r2; + + if (!(++cnt & 127)) + printf("%9d\r", cnt); + mp_rand(&a, abs(rand()) % 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("\n\nmp_div_3 => Failure\n"); + } + } + printf("\n\nPassed div_3 testing\n"); + +/* test the DR reduction */ + printf("testing mp_dr_reduce...\n"); + for (cnt = 2; cnt < 32; cnt++) { + printf("%d digit modulus\n", 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("%9lu\r", rr); + fflush(stdout); + } + mp_sqr(&b, &b); + mp_add_d(&b, 1, &b); + mp_copy(&b, &c); + + mp_mod(&b, &a, &b); + mp_dr_reduce(&c, &a, (((mp_digit) 1) << DIGIT_BIT) - a.dp[0]); + + if (mp_cmp(&b, &c) != MP_EQ) { + printf("Failed on trial %lu\n", rr); + exit(-1); + + } + } while (++rr < 500); + printf("Passed DR test for %d digits\n", cnt); + } + +#endif + +/* test the mp_reduce_2k_l code */ +#if 0 +#if 0 +/* 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 1 +/* 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); +#endif + + mp_todecimal(&a, buf); + printf("p==%s\n", buf); +/* 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"); + return EXIT_FAILURE; + } + 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 < (1UL << 20); cnt++) { + mp_sqr(&b, &b); + mp_add_d(&b, 1, &b); + mp_reduce_2k_l(&b, &a, &d); + mp_sqr(&c, &c); + mp_add_d(&c, 1, &c); + mp_mod(&c, &a, &c); + if (mp_cmp(&b, &c) != MP_EQ) { + printf("mp_reduce_2k_l() failed at step %lu\n", cnt); + mp_tohex(&b, buf); + printf("b == %s\n", buf); + mp_tohex(&c, buf); + printf("c == %s\n", buf); + return EXIT_FAILURE; + } + } + printf("...Passed\n"); +#endif + + div2_n = mul2_n = inv_n = expt_n = lcm_n = gcd_n = add_n = + sub_n = mul_n = div_n = sqr_n = mul2d_n = div2d_n = cnt = add_d_n = + sub_d_n = 0; + + /* force KARA and TOOM to enable despite cutoffs */ + KARATSUBA_SQR_CUTOFF = KARATSUBA_MUL_CUTOFF = 8; + TOOM_SQR_CUTOFF = TOOM_MUL_CUTOFF = 16; + + for (;;) { + /* randomly clear and re-init one variable, this has the affect of triming the alloc space */ + switch (abs(rand()) % 7) { + case 0: + mp_clear(&a); + mp_init(&a); + break; + case 1: + mp_clear(&b); + mp_init(&b); + break; + case 2: + mp_clear(&c); + mp_init(&c); + break; + case 3: + mp_clear(&d); + mp_init(&d); + break; + case 4: + mp_clear(&e); + mp_init(&e); + break; + case 5: + mp_clear(&f); + mp_init(&f); + break; + case 6: + break; /* don't clear any */ + } + + + printf + ("%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu ", + add_n, sub_n, mul_n, div_n, sqr_n, mul2d_n, div2d_n, gcd_n, lcm_n, + expt_n, inv_n, div2_n, mul2_n, add_d_n, sub_d_n); + fgets(cmd, 4095, stdin); + cmd[strlen(cmd) - 1] = 0; + printf("%s ]\r", cmd); + fflush(stdout); + if (!strcmp(cmd, "mul2d")) { + ++mul2d_n; + fgets(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + fgets(buf, 4095, stdin); + sscanf(buf, "%d", &rr); + fgets(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + + mp_mul_2d(&a, rr, &a); + a.sign = b.sign; + if (mp_cmp(&a, &b) != MP_EQ) { + printf("mul2d failed, rr == %d\n", rr); + draw(&a); + draw(&b); + return 0; + } + } else if (!strcmp(cmd, "div2d")) { + ++div2d_n; + fgets(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + fgets(buf, 4095, stdin); + sscanf(buf, "%d", &rr); + fgets(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + + mp_div_2d(&a, rr, &a, &e); + a.sign = b.sign; + if (a.used == b.used && a.used == 0) { + a.sign = b.sign = MP_ZPOS; + } + if (mp_cmp(&a, &b) != MP_EQ) { + printf("div2d failed, rr == %d\n", rr); + draw(&a); + draw(&b); + return 0; + } + } else if (!strcmp(cmd, "add")) { + ++add_n; + fgets(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + fgets(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + fgets(buf, 4095, stdin); + mp_read_radix(&c, buf, 64); + mp_copy(&a, &d); + mp_add(&d, &b, &d); + if (mp_cmp(&c, &d) != MP_EQ) { + printf("add %lu failure!\n", add_n); + draw(&a); + draw(&b); + draw(&c); + draw(&d); + return 0; + } + + /* test the sign/unsigned storage functions */ + + rr = mp_signed_bin_size(&c); + mp_to_signed_bin(&c, (unsigned char *) cmd); + memset(cmd + rr, rand() & 255, sizeof(cmd) - rr); + mp_read_signed_bin(&d, (unsigned char *) cmd, rr); + if (mp_cmp(&c, &d) != MP_EQ) { + printf("mp_signed_bin failure!\n"); + draw(&c); + draw(&d); + return 0; + } + + + rr = mp_unsigned_bin_size(&c); + mp_to_unsigned_bin(&c, (unsigned char *) cmd); + memset(cmd + rr, rand() & 255, sizeof(cmd) - rr); + mp_read_unsigned_bin(&d, (unsigned char *) cmd, rr); + if (mp_cmp_mag(&c, &d) != MP_EQ) { + printf("mp_unsigned_bin failure!\n"); + draw(&c); + draw(&d); + return 0; + } + + } else if (!strcmp(cmd, "sub")) { + ++sub_n; + fgets(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + fgets(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + fgets(buf, 4095, stdin); + mp_read_radix(&c, buf, 64); + mp_copy(&a, &d); + mp_sub(&d, &b, &d); + if (mp_cmp(&c, &d) != MP_EQ) { + printf("sub %lu failure!\n", sub_n); + draw(&a); + draw(&b); + draw(&c); + draw(&d); + return 0; + } + } else if (!strcmp(cmd, "mul")) { + ++mul_n; + fgets(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + fgets(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + fgets(buf, 4095, stdin); + mp_read_radix(&c, buf, 64); + mp_copy(&a, &d); + mp_mul(&d, &b, &d); + if (mp_cmp(&c, &d) != MP_EQ) { + printf("mul %lu failure!\n", mul_n); + draw(&a); + draw(&b); + draw(&c); + draw(&d); + return 0; + } + } else if (!strcmp(cmd, "div")) { + ++div_n; + fgets(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + fgets(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + fgets(buf, 4095, stdin); + mp_read_radix(&c, buf, 64); + fgets(buf, 4095, stdin); + mp_read_radix(&d, buf, 64); + + mp_div(&a, &b, &e, &f); + if (mp_cmp(&c, &e) != MP_EQ || mp_cmp(&d, &f) != MP_EQ) { + printf("div %lu %d, %d, failure!\n", div_n, mp_cmp(&c, &e), + mp_cmp(&d, &f)); + draw(&a); + draw(&b); + draw(&c); + draw(&d); + draw(&e); + draw(&f); + return 0; + } + + } else if (!strcmp(cmd, "sqr")) { + ++sqr_n; + fgets(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + fgets(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + mp_copy(&a, &c); + mp_sqr(&c, &c); + if (mp_cmp(&b, &c) != MP_EQ) { + printf("sqr %lu failure!\n", sqr_n); + draw(&a); + draw(&b); + draw(&c); + return 0; + } + } else if (!strcmp(cmd, "gcd")) { + ++gcd_n; + fgets(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + fgets(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + fgets(buf, 4095, stdin); + mp_read_radix(&c, buf, 64); + mp_copy(&a, &d); + mp_gcd(&d, &b, &d); + d.sign = c.sign; + if (mp_cmp(&c, &d) != MP_EQ) { + printf("gcd %lu failure!\n", gcd_n); + draw(&a); + draw(&b); + draw(&c); + draw(&d); + return 0; + } + } else if (!strcmp(cmd, "lcm")) { + ++lcm_n; + fgets(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + fgets(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + fgets(buf, 4095, stdin); + mp_read_radix(&c, buf, 64); + mp_copy(&a, &d); + mp_lcm(&d, &b, &d); + d.sign = c.sign; + if (mp_cmp(&c, &d) != MP_EQ) { + printf("lcm %lu failure!\n", lcm_n); + draw(&a); + draw(&b); + draw(&c); + draw(&d); + return 0; + } + } else if (!strcmp(cmd, "expt")) { + ++expt_n; + fgets(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + fgets(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + fgets(buf, 4095, stdin); + mp_read_radix(&c, buf, 64); + fgets(buf, 4095, stdin); + mp_read_radix(&d, buf, 64); + mp_copy(&a, &e); + mp_exptmod(&e, &b, &c, &e); + if (mp_cmp(&d, &e) != MP_EQ) { + printf("expt %lu failure!\n", expt_n); + draw(&a); + draw(&b); + draw(&c); + draw(&d); + draw(&e); + return 0; + } + } else if (!strcmp(cmd, "invmod")) { + ++inv_n; + fgets(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + fgets(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + fgets(buf, 4095, stdin); + mp_read_radix(&c, buf, 64); + mp_invmod(&a, &b, &d); + mp_mulmod(&d, &a, &b, &e); + if (mp_cmp_d(&e, 1) != MP_EQ) { + printf("inv [wrong value from MPI?!] failure\n"); + draw(&a); + draw(&b); + draw(&c); + draw(&d); + mp_gcd(&a, &b, &e); + draw(&e); + return 0; + } + + } else if (!strcmp(cmd, "div2")) { + ++div2_n; + fgets(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + fgets(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + mp_div_2(&a, &c); + if (mp_cmp(&c, &b) != MP_EQ) { + printf("div_2 %lu failure\n", div2_n); + draw(&a); + draw(&b); + draw(&c); + return 0; + } + } else if (!strcmp(cmd, "mul2")) { + ++mul2_n; + fgets(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + fgets(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + mp_mul_2(&a, &c); + if (mp_cmp(&c, &b) != MP_EQ) { + printf("mul_2 %lu failure\n", mul2_n); + draw(&a); + draw(&b); + draw(&c); + return 0; + } + } else if (!strcmp(cmd, "add_d")) { + ++add_d_n; + fgets(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + fgets(buf, 4095, stdin); + sscanf(buf, "%d", &ix); + fgets(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + mp_add_d(&a, ix, &c); + if (mp_cmp(&b, &c) != MP_EQ) { + printf("add_d %lu failure\n", add_d_n); + draw(&a); + draw(&b); + draw(&c); + printf("d == %d\n", ix); + return 0; + } + } else if (!strcmp(cmd, "sub_d")) { + ++sub_d_n; + fgets(buf, 4095, stdin); + mp_read_radix(&a, buf, 64); + fgets(buf, 4095, stdin); + sscanf(buf, "%d", &ix); + fgets(buf, 4095, stdin); + mp_read_radix(&b, buf, 64); + mp_sub_d(&a, ix, &c); + if (mp_cmp(&b, &c) != MP_EQ) { + printf("sub_d %lu failure\n", sub_d_n); + draw(&a); + draw(&b); + draw(&c); + printf("d == %d\n", ix); + return 0; + } + } + } + return 0; +} + +/* $Source: /cvs/libtom/libtommath/demo/demo.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2005/06/24 11:32:07 $ */ diff --git a/libtommath/demo/timing.c b/libtommath/demo/timing.c new file mode 100644 index 0000000..d4660a9 --- /dev/null +++ b/libtommath/demo/timing.c @@ -0,0 +1,319 @@ +#include <tommath.h> +#include <time.h> + +ulong64 _tt; + +#ifdef IOWNANATHLON +#include <unistd.h> +#define SLEEP sleep(4) +#else +#define SLEEP +#endif + + +void ndraw(mp_int * a, char *name) +{ + char buf[4096]; + + printf("%s: ", name); + mp_toradix(a, buf, 64); + printf("%s\n", buf); +} + +static void draw(mp_int * a) +{ + ndraw(a, ""); +} + + +unsigned long lfsr = 0xAAAAAAAAUL; + +int lbit(void) +{ + if (lfsr & 0x80000000UL) { + lfsr = ((lfsr << 1) ^ 0x8000001BUL) & 0xFFFFFFFFUL; + return 1; + } else { + lfsr <<= 1; + return 0; + } +} + +/* RDTSC from Scott Duplichan */ +static ulong64 TIMFUNC(void) +{ +#if defined __GNUC__ +#if defined(__i386__) || defined(__x86_64__) + unsigned long long a; + __asm__ __volatile__("rdtsc\nmovl %%eax,%0\nmovl %%edx,4+%0\n":: + "m"(a):"%eax", "%edx"); + return a; +#else /* gcc-IA64 version */ + unsigned long result; + __asm__ __volatile__("mov %0=ar.itc":"=r"(result)::"memory"); + + while (__builtin_expect((int) result == -1, 0)) + __asm__ __volatile__("mov %0=ar.itc":"=r"(result)::"memory"); + + return result; +#endif + + // Microsoft and Intel Windows compilers +#elif defined _M_IX86 + __asm rdtsc +#elif defined _M_AMD64 + return __rdtsc(); +#elif defined _M_IA64 +#if defined __INTEL_COMPILER +#include <ia64intrin.h> +#endif + return __getReg(3116); +#else +#error need rdtsc function for this build +#endif +} + +#define DO(x) x; x; +//#define DO4(x) DO2(x); DO2(x); +//#define DO8(x) DO4(x); DO4(x); +//#define DO(x) DO8(x); DO8(x); + +int main(void) +{ + ulong64 tt, gg, CLK_PER_SEC; + FILE *log, *logb, *logc, *logd; + mp_int a, b, c, d, e, f; + int n, cnt, ix, old_kara_m, old_kara_s; + unsigned rr; + + mp_init(&a); + mp_init(&b); + mp_init(&c); + mp_init(&d); + mp_init(&e); + mp_init(&f); + + srand(time(NULL)); + + + /* temp. turn off TOOM */ + TOOM_MUL_CUTOFF = TOOM_SQR_CUTOFF = 100000; + + CLK_PER_SEC = TIMFUNC(); + sleep(1); + CLK_PER_SEC = TIMFUNC() - CLK_PER_SEC; + + printf("CLK_PER_SEC == %llu\n", CLK_PER_SEC); + goto exptmod; + log = fopen("logs/add.log", "w"); + for (cnt = 8; cnt <= 128; cnt += 8) { + SLEEP; + mp_rand(&a, cnt); + mp_rand(&b, cnt); + rr = 0; + tt = -1; + do { + gg = TIMFUNC(); + DO(mp_add(&a, &b, &c)); + gg = (TIMFUNC() - gg) >> 1; + if (tt > gg) + tt = gg; + } while (++rr < 100000); + printf("Adding\t\t%4d-bit => %9llu/sec, %9llu cycles\n", + mp_count_bits(&a), CLK_PER_SEC / tt, tt); + fprintf(log, "%d %9llu\n", cnt * DIGIT_BIT, tt); + fflush(log); + } + fclose(log); + + log = fopen("logs/sub.log", "w"); + for (cnt = 8; cnt <= 128; cnt += 8) { + SLEEP; + mp_rand(&a, cnt); + mp_rand(&b, cnt); + rr = 0; + tt = -1; + do { + gg = TIMFUNC(); + DO(mp_sub(&a, &b, &c)); + gg = (TIMFUNC() - gg) >> 1; + if (tt > gg) + tt = gg; + } while (++rr < 100000); + + printf("Subtracting\t\t%4d-bit => %9llu/sec, %9llu cycles\n", + mp_count_bits(&a), CLK_PER_SEC / tt, tt); + fprintf(log, "%d %9llu\n", cnt * DIGIT_BIT, tt); + fflush(log); + } + fclose(log); + + /* do mult/square twice, first without karatsuba and second with */ + multtest: + old_kara_m = KARATSUBA_MUL_CUTOFF; + old_kara_s = KARATSUBA_SQR_CUTOFF; + for (ix = 0; ix < 2; ix++) { + printf("With%s Karatsuba\n", (ix == 0) ? "out" : ""); + + KARATSUBA_MUL_CUTOFF = (ix == 0) ? 9999 : old_kara_m; + KARATSUBA_SQR_CUTOFF = (ix == 0) ? 9999 : old_kara_s; + + log = fopen((ix == 0) ? "logs/mult.log" : "logs/mult_kara.log", "w"); + for (cnt = 4; cnt <= 10240 / DIGIT_BIT; cnt += 2) { + SLEEP; + mp_rand(&a, cnt); + mp_rand(&b, cnt); + rr = 0; + tt = -1; + do { + gg = TIMFUNC(); + DO(mp_mul(&a, &b, &c)); + gg = (TIMFUNC() - gg) >> 1; + if (tt > gg) + tt = gg; + } while (++rr < 100); + printf("Multiplying\t%4d-bit => %9llu/sec, %9llu cycles\n", + mp_count_bits(&a), CLK_PER_SEC / tt, tt); + fprintf(log, "%d %9llu\n", mp_count_bits(&a), tt); + fflush(log); + } + fclose(log); + + log = fopen((ix == 0) ? "logs/sqr.log" : "logs/sqr_kara.log", "w"); + for (cnt = 4; cnt <= 10240 / DIGIT_BIT; cnt += 2) { + SLEEP; + mp_rand(&a, cnt); + rr = 0; + tt = -1; + do { + gg = TIMFUNC(); + DO(mp_sqr(&a, &b)); + gg = (TIMFUNC() - gg) >> 1; + if (tt > gg) + tt = gg; + } while (++rr < 100); + printf("Squaring\t%4d-bit => %9llu/sec, %9llu cycles\n", + mp_count_bits(&a), CLK_PER_SEC / tt, tt); + fprintf(log, "%d %9llu\n", mp_count_bits(&a), tt); + fflush(log); + } + fclose(log); + + } + exptmod: + + { + char *primes[] = { + /* 2K large moduli */ + "179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586239334100047359817950870678242457666208137217", + "32317006071311007300714876688669951960444102669715484032130345427524655138867890893197201411522913463688717960921898019494119559150490921095088152386448283120630877367300996091750197750389652106796057638384067568276792218642619756161838094338476170470581645852036305042887575891541065808607552399123930385521914333389668342420684974786564569494856176035326322058077805659331026192708460314150258592864177116725943603718461857357598351152301645904403697613233287231227125684710820209725157101726931323469678542580656697935045997268352998638099733077152121140120031150424541696791951097529546801429027668869927491725169", + "1044388881413152506691752710716624382579964249047383780384233483283953907971557456848826811934997558340890106714439262837987573438185793607263236087851365277945956976543709998340361590134383718314428070011855946226376318839397712745672334684344586617496807908705803704071284048740118609114467977783598029006686938976881787785946905630190260940599579453432823469303026696443059025015972399867714215541693835559885291486318237914434496734087811872639496475100189041349008417061675093668333850551032972088269550769983616369411933015213796825837188091833656751221318492846368125550225998300412344784862595674492194617023806505913245610825731835380087608622102834270197698202313169017678006675195485079921636419370285375124784014907159135459982790513399611551794271106831134090584272884279791554849782954323534517065223269061394905987693002122963395687782878948440616007412945674919823050571642377154816321380631045902916136926708342856440730447899971901781465763473223850267253059899795996090799469201774624817718449867455659250178329070473119433165550807568221846571746373296884912819520317457002440926616910874148385078411929804522981857338977648103126085902995208257421855249796721729039744118165938433694823325696642096892124547425283", + /* 2K moduli mersenne primes */ + "6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", + "531137992816767098689588206552468627329593117727031923199444138200403559860852242739162502265229285668889329486246501015346579337652707239409519978766587351943831270835393219031728127", + "10407932194664399081925240327364085538615262247266704805319112350403608059673360298012239441732324184842421613954281007791383566248323464908139906605677320762924129509389220345773183349661583550472959420547689811211693677147548478866962501384438260291732348885311160828538416585028255604666224831890918801847068222203140521026698435488732958028878050869736186900714720710555703168729087", + "1475979915214180235084898622737381736312066145333169775147771216478570297878078949377407337049389289382748507531496480477281264838760259191814463365330269540496961201113430156902396093989090226259326935025281409614983499388222831448598601834318536230923772641390209490231836446899608210795482963763094236630945410832793769905399982457186322944729636418890623372171723742105636440368218459649632948538696905872650486914434637457507280441823676813517852099348660847172579408422316678097670224011990280170474894487426924742108823536808485072502240519452587542875349976558572670229633962575212637477897785501552646522609988869914013540483809865681250419497686697771007", + "259117086013202627776246767922441530941818887553125427303974923161874019266586362086201209516800483406550695241733194177441689509238807017410377709597512042313066624082916353517952311186154862265604547691127595848775610568757931191017711408826252153849035830401185072116424747461823031471398340229288074545677907941037288235820705892351068433882986888616658650280927692080339605869308790500409503709875902119018371991620994002568935113136548829739112656797303241986517250116412703509705427773477972349821676443446668383119322540099648994051790241624056519054483690809616061625743042361721863339415852426431208737266591962061753535748892894599629195183082621860853400937932839420261866586142503251450773096274235376822938649407127700846077124211823080804139298087057504713825264571448379371125032081826126566649084251699453951887789613650248405739378594599444335231188280123660406262468609212150349937584782292237144339628858485938215738821232393687046160677362909315071", + "190797007524439073807468042969529173669356994749940177394741882673528979787005053706368049835514900244303495954950709725762186311224148828811920216904542206960744666169364221195289538436845390250168663932838805192055137154390912666527533007309292687539092257043362517857366624699975402375462954490293259233303137330643531556539739921926201438606439020075174723029056838272505051571967594608350063404495977660656269020823960825567012344189908927956646011998057988548630107637380993519826582389781888135705408653045219655801758081251164080554609057468028203308718724654081055323215860189611391296030471108443146745671967766308925858547271507311563765171008318248647110097614890313562856541784154881743146033909602737947385055355960331855614540900081456378659068370317267696980001187750995491090350108417050917991562167972281070161305972518044872048331306383715094854938415738549894606070722584737978176686422134354526989443028353644037187375385397838259511833166416134323695660367676897722287918773420968982326089026150031515424165462111337527431154890666327374921446276833564519776797633875503548665093914556482031482248883127023777039667707976559857333357013727342079099064400455741830654320379350833236245819348824064783585692924881021978332974949906122664421376034687815350484991", + + /* DR moduli */ + "14059105607947488696282932836518693308967803494693489478439861164411992439598399594747002144074658928593502845729752797260025831423419686528151609940203368612079", + "101745825697019260773923519755878567461315282017759829107608914364075275235254395622580447400994175578963163918967182013639660669771108475957692810857098847138903161308502419410142185759152435680068435915159402496058513611411688900243039", + "736335108039604595805923406147184530889923370574768772191969612422073040099331944991573923112581267542507986451953227192970402893063850485730703075899286013451337291468249027691733891486704001513279827771740183629161065194874727962517148100775228363421083691764065477590823919364012917984605619526140821797602431", + "38564998830736521417281865696453025806593491967131023221754800625044118265468851210705360385717536794615180260494208076605798671660719333199513807806252394423283413430106003596332513246682903994829528690198205120921557533726473585751382193953592127439965050261476810842071573684505878854588706623484573925925903505747545471088867712185004135201289273405614415899438276535626346098904241020877974002916168099951885406379295536200413493190419727789712076165162175783", + "542189391331696172661670440619180536749994166415993334151601745392193484590296600979602378676624808129613777993466242203025054573692562689251250471628358318743978285860720148446448885701001277560572526947619392551574490839286458454994488665744991822837769918095117129546414124448777033941223565831420390846864429504774477949153794689948747680362212954278693335653935890352619041936727463717926744868338358149568368643403037768649616778526013610493696186055899318268339432671541328195724261329606699831016666359440874843103020666106568222401047720269951530296879490444224546654729111504346660859907296364097126834834235287147", + "1487259134814709264092032648525971038895865645148901180585340454985524155135260217788758027400478312256339496385275012465661575576202252063145698732079880294664220579764848767704076761853197216563262660046602703973050798218246170835962005598561669706844469447435461092542265792444947706769615695252256130901271870341005768912974433684521436211263358097522726462083917939091760026658925757076733484173202927141441492573799914240222628795405623953109131594523623353044898339481494120112723445689647986475279242446083151413667587008191682564376412347964146113898565886683139407005941383669325997475076910488086663256335689181157957571445067490187939553165903773554290260531009121879044170766615232300936675369451260747671432073394867530820527479172464106442450727640226503746586340279816318821395210726268291535648506190714616083163403189943334431056876038286530365757187367147446004855912033137386225053275419626102417236133948503", + "1095121115716677802856811290392395128588168592409109494900178008967955253005183831872715423151551999734857184538199864469605657805519106717529655044054833197687459782636297255219742994736751541815269727940751860670268774903340296040006114013971309257028332849679096824800250742691718610670812374272414086863715763724622797509437062518082383056050144624962776302147890521249477060215148275163688301275847155316042279405557632639366066847442861422164832655874655824221577849928863023018366835675399949740429332468186340518172487073360822220449055340582568461568645259954873303616953776393853174845132081121976327462740354930744487429617202585015510744298530101547706821590188733515880733527449780963163909830077616357506845523215289297624086914545378511082534229620116563260168494523906566709418166011112754529766183554579321224940951177394088465596712620076240067370589036924024728375076210477267488679008016579588696191194060127319035195370137160936882402244399699172017835144537488486396906144217720028992863941288217185353914991583400421682751000603596655790990815525126154394344641336397793791497068253936771017031980867706707490224041075826337383538651825493679503771934836094655802776331664261631740148281763487765852746577808019633679", + + /* generic unrestricted moduli */ + "17933601194860113372237070562165128350027320072176844226673287945873370751245439587792371960615073855669274087805055507977323024886880985062002853331424203", + "2893527720709661239493896562339544088620375736490408468011883030469939904368086092336458298221245707898933583190713188177399401852627749210994595974791782790253946539043962213027074922559572312141181787434278708783207966459019479487", + "347743159439876626079252796797422223177535447388206607607181663903045907591201940478223621722118173270898487582987137708656414344685816179420855160986340457973820182883508387588163122354089264395604796675278966117567294812714812796820596564876450716066283126720010859041484786529056457896367683122960411136319", + "47266428956356393164697365098120418976400602706072312735924071745438532218237979333351774907308168340693326687317443721193266215155735814510792148768576498491199122744351399489453533553203833318691678263241941706256996197460424029012419012634671862283532342656309677173602509498417976091509154360039893165037637034737020327399910409885798185771003505320583967737293415979917317338985837385734747478364242020380416892056650841470869294527543597349250299539682430605173321029026555546832473048600327036845781970289288898317888427517364945316709081173840186150794397479045034008257793436817683392375274635794835245695887", + "436463808505957768574894870394349739623346440601945961161254440072143298152040105676491048248110146278752857839930515766167441407021501229924721335644557342265864606569000117714935185566842453630868849121480179691838399545644365571106757731317371758557990781880691336695584799313313687287468894148823761785582982549586183756806449017542622267874275103877481475534991201849912222670102069951687572917937634467778042874315463238062009202992087620963771759666448266532858079402669920025224220613419441069718482837399612644978839925207109870840278194042158748845445131729137117098529028886770063736487420613144045836803985635654192482395882603511950547826439092832800532152534003936926017612446606135655146445620623395788978726744728503058670046885876251527122350275750995227", + "11424167473351836398078306042624362277956429440521137061889702611766348760692206243140413411077394583180726863277012016602279290144126785129569474909173584789822341986742719230331946072730319555984484911716797058875905400999504305877245849119687509023232790273637466821052576859232452982061831009770786031785669030271542286603956118755585683996118896215213488875253101894663403069677745948305893849505434201763745232895780711972432011344857521691017896316861403206449421332243658855453435784006517202894181640562433575390821384210960117518650374602256601091379644034244332285065935413233557998331562749140202965844219336298970011513882564935538704289446968322281451907487362046511461221329799897350993370560697505809686438782036235372137015731304779072430260986460269894522159103008260495503005267165927542949439526272736586626709581721032189532726389643625590680105784844246152702670169304203783072275089194754889511973916207", + "1214855636816562637502584060163403830270705000634713483015101384881871978446801224798536155406895823305035467591632531067547890948695117172076954220727075688048751022421198712032848890056357845974246560748347918630050853933697792254955890439720297560693579400297062396904306270145886830719309296352765295712183040773146419022875165382778007040109957609739589875590885701126197906063620133954893216612678838507540777138437797705602453719559017633986486649523611975865005712371194067612263330335590526176087004421363598470302731349138773205901447704682181517904064735636518462452242791676541725292378925568296858010151852326316777511935037531017413910506921922450666933202278489024521263798482237150056835746454842662048692127173834433089016107854491097456725016327709663199738238442164843147132789153725513257167915555162094970853584447993125488607696008169807374736711297007473812256272245489405898470297178738029484459690836250560495461579533254473316340608217876781986188705928270735695752830825527963838355419762516246028680280988020401914551825487349990306976304093109384451438813251211051597392127491464898797406789175453067960072008590614886532333015881171367104445044718144312416815712216611576221546455968770801413440778423979", + NULL + }; + log = fopen("logs/expt.log", "w"); + logb = fopen("logs/expt_dr.log", "w"); + logc = fopen("logs/expt_2k.log", "w"); + logd = fopen("logs/expt_2kl.log", "w"); + for (n = 0; primes[n]; n++) { + SLEEP; + mp_read_radix(&a, primes[n], 10); + mp_zero(&b); + for (rr = 0; rr < (unsigned) mp_count_bits(&a); rr++) { + mp_mul_2(&b, &b); + b.dp[0] |= lbit(); + b.used += 1; + } + mp_sub_d(&a, 1, &c); + mp_mod(&b, &c, &b); + mp_set(&c, 3); + rr = 0; + tt = -1; + do { + gg = TIMFUNC(); + DO(mp_exptmod(&c, &b, &a, &d)); + gg = (TIMFUNC() - gg) >> 1; + if (tt > gg) + tt = gg; + } while (++rr < 10); + mp_sub_d(&a, 1, &e); + mp_sub(&e, &b, &b); + mp_exptmod(&c, &b, &a, &e); /* c^(p-1-b) mod a */ + mp_mulmod(&e, &d, &a, &d); /* c^b * c^(p-1-b) == c^p-1 == 1 */ + if (mp_cmp_d(&d, 1)) { + printf("Different (%d)!!!\n", mp_count_bits(&a)); + draw(&d); + exit(0); + } + printf("Exponentiating\t%4d-bit => %9llu/sec, %9llu cycles\n", + mp_count_bits(&a), CLK_PER_SEC / tt, tt); + fprintf(n < 4 ? logd : (n < 9) ? logc : (n < 16) ? logb : log, + "%d %9llu\n", mp_count_bits(&a), tt); + } + } + fclose(log); + fclose(logb); + fclose(logc); + fclose(logd); + + log = fopen("logs/invmod.log", "w"); + for (cnt = 4; cnt <= 128; cnt += 4) { + SLEEP; + mp_rand(&a, cnt); + mp_rand(&b, cnt); + + do { + mp_add_d(&b, 1, &b); + mp_gcd(&a, &b, &c); + } while (mp_cmp_d(&c, 1) != MP_EQ); + + rr = 0; + tt = -1; + do { + gg = TIMFUNC(); + DO(mp_invmod(&b, &a, &c)); + gg = (TIMFUNC() - gg) >> 1; + if (tt > gg) + tt = gg; + } while (++rr < 1000); + mp_mulmod(&b, &c, &a, &d); + if (mp_cmp_d(&d, 1) != MP_EQ) { + printf("Failed to invert\n"); + return 0; + } + printf("Inverting mod\t%4d-bit => %9llu/sec, %9llu cycles\n", + mp_count_bits(&a), CLK_PER_SEC / tt, tt); + fprintf(log, "%d %9llu\n", cnt * DIGIT_BIT, tt); + } + fclose(log); + + return 0; +} + +/* $Source: /cvs/libtom/libtommath/demo/timing.c,v $ */ +/* $Revision: 1.2 $ */ +/* $Date: 2005/05/05 14:38:47 $ */ diff --git a/libtommath/dep.pl b/libtommath/dep.pl new file mode 100644 index 0000000..c39e27e --- /dev/null +++ b/libtommath/dep.pl @@ -0,0 +1,123 @@ +#!/usr/bin/perl +# +# Walk through source, add labels and make classes +# +#use strict; + +my %deplist; + +#open class file and write preamble +open(CLASS, ">tommath_class.h") or die "Couldn't open tommath_class.h for writing\n"; +print CLASS "#if !(defined(LTM1) && defined(LTM2) && defined(LTM3))\n#if defined(LTM2)\n#define LTM3\n#endif\n#if defined(LTM1)\n#define LTM2\n#endif\n#define LTM1\n\n#if defined(LTM_ALL)\n"; + +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(SRC, "<$filename"); + open(OUT, ">tmp"); + + # first line will be the #ifdef + my $line = <SRC>; + if ($line =~ /include/) { + print OUT $line; + } else { + print OUT "#include <tommath.h>\n#ifdef $define\n$line"; + $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\n"; + +# now do classes + +foreach my $filename (glob "bn*.c") { + open(SRC, "<$filename") or die "Can't open source file!\n"; + + # 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; + + # scan for mp_* and make classes + while (<SRC>) { + my $line = $_; + while ($line =~ m/(fast_)*(s_)*mp\_[a-z_0-9]*/) { + $line = $'; + # now $& is the match, we want to skip over LTM keywords like + # mp_int, mp_word, mp_digit + if (!($& eq "mp_digit") && !($& eq "mp_word") && !($& eq "mp_int")) { + my $a = $&; + $a =~ tr/[a-z]/[A-Z]/; + $a = "BN_" . $a . "_C"; + if (!($list =~ /$a/)) { + print CLASS " #define $a\n"; + } + $list = $list . "," . $a; + } + } + } + @deplist{$filename} = $list; + + print CLASS "#endif\n\n"; + close SRC; +} + +print CLASS "#ifdef LTM3\n#define LTM_LAST\n#endif\n#include <tommath_superclass.h>\n#include <tommath_class.h>\n#else\n#define LTM_LAST\n#endif\n"; +close CLASS; + +#now let's make a cool call graph... + +open(OUT,">callgraph.txt"); +$indent = 0; +foreach (keys %deplist) { + $list = ""; + draw_func(@deplist{$_}); + print OUT "\n\n"; +} +close(OUT); + +sub draw_func() +{ + my @funcs = split(",", $_[0]); + if ($list =~ /@funcs[0]/) { + return; + } else { + $list = $list . @funcs[0]; + } + if ($indent == 0) { } + elsif ($indent >= 1) { print OUT "| " x ($indent - 1) . "+--->"; } + print OUT @funcs[0] . "\n"; + shift @funcs; + my $temp = $list; + foreach my $i (@funcs) { + ++$indent; + draw_func(@deplist{$i}); + --$indent; + } + $list = $temp; +} + + diff --git a/libtommath/etc/2kprime.1 b/libtommath/etc/2kprime.1 new file mode 100644 index 0000000..c41ded1 --- /dev/null +++ b/libtommath/etc/2kprime.1 @@ -0,0 +1,2 @@ +256-bits (k = 36113) = 115792089237316195423570985008687907853269984665640564039457584007913129603823 +512-bits (k = 38117) = 13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006045979 diff --git a/libtommath/etc/2kprime.c b/libtommath/etc/2kprime.c new file mode 100644 index 0000000..c09818f --- /dev/null +++ b/libtommath/etc/2kprime.c @@ -0,0 +1,84 @@ +/* Makes safe primes of a 2k nature */ +#include <tommath.h> +#include <time.h> + +int sizes[] = {256, 512, 768, 1024, 1536, 2048, 3072, 4096}; + +int main(void) +{ + char buf[2000]; + int x, y; + mp_int q, p; + FILE *out; + clock_t t1; + mp_digit z; + + mp_init_multi(&q, &p, NULL); + + out = fopen("2kprime.1", "w"); + for (x = 0; x < (int)(sizeof(sizes) / sizeof(sizes[0])); x++) { + top: + mp_2expt(&q, sizes[x]); + mp_add_d(&q, 3, &q); + z = -3; + + t1 = clock(); + for(;;) { + mp_sub_d(&q, 4, &q); + z += 4; + + if (z > MP_MASK) { + printf("No primes of size %d found\n", sizes[x]); + break; + } + + if (clock() - t1 > CLOCKS_PER_SEC) { + printf("."); fflush(stdout); +// sleep((clock() - t1 + CLOCKS_PER_SEC/2)/CLOCKS_PER_SEC); + t1 = clock(); + } + + /* quick test on q */ + mp_prime_is_prime(&q, 1, &y); + if (y == 0) { + continue; + } + + /* find (q-1)/2 */ + mp_sub_d(&q, 1, &p); + mp_div_2(&p, &p); + mp_prime_is_prime(&p, 3, &y); + if (y == 0) { + continue; + } + + /* test on q */ + mp_prime_is_prime(&q, 3, &y); + if (y == 0) { + continue; + } + + break; + } + + if (y == 0) { + ++sizes[x]; + goto top; + } + + mp_toradix(&q, buf, 10); + printf("\n\n%d-bits (k = %lu) = %s\n", sizes[x], z, buf); + fprintf(out, "%d-bits (k = %lu) = %s\n", sizes[x], z, buf); fflush(out); + } + + return 0; +} + + + + + + +/* $Source: /cvs/libtom/libtommath/etc/2kprime.c,v $ */ +/* $Revision: 1.2 $ */ +/* $Date: 2005/05/05 14:38:47 $ */ diff --git a/libtommath/etc/drprime.c b/libtommath/etc/drprime.c new file mode 100644 index 0000000..e413985 --- /dev/null +++ b/libtommath/etc/drprime.c @@ -0,0 +1,64 @@ +/* Makes safe primes of a DR nature */ +#include <tommath.h> + +int sizes[] = { 1+256/DIGIT_BIT, 1+512/DIGIT_BIT, 1+768/DIGIT_BIT, 1+1024/DIGIT_BIT, 1+2048/DIGIT_BIT, 1+4096/DIGIT_BIT }; +int main(void) +{ + int res, x, y; + char buf[4096]; + FILE *out; + mp_int a, b; + + mp_init(&a); + mp_init(&b); + + out = fopen("drprimes.txt", "w"); + for (x = 0; x < (int)(sizeof(sizes)/sizeof(sizes[0])); x++) { + top: + printf("Seeking a %d-bit safe prime\n", sizes[x] * DIGIT_BIT); + mp_grow(&a, sizes[x]); + mp_zero(&a); + for (y = 1; y < sizes[x]; y++) { + a.dp[y] = MP_MASK; + } + + /* make a DR modulus */ + a.dp[0] = -1; + a.used = sizes[x]; + + /* now loop */ + res = 0; + for (;;) { + a.dp[0] += 4; + if (a.dp[0] >= MP_MASK) break; + mp_prime_is_prime(&a, 1, &res); + if (res == 0) continue; + printf("."); fflush(stdout); + mp_sub_d(&a, 1, &b); + mp_div_2(&b, &b); + mp_prime_is_prime(&b, 3, &res); + if (res == 0) continue; + mp_prime_is_prime(&a, 3, &res); + if (res == 1) break; + } + + if (res != 1) { + printf("Error not DR modulus\n"); sizes[x] += 1; goto top; + } else { + mp_toradix(&a, buf, 10); + printf("\n\np == %s\n\n", buf); + fprintf(out, "%d-bit prime:\np == %s\n\n", mp_count_bits(&a), buf); fflush(out); + } + } + fclose(out); + + mp_clear(&a); + mp_clear(&b); + + return 0; +} + + +/* $Source: /cvs/libtom/libtommath/etc/drprime.c,v $ */ +/* $Revision: 1.2 $ */ +/* $Date: 2005/05/05 14:38:47 $ */ diff --git a/libtommath/etc/drprimes.28 b/libtommath/etc/drprimes.28 new file mode 100644 index 0000000..9d438ad --- /dev/null +++ b/libtommath/etc/drprimes.28 @@ -0,0 +1,25 @@ +DR safe primes for 28-bit digits. + +224-bit prime: +p == 26959946667150639794667015087019630673637144422540572481103341844143 + +532-bit prime: +p == 14059105607947488696282932836518693308967803494693489478439861164411992439598399594747002144074658928593502845729752797260025831423419686528151609940203368691747 + +784-bit prime: +p == 101745825697019260773923519755878567461315282017759829107608914364075275235254395622580447400994175578963163918967182013639660669771108475957692810857098847138903161308502419410142185759152435680068435915159402496058513611411688900243039 + +1036-bit prime: +p == 736335108039604595805923406147184530889923370574768772191969612422073040099331944991573923112581267542507986451953227192970402893063850485730703075899286013451337291468249027691733891486704001513279827771740183629161065194874727962517148100775228363421083691764065477590823919364012917984605619526140821798437127 + +1540-bit prime: +p == 38564998830736521417281865696453025806593491967131023221754800625044118265468851210705360385717536794615180260494208076605798671660719333199513807806252394423283413430106003596332513246682903994829528690198205120921557533726473585751382193953592127439965050261476810842071573684505878854588706623484573925925903505747545471088867712185004135201289273405614415899438276535626346098904241020877974002916168099951885406379295536200413493190419727789712076165162175783 + +2072-bit prime: +p == 542189391331696172661670440619180536749994166415993334151601745392193484590296600979602378676624808129613777993466242203025054573692562689251250471628358318743978285860720148446448885701001277560572526947619392551574490839286458454994488665744991822837769918095117129546414124448777033941223565831420390846864429504774477949153794689948747680362212954278693335653935890352619041936727463717926744868338358149568368643403037768649616778526013610493696186055899318268339432671541328195724261329606699831016666359440874843103020666106568222401047720269951530296879490444224546654729111504346660859907296364097126834834235287147 + +3080-bit prime: +p == 1487259134814709264092032648525971038895865645148901180585340454985524155135260217788758027400478312256339496385275012465661575576202252063145698732079880294664220579764848767704076761853197216563262660046602703973050798218246170835962005598561669706844469447435461092542265792444947706769615695252256130901271870341005768912974433684521436211263358097522726462083917939091760026658925757076733484173202927141441492573799914240222628795405623953109131594523623353044898339481494120112723445689647986475279242446083151413667587008191682564376412347964146113898565886683139407005941383669325997475076910488086663256335689181157957571445067490187939553165903773554290260531009121879044170766615232300936675369451260747671432073394867530820527479172464106442450727640226503746586340279816318821395210726268291535648506190714616083163403189943334431056876038286530365757187367147446004855912033137386225053275419626102417236133948503 + +4116-bit prime: +p == 1095121115716677802856811290392395128588168592409109494900178008967955253005183831872715423151551999734857184538199864469605657805519106717529655044054833197687459782636297255219742994736751541815269727940751860670268774903340296040006114013971309257028332849679096824800250742691718610670812374272414086863715763724622797509437062518082383056050144624962776302147890521249477060215148275163688301275847155316042279405557632639366066847442861422164832655874655824221577849928863023018366835675399949740429332468186340518172487073360822220449055340582568461568645259954873303616953776393853174845132081121976327462740354930744487429617202585015510744298530101547706821590188733515880733527449780963163909830077616357506845523215289297624086914545378511082534229620116563260168494523906566709418166011112754529766183554579321224940951177394088465596712620076240067370589036924024728375076210477267488679008016579588696191194060127319035195370137160936882402244399699172017835144537488486396906144217720028992863941288217185353914991583400421682751000603596655790990815525126154394344641336397793791497068253936771017031980867706707490224041075826337383538651825493679503771934836094655802776331664261631740148281763487765852746577808019633679 diff --git a/libtommath/etc/drprimes.txt b/libtommath/etc/drprimes.txt new file mode 100644 index 0000000..7c97f67 --- /dev/null +++ b/libtommath/etc/drprimes.txt @@ -0,0 +1,9 @@ +300-bit prime: +p == 2037035976334486086268445688409378161051468393665936250636140449354381298610415201576637819 + +540-bit prime: +p == 3599131035634557106248430806148785487095757694641533306480604458089470064537190296255232548883112685719936728506816716098566612844395439751206810991770626477344739 + +780-bit prime: +p == 6359114106063703798370219984742410466332205126109989319225557147754704702203399726411277962562135973685197744935448875852478791860694279747355800678568677946181447581781401213133886609947027230004277244697462656003655947791725966271167 + diff --git a/libtommath/etc/makefile b/libtommath/etc/makefile new file mode 100644 index 0000000..99154d8 --- /dev/null +++ b/libtommath/etc/makefile @@ -0,0 +1,50 @@ +CFLAGS += -Wall -W -Wshadow -O3 -fomit-frame-pointer -funroll-loops -I../ + +# default lib name (requires install with root) +# LIBNAME=-ltommath + +# libname when you can't install the lib with install +LIBNAME=../libtommath.a + +#provable primes +pprime: pprime.o + $(CC) pprime.o $(LIBNAME) -o pprime + +# portable [well requires clock()] tuning app +tune: tune.o + $(CC) tune.o $(LIBNAME) -o tune + +# same app but using RDTSC for higher precision [requires 80586+], coff based gcc installs [e.g. ming, cygwin, djgpp] +tune86: tune.c + nasm -f coff timer.asm + $(CC) -DX86_TIMER $(CFLAGS) tune.c timer.o $(LIBNAME) -o tune86 + +# for cygwin +tune86c: tune.c + nasm -f gnuwin32 timer.asm + $(CC) -DX86_TIMER $(CFLAGS) tune.c timer.o $(LIBNAME) -o tune86 + +#make tune86 for linux or any ELF format +tune86l: tune.c + nasm -f elf -DUSE_ELF timer.asm + $(CC) -DX86_TIMER $(CFLAGS) tune.c timer.o $(LIBNAME) -o tune86l + +# spits out mersenne primes +mersenne: mersenne.o + $(CC) mersenne.o $(LIBNAME) -o mersenne + +# fines DR safe primes for the given config +drprime: drprime.o + $(CC) drprime.o $(LIBNAME) -o drprime + +# fines 2k safe primes for the given config +2kprime: 2kprime.o + $(CC) 2kprime.o $(LIBNAME) -o 2kprime + +mont: mont.o + $(CC) mont.o $(LIBNAME) -o mont + + +clean: + rm -f *.log *.o *.obj *.exe pprime tune mersenne drprime tune86 tune86l mont 2kprime pprime.dat \ + *.da *.dyn *.dpi *~ diff --git a/libtommath/etc/makefile.icc b/libtommath/etc/makefile.icc new file mode 100644 index 0000000..8a1ffff --- /dev/null +++ b/libtommath/etc/makefile.icc @@ -0,0 +1,67 @@ +CC = icc + +CFLAGS += -I../ + +# optimize for SPEED +# +# -mcpu= can be pentium, pentiumpro (covers PII through PIII) or pentium4 +# -ax? specifies make code specifically for ? but compatible with IA-32 +# -x? specifies compile solely for ? [not specifically IA-32 compatible] +# +# where ? is +# K - PIII +# W - first P4 [Williamette] +# N - P4 Northwood +# P - P4 Prescott +# B - Blend of P4 and PM [mobile] +# +# Default to just generic max opts +CFLAGS += -O3 -xP -ip + +# default lib name (requires install with root) +# LIBNAME=-ltommath + +# libname when you can't install the lib with install +LIBNAME=../libtommath.a + +#provable primes +pprime: pprime.o + $(CC) pprime.o $(LIBNAME) -o pprime + +# portable [well requires clock()] tuning app +tune: tune.o + $(CC) tune.o $(LIBNAME) -o tune + +# same app but using RDTSC for higher precision [requires 80586+], coff based gcc installs [e.g. ming, cygwin, djgpp] +tune86: tune.c + nasm -f coff timer.asm + $(CC) -DX86_TIMER $(CFLAGS) tune.c timer.o $(LIBNAME) -o tune86 + +# for cygwin +tune86c: tune.c + nasm -f gnuwin32 timer.asm + $(CC) -DX86_TIMER $(CFLAGS) tune.c timer.o $(LIBNAME) -o tune86 + +#make tune86 for linux or any ELF format +tune86l: tune.c + nasm -f elf -DUSE_ELF timer.asm + $(CC) -DX86_TIMER $(CFLAGS) tune.c timer.o $(LIBNAME) -o tune86l + +# spits out mersenne primes +mersenne: mersenne.o + $(CC) mersenne.o $(LIBNAME) -o mersenne + +# fines DR safe primes for the given config +drprime: drprime.o + $(CC) drprime.o $(LIBNAME) -o drprime + +# fines 2k safe primes for the given config +2kprime: 2kprime.o + $(CC) 2kprime.o $(LIBNAME) -o 2kprime + +mont: mont.o + $(CC) mont.o $(LIBNAME) -o mont + + +clean: + rm -f *.log *.o *.obj *.exe pprime tune mersenne drprime tune86 tune86l mont 2kprime pprime.dat *.il diff --git a/libtommath/etc/makefile.msvc b/libtommath/etc/makefile.msvc new file mode 100644 index 0000000..2833372 --- /dev/null +++ b/libtommath/etc/makefile.msvc @@ -0,0 +1,23 @@ +#MSVC Makefile +# +#Tom St Denis + +CFLAGS = /I../ /Ox /DWIN32 /W3 + +pprime: pprime.obj + cl pprime.obj ../tommath.lib + +mersenne: mersenne.obj + cl mersenne.obj ../tommath.lib + +tune: tune.obj + cl tune.obj ../tommath.lib + +mont: mont.obj + cl mont.obj ../tommath.lib + +drprime: drprime.obj + cl drprime.obj ../tommath.lib + +2kprime: 2kprime.obj + cl 2kprime.obj ../tommath.lib diff --git a/libtommath/etc/mersenne.c b/libtommath/etc/mersenne.c new file mode 100644 index 0000000..6a6497a --- /dev/null +++ b/libtommath/etc/mersenne.c @@ -0,0 +1,144 @@ +/* Finds Mersenne primes using the Lucas-Lehmer test + * + * Tom St Denis, tomstdenis@gmail.com + */ +#include <time.h> +#include <tommath.h> + +int +is_mersenne (long s, int *pp) +{ + mp_int n, u; + int res, k; + + *pp = 0; + + if ((res = mp_init (&n)) != MP_OKAY) { + return res; + } + + if ((res = mp_init (&u)) != MP_OKAY) { + goto LBL_N; + } + + /* n = 2^s - 1 */ + if ((res = mp_2expt(&n, s)) != MP_OKAY) { + goto LBL_MU; + } + if ((res = mp_sub_d (&n, 1, &n)) != MP_OKAY) { + goto LBL_MU; + } + + /* set u=4 */ + mp_set (&u, 4); + + /* for k=1 to s-2 do */ + for (k = 1; k <= s - 2; k++) { + /* u = u^2 - 2 mod n */ + if ((res = mp_sqr (&u, &u)) != MP_OKAY) { + goto LBL_MU; + } + if ((res = mp_sub_d (&u, 2, &u)) != MP_OKAY) { + goto LBL_MU; + } + + /* make sure u is positive */ + while (u.sign == MP_NEG) { + if ((res = mp_add (&u, &n, &u)) != MP_OKAY) { + goto LBL_MU; + } + } + + /* reduce */ + if ((res = mp_reduce_2k (&u, &n, 1)) != MP_OKAY) { + goto LBL_MU; + } + } + + /* if u == 0 then its prime */ + if (mp_iszero (&u) == 1) { + mp_prime_is_prime(&n, 8, pp); + if (*pp != 1) printf("FAILURE\n"); + } + + res = MP_OKAY; +LBL_MU:mp_clear (&u); +LBL_N:mp_clear (&n); + return res; +} + +/* square root of a long < 65536 */ +long +i_sqrt (long x) +{ + long x1, x2; + + x2 = 16; + do { + x1 = x2; + x2 = x1 - ((x1 * x1) - x) / (2 * x1); + } while (x1 != x2); + + if (x1 * x1 > x) { + --x1; + } + + return x1; +} + +/* is the long prime by brute force */ +int +isprime (long k) +{ + long y, z; + + y = i_sqrt (k); + for (z = 2; z <= y; z++) { + if ((k % z) == 0) + return 0; + } + return 1; +} + + +int +main (void) +{ + int pp; + long k; + clock_t tt; + + k = 3; + + for (;;) { + /* start time */ + tt = clock (); + + /* test if 2^k - 1 is prime */ + if (is_mersenne (k, &pp) != MP_OKAY) { + printf ("Whoa error\n"); + return -1; + } + + if (pp == 1) { + /* count time */ + tt = clock () - tt; + + /* display if prime */ + printf ("2^%-5ld - 1 is prime, test took %ld ticks\n", k, tt); + } + + /* goto next odd exponent */ + k += 2; + + /* but make sure its prime */ + while (isprime (k) == 0) { + k += 2; + } + } + return 0; +} + +/* $Source: /cvs/libtom/libtommath/etc/mersenne.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:47 $ */ diff --git a/libtommath/etc/mont.c b/libtommath/etc/mont.c new file mode 100644 index 0000000..393be4c --- /dev/null +++ b/libtommath/etc/mont.c @@ -0,0 +1,50 @@ +/* tests the montgomery routines */ +#include <tommath.h> + +int main(void) +{ + mp_int modulus, R, p, pp; + mp_digit mp; + long x, y; + + srand(time(NULL)); + mp_init_multi(&modulus, &R, &p, &pp, NULL); + + /* loop through various sizes */ + for (x = 4; x < 256; x++) { + printf("DIGITS == %3ld...", x); fflush(stdout); + + /* make up the odd modulus */ + mp_rand(&modulus, x); + modulus.dp[0] |= 1; + + /* now find the R value */ + mp_montgomery_calc_normalization(&R, &modulus); + mp_montgomery_setup(&modulus, &mp); + + /* now run through a bunch tests */ + for (y = 0; y < 1000; y++) { + mp_rand(&p, x/2); /* p = random */ + mp_mul(&p, &R, &pp); /* pp = R * p */ + mp_montgomery_reduce(&pp, &modulus, mp); + + /* should be equal to p */ + if (mp_cmp(&pp, &p) != MP_EQ) { + printf("FAILURE!\n"); + exit(-1); + } + } + printf("PASSED\n"); + } + + return 0; +} + + + + + + +/* $Source: /cvs/libtom/libtommath/etc/mont.c,v $ */ +/* $Revision: 1.2 $ */ +/* $Date: 2005/05/05 14:38:47 $ */ diff --git a/libtommath/etc/pprime.c b/libtommath/etc/pprime.c new file mode 100644 index 0000000..317e2a0 --- /dev/null +++ b/libtommath/etc/pprime.c @@ -0,0 +1,400 @@ +/* Generates provable primes + * + * See http://gmail.com:8080/papers/pp.pdf for more info. + * + * Tom St Denis, tomstdenis@gmail.com, http://tom.gmail.com + */ +#include <time.h> +#include "tommath.h" + +int n_prime; +FILE *primes; + +/* fast square root */ +static mp_digit +i_sqrt (mp_word x) +{ + mp_word x1, x2; + + x2 = x; + do { + x1 = x2; + x2 = x1 - ((x1 * x1) - x) / (2 * x1); + } while (x1 != x2); + + if (x1 * x1 > x) { + --x1; + } + + return x1; +} + + +/* generates a prime digit */ +static void gen_prime (void) +{ + mp_digit r, x, y, next; + FILE *out; + + out = fopen("pprime.dat", "wb"); + + /* write first set of primes */ + r = 3; fwrite(&r, 1, sizeof(mp_digit), out); + r = 5; fwrite(&r, 1, sizeof(mp_digit), out); + r = 7; fwrite(&r, 1, sizeof(mp_digit), out); + r = 11; fwrite(&r, 1, sizeof(mp_digit), out); + r = 13; fwrite(&r, 1, sizeof(mp_digit), out); + r = 17; fwrite(&r, 1, sizeof(mp_digit), out); + r = 19; fwrite(&r, 1, sizeof(mp_digit), out); + r = 23; fwrite(&r, 1, sizeof(mp_digit), out); + r = 29; fwrite(&r, 1, sizeof(mp_digit), out); + r = 31; fwrite(&r, 1, sizeof(mp_digit), out); + + /* get square root, since if 'r' is composite its factors must be < than this */ + y = i_sqrt (r); + next = (y + 1) * (y + 1); + + for (;;) { + do { + r += 2; /* next candidate */ + r &= MP_MASK; + if (r < 31) break; + + /* update sqrt ? */ + if (next <= r) { + ++y; + next = (y + 1) * (y + 1); + } + + /* loop if divisible by 3,5,7,11,13,17,19,23,29 */ + if ((r % 3) == 0) { + x = 0; + continue; + } + if ((r % 5) == 0) { + x = 0; + continue; + } + if ((r % 7) == 0) { + x = 0; + continue; + } + if ((r % 11) == 0) { + x = 0; + continue; + } + if ((r % 13) == 0) { + x = 0; + continue; + } + if ((r % 17) == 0) { + x = 0; + continue; + } + if ((r % 19) == 0) { + x = 0; + continue; + } + if ((r % 23) == 0) { + x = 0; + continue; + } + if ((r % 29) == 0) { + x = 0; + continue; + } + + /* now check if r is divisible by x + k={1,7,11,13,17,19,23,29} */ + for (x = 30; x <= y; x += 30) { + if ((r % (x + 1)) == 0) { + x = 0; + break; + } + if ((r % (x + 7)) == 0) { + x = 0; + break; + } + if ((r % (x + 11)) == 0) { + x = 0; + break; + } + if ((r % (x + 13)) == 0) { + x = 0; + break; + } + if ((r % (x + 17)) == 0) { + x = 0; + break; + } + if ((r % (x + 19)) == 0) { + x = 0; + break; + } + if ((r % (x + 23)) == 0) { + x = 0; + break; + } + if ((r % (x + 29)) == 0) { + x = 0; + break; + } + } + } while (x == 0); + if (r > 31) { fwrite(&r, 1, sizeof(mp_digit), out); printf("%9d\r", r); fflush(stdout); } + if (r < 31) break; + } + + fclose(out); +} + +void load_tab(void) +{ + primes = fopen("pprime.dat", "rb"); + if (primes == NULL) { + gen_prime(); + primes = fopen("pprime.dat", "rb"); + } + fseek(primes, 0, SEEK_END); + n_prime = ftell(primes) / sizeof(mp_digit); +} + +mp_digit prime_digit(void) +{ + int n; + mp_digit d; + + n = abs(rand()) % n_prime; + fseek(primes, n * sizeof(mp_digit), SEEK_SET); + fread(&d, 1, sizeof(mp_digit), primes); + return d; +} + + +/* makes a prime of at least k bits */ +int +pprime (int k, int li, mp_int * p, mp_int * q) +{ + mp_int a, b, c, n, x, y, z, v; + int res, ii; + static const mp_digit bases[] = { 2, 3, 5, 7, 11, 13, 17, 19 }; + + /* single digit ? */ + if (k <= (int) DIGIT_BIT) { + mp_set (p, prime_digit ()); + return MP_OKAY; + } + + if ((res = mp_init (&c)) != MP_OKAY) { + return res; + } + + if ((res = mp_init (&v)) != MP_OKAY) { + goto LBL_C; + } + + /* product of first 50 primes */ + if ((res = + mp_read_radix (&v, + "19078266889580195013601891820992757757219839668357012055907516904309700014933909014729740190", + 10)) != MP_OKAY) { + goto LBL_V; + } + + if ((res = mp_init (&a)) != MP_OKAY) { + goto LBL_V; + } + + /* set the prime */ + mp_set (&a, prime_digit ()); + + if ((res = mp_init (&b)) != MP_OKAY) { + goto LBL_A; + } + + if ((res = mp_init (&n)) != MP_OKAY) { + goto LBL_B; + } + + if ((res = mp_init (&x)) != MP_OKAY) { + goto LBL_N; + } + + if ((res = mp_init (&y)) != MP_OKAY) { + goto LBL_X; + } + + if ((res = mp_init (&z)) != MP_OKAY) { + goto LBL_Y; + } + + /* now loop making the single digit */ + while (mp_count_bits (&a) < k) { + fprintf (stderr, "prime has %4d bits left\r", k - mp_count_bits (&a)); + fflush (stderr); + top: + mp_set (&b, prime_digit ()); + + /* now compute z = a * b * 2 */ + if ((res = mp_mul (&a, &b, &z)) != MP_OKAY) { /* z = a * b */ + goto LBL_Z; + } + + if ((res = mp_copy (&z, &c)) != MP_OKAY) { /* c = a * b */ + goto LBL_Z; + } + + if ((res = mp_mul_2 (&z, &z)) != MP_OKAY) { /* z = 2 * a * b */ + goto LBL_Z; + } + + /* n = z + 1 */ + if ((res = mp_add_d (&z, 1, &n)) != MP_OKAY) { /* n = z + 1 */ + goto LBL_Z; + } + + /* check (n, v) == 1 */ + if ((res = mp_gcd (&n, &v, &y)) != MP_OKAY) { /* y = (n, v) */ + goto LBL_Z; + } + + if (mp_cmp_d (&y, 1) != MP_EQ) + goto top; + + /* now try base x=bases[ii] */ + for (ii = 0; ii < li; ii++) { + mp_set (&x, bases[ii]); + + /* compute x^a mod n */ + if ((res = mp_exptmod (&x, &a, &n, &y)) != MP_OKAY) { /* y = x^a mod n */ + goto LBL_Z; + } + + /* if y == 1 loop */ + if (mp_cmp_d (&y, 1) == MP_EQ) + continue; + + /* now x^2a mod n */ + if ((res = mp_sqrmod (&y, &n, &y)) != MP_OKAY) { /* y = x^2a mod n */ + goto LBL_Z; + } + + if (mp_cmp_d (&y, 1) == MP_EQ) + continue; + + /* compute x^b mod n */ + if ((res = mp_exptmod (&x, &b, &n, &y)) != MP_OKAY) { /* y = x^b mod n */ + goto LBL_Z; + } + + /* if y == 1 loop */ + if (mp_cmp_d (&y, 1) == MP_EQ) + continue; + + /* now x^2b mod n */ + if ((res = mp_sqrmod (&y, &n, &y)) != MP_OKAY) { /* y = x^2b mod n */ + goto LBL_Z; + } + + if (mp_cmp_d (&y, 1) == MP_EQ) + continue; + + /* compute x^c mod n == x^ab mod n */ + if ((res = mp_exptmod (&x, &c, &n, &y)) != MP_OKAY) { /* y = x^ab mod n */ + goto LBL_Z; + } + + /* if y == 1 loop */ + if (mp_cmp_d (&y, 1) == MP_EQ) + continue; + + /* now compute (x^c mod n)^2 */ + if ((res = mp_sqrmod (&y, &n, &y)) != MP_OKAY) { /* y = x^2ab mod n */ + goto LBL_Z; + } + + /* y should be 1 */ + if (mp_cmp_d (&y, 1) != MP_EQ) + continue; + break; + } + + /* no bases worked? */ + if (ii == li) + goto top; + +{ + char buf[4096]; + + mp_toradix(&n, buf, 10); + printf("Certificate of primality for:\n%s\n\n", buf); + mp_toradix(&a, buf, 10); + printf("A == \n%s\n\n", buf); + mp_toradix(&b, buf, 10); + printf("B == \n%s\n\nG == %d\n", buf, bases[ii]); + printf("----------------------------------------------------------------\n"); +} + + /* a = n */ + mp_copy (&n, &a); + } + + /* get q to be the order of the large prime subgroup */ + mp_sub_d (&n, 1, q); + mp_div_2 (q, q); + mp_div (q, &b, q, NULL); + + mp_exch (&n, p); + + res = MP_OKAY; +LBL_Z:mp_clear (&z); +LBL_Y:mp_clear (&y); +LBL_X:mp_clear (&x); +LBL_N:mp_clear (&n); +LBL_B:mp_clear (&b); +LBL_A:mp_clear (&a); +LBL_V:mp_clear (&v); +LBL_C:mp_clear (&c); + return res; +} + + +int +main (void) +{ + mp_int p, q; + char buf[4096]; + int k, li; + clock_t t1; + + srand (time (NULL)); + load_tab(); + + printf ("Enter # of bits: \n"); + fgets (buf, sizeof (buf), stdin); + sscanf (buf, "%d", &k); + + printf ("Enter number of bases to try (1 to 8):\n"); + fgets (buf, sizeof (buf), stdin); + sscanf (buf, "%d", &li); + + + mp_init (&p); + mp_init (&q); + + t1 = clock (); + pprime (k, li, &p, &q); + t1 = clock () - t1; + + printf ("\n\nTook %ld ticks, %d bits\n", t1, mp_count_bits (&p)); + + mp_toradix (&p, buf, 10); + printf ("P == %s\n", buf); + mp_toradix (&q, buf, 10); + printf ("Q == %s\n", buf); + + return 0; +} + +/* $Source: /cvs/libtom/libtommath/etc/pprime.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:47 $ */ diff --git a/libtommath/etc/prime.1024 b/libtommath/etc/prime.1024 new file mode 100644 index 0000000..5636e2d --- /dev/null +++ b/libtommath/etc/prime.1024 @@ -0,0 +1,414 @@ +Enter # of bits: +Enter number of bases to try (1 to 8): +Certificate of primality for: +36360080703173363 + +A == +89963569 + +B == +202082249 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +4851595597739856136987139 + +A == +36360080703173363 + +B == +66715963 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +19550639734462621430325731591027 + +A == +4851595597739856136987139 + +B == +2014867 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +10409036141344317165691858509923818734539 + +A == +19550639734462621430325731591027 + +B == +266207047 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +1049829549988285012736475602118094726647504414203 + +A == +10409036141344317165691858509923818734539 + +B == +50428759 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +77194737385528288387712399596835459931920358844586615003 + +A == +1049829549988285012736475602118094726647504414203 + +B == +36765367 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +35663756695365208574443215955488689578374232732893628896541201763 + +A == +77194737385528288387712399596835459931920358844586615003 + +B == +230998627 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +16711831463502165169495622246023119698415848120292671294127567620396469803 + +A == +35663756695365208574443215955488689578374232732893628896541201763 + +B == +234297127 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +6163534781560285962890718925972249753147470953579266394395432475622345597103528739 + +A == +16711831463502165169495622246023119698415848120292671294127567620396469803 + +B == +184406323 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +814258256205243497704094951432575867360065658372158511036259934640748088306764553488803787 + +A == +6163534781560285962890718925972249753147470953579266394395432475622345597103528739 + +B == +66054487 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +176469695533271657902814176811660357049007467856432383037590673407330246967781451723764079581998187 + +A == +814258256205243497704094951432575867360065658372158511036259934640748088306764553488803787 + +B == +108362239 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +44924492859445516541759485198544012102424796403707253610035148063863073596051272171194806669756971406400419 + +A == +176469695533271657902814176811660357049007467856432383037590673407330246967781451723764079581998187 + +B == +127286707 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +20600996927219343383225424320134474929609459588323857796871086845924186191561749519858600696159932468024710985371059 + +A == +44924492859445516541759485198544012102424796403707253610035148063863073596051272171194806669756971406400419 + +B == +229284691 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +6295696427695493110141186605837397185848992307978456138112526915330347715236378041486547994708748840844217371233735072572979 + +A == +20600996927219343383225424320134474929609459588323857796871086845924186191561749519858600696159932468024710985371059 + +B == +152800771 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +3104984078042317488749073016454213579257792635142218294052134804187631661145261015102617582090263808696699966840735333252107678792123 + +A == +6295696427695493110141186605837397185848992307978456138112526915330347715236378041486547994708748840844217371233735072572979 + +B == +246595759 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +26405175827665701256325699315126705508919255051121452292124404943796947287968603975320562847910946802396632302209435206627913466015741799499 + +A == +3104984078042317488749073016454213579257792635142218294052134804187631661145261015102617582090263808696699966840735333252107678792123 + +B == +4252063 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +11122146237908413610034600609460545703591095894418599759742741406628055069007082998134905595800236452010905900391505454890446585211975124558601770163 + +A == +26405175827665701256325699315126705508919255051121452292124404943796947287968603975320562847910946802396632302209435206627913466015741799499 + +B == +210605419 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +1649861642047798890580354082088712649911849362201343649289384923147797960364736011515757482030049342943790127685185806092659832129486307035500638595572396187 + +A == +11122146237908413610034600609460545703591095894418599759742741406628055069007082998134905595800236452010905900391505454890446585211975124558601770163 + +B == +74170111 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +857983367126266717607389719637086684134462613006415859877666235955788392464081914127715967940968197765042399904117392707518175220864852816390004264107201177394565363 + +A == +1649861642047798890580354082088712649911849362201343649289384923147797960364736011515757482030049342943790127685185806092659832129486307035500638595572396187 + +B == +260016763 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +175995909353623703257072120479340610010337144085688850745292031336724691277374210929188442230237711063783727092685448718515661641054886101716698390145283196296702450566161283 + +A == +857983367126266717607389719637086684134462613006415859877666235955788392464081914127715967940968197765042399904117392707518175220864852816390004264107201177394565363 + +B == +102563707 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +48486002551155667224487059713350447239190772068092630563272168418880661006593537218144160068395218642353495339720640699721703003648144463556291315694787862009052641640656933232794283 + +A == +175995909353623703257072120479340610010337144085688850745292031336724691277374210929188442230237711063783727092685448718515661641054886101716698390145283196296702450566161283 + +B == +137747527 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +13156468011529105025061495011938518171328604045212410096476697450506055664012861932372156505805788068791146986282263016790631108386790291275939575123375304599622623328517354163964228279867403 + +A == +48486002551155667224487059713350447239190772068092630563272168418880661006593537218144160068395218642353495339720640699721703003648144463556291315694787862009052641640656933232794283 + +B == +135672847 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +6355194692790533601105154341731997464407930009404822926832136060319955058388106456084549316415200519472481147942263916585428906582726749131479465958107142228236909665306781538860053107680830113869123 + +A == +13156468011529105025061495011938518171328604045212410096476697450506055664012861932372156505805788068791146986282263016790631108386790291275939575123375304599622623328517354163964228279867403 + +B == +241523587 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +3157116676535430302794438027544146642863331358530722860333745617571010460905857862561870488000265751138954271040017454405707755458702044884023184574412221802502351503929935224995314581932097706874819348858083 + +A == +6355194692790533601105154341731997464407930009404822926832136060319955058388106456084549316415200519472481147942263916585428906582726749131479465958107142228236909665306781538860053107680830113869123 + +B == +248388667 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +390533129219992506725320633489467713907837370444962163378727819939092929448752905310115311180032249230394348337568973177802874166228132778126338883671958897238722734394783244237133367055422297736215754829839364158067 + +A == +3157116676535430302794438027544146642863331358530722860333745617571010460905857862561870488000265751138954271040017454405707755458702044884023184574412221802502351503929935224995314581932097706874819348858083 + +B == +61849651 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +48583654555070224891047847050732516652910250240135992225139515777200432486685999462997073444468380434359929499498804723793106565291183220444221080449740542884172281158126259373095216435009661050109711341419005972852770440739 + +A == +390533129219992506725320633489467713907837370444962163378727819939092929448752905310115311180032249230394348337568973177802874166228132778126338883671958897238722734394783244237133367055422297736215754829839364158067 + +B == +62201707 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +25733035251905120039135866524384525138869748427727001128764704499071378939227862068500633813538831598776578372709963673670934388213622433800015759585470542686333039614931682098922935087822950084908715298627996115185849260703525317419 + +A == +48583654555070224891047847050732516652910250240135992225139515777200432486685999462997073444468380434359929499498804723793106565291183220444221080449740542884172281158126259373095216435009661050109711341419005972852770440739 + +B == +264832231 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +2804594464939948901906623499531073917980499195397462605359913717827014360538186518540781517129548650937632008683280555602633122170458773895504894807182664540529077836857897972175530148107545939211339044386106111633510166695386323426241809387 + +A == +25733035251905120039135866524384525138869748427727001128764704499071378939227862068500633813538831598776578372709963673670934388213622433800015759585470542686333039614931682098922935087822950084908715298627996115185849260703525317419 + +B == +54494047 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +738136612083433720096707308165797114449914259256979340471077690416567237592465306112484843530074782721390528773594351482384711900456440808251196845265132086486672447136822046628407467459921823150600138073268385534588238548865012638209515923513516547 + +A == +2804594464939948901906623499531073917980499195397462605359913717827014360538186518540781517129548650937632008683280555602633122170458773895504894807182664540529077836857897972175530148107545939211339044386106111633510166695386323426241809387 + +B == +131594179 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +392847529056126766528615419937165193421166694172790666626558750047057558168124866940509180171236517681470100877687445134633784815352076138790217228749332398026714192707447855731679485746120589851992221508292976900578299504461333767437280988393026452846013683 + +A == +738136612083433720096707308165797114449914259256979340471077690416567237592465306112484843530074782721390528773594351482384711900456440808251196845265132086486672447136822046628407467459921823150600138073268385534588238548865012638209515923513516547 + +B == +266107603 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +168459393231883505975876919268398655632763956627405508859662408056221544310200546265681845397346956580604208064328814319465940958080244889692368602591598503944015835190587740756859842792554282496742843600573336023639256008687581291233481455395123454655488735304365627 + +A == +392847529056126766528615419937165193421166694172790666626558750047057558168124866940509180171236517681470100877687445134633784815352076138790217228749332398026714192707447855731679485746120589851992221508292976900578299504461333767437280988393026452846013683 + +B == +214408111 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +14865774288636941404884923981945833072113667565310054952177860608355263252462409554658728941191929400198053290113492910272458441655458514080123870132092365833472436407455910185221474386718838138135065780840839893113912689594815485706154461164071775481134379794909690501684643 + +A == +168459393231883505975876919268398655632763956627405508859662408056221544310200546265681845397346956580604208064328814319465940958080244889692368602591598503944015835190587740756859842792554282496742843600573336023639256008687581291233481455395123454655488735304365627 + +B == +44122723 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +1213301773203241614897109856134894783021668292000023984098824423682568173639394290886185366993108292039068940333907505157813934962357206131450244004178619265868614859794316361031904412926604138893775068853175215502104744339658944443630407632290152772487455298652998368296998719996019 + +A == +14865774288636941404884923981945833072113667565310054952177860608355263252462409554658728941191929400198053290113492910272458441655458514080123870132092365833472436407455910185221474386718838138135065780840839893113912689594815485706154461164071775481134379794909690501684643 + +B == +40808563 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +186935245989515158127969129347464851990429060640910951266513740972248428651109062997368144722015290092846666943896556191257222521203647606911446635194198213436423080005867489516421559330500722264446765608763224572386410155413161172707802334865729654109050873820610813855041667633843601286843 + +A == +1213301773203241614897109856134894783021668292000023984098824423682568173639394290886185366993108292039068940333907505157813934962357206131450244004178619265868614859794316361031904412926604138893775068853175215502104744339658944443630407632290152772487455298652998368296998719996019 + +B == +77035759 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +83142661079751490510739960019112406284111408348732592580459037404394946037094409915127399165633756159385609671956087845517678367844901424617866988187132480585966721962585586730693443536100138246516868613250009028187662080828012497191775172228832247706080044971423654632146928165751885302331924491683 + +A == +186935245989515158127969129347464851990429060640910951266513740972248428651109062997368144722015290092846666943896556191257222521203647606911446635194198213436423080005867489516421559330500722264446765608763224572386410155413161172707802334865729654109050873820610813855041667633843601286843 + +B == +222383587 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +3892354773803809855317742245039794448230625839512638747643814927766738642436392673485997449586432241626440927010641564064764336402368634186618250134234189066179771240232458249806850838490410473462391401438160528157981942499581634732706904411807195259620779379274017704050790865030808501633772117217899534443 + +A == +83142661079751490510739960019112406284111408348732592580459037404394946037094409915127399165633756159385609671956087845517678367844901424617866988187132480585966721962585586730693443536100138246516868613250009028187662080828012497191775172228832247706080044971423654632146928165751885302331924491683 + +B == +23407687 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +1663606652988091811284014366560171522582683318514519379924950390627250155440313691226744227787921928894551755219495501365555370027257568506349958010457682898612082048959464465369892842603765280317696116552850664773291371490339084156052244256635115997453399761029567033971998617303988376172539172702246575225837054723 + +A == +3892354773803809855317742245039794448230625839512638747643814927766738642436392673485997449586432241626440927010641564064764336402368634186618250134234189066179771240232458249806850838490410473462391401438160528157981942499581634732706904411807195259620779379274017704050790865030808501633772117217899534443 + +B == +213701827 + +G == 2 +---------------------------------------------------------------- + + +Took 33057 ticks, 1048 bits +P == 1663606652988091811284014366560171522582683318514519379924950390627250155440313691226744227787921928894551755219495501365555370027257568506349958010457682898612082048959464465369892842603765280317696116552850664773291371490339084156052244256635115997453399761029567033971998617303988376172539172702246575225837054723 +Q == 3892354773803809855317742245039794448230625839512638747643814927766738642436392673485997449586432241626440927010641564064764336402368634186618250134234189066179771240232458249806850838490410473462391401438160528157981942499581634732706904411807195259620779379274017704050790865030808501633772117217899534443 diff --git a/libtommath/etc/prime.512 b/libtommath/etc/prime.512 new file mode 100644 index 0000000..cb6ec30 --- /dev/null +++ b/libtommath/etc/prime.512 @@ -0,0 +1,205 @@ +Enter # of bits: +Enter number of bases to try (1 to 8): +Certificate of primality for: +85933926807634727 + +A == +253758023 + +B == +169322581 + +G == 5 +---------------------------------------------------------------- +Certificate of primality for: +23930198825086241462113799 + +A == +85933926807634727 + +B == +139236037 + +G == 11 +---------------------------------------------------------------- +Certificate of primality for: +6401844647261612602378676572510019 + +A == +23930198825086241462113799 + +B == +133760791 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +269731366027728777712034888684015329354259 + +A == +6401844647261612602378676572510019 + +B == +21066691 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +37942338209025571690075025099189467992329684223707 + +A == +269731366027728777712034888684015329354259 + +B == +70333567 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +15306904714258982484473490774101705363308327436988160248323 + +A == +37942338209025571690075025099189467992329684223707 + +B == +201712723 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +1616744757018513392810355191503853040357155275733333124624513530099 + +A == +15306904714258982484473490774101705363308327436988160248323 + +B == +52810963 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +464222094814208047161771036072622485188658077940154689939306386289983787983 + +A == +1616744757018513392810355191503853040357155275733333124624513530099 + +B == +143566909 + +G == 5 +---------------------------------------------------------------- +Certificate of primality for: +187429931674053784626487560729643601208757374994177258429930699354770049369025096447 + +A == +464222094814208047161771036072622485188658077940154689939306386289983787983 + +B == +201875281 + +G == 5 +---------------------------------------------------------------- +Certificate of primality for: +100579220846502621074093727119851331775052664444339632682598589456666938521976625305832917563 + +A == +187429931674053784626487560729643601208757374994177258429930699354770049369025096447 + +B == +268311523 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +1173616081309758475197022137833792133815753368965945885089720153370737965497134878651384030219765163 + +A == +100579220846502621074093727119851331775052664444339632682598589456666938521976625305832917563 + +B == +5834287 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +191456913489905913185935197655672585713573070349044195411728114905691721186574907738081340754373032735283623 + +A == +1173616081309758475197022137833792133815753368965945885089720153370737965497134878651384030219765163 + +B == +81567097 + +G == 5 +---------------------------------------------------------------- +Certificate of primality for: +57856530489201750164178576399448868489243874083056587683743345599898489554401618943240901541005080049321706789987519 + +A == +191456913489905913185935197655672585713573070349044195411728114905691721186574907738081340754373032735283623 + +B == +151095433 + +G == 7 +---------------------------------------------------------------- +Certificate of primality for: +13790529750452576698109671710773784949185621244122040804792403407272729038377767162233653248852099545134831722512085881814803 + +A == +57856530489201750164178576399448868489243874083056587683743345599898489554401618943240901541005080049321706789987519 + +B == +119178679 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +7075985989000817742677547821106534174334812111605018857703825637170140040509067704269696198231266351631132464035671858077052876058979 + +A == +13790529750452576698109671710773784949185621244122040804792403407272729038377767162233653248852099545134831722512085881814803 + +B == +256552363 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +1227273006232588072907488910282307435921226646895131225407452056677899411162892829564455154080310937471747140942360789623819327234258162420463 + +A == +7075985989000817742677547821106534174334812111605018857703825637170140040509067704269696198231266351631132464035671858077052876058979 + +B == +86720989 + +G == 5 +---------------------------------------------------------------- +Certificate of primality for: +446764896913554613686067036908702877942872355053329937790398156069936255759889884246832779737114032666318220500106499161852193765380831330106375235763 + +A == +1227273006232588072907488910282307435921226646895131225407452056677899411162892829564455154080310937471747140942360789623819327234258162420463 + +B == +182015287 + +G == 2 +---------------------------------------------------------------- +Certificate of primality for: +5290203010849586596974953717018896543907195901082056939587768479377028575911127944611236020459652034082251335583308070846379514569838984811187823420951275243 + +A == +446764896913554613686067036908702877942872355053329937790398156069936255759889884246832779737114032666318220500106499161852193765380831330106375235763 + +B == +5920567 + +G == 2 +---------------------------------------------------------------- + + +Took 3454 ticks, 521 bits +P == 5290203010849586596974953717018896543907195901082056939587768479377028575911127944611236020459652034082251335583308070846379514569838984811187823420951275243 +Q == 446764896913554613686067036908702877942872355053329937790398156069936255759889884246832779737114032666318220500106499161852193765380831330106375235763 diff --git a/libtommath/etc/timer.asm b/libtommath/etc/timer.asm new file mode 100644 index 0000000..35890d9 --- /dev/null +++ b/libtommath/etc/timer.asm @@ -0,0 +1,37 @@ +; x86 timer in NASM
+;
+; Tom St Denis, tomstdenis@iahu.ca
+[bits 32]
+[section .data]
+time dd 0, 0
+
+[section .text]
+
+%ifdef USE_ELF
+[global t_start]
+t_start:
+%else
+[global _t_start]
+_t_start:
+%endif
+ push edx
+ push eax
+ rdtsc
+ mov [time+0],edx
+ mov [time+4],eax
+ pop eax
+ pop edx
+ ret
+
+%ifdef USE_ELF
+[global t_read]
+t_read:
+%else
+[global _t_read]
+_t_read:
+%endif
+ rdtsc
+ sub eax,[time+4]
+ sbb edx,[time+0]
+ ret
+
\ No newline at end of file diff --git a/libtommath/etc/tune.c b/libtommath/etc/tune.c new file mode 100644 index 0000000..d4a502c --- /dev/null +++ b/libtommath/etc/tune.c @@ -0,0 +1,142 @@ +/* Tune the Karatsuba parameters + * + * Tom St Denis, tomstdenis@gmail.com + */ +#include <tommath.h> +#include <time.h> + +/* how many times todo each size mult. Depends on your computer. For slow computers + * this can be low like 5 or 10. For fast [re: Athlon] should be 25 - 50 or so + */ +#define TIMES (1UL<<14UL) + +/* RDTSC from Scott Duplichan */ +static ulong64 TIMFUNC (void) + { + #if defined __GNUC__ + #if defined(__i386__) || defined(__x86_64__) + unsigned long long a; + __asm__ __volatile__ ("rdtsc\nmovl %%eax,%0\nmovl %%edx,4+%0\n"::"m"(a):"%eax","%edx"); + return a; + #else /* gcc-IA64 version */ + unsigned long result; + __asm__ __volatile__("mov %0=ar.itc" : "=r"(result) :: "memory"); + while (__builtin_expect ((int) result == -1, 0)) + __asm__ __volatile__("mov %0=ar.itc" : "=r"(result) :: "memory"); + return result; + #endif + + // Microsoft and Intel Windows compilers + #elif defined _M_IX86 + __asm rdtsc + #elif defined _M_AMD64 + return __rdtsc (); + #elif defined _M_IA64 + #if defined __INTEL_COMPILER + #include <ia64intrin.h> + #endif + return __getReg (3116); + #else + #error need rdtsc function for this build + #endif + } + + +#ifndef X86_TIMER + +/* generic ISO C timer */ +ulong64 LBL_T; +void t_start(void) { LBL_T = TIMFUNC(); } +ulong64 t_read(void) { return TIMFUNC() - LBL_T; } + +#else +extern void t_start(void); +extern ulong64 t_read(void); +#endif + +ulong64 time_mult(int size, int s) +{ + unsigned long x; + mp_int a, b, c; + ulong64 t1; + + mp_init (&a); + mp_init (&b); + mp_init (&c); + + mp_rand (&a, size); + mp_rand (&b, size); + + if (s == 1) { + KARATSUBA_MUL_CUTOFF = size; + } else { + KARATSUBA_MUL_CUTOFF = 100000; + } + + t_start(); + for (x = 0; x < TIMES; x++) { + mp_mul(&a,&b,&c); + } + t1 = t_read(); + mp_clear (&a); + mp_clear (&b); + mp_clear (&c); + return t1; +} + +ulong64 time_sqr(int size, int s) +{ + unsigned long x; + mp_int a, b; + ulong64 t1; + + mp_init (&a); + mp_init (&b); + + mp_rand (&a, size); + + if (s == 1) { + KARATSUBA_SQR_CUTOFF = size; + } else { + KARATSUBA_SQR_CUTOFF = 100000; + } + + t_start(); + for (x = 0; x < TIMES; x++) { + mp_sqr(&a,&b); + } + t1 = t_read(); + mp_clear (&a); + mp_clear (&b); + return t1; +} + +int +main (void) +{ + ulong64 t1, t2; + int x, y; + + for (x = 8; ; x += 2) { + t1 = time_mult(x, 0); + t2 = time_mult(x, 1); + printf("%d: %9llu %9llu, %9llu\n", x, t1, t2, t2 - t1); + if (t2 < t1) break; + } + y = x; + + for (x = 8; ; x += 2) { + t1 = time_sqr(x, 0); + t2 = time_sqr(x, 1); + printf("%d: %9llu %9llu, %9llu\n", x, t1, t2, t2 - t1); + if (t2 < t1) break; + } + printf("KARATSUBA_MUL_CUTOFF = %d\n", y); + printf("KARATSUBA_SQR_CUTOFF = %d\n", x); + + return 0; +} + +/* $Source: /cvs/libtom/libtommath/etc/tune.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:47 $ */ diff --git a/libtommath/gen.pl b/libtommath/gen.pl new file mode 100644 index 0000000..7236591 --- /dev/null +++ b/libtommath/gen.pl @@ -0,0 +1,17 @@ +#!/usr/bin/perl -w +# +# Generates a "single file" you can use to quickly +# add the whole source without any makefile troubles +# +use strict; + +open( OUT, ">mpi.c" ) or die "Couldn't open mpi.c for writing: $!"; +foreach my $filename (glob "bn*.c") { + open( SRC, "<$filename" ) or die "Couldn't open $filename for reading: $!"; + print OUT "/* Start: $filename */\n"; + print OUT while <SRC>; + print OUT "\n/* End: $filename */\n\n"; + close SRC or die "Error closing $filename after reading: $!"; +} +print OUT "\n/* EOF */\n"; +close OUT or die "Error closing mpi.c after writing: $!";
\ No newline at end of file diff --git a/libtommath/logs/README b/libtommath/logs/README new file mode 100644 index 0000000..ea20c81 --- /dev/null +++ b/libtommath/logs/README @@ -0,0 +1,13 @@ +To use the pretty graphs you have to first build/run the ltmtest from the root directory of the package.
+Todo this type
+
+make timing ; ltmtest
+
+in the root. It will run for a while [about ten minutes on most PCs] and produce a series of .log files in logs/.
+
+After doing that run "gnuplot graphs.dem" to make the PNGs. If you managed todo that all so far just open index.html to view
+them all :-)
+
+Have fun
+
+Tom
\ No newline at end of file diff --git a/libtommath/logs/add.log b/libtommath/logs/add.log new file mode 100644 index 0000000..43503ac --- /dev/null +++ b/libtommath/logs/add.log @@ -0,0 +1,16 @@ +480 87 +960 111 +1440 135 +1920 159 +2400 200 +2880 224 +3360 248 +3840 272 +4320 296 +4800 320 +5280 344 +5760 368 +6240 392 +6720 416 +7200 440 +7680 464 diff --git a/libtommath/logs/addsub.png b/libtommath/logs/addsub.png Binary files differnew file mode 100644 index 0000000..a5679ac --- /dev/null +++ b/libtommath/logs/addsub.png diff --git a/libtommath/logs/expt.log b/libtommath/logs/expt.log new file mode 100644 index 0000000..70932ab --- /dev/null +++ b/libtommath/logs/expt.log @@ -0,0 +1,7 @@ +513 1435869 +769 3544970 +1025 7791638 +2049 46902238 +2561 85334899 +3073 141451412 +4097 308770310 diff --git a/libtommath/logs/expt.png b/libtommath/logs/expt.png Binary files differnew file mode 100644 index 0000000..9ee8bb7 --- /dev/null +++ b/libtommath/logs/expt.png diff --git a/libtommath/logs/expt_2k.log b/libtommath/logs/expt_2k.log new file mode 100644 index 0000000..97d325f --- /dev/null +++ b/libtommath/logs/expt_2k.log @@ -0,0 +1,5 @@ +607 2109225 +1279 10148314 +2203 34126877 +3217 82716424 +4253 161569606 diff --git a/libtommath/logs/expt_2kl.log b/libtommath/logs/expt_2kl.log new file mode 100644 index 0000000..d9ad4be --- /dev/null +++ b/libtommath/logs/expt_2kl.log @@ -0,0 +1,4 @@ +1024 7705271 +2048 34286851 +4096 165207491 +521 1618631 diff --git a/libtommath/logs/expt_dr.log b/libtommath/logs/expt_dr.log new file mode 100644 index 0000000..c6bbe07 --- /dev/null +++ b/libtommath/logs/expt_dr.log @@ -0,0 +1,7 @@ +532 1928550 +784 3763908 +1036 7564221 +1540 16566059 +2072 32283784 +3080 79851565 +4116 157843530 diff --git a/libtommath/logs/graphs.dem b/libtommath/logs/graphs.dem new file mode 100644 index 0000000..dfaf613 --- /dev/null +++ b/libtommath/logs/graphs.dem @@ -0,0 +1,17 @@ +set terminal png +set size 1.75 +set ylabel "Cycles per Operation" +set xlabel "Operand size (bits)" + +set output "addsub.png" +plot 'add.log' smooth bezier title "Addition", 'sub.log' smooth bezier title "Subtraction" + +set output "mult.png" +plot 'sqr.log' smooth bezier title "Squaring (without Karatsuba)", 'sqr_kara.log' smooth bezier title "Squaring (Karatsuba)", 'mult.log' smooth bezier title "Multiplication (without Karatsuba)", 'mult_kara.log' smooth bezier title "Multiplication (Karatsuba)" + +set output "expt.png" +plot 'expt.log' smooth bezier title "Exptmod (Montgomery)", 'expt_dr.log' smooth bezier title "Exptmod (Dimminished Radix)", 'expt_2k.log' smooth bezier title "Exptmod (2k Reduction)" + +set output "invmod.png" +plot 'invmod.log' smooth bezier title "Modular Inverse" + diff --git a/libtommath/logs/index.html b/libtommath/logs/index.html new file mode 100644 index 0000000..4b68c25 --- /dev/null +++ b/libtommath/logs/index.html @@ -0,0 +1,27 @@ +<html> +<head> +<title>LibTomMath Log Plots</title> +</head> +<body> + +<h1>Addition and Subtraction</h1> +<center><img src=addsub.png></center> +<hr> + +<h1>Multipliers</h1> +<center><img src=mult.png></center> +<hr> + +<h1>Exptmod</h1> +<center><img src=expt.png></center> +<hr> + +<h1>Modular Inverse</h1> +<center><img src=invmod.png></center> +<hr> + +</body> +</html> +/* $Source: /cvs/libtom/libtommath/logs/index.html,v $ */ +/* $Revision: 1.2 $ */ +/* $Date: 2005/05/05 14:38:47 $ */ diff --git a/libtommath/logs/invmod.log b/libtommath/logs/invmod.log new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libtommath/logs/invmod.log diff --git a/libtommath/logs/invmod.png b/libtommath/logs/invmod.png Binary files differnew file mode 100644 index 0000000..0a8a4ad --- /dev/null +++ b/libtommath/logs/invmod.png diff --git a/libtommath/logs/mult.log b/libtommath/logs/mult.log new file mode 100644 index 0000000..33563fc --- /dev/null +++ b/libtommath/logs/mult.log @@ -0,0 +1,84 @@ +271 555 +390 855 +508 1161 +631 1605 +749 2117 +871 2687 +991 3329 +1108 4084 +1231 4786 +1351 5624 +1470 6392 +1586 7364 +1710 8218 +1830 9255 +1951 10217 +2067 11461 +2191 12463 +2308 13677 +2430 14800 +2551 16232 +2671 17460 +2791 18899 +2902 20247 +3028 21902 +3151 23240 +3267 24927 +3391 26441 +3511 28277 +3631 29838 +3749 31751 +3869 33673 +3989 35431 +4111 37518 +4231 39426 +4349 41504 +4471 43567 +4591 45786 +4711 47876 +4831 50299 +4951 52427 +5071 54785 +5189 57241 +5307 59730 +5431 62194 +5551 64761 +5670 67322 +5789 70073 +5907 72663 +6030 75437 +6151 78242 +6268 81202 +6389 83948 +6509 86985 +6631 89903 +6747 93184 +6869 96044 +6991 99286 +7109 102395 +7229 105917 +7351 108940 +7470 112490 +7589 115702 +7711 119508 +7831 122632 +7951 126410 +8071 129808 +8190 133895 +8311 137146 +8431 141218 +8549 144732 +8667 149131 +8790 152462 +8911 156754 +9030 160479 +9149 165138 +9271 168601 +9391 173185 +9511 176988 +9627 181976 +9751 185539 +9870 190388 +9991 194335 +10110 199605 +10228 203298 diff --git a/libtommath/logs/mult.png b/libtommath/logs/mult.png Binary files differnew file mode 100644 index 0000000..4f7a4ee --- /dev/null +++ b/libtommath/logs/mult.png diff --git a/libtommath/logs/mult_kara.log b/libtommath/logs/mult_kara.log new file mode 100644 index 0000000..7136c79 --- /dev/null +++ b/libtommath/logs/mult_kara.log @@ -0,0 +1,84 @@ +271 560 +391 870 +511 1159 +631 1605 +750 2111 +871 2737 +991 3361 +1111 4054 +1231 4778 +1351 5600 +1471 6404 +1591 7323 +1710 8255 +1831 9239 +1948 10257 +2070 11397 +2190 12531 +2308 13665 +2429 14870 +2550 16175 +2671 17539 +2787 18879 +2911 20350 +3031 21807 +3150 23415 +3270 24897 +3388 26567 +3511 28205 +3627 30076 +3751 31744 +3869 33657 +3991 35425 +4111 37522 +4229 39363 +4351 41503 +4470 43491 +4590 45827 +4711 47795 +4828 50166 +4951 52318 +5070 54911 +5191 57036 +5308 58237 +5431 60248 +5551 62678 +5671 64786 +5791 67294 +5908 69343 +6031 71607 +6151 74166 +6271 76590 +6391 78734 +6511 81175 +6631 83742 +6750 86403 +6868 88873 +6990 91150 +7110 94211 +7228 96922 +7351 99445 +7469 102216 +7589 104968 +7711 108113 +7827 110758 +7950 113714 +8071 116511 +8186 119643 +8310 122679 +8425 125581 +8551 128715 +8669 131778 +8788 135116 +8910 138138 +9031 141628 +9148 144754 +9268 148367 +9391 151551 +9511 155033 +9631 158652 +9751 162125 +9871 165248 +9988 168627 +10111 172427 +10231 176412 diff --git a/libtommath/logs/sqr.log b/libtommath/logs/sqr.log new file mode 100644 index 0000000..cd29fc5 --- /dev/null +++ b/libtommath/logs/sqr.log @@ -0,0 +1,84 @@ +265 562 +389 882 +509 1207 +631 1572 +750 1990 +859 2433 +991 2894 +1109 3555 +1230 4228 +1350 5018 +1471 5805 +1591 6579 +1709 7415 +1829 8329 +1949 9225 +2071 10139 +2188 11239 +2309 12178 +2431 13212 +2551 14294 +2671 15551 +2791 16512 +2911 17718 +3030 18876 +3150 20259 +3270 21374 +3391 22650 +3511 23948 +3631 25493 +3750 26756 +3870 28225 +3989 29705 +4110 31409 +4230 32834 +4351 34327 +4471 35818 +4591 37636 +4711 39228 +4830 40868 +4949 42393 +5070 44541 +5191 46269 +5310 48162 +5429 49728 +5548 51985 +5671 53948 +5791 55885 +5910 57584 +6031 60082 +6150 62239 +6270 64309 +6390 66014 +6511 68766 +6631 71012 +6750 73172 +6871 74952 +6991 77909 +7111 80371 +7231 82666 +7351 84531 +7469 87698 +7589 90318 +7711 225384 +7830 232428 +7950 240009 +8070 246522 +8190 253662 +8310 260961 +8431 269253 +8549 275743 +8671 283769 +8789 290811 +8911 300034 +9030 306873 +9149 315085 +9270 323944 +9390 332390 +9508 337519 +9631 348986 +9749 356904 +9871 367013 +9989 373831 +10108 381033 +10230 393475 diff --git a/libtommath/logs/sqr_kara.log b/libtommath/logs/sqr_kara.log new file mode 100644 index 0000000..06355a7 --- /dev/null +++ b/libtommath/logs/sqr_kara.log @@ -0,0 +1,84 @@ +271 560 +388 878 +511 1179 +629 1625 +751 1988 +871 2423 +989 2896 +1111 3561 +1231 4209 +1350 5015 +1470 5804 +1591 6556 +1709 7420 +1831 8263 +1951 9173 +2070 10153 +2191 11229 +2310 12167 +2431 13211 +2550 14309 +2671 15524 +2788 16525 +2910 17712 +3028 18822 +3148 20220 +3271 21343 +3391 22652 +3511 23944 +3630 25485 +3750 26778 +3868 28201 +3990 29653 +4111 31393 +4225 32841 +4350 34328 +4471 35786 +4590 37652 +4711 39245 +4830 40876 +4951 42433 +5068 44547 +5191 46321 +5311 48140 +5430 49727 +5550 52034 +5671 53954 +5791 55921 +5908 57597 +6031 60084 +6148 62226 +6270 64295 +6390 66045 +6511 68779 +6629 71003 +6751 73169 +6871 74992 +6991 77895 +7110 80376 +7231 82628 +7351 84468 +7470 87664 +7591 90284 +7711 91352 +7828 93995 +7950 96276 +8071 98691 +8190 101256 +8308 103631 +8431 105222 +8550 108343 +8671 110281 +8787 112764 +8911 115397 +9031 117690 +9151 120266 +9271 122715 +9391 124624 +9510 127937 +9630 130313 +9750 132914 +9871 136129 +9991 138517 +10108 141525 +10231 144225 diff --git a/libtommath/logs/sub.log b/libtommath/logs/sub.log new file mode 100644 index 0000000..9f84fa2 --- /dev/null +++ b/libtommath/logs/sub.log @@ -0,0 +1,16 @@ +480 94 +960 116 +1440 140 +1920 164 +2400 205 +2880 229 +3360 253 +3840 277 +4320 299 +4800 321 +5280 345 +5760 371 +6240 395 +6720 419 +7200 441 +7680 465 diff --git a/libtommath/makefile.bcc b/libtommath/makefile.bcc new file mode 100644 index 0000000..67743d9 --- /dev/null +++ b/libtommath/makefile.bcc @@ -0,0 +1,44 @@ +# +# Borland C++Builder Makefile (makefile.bcc) +# + + +LIB = tlib +CC = bcc32 +CFLAGS = -c -O2 -I. + +OBJECTS=bncore.obj bn_mp_init.obj bn_mp_clear.obj bn_mp_exch.obj bn_mp_grow.obj bn_mp_shrink.obj \ +bn_mp_clamp.obj bn_mp_zero.obj bn_mp_set.obj bn_mp_set_int.obj bn_mp_init_size.obj bn_mp_copy.obj \ +bn_mp_init_copy.obj bn_mp_abs.obj bn_mp_neg.obj bn_mp_cmp_mag.obj bn_mp_cmp.obj bn_mp_cmp_d.obj \ +bn_mp_rshd.obj bn_mp_lshd.obj bn_mp_mod_2d.obj bn_mp_div_2d.obj bn_mp_mul_2d.obj bn_mp_div_2.obj \ +bn_mp_mul_2.obj bn_s_mp_add.obj bn_s_mp_sub.obj bn_fast_s_mp_mul_digs.obj bn_s_mp_mul_digs.obj \ +bn_fast_s_mp_mul_high_digs.obj bn_s_mp_mul_high_digs.obj bn_fast_s_mp_sqr.obj bn_s_mp_sqr.obj \ +bn_mp_add.obj bn_mp_sub.obj bn_mp_karatsuba_mul.obj bn_mp_mul.obj bn_mp_karatsuba_sqr.obj \ +bn_mp_sqr.obj bn_mp_div.obj bn_mp_mod.obj bn_mp_add_d.obj bn_mp_sub_d.obj bn_mp_mul_d.obj \ +bn_mp_div_d.obj bn_mp_mod_d.obj bn_mp_expt_d.obj bn_mp_addmod.obj bn_mp_submod.obj \ +bn_mp_mulmod.obj bn_mp_sqrmod.obj bn_mp_gcd.obj bn_mp_lcm.obj bn_fast_mp_invmod.obj bn_mp_invmod.obj \ +bn_mp_reduce.obj bn_mp_montgomery_setup.obj bn_fast_mp_montgomery_reduce.obj bn_mp_montgomery_reduce.obj \ +bn_mp_exptmod_fast.obj bn_mp_exptmod.obj bn_mp_2expt.obj bn_mp_n_root.obj bn_mp_jacobi.obj bn_reverse.obj \ +bn_mp_count_bits.obj bn_mp_read_unsigned_bin.obj bn_mp_read_signed_bin.obj bn_mp_to_unsigned_bin.obj \ +bn_mp_to_signed_bin.obj bn_mp_unsigned_bin_size.obj bn_mp_signed_bin_size.obj \ +bn_mp_xor.obj bn_mp_and.obj bn_mp_or.obj bn_mp_rand.obj bn_mp_montgomery_calc_normalization.obj \ +bn_mp_prime_is_divisible.obj bn_prime_tab.obj bn_mp_prime_fermat.obj bn_mp_prime_miller_rabin.obj \ +bn_mp_prime_is_prime.obj bn_mp_prime_next_prime.obj bn_mp_dr_reduce.obj \ +bn_mp_dr_is_modulus.obj bn_mp_dr_setup.obj bn_mp_reduce_setup.obj \ +bn_mp_toom_mul.obj bn_mp_toom_sqr.obj bn_mp_div_3.obj bn_s_mp_exptmod.obj \ +bn_mp_reduce_2k.obj bn_mp_reduce_is_2k.obj bn_mp_reduce_2k_setup.obj \ +bn_mp_reduce_2k_l.obj bn_mp_reduce_is_2k_l.obj bn_mp_reduce_2k_setup_l.obj \ +bn_mp_radix_smap.obj bn_mp_read_radix.obj bn_mp_toradix.obj bn_mp_radix_size.obj \ +bn_mp_fread.obj bn_mp_fwrite.obj bn_mp_cnt_lsb.obj bn_error.obj \ +bn_mp_init_multi.obj bn_mp_clear_multi.obj bn_mp_exteuclid.obj bn_mp_toradix_n.obj \ +bn_mp_prime_random_ex.obj bn_mp_get_int.obj bn_mp_sqrt.obj bn_mp_is_square.obj \ +bn_mp_init_set.obj bn_mp_init_set_int.obj bn_mp_invmod_slow.obj bn_mp_prime_rabin_miller_trials.obj \ +bn_mp_to_signed_bin_n.obj bn_mp_to_unsigned_bin_n.obj + +TARGET = libtommath.lib + +$(TARGET): $(OBJECTS) + +.c.obj: + $(CC) $(CFLAGS) $< + $(LIB) $(TARGET) -+$@ diff --git a/libtommath/makefile.cygwin_dll b/libtommath/makefile.cygwin_dll new file mode 100644 index 0000000..85a9b20 --- /dev/null +++ b/libtommath/makefile.cygwin_dll @@ -0,0 +1,55 @@ +#Makefile for Cygwin-GCC +# +#This makefile will build a Windows DLL [doesn't require cygwin to run] in the file +#libtommath.dll. The import library is in libtommath.dll.a. Remember to add +#"-Wl,--enable-auto-import" to your client build to avoid the auto-import warnings +# +#Tom St Denis +CFLAGS += -I./ -Wall -W -Wshadow -O3 -funroll-loops -mno-cygwin + +#x86 optimizations [should be valid for any GCC install though] +CFLAGS += -fomit-frame-pointer + +default: windll + +OBJECTS=bncore.o bn_mp_init.o bn_mp_clear.o bn_mp_exch.o bn_mp_grow.o bn_mp_shrink.o \ +bn_mp_clamp.o bn_mp_zero.o bn_mp_set.o bn_mp_set_int.o bn_mp_init_size.o bn_mp_copy.o \ +bn_mp_init_copy.o bn_mp_abs.o bn_mp_neg.o bn_mp_cmp_mag.o bn_mp_cmp.o bn_mp_cmp_d.o \ +bn_mp_rshd.o bn_mp_lshd.o bn_mp_mod_2d.o bn_mp_div_2d.o bn_mp_mul_2d.o bn_mp_div_2.o \ +bn_mp_mul_2.o bn_s_mp_add.o bn_s_mp_sub.o bn_fast_s_mp_mul_digs.o bn_s_mp_mul_digs.o \ +bn_fast_s_mp_mul_high_digs.o bn_s_mp_mul_high_digs.o bn_fast_s_mp_sqr.o bn_s_mp_sqr.o \ +bn_mp_add.o bn_mp_sub.o bn_mp_karatsuba_mul.o bn_mp_mul.o bn_mp_karatsuba_sqr.o \ +bn_mp_sqr.o bn_mp_div.o bn_mp_mod.o bn_mp_add_d.o bn_mp_sub_d.o bn_mp_mul_d.o \ +bn_mp_div_d.o bn_mp_mod_d.o bn_mp_expt_d.o bn_mp_addmod.o bn_mp_submod.o \ +bn_mp_mulmod.o bn_mp_sqrmod.o bn_mp_gcd.o bn_mp_lcm.o bn_fast_mp_invmod.o bn_mp_invmod.o \ +bn_mp_reduce.o bn_mp_montgomery_setup.o bn_fast_mp_montgomery_reduce.o bn_mp_montgomery_reduce.o \ +bn_mp_exptmod_fast.o bn_mp_exptmod.o bn_mp_2expt.o bn_mp_n_root.o bn_mp_jacobi.o bn_reverse.o \ +bn_mp_count_bits.o bn_mp_read_unsigned_bin.o bn_mp_read_signed_bin.o bn_mp_to_unsigned_bin.o \ +bn_mp_to_signed_bin.o bn_mp_unsigned_bin_size.o bn_mp_signed_bin_size.o \ +bn_mp_xor.o bn_mp_and.o bn_mp_or.o bn_mp_rand.o bn_mp_montgomery_calc_normalization.o \ +bn_mp_prime_is_divisible.o bn_prime_tab.o bn_mp_prime_fermat.o bn_mp_prime_miller_rabin.o \ +bn_mp_prime_is_prime.o bn_mp_prime_next_prime.o bn_mp_dr_reduce.o \ +bn_mp_dr_is_modulus.o bn_mp_dr_setup.o bn_mp_reduce_setup.o \ +bn_mp_toom_mul.o bn_mp_toom_sqr.o bn_mp_div_3.o bn_s_mp_exptmod.o \ +bn_mp_reduce_2k.o bn_mp_reduce_is_2k.o bn_mp_reduce_2k_setup.o \ +bn_mp_reduce_2k_l.o bn_mp_reduce_is_2k_l.o bn_mp_reduce_2k_setup_l.o \ +bn_mp_radix_smap.o bn_mp_read_radix.o bn_mp_toradix.o bn_mp_radix_size.o \ +bn_mp_fread.o bn_mp_fwrite.o bn_mp_cnt_lsb.o bn_error.o \ +bn_mp_init_multi.o bn_mp_clear_multi.o bn_mp_exteuclid.o bn_mp_toradix_n.o \ +bn_mp_prime_random_ex.o bn_mp_get_int.o bn_mp_sqrt.o bn_mp_is_square.o bn_mp_init_set.o \ +bn_mp_init_set_int.o bn_mp_invmod_slow.o bn_mp_prime_rabin_miller_trials.o \ +bn_mp_to_signed_bin_n.o bn_mp_to_unsigned_bin_n.o + +# make a Windows DLL via Cygwin +windll: $(OBJECTS) + gcc -mno-cygwin -mdll -o libtommath.dll -Wl,--out-implib=libtommath.dll.a -Wl,--export-all-symbols *.o + ranlib libtommath.dll.a + +# build the test program using the windows DLL +test: $(OBJECTS) windll + gcc $(CFLAGS) demo/demo.c libtommath.dll.a -Wl,--enable-auto-import -o test -s + cd mtest ; $(CC) -O3 -fomit-frame-pointer -funroll-loops mtest.c -o mtest -s + +/* $Source: /cvs/libtom/libtommath/makefile.cygwin_dll,v $ */ +/* $Revision: 1.2 $ */ +/* $Date: 2005/05/05 14:38:45 $ */ diff --git a/libtommath/makefile.icc b/libtommath/makefile.icc new file mode 100644 index 0000000..cf70ab0 --- /dev/null +++ b/libtommath/makefile.icc @@ -0,0 +1,116 @@ +#Makefile for ICC +# +#Tom St Denis +CC=icc + +CFLAGS += -I./ + +# optimize for SPEED +# +# -mcpu= can be pentium, pentiumpro (covers PII through PIII) or pentium4 +# -ax? specifies make code specifically for ? but compatible with IA-32 +# -x? specifies compile solely for ? [not specifically IA-32 compatible] +# +# where ? is +# K - PIII +# W - first P4 [Williamette] +# N - P4 Northwood +# P - P4 Prescott +# B - Blend of P4 and PM [mobile] +# +# Default to just generic max opts +CFLAGS += -O3 -xP -ip + +#install as this user +USER=root +GROUP=root + +default: libtommath.a + +#default files to install +LIBNAME=libtommath.a +HEADERS=tommath.h + +#LIBPATH-The directory for libtomcrypt to be installed to. +#INCPATH-The directory to install the header files for libtommath. +#DATAPATH-The directory to install the pdf docs. +DESTDIR= +LIBPATH=/usr/lib +INCPATH=/usr/include +DATAPATH=/usr/share/doc/libtommath/pdf + +OBJECTS=bncore.o bn_mp_init.o bn_mp_clear.o bn_mp_exch.o bn_mp_grow.o bn_mp_shrink.o \ +bn_mp_clamp.o bn_mp_zero.o bn_mp_set.o bn_mp_set_int.o bn_mp_init_size.o bn_mp_copy.o \ +bn_mp_init_copy.o bn_mp_abs.o bn_mp_neg.o bn_mp_cmp_mag.o bn_mp_cmp.o bn_mp_cmp_d.o \ +bn_mp_rshd.o bn_mp_lshd.o bn_mp_mod_2d.o bn_mp_div_2d.o bn_mp_mul_2d.o bn_mp_div_2.o \ +bn_mp_mul_2.o bn_s_mp_add.o bn_s_mp_sub.o bn_fast_s_mp_mul_digs.o bn_s_mp_mul_digs.o \ +bn_fast_s_mp_mul_high_digs.o bn_s_mp_mul_high_digs.o bn_fast_s_mp_sqr.o bn_s_mp_sqr.o \ +bn_mp_add.o bn_mp_sub.o bn_mp_karatsuba_mul.o bn_mp_mul.o bn_mp_karatsuba_sqr.o \ +bn_mp_sqr.o bn_mp_div.o bn_mp_mod.o bn_mp_add_d.o bn_mp_sub_d.o bn_mp_mul_d.o \ +bn_mp_div_d.o bn_mp_mod_d.o bn_mp_expt_d.o bn_mp_addmod.o bn_mp_submod.o \ +bn_mp_mulmod.o bn_mp_sqrmod.o bn_mp_gcd.o bn_mp_lcm.o bn_fast_mp_invmod.o bn_mp_invmod.o \ +bn_mp_reduce.o bn_mp_montgomery_setup.o bn_fast_mp_montgomery_reduce.o bn_mp_montgomery_reduce.o \ +bn_mp_exptmod_fast.o bn_mp_exptmod.o bn_mp_2expt.o bn_mp_n_root.o bn_mp_jacobi.o bn_reverse.o \ +bn_mp_count_bits.o bn_mp_read_unsigned_bin.o bn_mp_read_signed_bin.o bn_mp_to_unsigned_bin.o \ +bn_mp_to_signed_bin.o bn_mp_unsigned_bin_size.o bn_mp_signed_bin_size.o \ +bn_mp_xor.o bn_mp_and.o bn_mp_or.o bn_mp_rand.o bn_mp_montgomery_calc_normalization.o \ +bn_mp_prime_is_divisible.o bn_prime_tab.o bn_mp_prime_fermat.o bn_mp_prime_miller_rabin.o \ +bn_mp_prime_is_prime.o bn_mp_prime_next_prime.o bn_mp_dr_reduce.o \ +bn_mp_dr_is_modulus.o bn_mp_dr_setup.o bn_mp_reduce_setup.o \ +bn_mp_toom_mul.o bn_mp_toom_sqr.o bn_mp_div_3.o bn_s_mp_exptmod.o \ +bn_mp_reduce_2k.o bn_mp_reduce_is_2k.o bn_mp_reduce_2k_setup.o \ +bn_mp_reduce_2k_l.o bn_mp_reduce_is_2k_l.o bn_mp_reduce_2k_setup_l.o \ +bn_mp_radix_smap.o bn_mp_read_radix.o bn_mp_toradix.o bn_mp_radix_size.o \ +bn_mp_fread.o bn_mp_fwrite.o bn_mp_cnt_lsb.o bn_error.o \ +bn_mp_init_multi.o bn_mp_clear_multi.o bn_mp_exteuclid.o bn_mp_toradix_n.o \ +bn_mp_prime_random_ex.o bn_mp_get_int.o bn_mp_sqrt.o bn_mp_is_square.o bn_mp_init_set.o \ +bn_mp_init_set_int.o bn_mp_invmod_slow.o bn_mp_prime_rabin_miller_trials.o \ +bn_mp_to_signed_bin_n.o bn_mp_to_unsigned_bin_n.o + +libtommath.a: $(OBJECTS) + $(AR) $(ARFLAGS) libtommath.a $(OBJECTS) + ranlib libtommath.a + +#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 -f makefile.icc CFLAGS="$(CFLAGS) -prof_gen -DTESTING" timing + ./ltmtest + rm -f *.a *.o ltmtest + make -f makefile.icc CFLAGS="$(CFLAGS) -prof_use" + +#make a single object profiled library +profiled_single: + perl gen.pl + $(CC) $(CFLAGS) -prof_gen -DTESTING -c mpi.c -o mpi.o + $(CC) $(CFLAGS) -DTESTING -DTIMER demo/demo.c mpi.o -o ltmtest + ./ltmtest + rm -f *.o ltmtest + $(CC) $(CFLAGS) -prof_use -ip -DTESTING -c mpi.c -o mpi.o + $(AR) $(ARFLAGS) libtommath.a mpi.o + ranlib libtommath.a + +install: libtommath.a + install -d -g $(GROUP) -o $(USER) $(DESTDIR)$(LIBPATH) + install -d -g $(GROUP) -o $(USER) $(DESTDIR)$(INCPATH) + install -g $(GROUP) -o $(USER) $(LIBNAME) $(DESTDIR)$(LIBPATH) + install -g $(GROUP) -o $(USER) $(HEADERS) $(DESTDIR)$(INCPATH) + +test: libtommath.a demo/demo.o + $(CC) demo/demo.o libtommath.a -o test + +mtest: test + cd mtest ; $(CC) $(CFLAGS) mtest.c -o mtest + +timing: libtommath.a + $(CC) $(CFLAGS) -DTIMER demo/timing.c libtommath.a -o ltmtest + +clean: + rm -f *.bat *.pdf *.o *.a *.obj *.lib *.exe *.dll etclib/*.o demo/demo.o test ltmtest mpitest mtest/mtest mtest/mtest.exe \ + *.idx *.toc *.log *.aux *.dvi *.lof *.ind *.ilg *.ps *.log *.s mpi.c *.il etc/*.il *.dyn + cd etc ; make clean + cd pics ; make clean diff --git a/libtommath/makefile.msvc b/libtommath/makefile.msvc new file mode 100644 index 0000000..5edebec --- /dev/null +++ b/libtommath/makefile.msvc @@ -0,0 +1,40 @@ +#MSVC Makefile +# +#Tom St Denis + +CFLAGS = /I. /Ox /DWIN32 /W3 /Fo$@ + +default: library + +OBJECTS=bncore.obj bn_mp_init.obj bn_mp_clear.obj bn_mp_exch.obj bn_mp_grow.obj bn_mp_shrink.obj \ +bn_mp_clamp.obj bn_mp_zero.obj bn_mp_set.obj bn_mp_set_int.obj bn_mp_init_size.obj bn_mp_copy.obj \ +bn_mp_init_copy.obj bn_mp_abs.obj bn_mp_neg.obj bn_mp_cmp_mag.obj bn_mp_cmp.obj bn_mp_cmp_d.obj \ +bn_mp_rshd.obj bn_mp_lshd.obj bn_mp_mod_2d.obj bn_mp_div_2d.obj bn_mp_mul_2d.obj bn_mp_div_2.obj \ +bn_mp_mul_2.obj bn_s_mp_add.obj bn_s_mp_sub.obj bn_fast_s_mp_mul_digs.obj bn_s_mp_mul_digs.obj \ +bn_fast_s_mp_mul_high_digs.obj bn_s_mp_mul_high_digs.obj bn_fast_s_mp_sqr.obj bn_s_mp_sqr.obj \ +bn_mp_add.obj bn_mp_sub.obj bn_mp_karatsuba_mul.obj bn_mp_mul.obj bn_mp_karatsuba_sqr.obj \ +bn_mp_sqr.obj bn_mp_div.obj bn_mp_mod.obj bn_mp_add_d.obj bn_mp_sub_d.obj bn_mp_mul_d.obj \ +bn_mp_div_d.obj bn_mp_mod_d.obj bn_mp_expt_d.obj bn_mp_addmod.obj bn_mp_submod.obj \ +bn_mp_mulmod.obj bn_mp_sqrmod.obj bn_mp_gcd.obj bn_mp_lcm.obj bn_fast_mp_invmod.obj bn_mp_invmod.obj \ +bn_mp_reduce.obj bn_mp_montgomery_setup.obj bn_fast_mp_montgomery_reduce.obj bn_mp_montgomery_reduce.obj \ +bn_mp_exptmod_fast.obj bn_mp_exptmod.obj bn_mp_2expt.obj bn_mp_n_root.obj bn_mp_jacobi.obj bn_reverse.obj \ +bn_mp_count_bits.obj bn_mp_read_unsigned_bin.obj bn_mp_read_signed_bin.obj bn_mp_to_unsigned_bin.obj \ +bn_mp_to_signed_bin.obj bn_mp_unsigned_bin_size.obj bn_mp_signed_bin_size.obj \ +bn_mp_xor.obj bn_mp_and.obj bn_mp_or.obj bn_mp_rand.obj bn_mp_montgomery_calc_normalization.obj \ +bn_mp_prime_is_divisible.obj bn_prime_tab.obj bn_mp_prime_fermat.obj bn_mp_prime_miller_rabin.obj \ +bn_mp_prime_is_prime.obj bn_mp_prime_next_prime.obj bn_mp_dr_reduce.obj \ +bn_mp_dr_is_modulus.obj bn_mp_dr_setup.obj bn_mp_reduce_setup.obj \ +bn_mp_toom_mul.obj bn_mp_toom_sqr.obj bn_mp_div_3.obj bn_s_mp_exptmod.obj \ +bn_mp_reduce_2k.obj bn_mp_reduce_is_2k.obj bn_mp_reduce_2k_setup.obj \ +bn_mp_reduce_2k_l.obj bn_mp_reduce_is_2k_l.obj bn_mp_reduce_2k_setup_l.obj \ +bn_mp_radix_smap.obj bn_mp_read_radix.obj bn_mp_toradix.obj bn_mp_radix_size.obj \ +bn_mp_fread.obj bn_mp_fwrite.obj bn_mp_cnt_lsb.obj bn_error.obj \ +bn_mp_init_multi.obj bn_mp_clear_multi.obj bn_mp_exteuclid.obj bn_mp_toradix_n.obj \ +bn_mp_prime_random_ex.obj bn_mp_get_int.obj bn_mp_sqrt.obj bn_mp_is_square.obj \ +bn_mp_init_set.obj bn_mp_init_set_int.obj bn_mp_invmod_slow.obj bn_mp_prime_rabin_miller_trials.obj \ +bn_mp_to_signed_bin_n.obj bn_mp_to_unsigned_bin_n.obj + +HEADERS=tommath.h tommath_class.h tommath_superclass.h + +library: $(OBJECTS) + lib /out:tommath.lib $(OBJECTS) diff --git a/libtommath/makefile.shared b/libtommath/makefile.shared new file mode 100644 index 0000000..e230fb8 --- /dev/null +++ b/libtommath/makefile.shared @@ -0,0 +1,102 @@ +#Makefile for GCC +# +#Tom St Denis +VERSION=0:40 + +CC = libtool --mode=compile --tag=CC gcc + +CFLAGS += -I./ -Wall -W -Wshadow -Wsign-compare + +ifndef IGNORE_SPEED + +#for speed +CFLAGS += -O3 -funroll-loops + +#for size +#CFLAGS += -Os + +#x86 optimizations [should be valid for any GCC install though] +CFLAGS += -fomit-frame-pointer + +endif + +#install as this user +ifndef INSTALL_GROUP + GROUP=wheel +else + GROUP=$(INSTALL_GROUP) +endif + +ifndef INSTALL_USER + USER=root +else + USER=$(INSTALL_USER) +endif + +default: libtommath.la + +#default files to install +ifndef LIBNAME + LIBNAME=libtommath.la +endif +ifndef LIBNAME_S + LIBNAME_S=libtommath.a +endif +HEADERS=tommath.h tommath_class.h tommath_superclass.h + +#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= +LIBPATH=/usr/lib +INCPATH=/usr/include +DATAPATH=/usr/share/doc/libtommath/pdf + +OBJECTS=bncore.o bn_mp_init.o bn_mp_clear.o bn_mp_exch.o bn_mp_grow.o bn_mp_shrink.o \ +bn_mp_clamp.o bn_mp_zero.o bn_mp_set.o bn_mp_set_int.o bn_mp_init_size.o bn_mp_copy.o \ +bn_mp_init_copy.o bn_mp_abs.o bn_mp_neg.o bn_mp_cmp_mag.o bn_mp_cmp.o bn_mp_cmp_d.o \ +bn_mp_rshd.o bn_mp_lshd.o bn_mp_mod_2d.o bn_mp_div_2d.o bn_mp_mul_2d.o bn_mp_div_2.o \ +bn_mp_mul_2.o bn_s_mp_add.o bn_s_mp_sub.o bn_fast_s_mp_mul_digs.o bn_s_mp_mul_digs.o \ +bn_fast_s_mp_mul_high_digs.o bn_s_mp_mul_high_digs.o bn_fast_s_mp_sqr.o bn_s_mp_sqr.o \ +bn_mp_add.o bn_mp_sub.o bn_mp_karatsuba_mul.o bn_mp_mul.o bn_mp_karatsuba_sqr.o \ +bn_mp_sqr.o bn_mp_div.o bn_mp_mod.o bn_mp_add_d.o bn_mp_sub_d.o bn_mp_mul_d.o \ +bn_mp_div_d.o bn_mp_mod_d.o bn_mp_expt_d.o bn_mp_addmod.o bn_mp_submod.o \ +bn_mp_mulmod.o bn_mp_sqrmod.o bn_mp_gcd.o bn_mp_lcm.o bn_fast_mp_invmod.o bn_mp_invmod.o \ +bn_mp_reduce.o bn_mp_montgomery_setup.o bn_fast_mp_montgomery_reduce.o bn_mp_montgomery_reduce.o \ +bn_mp_exptmod_fast.o bn_mp_exptmod.o bn_mp_2expt.o bn_mp_n_root.o bn_mp_jacobi.o bn_reverse.o \ +bn_mp_count_bits.o bn_mp_read_unsigned_bin.o bn_mp_read_signed_bin.o bn_mp_to_unsigned_bin.o \ +bn_mp_to_signed_bin.o bn_mp_unsigned_bin_size.o bn_mp_signed_bin_size.o \ +bn_mp_xor.o bn_mp_and.o bn_mp_or.o bn_mp_rand.o bn_mp_montgomery_calc_normalization.o \ +bn_mp_prime_is_divisible.o bn_prime_tab.o bn_mp_prime_fermat.o bn_mp_prime_miller_rabin.o \ +bn_mp_prime_is_prime.o bn_mp_prime_next_prime.o bn_mp_dr_reduce.o \ +bn_mp_dr_is_modulus.o bn_mp_dr_setup.o bn_mp_reduce_setup.o \ +bn_mp_toom_mul.o bn_mp_toom_sqr.o bn_mp_div_3.o bn_s_mp_exptmod.o \ +bn_mp_reduce_2k.o bn_mp_reduce_is_2k.o bn_mp_reduce_2k_setup.o \ +bn_mp_reduce_2k_l.o bn_mp_reduce_is_2k_l.o bn_mp_reduce_2k_setup_l.o \ +bn_mp_radix_smap.o bn_mp_read_radix.o bn_mp_toradix.o bn_mp_radix_size.o \ +bn_mp_fread.o bn_mp_fwrite.o bn_mp_cnt_lsb.o bn_error.o \ +bn_mp_init_multi.o bn_mp_clear_multi.o bn_mp_exteuclid.o bn_mp_toradix_n.o \ +bn_mp_prime_random_ex.o bn_mp_get_int.o bn_mp_sqrt.o bn_mp_is_square.o bn_mp_init_set.o \ +bn_mp_init_set_int.o bn_mp_invmod_slow.o bn_mp_prime_rabin_miller_trials.o \ +bn_mp_to_signed_bin_n.o bn_mp_to_unsigned_bin_n.o + +objs: $(OBJECTS) + +$(LIBNAME): $(OBJECTS) + libtool --mode=link gcc *.lo -o $(LIBNAME) -rpath $(LIBPATH) -version-info $(VERSION) + +install: $(LIBNAME) + install -d -g $(GROUP) -o $(USER) $(DESTDIR)$(LIBPATH) + libtool --mode=install install -c $(LIBNAME) $(DESTDIR)$(LIBPATH)/$(LIBNAME) + install -d -g $(GROUP) -o $(USER) $(DESTDIR)$(INCPATH) + install -g $(GROUP) -o $(USER) $(HEADERS) $(DESTDIR)$(INCPATH) + +test: $(LIBNAME) demo/demo.o + gcc $(CFLAGS) -c demo/demo.c -o demo/demo.o + libtool --mode=link gcc -o test demo/demo.o $(LIBNAME_S) + +mtest: test + cd mtest ; gcc $(CFLAGS) mtest.c -o mtest + +timing: $(LIBNAME) + gcc $(CFLAGS) -DTIMER demo/timing.c $(LIBNAME_S) -o ltmtest diff --git a/libtommath/mess.sh b/libtommath/mess.sh new file mode 100644 index 0000000..bf639ce --- /dev/null +++ b/libtommath/mess.sh @@ -0,0 +1,4 @@ +#!/bin/bash +if cvs log $1 >/dev/null 2>/dev/null; then exit 0; else echo "$1 shouldn't be here" ; exit 1; fi + + diff --git a/libtommath/mtest/logtab.h b/libtommath/mtest/logtab.h new file mode 100644 index 0000000..bbefaef --- /dev/null +++ b/libtommath/mtest/logtab.h @@ -0,0 +1,24 @@ +const float s_logv_2[] = { + 0.000000000, 0.000000000, 1.000000000, 0.630929754, /* 0 1 2 3 */ + 0.500000000, 0.430676558, 0.386852807, 0.356207187, /* 4 5 6 7 */ + 0.333333333, 0.315464877, 0.301029996, 0.289064826, /* 8 9 10 11 */ + 0.278942946, 0.270238154, 0.262649535, 0.255958025, /* 12 13 14 15 */ + 0.250000000, 0.244650542, 0.239812467, 0.235408913, /* 16 17 18 19 */ + 0.231378213, 0.227670249, 0.224243824, 0.221064729, /* 20 21 22 23 */ + 0.218104292, 0.215338279, 0.212746054, 0.210309918, /* 24 25 26 27 */ + 0.208014598, 0.205846832, 0.203795047, 0.201849087, /* 28 29 30 31 */ + 0.200000000, 0.198239863, 0.196561632, 0.194959022, /* 32 33 34 35 */ + 0.193426404, 0.191958720, 0.190551412, 0.189200360, /* 36 37 38 39 */ + 0.187901825, 0.186652411, 0.185449023, 0.184288833, /* 40 41 42 43 */ + 0.183169251, 0.182087900, 0.181042597, 0.180031327, /* 44 45 46 47 */ + 0.179052232, 0.178103594, 0.177183820, 0.176291434, /* 48 49 50 51 */ + 0.175425064, 0.174583430, 0.173765343, 0.172969690, /* 52 53 54 55 */ + 0.172195434, 0.171441601, 0.170707280, 0.169991616, /* 56 57 58 59 */ + 0.169293808, 0.168613099, 0.167948779, 0.167300179, /* 60 61 62 63 */ + 0.166666667 +}; + + +/* $Source: /cvs/libtom/libtommath/mtest/logtab.h,v $ */ +/* $Revision: 1.2 $ */ +/* $Date: 2005/05/05 14:38:47 $ */ diff --git a/libtommath/mtest/mpi-config.h b/libtommath/mtest/mpi-config.h new file mode 100644 index 0000000..6049c25 --- /dev/null +++ b/libtommath/mtest/mpi-config.h @@ -0,0 +1,90 @@ +/* Default configuration for MPI library */ +/* $Id: mpi-config.h,v 1.2 2005/05/05 14:38:47 tom Exp $ */ + +#ifndef MPI_CONFIG_H_ +#define MPI_CONFIG_H_ + +/* + For boolean options, + 0 = no + 1 = yes + + Other options are documented individually. + + */ + +#ifndef MP_IOFUNC +#define MP_IOFUNC 0 /* include mp_print() ? */ +#endif + +#ifndef MP_MODARITH +#define MP_MODARITH 1 /* include modular arithmetic ? */ +#endif + +#ifndef MP_NUMTH +#define MP_NUMTH 1 /* include number theoretic functions? */ +#endif + +#ifndef MP_LOGTAB +#define MP_LOGTAB 1 /* use table of logs instead of log()? */ +#endif + +#ifndef MP_MEMSET +#define MP_MEMSET 1 /* use memset() to zero buffers? */ +#endif + +#ifndef MP_MEMCPY +#define MP_MEMCPY 1 /* use memcpy() to copy buffers? */ +#endif + +#ifndef MP_CRYPTO +#define MP_CRYPTO 1 /* erase memory on free? */ +#endif + +#ifndef MP_ARGCHK +/* + 0 = no parameter checks + 1 = runtime checks, continue execution and return an error to caller + 2 = assertions; dump core on parameter errors + */ +#define MP_ARGCHK 2 /* how to check input arguments */ +#endif + +#ifndef MP_DEBUG +#define MP_DEBUG 0 /* print diagnostic output? */ +#endif + +#ifndef MP_DEFPREC +#define MP_DEFPREC 64 /* default precision, in digits */ +#endif + +#ifndef MP_MACRO +#define MP_MACRO 1 /* use macros for frequent calls? */ +#endif + +#ifndef MP_SQUARE +#define MP_SQUARE 1 /* use separate squaring code? */ +#endif + +#ifndef MP_PTAB_SIZE +/* + When building mpprime.c, we build in a table of small prime + values to use for primality testing. The more you include, + the more space they take up. See primes.c for the possible + values (currently 16, 32, 64, 128, 256, and 6542) + */ +#define MP_PTAB_SIZE 128 /* how many built-in primes? */ +#endif + +#ifndef MP_COMPAT_MACROS +#define MP_COMPAT_MACROS 1 /* define compatibility macros? */ +#endif + +#endif /* ifndef MPI_CONFIG_H_ */ + + +/* crc==3287762869, version==2, Sat Feb 02 06:43:53 2002 */ + +/* $Source: /cvs/libtom/libtommath/mtest/mpi-config.h,v $ */ +/* $Revision: 1.2 $ */ +/* $Date: 2005/05/05 14:38:47 $ */ diff --git a/libtommath/mtest/mpi-types.h b/libtommath/mtest/mpi-types.h new file mode 100644 index 0000000..026de58 --- /dev/null +++ b/libtommath/mtest/mpi-types.h @@ -0,0 +1,20 @@ +/* Type definitions generated by 'types.pl' */ +typedef char mp_sign; +typedef unsigned short mp_digit; /* 2 byte type */ +typedef unsigned int mp_word; /* 4 byte type */ +typedef unsigned int mp_size; +typedef int mp_err; + +#define MP_DIGIT_BIT (CHAR_BIT*sizeof(mp_digit)) +#define MP_DIGIT_MAX USHRT_MAX +#define MP_WORD_BIT (CHAR_BIT*sizeof(mp_word)) +#define MP_WORD_MAX UINT_MAX + +#define MP_DIGIT_SIZE 2 +#define DIGIT_FMT "%04X" +#define RADIX (MP_DIGIT_MAX+1) + + +/* $Source: /cvs/libtom/libtommath/mtest/mpi-types.h,v $ */ +/* $Revision: 1.2 $ */ +/* $Date: 2005/05/05 14:38:47 $ */ diff --git a/libtommath/mtest/mpi.c b/libtommath/mtest/mpi.c new file mode 100644 index 0000000..7c712dd --- /dev/null +++ b/libtommath/mtest/mpi.c @@ -0,0 +1,3985 @@ +/* + mpi.c + + by Michael J. Fromberger <sting@linguist.dartmouth.edu> + Copyright (C) 1998 Michael J. Fromberger, All Rights Reserved + + Arbitrary precision integer arithmetic library + + $Id: mpi.c,v 1.2 2005/05/05 14:38:47 tom Exp $ + */ + +#include "mpi.h" +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#if MP_DEBUG +#include <stdio.h> + +#define DIAG(T,V) {fprintf(stderr,T);mp_print(V,stderr);fputc('\n',stderr);} +#else +#define DIAG(T,V) +#endif + +/* + If MP_LOGTAB is not defined, use the math library to compute the + logarithms on the fly. Otherwise, use the static table below. + Pick which works best for your system. + */ +#if MP_LOGTAB + +/* {{{ s_logv_2[] - log table for 2 in various bases */ + +/* + A table of the logs of 2 for various bases (the 0 and 1 entries of + this table are meaningless and should not be referenced). + + This table is used to compute output lengths for the mp_toradix() + function. Since a number n in radix r takes up about log_r(n) + digits, we estimate the output size by taking the least integer + greater than log_r(n), where: + + log_r(n) = log_2(n) * log_r(2) + + This table, therefore, is a table of log_r(2) for 2 <= r <= 36, + which are the output bases supported. + */ + +#include "logtab.h" + +/* }}} */ +#define LOG_V_2(R) s_logv_2[(R)] + +#else + +#include <math.h> +#define LOG_V_2(R) (log(2.0)/log(R)) + +#endif + +/* Default precision for newly created mp_int's */ +static unsigned int s_mp_defprec = MP_DEFPREC; + +/* {{{ Digit arithmetic macros */ + +/* + When adding and multiplying digits, the results can be larger than + can be contained in an mp_digit. Thus, an mp_word is used. These + macros mask off the upper and lower digits of the mp_word (the + mp_word may be more than 2 mp_digits wide, but we only concern + ourselves with the low-order 2 mp_digits) + + If your mp_word DOES have more than 2 mp_digits, you need to + uncomment the first line, and comment out the second. + */ + +/* #define CARRYOUT(W) (((W)>>DIGIT_BIT)&MP_DIGIT_MAX) */ +#define CARRYOUT(W) ((W)>>DIGIT_BIT) +#define ACCUM(W) ((W)&MP_DIGIT_MAX) + +/* }}} */ + +/* {{{ Comparison constants */ + +#define MP_LT -1 +#define MP_EQ 0 +#define MP_GT 1 + +/* }}} */ + +/* {{{ Constant strings */ + +/* Constant strings returned by mp_strerror() */ +static const char *mp_err_string[] = { + "unknown result code", /* say what? */ + "boolean true", /* MP_OKAY, MP_YES */ + "boolean false", /* MP_NO */ + "out of memory", /* MP_MEM */ + "argument out of range", /* MP_RANGE */ + "invalid input parameter", /* MP_BADARG */ + "result is undefined" /* MP_UNDEF */ +}; + +/* Value to digit maps for radix conversion */ + +/* s_dmap_1 - standard digits and letters */ +static const char *s_dmap_1 = + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; + +#if 0 +/* s_dmap_2 - base64 ordering for digits */ +static const char *s_dmap_2 = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +#endif + +/* }}} */ + +/* {{{ Static function declarations */ + +/* + If MP_MACRO is false, these will be defined as actual functions; + otherwise, suitable macro definitions will be used. This works + around the fact that ANSI C89 doesn't support an 'inline' keyword + (although I hear C9x will ... about bloody time). At present, the + macro definitions are identical to the function bodies, but they'll + expand in place, instead of generating a function call. + + I chose these particular functions to be made into macros because + some profiling showed they are called a lot on a typical workload, + and yet they are primarily housekeeping. + */ +#if MP_MACRO == 0 + void s_mp_setz(mp_digit *dp, mp_size count); /* zero digits */ + void s_mp_copy(mp_digit *sp, mp_digit *dp, mp_size count); /* copy */ + void *s_mp_alloc(size_t nb, size_t ni); /* general allocator */ + void s_mp_free(void *ptr); /* general free function */ +#else + + /* Even if these are defined as macros, we need to respect the settings + of the MP_MEMSET and MP_MEMCPY configuration options... + */ + #if MP_MEMSET == 0 + #define s_mp_setz(dp, count) \ + {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=0;} + #else + #define s_mp_setz(dp, count) memset(dp, 0, (count) * sizeof(mp_digit)) + #endif /* MP_MEMSET */ + + #if MP_MEMCPY == 0 + #define s_mp_copy(sp, dp, count) \ + {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=(sp)[ix];} + #else + #define s_mp_copy(sp, dp, count) memcpy(dp, sp, (count) * sizeof(mp_digit)) + #endif /* MP_MEMCPY */ + + #define s_mp_alloc(nb, ni) calloc(nb, ni) + #define s_mp_free(ptr) {if(ptr) free(ptr);} +#endif /* MP_MACRO */ + +mp_err s_mp_grow(mp_int *mp, mp_size min); /* increase allocated size */ +mp_err s_mp_pad(mp_int *mp, mp_size min); /* left pad with zeroes */ + +void s_mp_clamp(mp_int *mp); /* clip leading zeroes */ + +void s_mp_exch(mp_int *a, mp_int *b); /* swap a and b in place */ + +mp_err s_mp_lshd(mp_int *mp, mp_size p); /* left-shift by p digits */ +void s_mp_rshd(mp_int *mp, mp_size p); /* right-shift by p digits */ +void s_mp_div_2d(mp_int *mp, mp_digit d); /* divide by 2^d in place */ +void s_mp_mod_2d(mp_int *mp, mp_digit d); /* modulo 2^d in place */ +mp_err s_mp_mul_2d(mp_int *mp, mp_digit d); /* multiply by 2^d in place*/ +void s_mp_div_2(mp_int *mp); /* divide by 2 in place */ +mp_err s_mp_mul_2(mp_int *mp); /* multiply by 2 in place */ +mp_digit s_mp_norm(mp_int *a, mp_int *b); /* normalize for division */ +mp_err s_mp_add_d(mp_int *mp, mp_digit d); /* unsigned digit addition */ +mp_err s_mp_sub_d(mp_int *mp, mp_digit d); /* unsigned digit subtract */ +mp_err s_mp_mul_d(mp_int *mp, mp_digit d); /* unsigned digit multiply */ +mp_err s_mp_div_d(mp_int *mp, mp_digit d, mp_digit *r); + /* unsigned digit divide */ +mp_err s_mp_reduce(mp_int *x, mp_int *m, mp_int *mu); + /* Barrett reduction */ +mp_err s_mp_add(mp_int *a, mp_int *b); /* magnitude addition */ +mp_err s_mp_sub(mp_int *a, mp_int *b); /* magnitude subtract */ +mp_err s_mp_mul(mp_int *a, mp_int *b); /* magnitude multiply */ +#if 0 +void s_mp_kmul(mp_digit *a, mp_digit *b, mp_digit *out, mp_size len); + /* multiply buffers in place */ +#endif +#if MP_SQUARE +mp_err s_mp_sqr(mp_int *a); /* magnitude square */ +#else +#define s_mp_sqr(a) s_mp_mul(a, a) +#endif +mp_err s_mp_div(mp_int *a, mp_int *b); /* magnitude divide */ +mp_err s_mp_2expt(mp_int *a, mp_digit k); /* a = 2^k */ +int s_mp_cmp(mp_int *a, mp_int *b); /* magnitude comparison */ +int s_mp_cmp_d(mp_int *a, mp_digit d); /* magnitude digit compare */ +int s_mp_ispow2(mp_int *v); /* is v a power of 2? */ +int s_mp_ispow2d(mp_digit d); /* is d a power of 2? */ + +int s_mp_tovalue(char ch, int r); /* convert ch to value */ +char s_mp_todigit(int val, int r, int low); /* convert val to digit */ +int s_mp_outlen(int bits, int r); /* output length in bytes */ + +/* }}} */ + +/* {{{ Default precision manipulation */ + +unsigned int mp_get_prec(void) +{ + return s_mp_defprec; + +} /* end mp_get_prec() */ + +void mp_set_prec(unsigned int prec) +{ + if(prec == 0) + s_mp_defprec = MP_DEFPREC; + else + s_mp_defprec = prec; + +} /* end mp_set_prec() */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ mp_init(mp) */ + +/* + mp_init(mp) + + Initialize a new zero-valued mp_int. Returns MP_OKAY if successful, + MP_MEM if memory could not be allocated for the structure. + */ + +mp_err mp_init(mp_int *mp) +{ + return mp_init_size(mp, s_mp_defprec); + +} /* end mp_init() */ + +/* }}} */ + +/* {{{ mp_init_array(mp[], count) */ + +mp_err mp_init_array(mp_int mp[], int count) +{ + mp_err res; + int pos; + + ARGCHK(mp !=NULL && count > 0, MP_BADARG); + + for(pos = 0; pos < count; ++pos) { + if((res = mp_init(&mp[pos])) != MP_OKAY) + goto CLEANUP; + } + + return MP_OKAY; + + CLEANUP: + while(--pos >= 0) + mp_clear(&mp[pos]); + + return res; + +} /* end mp_init_array() */ + +/* }}} */ + +/* {{{ mp_init_size(mp, prec) */ + +/* + mp_init_size(mp, prec) + + Initialize a new zero-valued mp_int with at least the given + precision; returns MP_OKAY if successful, or MP_MEM if memory could + not be allocated for the structure. + */ + +mp_err mp_init_size(mp_int *mp, mp_size prec) +{ + ARGCHK(mp != NULL && prec > 0, MP_BADARG); + + if((DIGITS(mp) = s_mp_alloc(prec, sizeof(mp_digit))) == NULL) + return MP_MEM; + + SIGN(mp) = MP_ZPOS; + USED(mp) = 1; + ALLOC(mp) = prec; + + return MP_OKAY; + +} /* end mp_init_size() */ + +/* }}} */ + +/* {{{ mp_init_copy(mp, from) */ + +/* + mp_init_copy(mp, from) + + Initialize mp as an exact copy of from. Returns MP_OKAY if + successful, MP_MEM if memory could not be allocated for the new + structure. + */ + +mp_err mp_init_copy(mp_int *mp, mp_int *from) +{ + ARGCHK(mp != NULL && from != NULL, MP_BADARG); + + if(mp == from) + return MP_OKAY; + + if((DIGITS(mp) = s_mp_alloc(USED(from), sizeof(mp_digit))) == NULL) + return MP_MEM; + + s_mp_copy(DIGITS(from), DIGITS(mp), USED(from)); + USED(mp) = USED(from); + ALLOC(mp) = USED(from); + SIGN(mp) = SIGN(from); + + return MP_OKAY; + +} /* end mp_init_copy() */ + +/* }}} */ + +/* {{{ mp_copy(from, to) */ + +/* + mp_copy(from, to) + + Copies the mp_int 'from' to the mp_int 'to'. It is presumed that + 'to' has already been initialized (if not, use mp_init_copy() + instead). If 'from' and 'to' are identical, nothing happens. + */ + +mp_err mp_copy(mp_int *from, mp_int *to) +{ + ARGCHK(from != NULL && to != NULL, MP_BADARG); + + if(from == to) + return MP_OKAY; + + { /* copy */ + mp_digit *tmp; + + /* + If the allocated buffer in 'to' already has enough space to hold + all the used digits of 'from', we'll re-use it to avoid hitting + the memory allocater more than necessary; otherwise, we'd have + to grow anyway, so we just allocate a hunk and make the copy as + usual + */ + if(ALLOC(to) >= USED(from)) { + s_mp_setz(DIGITS(to) + USED(from), ALLOC(to) - USED(from)); + s_mp_copy(DIGITS(from), DIGITS(to), USED(from)); + + } else { + if((tmp = s_mp_alloc(USED(from), sizeof(mp_digit))) == NULL) + return MP_MEM; + + s_mp_copy(DIGITS(from), tmp, USED(from)); + + if(DIGITS(to) != NULL) { +#if MP_CRYPTO + s_mp_setz(DIGITS(to), ALLOC(to)); +#endif + s_mp_free(DIGITS(to)); + } + + DIGITS(to) = tmp; + ALLOC(to) = USED(from); + } + + /* Copy the precision and sign from the original */ + USED(to) = USED(from); + SIGN(to) = SIGN(from); + } /* end copy */ + + return MP_OKAY; + +} /* end mp_copy() */ + +/* }}} */ + +/* {{{ mp_exch(mp1, mp2) */ + +/* + mp_exch(mp1, mp2) + + Exchange mp1 and mp2 without allocating any intermediate memory + (well, unless you count the stack space needed for this call and the + locals it creates...). This cannot fail. + */ + +void mp_exch(mp_int *mp1, mp_int *mp2) +{ +#if MP_ARGCHK == 2 + assert(mp1 != NULL && mp2 != NULL); +#else + if(mp1 == NULL || mp2 == NULL) + return; +#endif + + s_mp_exch(mp1, mp2); + +} /* end mp_exch() */ + +/* }}} */ + +/* {{{ mp_clear(mp) */ + +/* + mp_clear(mp) + + Release the storage used by an mp_int, and void its fields so that + if someone calls mp_clear() again for the same int later, we won't + get tollchocked. + */ + +void mp_clear(mp_int *mp) +{ + if(mp == NULL) + return; + + if(DIGITS(mp) != NULL) { +#if MP_CRYPTO + s_mp_setz(DIGITS(mp), ALLOC(mp)); +#endif + s_mp_free(DIGITS(mp)); + DIGITS(mp) = NULL; + } + + USED(mp) = 0; + ALLOC(mp) = 0; + +} /* end mp_clear() */ + +/* }}} */ + +/* {{{ mp_clear_array(mp[], count) */ + +void mp_clear_array(mp_int mp[], int count) +{ + ARGCHK(mp != NULL && count > 0, MP_BADARG); + + while(--count >= 0) + mp_clear(&mp[count]); + +} /* end mp_clear_array() */ + +/* }}} */ + +/* {{{ mp_zero(mp) */ + +/* + mp_zero(mp) + + Set mp to zero. Does not change the allocated size of the structure, + and therefore cannot fail (except on a bad argument, which we ignore) + */ +void mp_zero(mp_int *mp) +{ + if(mp == NULL) + return; + + s_mp_setz(DIGITS(mp), ALLOC(mp)); + USED(mp) = 1; + SIGN(mp) = MP_ZPOS; + +} /* end mp_zero() */ + +/* }}} */ + +/* {{{ mp_set(mp, d) */ + +void mp_set(mp_int *mp, mp_digit d) +{ + if(mp == NULL) + return; + + mp_zero(mp); + DIGIT(mp, 0) = d; + +} /* end mp_set() */ + +/* }}} */ + +/* {{{ mp_set_int(mp, z) */ + +mp_err mp_set_int(mp_int *mp, long z) +{ + int ix; + unsigned long v = abs(z); + mp_err res; + + ARGCHK(mp != NULL, MP_BADARG); + + mp_zero(mp); + if(z == 0) + return MP_OKAY; /* shortcut for zero */ + + for(ix = sizeof(long) - 1; ix >= 0; ix--) { + + if((res = s_mp_mul_2d(mp, CHAR_BIT)) != MP_OKAY) + return res; + + res = s_mp_add_d(mp, + (mp_digit)((v >> (ix * CHAR_BIT)) & UCHAR_MAX)); + if(res != MP_OKAY) + return res; + + } + + if(z < 0) + SIGN(mp) = MP_NEG; + + return MP_OKAY; + +} /* end mp_set_int() */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ Digit arithmetic */ + +/* {{{ mp_add_d(a, d, b) */ + +/* + mp_add_d(a, d, b) + + Compute the sum b = a + d, for a single digit d. Respects the sign of + its primary addend (single digits are unsigned anyway). + */ + +mp_err mp_add_d(mp_int *a, mp_digit d, mp_int *b) +{ + mp_err res = MP_OKAY; + + ARGCHK(a != NULL && b != NULL, MP_BADARG); + + if((res = mp_copy(a, b)) != MP_OKAY) + return res; + + if(SIGN(b) == MP_ZPOS) { + res = s_mp_add_d(b, d); + } else if(s_mp_cmp_d(b, d) >= 0) { + res = s_mp_sub_d(b, d); + } else { + SIGN(b) = MP_ZPOS; + + DIGIT(b, 0) = d - DIGIT(b, 0); + } + + return res; + +} /* end mp_add_d() */ + +/* }}} */ + +/* {{{ mp_sub_d(a, d, b) */ + +/* + mp_sub_d(a, d, b) + + Compute the difference b = a - d, for a single digit d. Respects the + sign of its subtrahend (single digits are unsigned anyway). + */ + +mp_err mp_sub_d(mp_int *a, mp_digit d, mp_int *b) +{ + mp_err res; + + ARGCHK(a != NULL && b != NULL, MP_BADARG); + + if((res = mp_copy(a, b)) != MP_OKAY) + return res; + + if(SIGN(b) == MP_NEG) { + if((res = s_mp_add_d(b, d)) != MP_OKAY) + return res; + + } else if(s_mp_cmp_d(b, d) >= 0) { + if((res = s_mp_sub_d(b, d)) != MP_OKAY) + return res; + + } else { + mp_neg(b, b); + + DIGIT(b, 0) = d - DIGIT(b, 0); + SIGN(b) = MP_NEG; + } + + if(s_mp_cmp_d(b, 0) == 0) + SIGN(b) = MP_ZPOS; + + return MP_OKAY; + +} /* end mp_sub_d() */ + +/* }}} */ + +/* {{{ mp_mul_d(a, d, b) */ + +/* + mp_mul_d(a, d, b) + + Compute the product b = a * d, for a single digit d. Respects the sign + of its multiplicand (single digits are unsigned anyway) + */ + +mp_err mp_mul_d(mp_int *a, mp_digit d, mp_int *b) +{ + mp_err res; + + ARGCHK(a != NULL && b != NULL, MP_BADARG); + + if(d == 0) { + mp_zero(b); + return MP_OKAY; + } + + if((res = mp_copy(a, b)) != MP_OKAY) + return res; + + res = s_mp_mul_d(b, d); + + return res; + +} /* end mp_mul_d() */ + +/* }}} */ + +/* {{{ mp_mul_2(a, c) */ + +mp_err mp_mul_2(mp_int *a, mp_int *c) +{ + mp_err res; + + ARGCHK(a != NULL && c != NULL, MP_BADARG); + + if((res = mp_copy(a, c)) != MP_OKAY) + return res; + + return s_mp_mul_2(c); + +} /* end mp_mul_2() */ + +/* }}} */ + +/* {{{ mp_div_d(a, d, q, r) */ + +/* + mp_div_d(a, d, q, r) + + Compute the quotient q = a / d and remainder r = a mod d, for a + single digit d. Respects the sign of its divisor (single digits are + unsigned anyway). + */ + +mp_err mp_div_d(mp_int *a, mp_digit d, mp_int *q, mp_digit *r) +{ + mp_err res; + mp_digit rem; + int pow; + + ARGCHK(a != NULL, MP_BADARG); + + if(d == 0) + return MP_RANGE; + + /* Shortcut for powers of two ... */ + if((pow = s_mp_ispow2d(d)) >= 0) { + mp_digit mask; + + mask = (1 << pow) - 1; + rem = DIGIT(a, 0) & mask; + + if(q) { + mp_copy(a, q); + s_mp_div_2d(q, pow); + } + + if(r) + *r = rem; + + return MP_OKAY; + } + + /* + If the quotient is actually going to be returned, we'll try to + avoid hitting the memory allocator by copying the dividend into it + and doing the division there. This can't be any _worse_ than + always copying, and will sometimes be better (since it won't make + another copy) + + If it's not going to be returned, we need to allocate a temporary + to hold the quotient, which will just be discarded. + */ + if(q) { + if((res = mp_copy(a, q)) != MP_OKAY) + return res; + + res = s_mp_div_d(q, d, &rem); + if(s_mp_cmp_d(q, 0) == MP_EQ) + SIGN(q) = MP_ZPOS; + + } else { + mp_int qp; + + if((res = mp_init_copy(&qp, a)) != MP_OKAY) + return res; + + res = s_mp_div_d(&qp, d, &rem); + if(s_mp_cmp_d(&qp, 0) == 0) + SIGN(&qp) = MP_ZPOS; + + mp_clear(&qp); + } + + if(r) + *r = rem; + + return res; + +} /* end mp_div_d() */ + +/* }}} */ + +/* {{{ mp_div_2(a, c) */ + +/* + mp_div_2(a, c) + + Compute c = a / 2, disregarding the remainder. + */ + +mp_err mp_div_2(mp_int *a, mp_int *c) +{ + mp_err res; + + ARGCHK(a != NULL && c != NULL, MP_BADARG); + + if((res = mp_copy(a, c)) != MP_OKAY) + return res; + + s_mp_div_2(c); + + return MP_OKAY; + +} /* end mp_div_2() */ + +/* }}} */ + +/* {{{ mp_expt_d(a, d, b) */ + +mp_err mp_expt_d(mp_int *a, mp_digit d, mp_int *c) +{ + mp_int s, x; + mp_err res; + + ARGCHK(a != NULL && c != NULL, MP_BADARG); + + if((res = mp_init(&s)) != MP_OKAY) + return res; + if((res = mp_init_copy(&x, a)) != MP_OKAY) + goto X; + + DIGIT(&s, 0) = 1; + + while(d != 0) { + if(d & 1) { + if((res = s_mp_mul(&s, &x)) != MP_OKAY) + goto CLEANUP; + } + + d >>= 1; + + if((res = s_mp_sqr(&x)) != MP_OKAY) + goto CLEANUP; + } + + s_mp_exch(&s, c); + +CLEANUP: + mp_clear(&x); +X: + mp_clear(&s); + + return res; + +} /* end mp_expt_d() */ + +/* }}} */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ Full arithmetic */ + +/* {{{ mp_abs(a, b) */ + +/* + mp_abs(a, b) + + Compute b = |a|. 'a' and 'b' may be identical. + */ + +mp_err mp_abs(mp_int *a, mp_int *b) +{ + mp_err res; + + ARGCHK(a != NULL && b != NULL, MP_BADARG); + + if((res = mp_copy(a, b)) != MP_OKAY) + return res; + + SIGN(b) = MP_ZPOS; + + return MP_OKAY; + +} /* end mp_abs() */ + +/* }}} */ + +/* {{{ mp_neg(a, b) */ + +/* + mp_neg(a, b) + + Compute b = -a. 'a' and 'b' may be identical. + */ + +mp_err mp_neg(mp_int *a, mp_int *b) +{ + mp_err res; + + ARGCHK(a != NULL && b != NULL, MP_BADARG); + + if((res = mp_copy(a, b)) != MP_OKAY) + return res; + + if(s_mp_cmp_d(b, 0) == MP_EQ) + SIGN(b) = MP_ZPOS; + else + SIGN(b) = (SIGN(b) == MP_NEG) ? MP_ZPOS : MP_NEG; + + return MP_OKAY; + +} /* end mp_neg() */ + +/* }}} */ + +/* {{{ mp_add(a, b, c) */ + +/* + mp_add(a, b, c) + + Compute c = a + b. All parameters may be identical. + */ + +mp_err mp_add(mp_int *a, mp_int *b, mp_int *c) +{ + mp_err res; + int cmp; + + ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); + + if(SIGN(a) == SIGN(b)) { /* same sign: add values, keep sign */ + + /* Commutativity of addition lets us do this in either order, + so we avoid having to use a temporary even if the result + is supposed to replace the output + */ + if(c == b) { + if((res = s_mp_add(c, a)) != MP_OKAY) + return res; + } else { + if(c != a && (res = mp_copy(a, c)) != MP_OKAY) + return res; + + if((res = s_mp_add(c, b)) != MP_OKAY) + return res; + } + + } else if((cmp = s_mp_cmp(a, b)) > 0) { /* different sign: a > b */ + + /* If the output is going to be clobbered, we will use a temporary + variable; otherwise, we'll do it without touching the memory + allocator at all, if possible + */ + if(c == b) { + mp_int tmp; + + if((res = mp_init_copy(&tmp, a)) != MP_OKAY) + return res; + if((res = s_mp_sub(&tmp, b)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + + s_mp_exch(&tmp, c); + mp_clear(&tmp); + + } else { + + if(c != a && (res = mp_copy(a, c)) != MP_OKAY) + return res; + if((res = s_mp_sub(c, b)) != MP_OKAY) + return res; + + } + + } else if(cmp == 0) { /* different sign, a == b */ + + mp_zero(c); + return MP_OKAY; + + } else { /* different sign: a < b */ + + /* See above... */ + if(c == a) { + mp_int tmp; + + if((res = mp_init_copy(&tmp, b)) != MP_OKAY) + return res; + if((res = s_mp_sub(&tmp, a)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + + s_mp_exch(&tmp, c); + mp_clear(&tmp); + + } else { + + if(c != b && (res = mp_copy(b, c)) != MP_OKAY) + return res; + if((res = s_mp_sub(c, a)) != MP_OKAY) + return res; + + } + } + + if(USED(c) == 1 && DIGIT(c, 0) == 0) + SIGN(c) = MP_ZPOS; + + return MP_OKAY; + +} /* end mp_add() */ + +/* }}} */ + +/* {{{ mp_sub(a, b, c) */ + +/* + mp_sub(a, b, c) + + Compute c = a - b. All parameters may be identical. + */ + +mp_err mp_sub(mp_int *a, mp_int *b, mp_int *c) +{ + mp_err res; + int cmp; + + ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); + + if(SIGN(a) != SIGN(b)) { + if(c == a) { + if((res = s_mp_add(c, b)) != MP_OKAY) + return res; + } else { + if(c != b && ((res = mp_copy(b, c)) != MP_OKAY)) + return res; + if((res = s_mp_add(c, a)) != MP_OKAY) + return res; + SIGN(c) = SIGN(a); + } + + } else if((cmp = s_mp_cmp(a, b)) > 0) { /* Same sign, a > b */ + if(c == b) { + mp_int tmp; + + if((res = mp_init_copy(&tmp, a)) != MP_OKAY) + return res; + if((res = s_mp_sub(&tmp, b)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + s_mp_exch(&tmp, c); + mp_clear(&tmp); + + } else { + if(c != a && ((res = mp_copy(a, c)) != MP_OKAY)) + return res; + + if((res = s_mp_sub(c, b)) != MP_OKAY) + return res; + } + + } else if(cmp == 0) { /* Same sign, equal magnitude */ + mp_zero(c); + return MP_OKAY; + + } else { /* Same sign, b > a */ + if(c == a) { + mp_int tmp; + + if((res = mp_init_copy(&tmp, b)) != MP_OKAY) + return res; + + if((res = s_mp_sub(&tmp, a)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + s_mp_exch(&tmp, c); + mp_clear(&tmp); + + } else { + if(c != b && ((res = mp_copy(b, c)) != MP_OKAY)) + return res; + + if((res = s_mp_sub(c, a)) != MP_OKAY) + return res; + } + + SIGN(c) = !SIGN(b); + } + + if(USED(c) == 1 && DIGIT(c, 0) == 0) + SIGN(c) = MP_ZPOS; + + return MP_OKAY; + +} /* end mp_sub() */ + +/* }}} */ + +/* {{{ mp_mul(a, b, c) */ + +/* + mp_mul(a, b, c) + + Compute c = a * b. All parameters may be identical. + */ + +mp_err mp_mul(mp_int *a, mp_int *b, mp_int *c) +{ + mp_err res; + mp_sign sgn; + + ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); + + sgn = (SIGN(a) == SIGN(b)) ? MP_ZPOS : MP_NEG; + + if(c == b) { + if((res = s_mp_mul(c, a)) != MP_OKAY) + return res; + + } else { + if((res = mp_copy(a, c)) != MP_OKAY) + return res; + + if((res = s_mp_mul(c, b)) != MP_OKAY) + return res; + } + + if(sgn == MP_ZPOS || s_mp_cmp_d(c, 0) == MP_EQ) + SIGN(c) = MP_ZPOS; + else + SIGN(c) = sgn; + + return MP_OKAY; + +} /* end mp_mul() */ + +/* }}} */ + +/* {{{ mp_mul_2d(a, d, c) */ + +/* + mp_mul_2d(a, d, c) + + Compute c = a * 2^d. a may be the same as c. + */ + +mp_err mp_mul_2d(mp_int *a, mp_digit d, mp_int *c) +{ + mp_err res; + + ARGCHK(a != NULL && c != NULL, MP_BADARG); + + if((res = mp_copy(a, c)) != MP_OKAY) + return res; + + if(d == 0) + return MP_OKAY; + + return s_mp_mul_2d(c, d); + +} /* end mp_mul() */ + +/* }}} */ + +/* {{{ mp_sqr(a, b) */ + +#if MP_SQUARE +mp_err mp_sqr(mp_int *a, mp_int *b) +{ + mp_err res; + + ARGCHK(a != NULL && b != NULL, MP_BADARG); + + if((res = mp_copy(a, b)) != MP_OKAY) + return res; + + if((res = s_mp_sqr(b)) != MP_OKAY) + return res; + + SIGN(b) = MP_ZPOS; + + return MP_OKAY; + +} /* end mp_sqr() */ +#endif + +/* }}} */ + +/* {{{ mp_div(a, b, q, r) */ + +/* + mp_div(a, b, q, r) + + Compute q = a / b and r = a mod b. Input parameters may be re-used + as output parameters. If q or r is NULL, that portion of the + computation will be discarded (although it will still be computed) + + Pay no attention to the hacker behind the curtain. + */ + +mp_err mp_div(mp_int *a, mp_int *b, mp_int *q, mp_int *r) +{ + mp_err res; + mp_int qtmp, rtmp; + int cmp; + + ARGCHK(a != NULL && b != NULL, MP_BADARG); + + if(mp_cmp_z(b) == MP_EQ) + return MP_RANGE; + + /* If a <= b, we can compute the solution without division, and + avoid any memory allocation + */ + if((cmp = s_mp_cmp(a, b)) < 0) { + if(r) { + if((res = mp_copy(a, r)) != MP_OKAY) + return res; + } + + if(q) + mp_zero(q); + + return MP_OKAY; + + } else if(cmp == 0) { + + /* Set quotient to 1, with appropriate sign */ + if(q) { + int qneg = (SIGN(a) != SIGN(b)); + + mp_set(q, 1); + if(qneg) + SIGN(q) = MP_NEG; + } + + if(r) + mp_zero(r); + + return MP_OKAY; + } + + /* If we get here, it means we actually have to do some division */ + + /* Set up some temporaries... */ + if((res = mp_init_copy(&qtmp, a)) != MP_OKAY) + return res; + if((res = mp_init_copy(&rtmp, b)) != MP_OKAY) + goto CLEANUP; + + if((res = s_mp_div(&qtmp, &rtmp)) != MP_OKAY) + goto CLEANUP; + + /* Compute the signs for the output */ + SIGN(&rtmp) = SIGN(a); /* Sr = Sa */ + if(SIGN(a) == SIGN(b)) + SIGN(&qtmp) = MP_ZPOS; /* Sq = MP_ZPOS if Sa = Sb */ + else + SIGN(&qtmp) = MP_NEG; /* Sq = MP_NEG if Sa != Sb */ + + if(s_mp_cmp_d(&qtmp, 0) == MP_EQ) + SIGN(&qtmp) = MP_ZPOS; + if(s_mp_cmp_d(&rtmp, 0) == MP_EQ) + SIGN(&rtmp) = MP_ZPOS; + + /* Copy output, if it is needed */ + if(q) + s_mp_exch(&qtmp, q); + + if(r) + s_mp_exch(&rtmp, r); + +CLEANUP: + mp_clear(&rtmp); + mp_clear(&qtmp); + + return res; + +} /* end mp_div() */ + +/* }}} */ + +/* {{{ mp_div_2d(a, d, q, r) */ + +mp_err mp_div_2d(mp_int *a, mp_digit d, mp_int *q, mp_int *r) +{ + mp_err res; + + ARGCHK(a != NULL, MP_BADARG); + + if(q) { + if((res = mp_copy(a, q)) != MP_OKAY) + return res; + + s_mp_div_2d(q, d); + } + + if(r) { + if((res = mp_copy(a, r)) != MP_OKAY) + return res; + + s_mp_mod_2d(r, d); + } + + return MP_OKAY; + +} /* end mp_div_2d() */ + +/* }}} */ + +/* {{{ mp_expt(a, b, c) */ + +/* + mp_expt(a, b, c) + + Compute c = a ** b, that is, raise a to the b power. Uses a + standard iterative square-and-multiply technique. + */ + +mp_err mp_expt(mp_int *a, mp_int *b, mp_int *c) +{ + mp_int s, x; + mp_err res; + mp_digit d; + int dig, bit; + + ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); + + if(mp_cmp_z(b) < 0) + return MP_RANGE; + + if((res = mp_init(&s)) != MP_OKAY) + return res; + + mp_set(&s, 1); + + if((res = mp_init_copy(&x, a)) != MP_OKAY) + goto X; + + /* Loop over low-order digits in ascending order */ + for(dig = 0; dig < (USED(b) - 1); dig++) { + d = DIGIT(b, dig); + + /* Loop over bits of each non-maximal digit */ + for(bit = 0; bit < DIGIT_BIT; bit++) { + if(d & 1) { + if((res = s_mp_mul(&s, &x)) != MP_OKAY) + goto CLEANUP; + } + + d >>= 1; + + if((res = s_mp_sqr(&x)) != MP_OKAY) + goto CLEANUP; + } + } + + /* Consider now the last digit... */ + d = DIGIT(b, dig); + + while(d) { + if(d & 1) { + if((res = s_mp_mul(&s, &x)) != MP_OKAY) + goto CLEANUP; + } + + d >>= 1; + + if((res = s_mp_sqr(&x)) != MP_OKAY) + goto CLEANUP; + } + + if(mp_iseven(b)) + SIGN(&s) = SIGN(a); + + res = mp_copy(&s, c); + +CLEANUP: + mp_clear(&x); +X: + mp_clear(&s); + + return res; + +} /* end mp_expt() */ + +/* }}} */ + +/* {{{ mp_2expt(a, k) */ + +/* Compute a = 2^k */ + +mp_err mp_2expt(mp_int *a, mp_digit k) +{ + ARGCHK(a != NULL, MP_BADARG); + + return s_mp_2expt(a, k); + +} /* end mp_2expt() */ + +/* }}} */ + +/* {{{ mp_mod(a, m, c) */ + +/* + mp_mod(a, m, c) + + Compute c = a (mod m). Result will always be 0 <= c < m. + */ + +mp_err mp_mod(mp_int *a, mp_int *m, mp_int *c) +{ + mp_err res; + int mag; + + ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG); + + if(SIGN(m) == MP_NEG) + return MP_RANGE; + + /* + If |a| > m, we need to divide to get the remainder and take the + absolute value. + + If |a| < m, we don't need to do any division, just copy and adjust + the sign (if a is negative). + + If |a| == m, we can simply set the result to zero. + + This order is intended to minimize the average path length of the + comparison chain on common workloads -- the most frequent cases are + that |a| != m, so we do those first. + */ + if((mag = s_mp_cmp(a, m)) > 0) { + if((res = mp_div(a, m, NULL, c)) != MP_OKAY) + return res; + + if(SIGN(c) == MP_NEG) { + if((res = mp_add(c, m, c)) != MP_OKAY) + return res; + } + + } else if(mag < 0) { + if((res = mp_copy(a, c)) != MP_OKAY) + return res; + + if(mp_cmp_z(a) < 0) { + if((res = mp_add(c, m, c)) != MP_OKAY) + return res; + + } + + } else { + mp_zero(c); + + } + + return MP_OKAY; + +} /* end mp_mod() */ + +/* }}} */ + +/* {{{ mp_mod_d(a, d, c) */ + +/* + mp_mod_d(a, d, c) + + Compute c = a (mod d). Result will always be 0 <= c < d + */ +mp_err mp_mod_d(mp_int *a, mp_digit d, mp_digit *c) +{ + mp_err res; + mp_digit rem; + + ARGCHK(a != NULL && c != NULL, MP_BADARG); + + if(s_mp_cmp_d(a, d) > 0) { + if((res = mp_div_d(a, d, NULL, &rem)) != MP_OKAY) + return res; + + } else { + if(SIGN(a) == MP_NEG) + rem = d - DIGIT(a, 0); + else + rem = DIGIT(a, 0); + } + + if(c) + *c = rem; + + return MP_OKAY; + +} /* end mp_mod_d() */ + +/* }}} */ + +/* {{{ mp_sqrt(a, b) */ + +/* + mp_sqrt(a, b) + + Compute the integer square root of a, and store the result in b. + Uses an integer-arithmetic version of Newton's iterative linear + approximation technique to determine this value; the result has the + following two properties: + + b^2 <= a + (b+1)^2 >= a + + It is a range error to pass a negative value. + */ +mp_err mp_sqrt(mp_int *a, mp_int *b) +{ + mp_int x, t; + mp_err res; + + ARGCHK(a != NULL && b != NULL, MP_BADARG); + + /* Cannot take square root of a negative value */ + if(SIGN(a) == MP_NEG) + return MP_RANGE; + + /* Special cases for zero and one, trivial */ + if(mp_cmp_d(a, 0) == MP_EQ || mp_cmp_d(a, 1) == MP_EQ) + return mp_copy(a, b); + + /* Initialize the temporaries we'll use below */ + if((res = mp_init_size(&t, USED(a))) != MP_OKAY) + return res; + + /* Compute an initial guess for the iteration as a itself */ + if((res = mp_init_copy(&x, a)) != MP_OKAY) + goto X; + +s_mp_rshd(&x, (USED(&x)/2)+1); +mp_add_d(&x, 1, &x); + + for(;;) { + /* t = (x * x) - a */ + mp_copy(&x, &t); /* can't fail, t is big enough for original x */ + if((res = mp_sqr(&t, &t)) != MP_OKAY || + (res = mp_sub(&t, a, &t)) != MP_OKAY) + goto CLEANUP; + + /* t = t / 2x */ + s_mp_mul_2(&x); + if((res = mp_div(&t, &x, &t, NULL)) != MP_OKAY) + goto CLEANUP; + s_mp_div_2(&x); + + /* Terminate the loop, if the quotient is zero */ + if(mp_cmp_z(&t) == MP_EQ) + break; + + /* x = x - t */ + if((res = mp_sub(&x, &t, &x)) != MP_OKAY) + goto CLEANUP; + + } + + /* Copy result to output parameter */ + mp_sub_d(&x, 1, &x); + s_mp_exch(&x, b); + + CLEANUP: + mp_clear(&x); + X: + mp_clear(&t); + + return res; + +} /* end mp_sqrt() */ + +/* }}} */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ Modular arithmetic */ + +#if MP_MODARITH +/* {{{ mp_addmod(a, b, m, c) */ + +/* + mp_addmod(a, b, m, c) + + Compute c = (a + b) mod m + */ + +mp_err mp_addmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c) +{ + mp_err res; + + ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG); + + if((res = mp_add(a, b, c)) != MP_OKAY) + return res; + if((res = mp_mod(c, m, c)) != MP_OKAY) + return res; + + return MP_OKAY; + +} + +/* }}} */ + +/* {{{ mp_submod(a, b, m, c) */ + +/* + mp_submod(a, b, m, c) + + Compute c = (a - b) mod m + */ + +mp_err mp_submod(mp_int *a, mp_int *b, mp_int *m, mp_int *c) +{ + mp_err res; + + ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG); + + if((res = mp_sub(a, b, c)) != MP_OKAY) + return res; + if((res = mp_mod(c, m, c)) != MP_OKAY) + return res; + + return MP_OKAY; + +} + +/* }}} */ + +/* {{{ mp_mulmod(a, b, m, c) */ + +/* + mp_mulmod(a, b, m, c) + + Compute c = (a * b) mod m + */ + +mp_err mp_mulmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c) +{ + mp_err res; + + ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG); + + if((res = mp_mul(a, b, c)) != MP_OKAY) + return res; + if((res = mp_mod(c, m, c)) != MP_OKAY) + return res; + + return MP_OKAY; + +} + +/* }}} */ + +/* {{{ mp_sqrmod(a, m, c) */ + +#if MP_SQUARE +mp_err mp_sqrmod(mp_int *a, mp_int *m, mp_int *c) +{ + mp_err res; + + ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG); + + if((res = mp_sqr(a, c)) != MP_OKAY) + return res; + if((res = mp_mod(c, m, c)) != MP_OKAY) + return res; + + return MP_OKAY; + +} /* end mp_sqrmod() */ +#endif + +/* }}} */ + +/* {{{ mp_exptmod(a, b, m, c) */ + +/* + mp_exptmod(a, b, m, c) + + Compute c = (a ** b) mod m. Uses a standard square-and-multiply + method with modular reductions at each step. (This is basically the + same code as mp_expt(), except for the addition of the reductions) + + The modular reductions are done using Barrett's algorithm (see + s_mp_reduce() below for details) + */ + +mp_err mp_exptmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c) +{ + mp_int s, x, mu; + mp_err res; + mp_digit d, *db = DIGITS(b); + mp_size ub = USED(b); + int dig, bit; + + ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); + + if(mp_cmp_z(b) < 0 || mp_cmp_z(m) <= 0) + return MP_RANGE; + + if((res = mp_init(&s)) != MP_OKAY) + return res; + if((res = mp_init_copy(&x, a)) != MP_OKAY) + goto X; + if((res = mp_mod(&x, m, &x)) != MP_OKAY || + (res = mp_init(&mu)) != MP_OKAY) + goto MU; + + mp_set(&s, 1); + + /* mu = b^2k / m */ + s_mp_add_d(&mu, 1); + s_mp_lshd(&mu, 2 * USED(m)); + if((res = mp_div(&mu, m, &mu, NULL)) != MP_OKAY) + goto CLEANUP; + + /* Loop over digits of b in ascending order, except highest order */ + for(dig = 0; dig < (ub - 1); dig++) { + d = *db++; + + /* Loop over the bits of the lower-order digits */ + for(bit = 0; bit < DIGIT_BIT; bit++) { + if(d & 1) { + if((res = s_mp_mul(&s, &x)) != MP_OKAY) + goto CLEANUP; + if((res = s_mp_reduce(&s, m, &mu)) != MP_OKAY) + goto CLEANUP; + } + + d >>= 1; + + if((res = s_mp_sqr(&x)) != MP_OKAY) + goto CLEANUP; + if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY) + goto CLEANUP; + } + } + + /* Now do the last digit... */ + d = *db; + + while(d) { + if(d & 1) { + if((res = s_mp_mul(&s, &x)) != MP_OKAY) + goto CLEANUP; + if((res = s_mp_reduce(&s, m, &mu)) != MP_OKAY) + goto CLEANUP; + } + + d >>= 1; + + if((res = s_mp_sqr(&x)) != MP_OKAY) + goto CLEANUP; + if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY) + goto CLEANUP; + } + + s_mp_exch(&s, c); + + CLEANUP: + mp_clear(&mu); + MU: + mp_clear(&x); + X: + mp_clear(&s); + + return res; + +} /* end mp_exptmod() */ + +/* }}} */ + +/* {{{ mp_exptmod_d(a, d, m, c) */ + +mp_err mp_exptmod_d(mp_int *a, mp_digit d, mp_int *m, mp_int *c) +{ + mp_int s, x; + mp_err res; + + ARGCHK(a != NULL && c != NULL, MP_BADARG); + + if((res = mp_init(&s)) != MP_OKAY) + return res; + if((res = mp_init_copy(&x, a)) != MP_OKAY) + goto X; + + mp_set(&s, 1); + + while(d != 0) { + if(d & 1) { + if((res = s_mp_mul(&s, &x)) != MP_OKAY || + (res = mp_mod(&s, m, &s)) != MP_OKAY) + goto CLEANUP; + } + + d /= 2; + + if((res = s_mp_sqr(&x)) != MP_OKAY || + (res = mp_mod(&x, m, &x)) != MP_OKAY) + goto CLEANUP; + } + + s_mp_exch(&s, c); + +CLEANUP: + mp_clear(&x); +X: + mp_clear(&s); + + return res; + +} /* end mp_exptmod_d() */ + +/* }}} */ +#endif /* if MP_MODARITH */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ Comparison functions */ + +/* {{{ mp_cmp_z(a) */ + +/* + mp_cmp_z(a) + + Compare a <=> 0. Returns <0 if a<0, 0 if a=0, >0 if a>0. + */ + +int mp_cmp_z(mp_int *a) +{ + if(SIGN(a) == MP_NEG) + return MP_LT; + else if(USED(a) == 1 && DIGIT(a, 0) == 0) + return MP_EQ; + else + return MP_GT; + +} /* end mp_cmp_z() */ + +/* }}} */ + +/* {{{ mp_cmp_d(a, d) */ + +/* + mp_cmp_d(a, d) + + Compare a <=> d. Returns <0 if a<d, 0 if a=d, >0 if a>d + */ + +int mp_cmp_d(mp_int *a, mp_digit d) +{ + ARGCHK(a != NULL, MP_EQ); + + if(SIGN(a) == MP_NEG) + return MP_LT; + + return s_mp_cmp_d(a, d); + +} /* end mp_cmp_d() */ + +/* }}} */ + +/* {{{ mp_cmp(a, b) */ + +int mp_cmp(mp_int *a, mp_int *b) +{ + ARGCHK(a != NULL && b != NULL, MP_EQ); + + if(SIGN(a) == SIGN(b)) { + int mag; + + if((mag = s_mp_cmp(a, b)) == MP_EQ) + return MP_EQ; + + if(SIGN(a) == MP_ZPOS) + return mag; + else + return -mag; + + } else if(SIGN(a) == MP_ZPOS) { + return MP_GT; + } else { + return MP_LT; + } + +} /* end mp_cmp() */ + +/* }}} */ + +/* {{{ mp_cmp_mag(a, b) */ + +/* + mp_cmp_mag(a, b) + + Compares |a| <=> |b|, and returns an appropriate comparison result + */ + +int mp_cmp_mag(mp_int *a, mp_int *b) +{ + ARGCHK(a != NULL && b != NULL, MP_EQ); + + return s_mp_cmp(a, b); + +} /* end mp_cmp_mag() */ + +/* }}} */ + +/* {{{ mp_cmp_int(a, z) */ + +/* + This just converts z to an mp_int, and uses the existing comparison + routines. This is sort of inefficient, but it's not clear to me how + frequently this wil get used anyway. For small positive constants, + you can always use mp_cmp_d(), and for zero, there is mp_cmp_z(). + */ +int mp_cmp_int(mp_int *a, long z) +{ + mp_int tmp; + int out; + + ARGCHK(a != NULL, MP_EQ); + + mp_init(&tmp); mp_set_int(&tmp, z); + out = mp_cmp(a, &tmp); + mp_clear(&tmp); + + return out; + +} /* end mp_cmp_int() */ + +/* }}} */ + +/* {{{ mp_isodd(a) */ + +/* + mp_isodd(a) + + Returns a true (non-zero) value if a is odd, false (zero) otherwise. + */ +int mp_isodd(mp_int *a) +{ + ARGCHK(a != NULL, 0); + + return (DIGIT(a, 0) & 1); + +} /* end mp_isodd() */ + +/* }}} */ + +/* {{{ mp_iseven(a) */ + +int mp_iseven(mp_int *a) +{ + return !mp_isodd(a); + +} /* end mp_iseven() */ + +/* }}} */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ Number theoretic functions */ + +#if MP_NUMTH +/* {{{ mp_gcd(a, b, c) */ + +/* + Like the old mp_gcd() function, except computes the GCD using the + binary algorithm due to Josef Stein in 1961 (via Knuth). + */ +mp_err mp_gcd(mp_int *a, mp_int *b, mp_int *c) +{ + mp_err res; + mp_int u, v, t; + mp_size k = 0; + + ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); + + if(mp_cmp_z(a) == MP_EQ && mp_cmp_z(b) == MP_EQ) + return MP_RANGE; + if(mp_cmp_z(a) == MP_EQ) { + return mp_copy(b, c); + } else if(mp_cmp_z(b) == MP_EQ) { + return mp_copy(a, c); + } + + if((res = mp_init(&t)) != MP_OKAY) + return res; + if((res = mp_init_copy(&u, a)) != MP_OKAY) + goto U; + if((res = mp_init_copy(&v, b)) != MP_OKAY) + goto V; + + SIGN(&u) = MP_ZPOS; + SIGN(&v) = MP_ZPOS; + + /* Divide out common factors of 2 until at least 1 of a, b is even */ + while(mp_iseven(&u) && mp_iseven(&v)) { + s_mp_div_2(&u); + s_mp_div_2(&v); + ++k; + } + + /* Initialize t */ + if(mp_isodd(&u)) { + if((res = mp_copy(&v, &t)) != MP_OKAY) + goto CLEANUP; + + /* t = -v */ + if(SIGN(&v) == MP_ZPOS) + SIGN(&t) = MP_NEG; + else + SIGN(&t) = MP_ZPOS; + + } else { + if((res = mp_copy(&u, &t)) != MP_OKAY) + goto CLEANUP; + + } + + for(;;) { + while(mp_iseven(&t)) { + s_mp_div_2(&t); + } + + if(mp_cmp_z(&t) == MP_GT) { + if((res = mp_copy(&t, &u)) != MP_OKAY) + goto CLEANUP; + + } else { + if((res = mp_copy(&t, &v)) != MP_OKAY) + goto CLEANUP; + + /* v = -t */ + if(SIGN(&t) == MP_ZPOS) + SIGN(&v) = MP_NEG; + else + SIGN(&v) = MP_ZPOS; + } + + if((res = mp_sub(&u, &v, &t)) != MP_OKAY) + goto CLEANUP; + + if(s_mp_cmp_d(&t, 0) == MP_EQ) + break; + } + + s_mp_2expt(&v, k); /* v = 2^k */ + res = mp_mul(&u, &v, c); /* c = u * v */ + + CLEANUP: + mp_clear(&v); + V: + mp_clear(&u); + U: + mp_clear(&t); + + return res; + +} /* end mp_bgcd() */ + +/* }}} */ + +/* {{{ mp_lcm(a, b, c) */ + +/* We compute the least common multiple using the rule: + + ab = [a, b](a, b) + + ... by computing the product, and dividing out the gcd. + */ + +mp_err mp_lcm(mp_int *a, mp_int *b, mp_int *c) +{ + mp_int gcd, prod; + mp_err res; + + ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); + + /* Set up temporaries */ + if((res = mp_init(&gcd)) != MP_OKAY) + return res; + if((res = mp_init(&prod)) != MP_OKAY) + goto GCD; + + if((res = mp_mul(a, b, &prod)) != MP_OKAY) + goto CLEANUP; + if((res = mp_gcd(a, b, &gcd)) != MP_OKAY) + goto CLEANUP; + + res = mp_div(&prod, &gcd, c, NULL); + + CLEANUP: + mp_clear(&prod); + GCD: + mp_clear(&gcd); + + return res; + +} /* end mp_lcm() */ + +/* }}} */ + +/* {{{ mp_xgcd(a, b, g, x, y) */ + +/* + mp_xgcd(a, b, g, x, y) + + Compute g = (a, b) and values x and y satisfying Bezout's identity + (that is, ax + by = g). This uses the extended binary GCD algorithm + based on the Stein algorithm used for mp_gcd() + */ + +mp_err mp_xgcd(mp_int *a, mp_int *b, mp_int *g, mp_int *x, mp_int *y) +{ + mp_int gx, xc, yc, u, v, A, B, C, D; + mp_int *clean[9]; + mp_err res; + int last = -1; + + if(mp_cmp_z(b) == 0) + return MP_RANGE; + + /* Initialize all these variables we need */ + if((res = mp_init(&u)) != MP_OKAY) goto CLEANUP; + clean[++last] = &u; + if((res = mp_init(&v)) != MP_OKAY) goto CLEANUP; + clean[++last] = &v; + if((res = mp_init(&gx)) != MP_OKAY) goto CLEANUP; + clean[++last] = &gx; + if((res = mp_init(&A)) != MP_OKAY) goto CLEANUP; + clean[++last] = &A; + if((res = mp_init(&B)) != MP_OKAY) goto CLEANUP; + clean[++last] = &B; + if((res = mp_init(&C)) != MP_OKAY) goto CLEANUP; + clean[++last] = &C; + if((res = mp_init(&D)) != MP_OKAY) goto CLEANUP; + clean[++last] = &D; + if((res = mp_init_copy(&xc, a)) != MP_OKAY) goto CLEANUP; + clean[++last] = &xc; + mp_abs(&xc, &xc); + if((res = mp_init_copy(&yc, b)) != MP_OKAY) goto CLEANUP; + clean[++last] = &yc; + mp_abs(&yc, &yc); + + mp_set(&gx, 1); + + /* Divide by two until at least one of them is even */ + while(mp_iseven(&xc) && mp_iseven(&yc)) { + s_mp_div_2(&xc); + s_mp_div_2(&yc); + if((res = s_mp_mul_2(&gx)) != MP_OKAY) + goto CLEANUP; + } + + mp_copy(&xc, &u); + mp_copy(&yc, &v); + mp_set(&A, 1); mp_set(&D, 1); + + /* Loop through binary GCD algorithm */ + for(;;) { + while(mp_iseven(&u)) { + s_mp_div_2(&u); + + if(mp_iseven(&A) && mp_iseven(&B)) { + s_mp_div_2(&A); s_mp_div_2(&B); + } else { + if((res = mp_add(&A, &yc, &A)) != MP_OKAY) goto CLEANUP; + s_mp_div_2(&A); + if((res = mp_sub(&B, &xc, &B)) != MP_OKAY) goto CLEANUP; + s_mp_div_2(&B); + } + } + + while(mp_iseven(&v)) { + s_mp_div_2(&v); + + if(mp_iseven(&C) && mp_iseven(&D)) { + s_mp_div_2(&C); s_mp_div_2(&D); + } else { + if((res = mp_add(&C, &yc, &C)) != MP_OKAY) goto CLEANUP; + s_mp_div_2(&C); + if((res = mp_sub(&D, &xc, &D)) != MP_OKAY) goto CLEANUP; + s_mp_div_2(&D); + } + } + + if(mp_cmp(&u, &v) >= 0) { + if((res = mp_sub(&u, &v, &u)) != MP_OKAY) goto CLEANUP; + if((res = mp_sub(&A, &C, &A)) != MP_OKAY) goto CLEANUP; + if((res = mp_sub(&B, &D, &B)) != MP_OKAY) goto CLEANUP; + + } else { + if((res = mp_sub(&v, &u, &v)) != MP_OKAY) goto CLEANUP; + if((res = mp_sub(&C, &A, &C)) != MP_OKAY) goto CLEANUP; + if((res = mp_sub(&D, &B, &D)) != MP_OKAY) goto CLEANUP; + + } + + /* If we're done, copy results to output */ + if(mp_cmp_z(&u) == 0) { + if(x) + if((res = mp_copy(&C, x)) != MP_OKAY) goto CLEANUP; + + if(y) + if((res = mp_copy(&D, y)) != MP_OKAY) goto CLEANUP; + + if(g) + if((res = mp_mul(&gx, &v, g)) != MP_OKAY) goto CLEANUP; + + break; + } + } + + CLEANUP: + while(last >= 0) + mp_clear(clean[last--]); + + return res; + +} /* end mp_xgcd() */ + +/* }}} */ + +/* {{{ mp_invmod(a, m, c) */ + +/* + mp_invmod(a, m, c) + + Compute c = a^-1 (mod m), if there is an inverse for a (mod m). + This is equivalent to the question of whether (a, m) = 1. If not, + MP_UNDEF is returned, and there is no inverse. + */ + +mp_err mp_invmod(mp_int *a, mp_int *m, mp_int *c) +{ + mp_int g, x; + mp_err res; + + ARGCHK(a && m && c, MP_BADARG); + + if(mp_cmp_z(a) == 0 || mp_cmp_z(m) == 0) + return MP_RANGE; + + if((res = mp_init(&g)) != MP_OKAY) + return res; + if((res = mp_init(&x)) != MP_OKAY) + goto X; + + if((res = mp_xgcd(a, m, &g, &x, NULL)) != MP_OKAY) + goto CLEANUP; + + if(mp_cmp_d(&g, 1) != MP_EQ) { + res = MP_UNDEF; + goto CLEANUP; + } + + res = mp_mod(&x, m, c); + SIGN(c) = SIGN(a); + +CLEANUP: + mp_clear(&x); +X: + mp_clear(&g); + + return res; + +} /* end mp_invmod() */ + +/* }}} */ +#endif /* if MP_NUMTH */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ mp_print(mp, ofp) */ + +#if MP_IOFUNC +/* + mp_print(mp, ofp) + + Print a textual representation of the given mp_int on the output + stream 'ofp'. Output is generated using the internal radix. + */ + +void mp_print(mp_int *mp, FILE *ofp) +{ + int ix; + + if(mp == NULL || ofp == NULL) + return; + + fputc((SIGN(mp) == MP_NEG) ? '-' : '+', ofp); + + for(ix = USED(mp) - 1; ix >= 0; ix--) { + fprintf(ofp, DIGIT_FMT, DIGIT(mp, ix)); + } + +} /* end mp_print() */ + +#endif /* if MP_IOFUNC */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ More I/O Functions */ + +/* {{{ mp_read_signed_bin(mp, str, len) */ + +/* + mp_read_signed_bin(mp, str, len) + + Read in a raw value (base 256) into the given mp_int + */ + +mp_err mp_read_signed_bin(mp_int *mp, unsigned char *str, int len) +{ + mp_err res; + + ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG); + + if((res = mp_read_unsigned_bin(mp, str + 1, len - 1)) == MP_OKAY) { + /* Get sign from first byte */ + if(str[0]) + SIGN(mp) = MP_NEG; + else + SIGN(mp) = MP_ZPOS; + } + + return res; + +} /* end mp_read_signed_bin() */ + +/* }}} */ + +/* {{{ mp_signed_bin_size(mp) */ + +int mp_signed_bin_size(mp_int *mp) +{ + ARGCHK(mp != NULL, 0); + + return mp_unsigned_bin_size(mp) + 1; + +} /* end mp_signed_bin_size() */ + +/* }}} */ + +/* {{{ mp_to_signed_bin(mp, str) */ + +mp_err mp_to_signed_bin(mp_int *mp, unsigned char *str) +{ + ARGCHK(mp != NULL && str != NULL, MP_BADARG); + + /* Caller responsible for allocating enough memory (use mp_raw_size(mp)) */ + str[0] = (char)SIGN(mp); + + return mp_to_unsigned_bin(mp, str + 1); + +} /* end mp_to_signed_bin() */ + +/* }}} */ + +/* {{{ mp_read_unsigned_bin(mp, str, len) */ + +/* + mp_read_unsigned_bin(mp, str, len) + + Read in an unsigned value (base 256) into the given mp_int + */ + +mp_err mp_read_unsigned_bin(mp_int *mp, unsigned char *str, int len) +{ + int ix; + mp_err res; + + ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG); + + mp_zero(mp); + + for(ix = 0; ix < len; ix++) { + if((res = s_mp_mul_2d(mp, CHAR_BIT)) != MP_OKAY) + return res; + + if((res = mp_add_d(mp, str[ix], mp)) != MP_OKAY) + return res; + } + + return MP_OKAY; + +} /* end mp_read_unsigned_bin() */ + +/* }}} */ + +/* {{{ mp_unsigned_bin_size(mp) */ + +int mp_unsigned_bin_size(mp_int *mp) +{ + mp_digit topdig; + int count; + + ARGCHK(mp != NULL, 0); + + /* Special case for the value zero */ + if(USED(mp) == 1 && DIGIT(mp, 0) == 0) + return 1; + + count = (USED(mp) - 1) * sizeof(mp_digit); + topdig = DIGIT(mp, USED(mp) - 1); + + while(topdig != 0) { + ++count; + topdig >>= CHAR_BIT; + } + + return count; + +} /* end mp_unsigned_bin_size() */ + +/* }}} */ + +/* {{{ mp_to_unsigned_bin(mp, str) */ + +mp_err mp_to_unsigned_bin(mp_int *mp, unsigned char *str) +{ + mp_digit *dp, *end, d; + unsigned char *spos; + + ARGCHK(mp != NULL && str != NULL, MP_BADARG); + + dp = DIGITS(mp); + end = dp + USED(mp) - 1; + spos = str; + + /* Special case for zero, quick test */ + if(dp == end && *dp == 0) { + *str = '\0'; + return MP_OKAY; + } + + /* Generate digits in reverse order */ + while(dp < end) { + int ix; + + d = *dp; + for(ix = 0; ix < sizeof(mp_digit); ++ix) { + *spos = d & UCHAR_MAX; + d >>= CHAR_BIT; + ++spos; + } + + ++dp; + } + + /* Now handle last digit specially, high order zeroes are not written */ + d = *end; + while(d != 0) { + *spos = d & UCHAR_MAX; + d >>= CHAR_BIT; + ++spos; + } + + /* Reverse everything to get digits in the correct order */ + while(--spos > str) { + unsigned char t = *str; + *str = *spos; + *spos = t; + + ++str; + } + + return MP_OKAY; + +} /* end mp_to_unsigned_bin() */ + +/* }}} */ + +/* {{{ mp_count_bits(mp) */ + +int mp_count_bits(mp_int *mp) +{ + int len; + mp_digit d; + + ARGCHK(mp != NULL, MP_BADARG); + + len = DIGIT_BIT * (USED(mp) - 1); + d = DIGIT(mp, USED(mp) - 1); + + while(d != 0) { + ++len; + d >>= 1; + } + + return len; + +} /* end mp_count_bits() */ + +/* }}} */ + +/* {{{ mp_read_radix(mp, str, radix) */ + +/* + mp_read_radix(mp, str, radix) + + Read an integer from the given string, and set mp to the resulting + value. The input is presumed to be in base 10. Leading non-digit + characters are ignored, and the function reads until a non-digit + character or the end of the string. + */ + +mp_err mp_read_radix(mp_int *mp, unsigned char *str, int radix) +{ + int ix = 0, val = 0; + mp_err res; + mp_sign sig = MP_ZPOS; + + ARGCHK(mp != NULL && str != NULL && radix >= 2 && radix <= MAX_RADIX, + MP_BADARG); + + mp_zero(mp); + + /* Skip leading non-digit characters until a digit or '-' or '+' */ + while(str[ix] && + (s_mp_tovalue(str[ix], radix) < 0) && + str[ix] != '-' && + str[ix] != '+') { + ++ix; + } + + if(str[ix] == '-') { + sig = MP_NEG; + ++ix; + } else if(str[ix] == '+') { + sig = MP_ZPOS; /* this is the default anyway... */ + ++ix; + } + + while((val = s_mp_tovalue(str[ix], radix)) >= 0) { + if((res = s_mp_mul_d(mp, radix)) != MP_OKAY) + return res; + if((res = s_mp_add_d(mp, val)) != MP_OKAY) + return res; + ++ix; + } + + if(s_mp_cmp_d(mp, 0) == MP_EQ) + SIGN(mp) = MP_ZPOS; + else + SIGN(mp) = sig; + + return MP_OKAY; + +} /* end mp_read_radix() */ + +/* }}} */ + +/* {{{ mp_radix_size(mp, radix) */ + +int mp_radix_size(mp_int *mp, int radix) +{ + int len; + ARGCHK(mp != NULL, 0); + + len = s_mp_outlen(mp_count_bits(mp), radix) + 1; /* for NUL terminator */ + + if(mp_cmp_z(mp) < 0) + ++len; /* for sign */ + + return len; + +} /* end mp_radix_size() */ + +/* }}} */ + +/* {{{ mp_value_radix_size(num, qty, radix) */ + +/* num = number of digits + qty = number of bits per digit + radix = target base + + Return the number of digits in the specified radix that would be + needed to express 'num' digits of 'qty' bits each. + */ +int mp_value_radix_size(int num, int qty, int radix) +{ + ARGCHK(num >= 0 && qty > 0 && radix >= 2 && radix <= MAX_RADIX, 0); + + return s_mp_outlen(num * qty, radix); + +} /* end mp_value_radix_size() */ + +/* }}} */ + +/* {{{ mp_toradix(mp, str, radix) */ + +mp_err mp_toradix(mp_int *mp, unsigned char *str, int radix) +{ + int ix, pos = 0; + + ARGCHK(mp != NULL && str != NULL, MP_BADARG); + ARGCHK(radix > 1 && radix <= MAX_RADIX, MP_RANGE); + + if(mp_cmp_z(mp) == MP_EQ) { + str[0] = '0'; + str[1] = '\0'; + } else { + mp_err res; + mp_int tmp; + mp_sign sgn; + mp_digit rem, rdx = (mp_digit)radix; + char ch; + + if((res = mp_init_copy(&tmp, mp)) != MP_OKAY) + return res; + + /* Save sign for later, and take absolute value */ + sgn = SIGN(&tmp); SIGN(&tmp) = MP_ZPOS; + + /* Generate output digits in reverse order */ + while(mp_cmp_z(&tmp) != 0) { + if((res = s_mp_div_d(&tmp, rdx, &rem)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + + /* Generate digits, use capital letters */ + ch = s_mp_todigit(rem, radix, 0); + + str[pos++] = ch; + } + + /* Add - sign if original value was negative */ + if(sgn == MP_NEG) + str[pos++] = '-'; + + /* Add trailing NUL to end the string */ + str[pos--] = '\0'; + + /* Reverse the digits and sign indicator */ + ix = 0; + while(ix < pos) { + char tmp = str[ix]; + + str[ix] = str[pos]; + str[pos] = tmp; + ++ix; + --pos; + } + + mp_clear(&tmp); + } + + return MP_OKAY; + +} /* end mp_toradix() */ + +/* }}} */ + +/* {{{ mp_char2value(ch, r) */ + +int mp_char2value(char ch, int r) +{ + return s_mp_tovalue(ch, r); + +} /* end mp_tovalue() */ + +/* }}} */ + +/* }}} */ + +/* {{{ mp_strerror(ec) */ + +/* + mp_strerror(ec) + + Return a string describing the meaning of error code 'ec'. The + string returned is allocated in static memory, so the caller should + not attempt to modify or free the memory associated with this + string. + */ +const char *mp_strerror(mp_err ec) +{ + int aec = (ec < 0) ? -ec : ec; + + /* Code values are negative, so the senses of these comparisons + are accurate */ + if(ec < MP_LAST_CODE || ec > MP_OKAY) { + return mp_err_string[0]; /* unknown error code */ + } else { + return mp_err_string[aec + 1]; + } + +} /* end mp_strerror() */ + +/* }}} */ + +/*========================================================================*/ +/*------------------------------------------------------------------------*/ +/* Static function definitions (internal use only) */ + +/* {{{ Memory management */ + +/* {{{ s_mp_grow(mp, min) */ + +/* Make sure there are at least 'min' digits allocated to mp */ +mp_err s_mp_grow(mp_int *mp, mp_size min) +{ + if(min > ALLOC(mp)) { + mp_digit *tmp; + + /* Set min to next nearest default precision block size */ + min = ((min + (s_mp_defprec - 1)) / s_mp_defprec) * s_mp_defprec; + + if((tmp = s_mp_alloc(min, sizeof(mp_digit))) == NULL) + return MP_MEM; + + s_mp_copy(DIGITS(mp), tmp, USED(mp)); + +#if MP_CRYPTO + s_mp_setz(DIGITS(mp), ALLOC(mp)); +#endif + s_mp_free(DIGITS(mp)); + DIGITS(mp) = tmp; + ALLOC(mp) = min; + } + + return MP_OKAY; + +} /* end s_mp_grow() */ + +/* }}} */ + +/* {{{ s_mp_pad(mp, min) */ + +/* Make sure the used size of mp is at least 'min', growing if needed */ +mp_err s_mp_pad(mp_int *mp, mp_size min) +{ + if(min > USED(mp)) { + mp_err res; + + /* Make sure there is room to increase precision */ + if(min > ALLOC(mp) && (res = s_mp_grow(mp, min)) != MP_OKAY) + return res; + + /* Increase precision; should already be 0-filled */ + USED(mp) = min; + } + + return MP_OKAY; + +} /* end s_mp_pad() */ + +/* }}} */ + +/* {{{ s_mp_setz(dp, count) */ + +#if MP_MACRO == 0 +/* Set 'count' digits pointed to by dp to be zeroes */ +void s_mp_setz(mp_digit *dp, mp_size count) +{ +#if MP_MEMSET == 0 + int ix; + + for(ix = 0; ix < count; ix++) + dp[ix] = 0; +#else + memset(dp, 0, count * sizeof(mp_digit)); +#endif + +} /* end s_mp_setz() */ +#endif + +/* }}} */ + +/* {{{ s_mp_copy(sp, dp, count) */ + +#if MP_MACRO == 0 +/* Copy 'count' digits from sp to dp */ +void s_mp_copy(mp_digit *sp, mp_digit *dp, mp_size count) +{ +#if MP_MEMCPY == 0 + int ix; + + for(ix = 0; ix < count; ix++) + dp[ix] = sp[ix]; +#else + memcpy(dp, sp, count * sizeof(mp_digit)); +#endif + +} /* end s_mp_copy() */ +#endif + +/* }}} */ + +/* {{{ s_mp_alloc(nb, ni) */ + +#if MP_MACRO == 0 +/* Allocate ni records of nb bytes each, and return a pointer to that */ +void *s_mp_alloc(size_t nb, size_t ni) +{ + return calloc(nb, ni); + +} /* end s_mp_alloc() */ +#endif + +/* }}} */ + +/* {{{ s_mp_free(ptr) */ + +#if MP_MACRO == 0 +/* Free the memory pointed to by ptr */ +void s_mp_free(void *ptr) +{ + if(ptr) + free(ptr); + +} /* end s_mp_free() */ +#endif + +/* }}} */ + +/* {{{ s_mp_clamp(mp) */ + +/* Remove leading zeroes from the given value */ +void s_mp_clamp(mp_int *mp) +{ + mp_size du = USED(mp); + mp_digit *zp = DIGITS(mp) + du - 1; + + while(du > 1 && !*zp--) + --du; + + USED(mp) = du; + +} /* end s_mp_clamp() */ + + +/* }}} */ + +/* {{{ s_mp_exch(a, b) */ + +/* Exchange the data for a and b; (b, a) = (a, b) */ +void s_mp_exch(mp_int *a, mp_int *b) +{ + mp_int tmp; + + tmp = *a; + *a = *b; + *b = tmp; + +} /* end s_mp_exch() */ + +/* }}} */ + +/* }}} */ + +/* {{{ Arithmetic helpers */ + +/* {{{ s_mp_lshd(mp, p) */ + +/* + Shift mp leftward by p digits, growing if needed, and zero-filling + the in-shifted digits at the right end. This is a convenient + alternative to multiplication by powers of the radix + */ + +mp_err s_mp_lshd(mp_int *mp, mp_size p) +{ + mp_err res; + mp_size pos; + mp_digit *dp; + int ix; + + if(p == 0) + return MP_OKAY; + + if((res = s_mp_pad(mp, USED(mp) + p)) != MP_OKAY) + return res; + + pos = USED(mp) - 1; + dp = DIGITS(mp); + + /* Shift all the significant figures over as needed */ + for(ix = pos - p; ix >= 0; ix--) + dp[ix + p] = dp[ix]; + + /* Fill the bottom digits with zeroes */ + for(ix = 0; ix < p; ix++) + dp[ix] = 0; + + return MP_OKAY; + +} /* end s_mp_lshd() */ + +/* }}} */ + +/* {{{ s_mp_rshd(mp, p) */ + +/* + Shift mp rightward by p digits. Maintains the invariant that + digits above the precision are all zero. Digits shifted off the + end are lost. Cannot fail. + */ + +void s_mp_rshd(mp_int *mp, mp_size p) +{ + mp_size ix; + mp_digit *dp; + + if(p == 0) + return; + + /* Shortcut when all digits are to be shifted off */ + if(p >= USED(mp)) { + s_mp_setz(DIGITS(mp), ALLOC(mp)); + USED(mp) = 1; + SIGN(mp) = MP_ZPOS; + return; + } + + /* Shift all the significant figures over as needed */ + dp = DIGITS(mp); + for(ix = p; ix < USED(mp); ix++) + dp[ix - p] = dp[ix]; + + /* Fill the top digits with zeroes */ + ix -= p; + while(ix < USED(mp)) + dp[ix++] = 0; + + /* Strip off any leading zeroes */ + s_mp_clamp(mp); + +} /* end s_mp_rshd() */ + +/* }}} */ + +/* {{{ s_mp_div_2(mp) */ + +/* Divide by two -- take advantage of radix properties to do it fast */ +void s_mp_div_2(mp_int *mp) +{ + s_mp_div_2d(mp, 1); + +} /* end s_mp_div_2() */ + +/* }}} */ + +/* {{{ s_mp_mul_2(mp) */ + +mp_err s_mp_mul_2(mp_int *mp) +{ + int ix; + mp_digit kin = 0, kout, *dp = DIGITS(mp); + mp_err res; + + /* Shift digits leftward by 1 bit */ + for(ix = 0; ix < USED(mp); ix++) { + kout = (dp[ix] >> (DIGIT_BIT - 1)) & 1; + dp[ix] = (dp[ix] << 1) | kin; + + kin = kout; + } + + /* Deal with rollover from last digit */ + if(kin) { + if(ix >= ALLOC(mp)) { + if((res = s_mp_grow(mp, ALLOC(mp) + 1)) != MP_OKAY) + return res; + dp = DIGITS(mp); + } + + dp[ix] = kin; + USED(mp) += 1; + } + + return MP_OKAY; + +} /* end s_mp_mul_2() */ + +/* }}} */ + +/* {{{ s_mp_mod_2d(mp, d) */ + +/* + Remainder the integer by 2^d, where d is a number of bits. This + amounts to a bitwise AND of the value, and does not require the full + division code + */ +void s_mp_mod_2d(mp_int *mp, mp_digit d) +{ + unsigned int ndig = (d / DIGIT_BIT), nbit = (d % DIGIT_BIT); + unsigned int ix; + mp_digit dmask, *dp = DIGITS(mp); + + if(ndig >= USED(mp)) + return; + + /* Flush all the bits above 2^d in its digit */ + dmask = (1 << nbit) - 1; + dp[ndig] &= dmask; + + /* Flush all digits above the one with 2^d in it */ + for(ix = ndig + 1; ix < USED(mp); ix++) + dp[ix] = 0; + + s_mp_clamp(mp); + +} /* end s_mp_mod_2d() */ + +/* }}} */ + +/* {{{ s_mp_mul_2d(mp, d) */ + +/* + Multiply by the integer 2^d, where d is a number of bits. This + amounts to a bitwise shift of the value, and does not require the + full multiplication code. + */ +mp_err s_mp_mul_2d(mp_int *mp, mp_digit d) +{ + mp_err res; + mp_digit save, next, mask, *dp; + mp_size used; + int ix; + + if((res = s_mp_lshd(mp, d / DIGIT_BIT)) != MP_OKAY) + return res; + + dp = DIGITS(mp); used = USED(mp); + d %= DIGIT_BIT; + + mask = (1 << d) - 1; + + /* If the shift requires another digit, make sure we've got one to + work with */ + if((dp[used - 1] >> (DIGIT_BIT - d)) & mask) { + if((res = s_mp_grow(mp, used + 1)) != MP_OKAY) + return res; + dp = DIGITS(mp); + } + + /* Do the shifting... */ + save = 0; + for(ix = 0; ix < used; ix++) { + next = (dp[ix] >> (DIGIT_BIT - d)) & mask; + dp[ix] = (dp[ix] << d) | save; + save = next; + } + + /* If, at this point, we have a nonzero carryout into the next + digit, we'll increase the size by one digit, and store it... + */ + if(save) { + dp[used] = save; + USED(mp) += 1; + } + + s_mp_clamp(mp); + return MP_OKAY; + +} /* end s_mp_mul_2d() */ + +/* }}} */ + +/* {{{ s_mp_div_2d(mp, d) */ + +/* + Divide the integer by 2^d, where d is a number of bits. This + amounts to a bitwise shift of the value, and does not require the + full division code (used in Barrett reduction, see below) + */ +void s_mp_div_2d(mp_int *mp, mp_digit d) +{ + int ix; + mp_digit save, next, mask, *dp = DIGITS(mp); + + s_mp_rshd(mp, d / DIGIT_BIT); + d %= DIGIT_BIT; + + mask = (1 << d) - 1; + + save = 0; + for(ix = USED(mp) - 1; ix >= 0; ix--) { + next = dp[ix] & mask; + dp[ix] = (dp[ix] >> d) | (save << (DIGIT_BIT - d)); + save = next; + } + + s_mp_clamp(mp); + +} /* end s_mp_div_2d() */ + +/* }}} */ + +/* {{{ s_mp_norm(a, b) */ + +/* + s_mp_norm(a, b) + + Normalize a and b for division, where b is the divisor. In order + that we might make good guesses for quotient digits, we want the + leading digit of b to be at least half the radix, which we + accomplish by multiplying a and b by a constant. This constant is + returned (so that it can be divided back out of the remainder at the + end of the division process). + + We multiply by the smallest power of 2 that gives us a leading digit + at least half the radix. By choosing a power of 2, we simplify the + multiplication and division steps to simple shifts. + */ +mp_digit s_mp_norm(mp_int *a, mp_int *b) +{ + mp_digit t, d = 0; + + t = DIGIT(b, USED(b) - 1); + while(t < (RADIX / 2)) { + t <<= 1; + ++d; + } + + if(d != 0) { + s_mp_mul_2d(a, d); + s_mp_mul_2d(b, d); + } + + return d; + +} /* end s_mp_norm() */ + +/* }}} */ + +/* }}} */ + +/* {{{ Primitive digit arithmetic */ + +/* {{{ s_mp_add_d(mp, d) */ + +/* Add d to |mp| in place */ +mp_err s_mp_add_d(mp_int *mp, mp_digit d) /* unsigned digit addition */ +{ + mp_word w, k = 0; + mp_size ix = 1, used = USED(mp); + mp_digit *dp = DIGITS(mp); + + w = dp[0] + d; + dp[0] = ACCUM(w); + k = CARRYOUT(w); + + while(ix < used && k) { + w = dp[ix] + k; + dp[ix] = ACCUM(w); + k = CARRYOUT(w); + ++ix; + } + + if(k != 0) { + mp_err res; + + if((res = s_mp_pad(mp, USED(mp) + 1)) != MP_OKAY) + return res; + + DIGIT(mp, ix) = k; + } + + return MP_OKAY; + +} /* end s_mp_add_d() */ + +/* }}} */ + +/* {{{ s_mp_sub_d(mp, d) */ + +/* Subtract d from |mp| in place, assumes |mp| > d */ +mp_err s_mp_sub_d(mp_int *mp, mp_digit d) /* unsigned digit subtract */ +{ + mp_word w, b = 0; + mp_size ix = 1, used = USED(mp); + mp_digit *dp = DIGITS(mp); + + /* Compute initial subtraction */ + w = (RADIX + dp[0]) - d; + b = CARRYOUT(w) ? 0 : 1; + dp[0] = ACCUM(w); + + /* Propagate borrows leftward */ + while(b && ix < used) { + w = (RADIX + dp[ix]) - b; + b = CARRYOUT(w) ? 0 : 1; + dp[ix] = ACCUM(w); + ++ix; + } + + /* Remove leading zeroes */ + s_mp_clamp(mp); + + /* If we have a borrow out, it's a violation of the input invariant */ + if(b) + return MP_RANGE; + else + return MP_OKAY; + +} /* end s_mp_sub_d() */ + +/* }}} */ + +/* {{{ s_mp_mul_d(a, d) */ + +/* Compute a = a * d, single digit multiplication */ +mp_err s_mp_mul_d(mp_int *a, mp_digit d) +{ + mp_word w, k = 0; + mp_size ix, max; + mp_err res; + mp_digit *dp = DIGITS(a); + + /* + Single-digit multiplication will increase the precision of the + output by at most one digit. However, we can detect when this + will happen -- if the high-order digit of a, times d, gives a + two-digit result, then the precision of the result will increase; + otherwise it won't. We use this fact to avoid calling s_mp_pad() + unless absolutely necessary. + */ + max = USED(a); + w = dp[max - 1] * d; + if(CARRYOUT(w) != 0) { + if((res = s_mp_pad(a, max + 1)) != MP_OKAY) + return res; + dp = DIGITS(a); + } + + for(ix = 0; ix < max; ix++) { + w = (dp[ix] * d) + k; + dp[ix] = ACCUM(w); + k = CARRYOUT(w); + } + + /* If there is a precision increase, take care of it here; the above + test guarantees we have enough storage to do this safely. + */ + if(k) { + dp[max] = k; + USED(a) = max + 1; + } + + s_mp_clamp(a); + + return MP_OKAY; + +} /* end s_mp_mul_d() */ + +/* }}} */ + +/* {{{ s_mp_div_d(mp, d, r) */ + +/* + s_mp_div_d(mp, d, r) + + Compute the quotient mp = mp / d and remainder r = mp mod d, for a + single digit d. If r is null, the remainder will be discarded. + */ + +mp_err s_mp_div_d(mp_int *mp, mp_digit d, mp_digit *r) +{ + mp_word w = 0, t; + mp_int quot; + mp_err res; + mp_digit *dp = DIGITS(mp), *qp; + int ix; + + if(d == 0) + return MP_RANGE; + + /* Make room for the quotient */ + if((res = mp_init_size(", USED(mp))) != MP_OKAY) + return res; + + USED(") = USED(mp); /* so clamping will work below */ + qp = DIGITS("); + + /* Divide without subtraction */ + for(ix = USED(mp) - 1; ix >= 0; ix--) { + w = (w << DIGIT_BIT) | dp[ix]; + + if(w >= d) { + t = w / d; + w = w % d; + } else { + t = 0; + } + + qp[ix] = t; + } + + /* Deliver the remainder, if desired */ + if(r) + *r = w; + + s_mp_clamp("); + mp_exch(", mp); + mp_clear("); + + return MP_OKAY; + +} /* end s_mp_div_d() */ + +/* }}} */ + +/* }}} */ + +/* {{{ Primitive full arithmetic */ + +/* {{{ s_mp_add(a, b) */ + +/* Compute a = |a| + |b| */ +mp_err s_mp_add(mp_int *a, mp_int *b) /* magnitude addition */ +{ + mp_word w = 0; + mp_digit *pa, *pb; + mp_size ix, used = USED(b); + mp_err res; + + /* Make sure a has enough precision for the output value */ + if((used > USED(a)) && (res = s_mp_pad(a, used)) != MP_OKAY) + return res; + + /* + Add up all digits up to the precision of b. If b had initially + the same precision as a, or greater, we took care of it by the + padding step above, so there is no problem. If b had initially + less precision, we'll have to make sure the carry out is duly + propagated upward among the higher-order digits of the sum. + */ + pa = DIGITS(a); + pb = DIGITS(b); + for(ix = 0; ix < used; ++ix) { + w += *pa + *pb++; + *pa++ = ACCUM(w); + w = CARRYOUT(w); + } + + /* If we run out of 'b' digits before we're actually done, make + sure the carries get propagated upward... + */ + used = USED(a); + while(w && ix < used) { + w += *pa; + *pa++ = ACCUM(w); + w = CARRYOUT(w); + ++ix; + } + + /* If there's an overall carry out, increase precision and include + it. We could have done this initially, but why touch the memory + allocator unless we're sure we have to? + */ + if(w) { + if((res = s_mp_pad(a, used + 1)) != MP_OKAY) + return res; + + DIGIT(a, ix) = w; /* pa may not be valid after s_mp_pad() call */ + } + + return MP_OKAY; + +} /* end s_mp_add() */ + +/* }}} */ + +/* {{{ s_mp_sub(a, b) */ + +/* Compute a = |a| - |b|, assumes |a| >= |b| */ +mp_err s_mp_sub(mp_int *a, mp_int *b) /* magnitude subtract */ +{ + mp_word w = 0; + mp_digit *pa, *pb; + mp_size ix, used = USED(b); + + /* + Subtract and propagate borrow. Up to the precision of b, this + accounts for the digits of b; after that, we just make sure the + carries get to the right place. This saves having to pad b out to + the precision of a just to make the loops work right... + */ + pa = DIGITS(a); + pb = DIGITS(b); + + for(ix = 0; ix < used; ++ix) { + w = (RADIX + *pa) - w - *pb++; + *pa++ = ACCUM(w); + w = CARRYOUT(w) ? 0 : 1; + } + + used = USED(a); + while(ix < used) { + w = RADIX + *pa - w; + *pa++ = ACCUM(w); + w = CARRYOUT(w) ? 0 : 1; + ++ix; + } + + /* Clobber any leading zeroes we created */ + s_mp_clamp(a); + + /* + If there was a borrow out, then |b| > |a| in violation + of our input invariant. We've already done the work, + but we'll at least complain about it... + */ + if(w) + return MP_RANGE; + else + return MP_OKAY; + +} /* end s_mp_sub() */ + +/* }}} */ + +mp_err s_mp_reduce(mp_int *x, mp_int *m, mp_int *mu) +{ + mp_int q; + mp_err res; + mp_size um = USED(m); + + if((res = mp_init_copy(&q, x)) != MP_OKAY) + return res; + + s_mp_rshd(&q, um - 1); /* q1 = x / b^(k-1) */ + s_mp_mul(&q, mu); /* q2 = q1 * mu */ + s_mp_rshd(&q, um + 1); /* q3 = q2 / b^(k+1) */ + + /* x = x mod b^(k+1), quick (no division) */ + s_mp_mod_2d(x, (mp_digit)(DIGIT_BIT * (um + 1))); + + /* q = q * m mod b^(k+1), quick (no division), uses the short multiplier */ +#ifndef SHRT_MUL + s_mp_mul(&q, m); + s_mp_mod_2d(&q, (mp_digit)(DIGIT_BIT * (um + 1))); +#else + s_mp_mul_dig(&q, m, um + 1); +#endif + + /* x = x - q */ + if((res = mp_sub(x, &q, x)) != MP_OKAY) + goto CLEANUP; + + /* If x < 0, add b^(k+1) to it */ + if(mp_cmp_z(x) < 0) { + mp_set(&q, 1); + if((res = s_mp_lshd(&q, um + 1)) != MP_OKAY) + goto CLEANUP; + if((res = mp_add(x, &q, x)) != MP_OKAY) + goto CLEANUP; + } + + /* Back off if it's too big */ + while(mp_cmp(x, m) >= 0) { + if((res = s_mp_sub(x, m)) != MP_OKAY) + break; + } + + CLEANUP: + mp_clear(&q); + + return res; + +} /* end s_mp_reduce() */ + + + +/* {{{ s_mp_mul(a, b) */ + +/* Compute a = |a| * |b| */ +mp_err s_mp_mul(mp_int *a, mp_int *b) +{ + mp_word w, k = 0; + mp_int tmp; + mp_err res; + mp_size ix, jx, ua = USED(a), ub = USED(b); + mp_digit *pa, *pb, *pt, *pbt; + + if((res = mp_init_size(&tmp, ua + ub)) != MP_OKAY) + return res; + + /* This has the effect of left-padding with zeroes... */ + USED(&tmp) = ua + ub; + + /* We're going to need the base value each iteration */ + pbt = DIGITS(&tmp); + + /* Outer loop: Digits of b */ + + pb = DIGITS(b); + for(ix = 0; ix < ub; ++ix, ++pb) { + if(*pb == 0) + continue; + + /* Inner product: Digits of a */ + pa = DIGITS(a); + for(jx = 0; jx < ua; ++jx, ++pa) { + pt = pbt + ix + jx; + w = *pb * *pa + k + *pt; + *pt = ACCUM(w); + k = CARRYOUT(w); + } + + pbt[ix + jx] = k; + k = 0; + } + + s_mp_clamp(&tmp); + s_mp_exch(&tmp, a); + + mp_clear(&tmp); + + return MP_OKAY; + +} /* end s_mp_mul() */ + +/* }}} */ + +/* {{{ s_mp_kmul(a, b, out, len) */ + +#if 0 +void s_mp_kmul(mp_digit *a, mp_digit *b, mp_digit *out, mp_size len) +{ + mp_word w, k = 0; + mp_size ix, jx; + mp_digit *pa, *pt; + + for(ix = 0; ix < len; ++ix, ++b) { + if(*b == 0) + continue; + + pa = a; + for(jx = 0; jx < len; ++jx, ++pa) { + pt = out + ix + jx; + w = *b * *pa + k + *pt; + *pt = ACCUM(w); + k = CARRYOUT(w); + } + + out[ix + jx] = k; + k = 0; + } + +} /* end s_mp_kmul() */ +#endif + +/* }}} */ + +/* {{{ s_mp_sqr(a) */ + +/* + Computes the square of a, in place. This can be done more + efficiently than a general multiplication, because many of the + computation steps are redundant when squaring. The inner product + step is a bit more complicated, but we save a fair number of + iterations of the multiplication loop. + */ +#if MP_SQUARE +mp_err s_mp_sqr(mp_int *a) +{ + mp_word w, k = 0; + mp_int tmp; + mp_err res; + mp_size ix, jx, kx, used = USED(a); + mp_digit *pa1, *pa2, *pt, *pbt; + + if((res = mp_init_size(&tmp, 2 * used)) != MP_OKAY) + return res; + + /* Left-pad with zeroes */ + USED(&tmp) = 2 * used; + + /* We need the base value each time through the loop */ + pbt = DIGITS(&tmp); + + pa1 = DIGITS(a); + for(ix = 0; ix < used; ++ix, ++pa1) { + if(*pa1 == 0) + continue; + + w = DIGIT(&tmp, ix + ix) + (*pa1 * *pa1); + + pbt[ix + ix] = ACCUM(w); + k = CARRYOUT(w); + + /* + The inner product is computed as: + + (C, S) = t[i,j] + 2 a[i] a[j] + C + + This can overflow what can be represented in an mp_word, and + since C arithmetic does not provide any way to check for + overflow, we have to check explicitly for overflow conditions + before they happen. + */ + for(jx = ix + 1, pa2 = DIGITS(a) + jx; jx < used; ++jx, ++pa2) { + mp_word u = 0, v; + + /* Store this in a temporary to avoid indirections later */ + pt = pbt + ix + jx; + + /* Compute the multiplicative step */ + w = *pa1 * *pa2; + + /* If w is more than half MP_WORD_MAX, the doubling will + overflow, and we need to record a carry out into the next + word */ + u = (w >> (MP_WORD_BIT - 1)) & 1; + + /* Double what we've got, overflow will be ignored as defined + for C arithmetic (we've already noted if it is to occur) + */ + w *= 2; + + /* Compute the additive step */ + v = *pt + k; + + /* If we do not already have an overflow carry, check to see + if the addition will cause one, and set the carry out if so + */ + u |= ((MP_WORD_MAX - v) < w); + + /* Add in the rest, again ignoring overflow */ + w += v; + + /* Set the i,j digit of the output */ + *pt = ACCUM(w); + + /* Save carry information for the next iteration of the loop. + This is why k must be an mp_word, instead of an mp_digit */ + k = CARRYOUT(w) | (u << DIGIT_BIT); + + } /* for(jx ...) */ + + /* Set the last digit in the cycle and reset the carry */ + k = DIGIT(&tmp, ix + jx) + k; + pbt[ix + jx] = ACCUM(k); + k = CARRYOUT(k); + + /* If we are carrying out, propagate the carry to the next digit + in the output. This may cascade, so we have to be somewhat + circumspect -- but we will have enough precision in the output + that we won't overflow + */ + kx = 1; + while(k) { + k = pbt[ix + jx + kx] + 1; + pbt[ix + jx + kx] = ACCUM(k); + k = CARRYOUT(k); + ++kx; + } + } /* for(ix ...) */ + + s_mp_clamp(&tmp); + s_mp_exch(&tmp, a); + + mp_clear(&tmp); + + return MP_OKAY; + +} /* end s_mp_sqr() */ +#endif + +/* }}} */ + +/* {{{ s_mp_div(a, b) */ + +/* + s_mp_div(a, b) + + Compute a = a / b and b = a mod b. Assumes b > a. + */ + +mp_err s_mp_div(mp_int *a, mp_int *b) +{ + mp_int quot, rem, t; + mp_word q; + mp_err res; + mp_digit d; + int ix; + + if(mp_cmp_z(b) == 0) + return MP_RANGE; + + /* Shortcut if b is power of two */ + if((ix = s_mp_ispow2(b)) >= 0) { + mp_copy(a, b); /* need this for remainder */ + s_mp_div_2d(a, (mp_digit)ix); + s_mp_mod_2d(b, (mp_digit)ix); + + return MP_OKAY; + } + + /* Allocate space to store the quotient */ + if((res = mp_init_size(", USED(a))) != MP_OKAY) + return res; + + /* A working temporary for division */ + if((res = mp_init_size(&t, USED(a))) != MP_OKAY) + goto T; + + /* Allocate space for the remainder */ + if((res = mp_init_size(&rem, USED(a))) != MP_OKAY) + goto REM; + + /* Normalize to optimize guessing */ + d = s_mp_norm(a, b); + + /* Perform the division itself...woo! */ + ix = USED(a) - 1; + + while(ix >= 0) { + /* Find a partial substring of a which is at least b */ + while(s_mp_cmp(&rem, b) < 0 && ix >= 0) { + if((res = s_mp_lshd(&rem, 1)) != MP_OKAY) + goto CLEANUP; + + if((res = s_mp_lshd(", 1)) != MP_OKAY) + goto CLEANUP; + + DIGIT(&rem, 0) = DIGIT(a, ix); + s_mp_clamp(&rem); + --ix; + } + + /* If we didn't find one, we're finished dividing */ + if(s_mp_cmp(&rem, b) < 0) + break; + + /* Compute a guess for the next quotient digit */ + q = DIGIT(&rem, USED(&rem) - 1); + if(q <= DIGIT(b, USED(b) - 1) && USED(&rem) > 1) + q = (q << DIGIT_BIT) | DIGIT(&rem, USED(&rem) - 2); + + q /= DIGIT(b, USED(b) - 1); + + /* The guess can be as much as RADIX + 1 */ + if(q >= RADIX) + q = RADIX - 1; + + /* See what that multiplies out to */ + mp_copy(b, &t); + if((res = s_mp_mul_d(&t, q)) != MP_OKAY) + goto CLEANUP; + + /* + If it's too big, back it off. We should not have to do this + more than once, or, in rare cases, twice. Knuth describes a + method by which this could be reduced to a maximum of once, but + I didn't implement that here. + */ + while(s_mp_cmp(&t, &rem) > 0) { + --q; + s_mp_sub(&t, b); + } + + /* At this point, q should be the right next digit */ + if((res = s_mp_sub(&rem, &t)) != MP_OKAY) + goto CLEANUP; + + /* + Include the digit in the quotient. We allocated enough memory + for any quotient we could ever possibly get, so we should not + have to check for failures here + */ + DIGIT(", 0) = q; + } + + /* Denormalize remainder */ + if(d != 0) + s_mp_div_2d(&rem, d); + + s_mp_clamp("); + s_mp_clamp(&rem); + + /* Copy quotient back to output */ + s_mp_exch(", a); + + /* Copy remainder back to output */ + s_mp_exch(&rem, b); + +CLEANUP: + mp_clear(&rem); +REM: + mp_clear(&t); +T: + mp_clear("); + + return res; + +} /* end s_mp_div() */ + +/* }}} */ + +/* {{{ s_mp_2expt(a, k) */ + +mp_err s_mp_2expt(mp_int *a, mp_digit k) +{ + mp_err res; + mp_size dig, bit; + + dig = k / DIGIT_BIT; + bit = k % DIGIT_BIT; + + mp_zero(a); + if((res = s_mp_pad(a, dig + 1)) != MP_OKAY) + return res; + + DIGIT(a, dig) |= (1 << bit); + + return MP_OKAY; + +} /* end s_mp_2expt() */ + +/* }}} */ + + +/* }}} */ + +/* }}} */ + +/* {{{ Primitive comparisons */ + +/* {{{ s_mp_cmp(a, b) */ + +/* Compare |a| <=> |b|, return 0 if equal, <0 if a<b, >0 if a>b */ +int s_mp_cmp(mp_int *a, mp_int *b) +{ + mp_size ua = USED(a), ub = USED(b); + + if(ua > ub) + return MP_GT; + else if(ua < ub) + return MP_LT; + else { + int ix = ua - 1; + mp_digit *ap = DIGITS(a) + ix, *bp = DIGITS(b) + ix; + + while(ix >= 0) { + if(*ap > *bp) + return MP_GT; + else if(*ap < *bp) + return MP_LT; + + --ap; --bp; --ix; + } + + return MP_EQ; + } + +} /* end s_mp_cmp() */ + +/* }}} */ + +/* {{{ s_mp_cmp_d(a, d) */ + +/* Compare |a| <=> d, return 0 if equal, <0 if a<d, >0 if a>d */ +int s_mp_cmp_d(mp_int *a, mp_digit d) +{ + mp_size ua = USED(a); + mp_digit *ap = DIGITS(a); + + if(ua > 1) + return MP_GT; + + if(*ap < d) + return MP_LT; + else if(*ap > d) + return MP_GT; + else + return MP_EQ; + +} /* end s_mp_cmp_d() */ + +/* }}} */ + +/* {{{ s_mp_ispow2(v) */ + +/* + Returns -1 if the value is not a power of two; otherwise, it returns + k such that v = 2^k, i.e. lg(v). + */ +int s_mp_ispow2(mp_int *v) +{ + mp_digit d, *dp; + mp_size uv = USED(v); + int extra = 0, ix; + + d = DIGIT(v, uv - 1); /* most significant digit of v */ + + while(d && ((d & 1) == 0)) { + d >>= 1; + ++extra; + } + + if(d == 1) { + ix = uv - 2; + dp = DIGITS(v) + ix; + + while(ix >= 0) { + if(*dp) + return -1; /* not a power of two */ + + --dp; --ix; + } + + return ((uv - 1) * DIGIT_BIT) + extra; + } + + return -1; + +} /* end s_mp_ispow2() */ + +/* }}} */ + +/* {{{ s_mp_ispow2d(d) */ + +int s_mp_ispow2d(mp_digit d) +{ + int pow = 0; + + while((d & 1) == 0) { + ++pow; d >>= 1; + } + + if(d == 1) + return pow; + + return -1; + +} /* end s_mp_ispow2d() */ + +/* }}} */ + +/* }}} */ + +/* {{{ Primitive I/O helpers */ + +/* {{{ s_mp_tovalue(ch, r) */ + +/* + Convert the given character to its digit value, in the given radix. + If the given character is not understood in the given radix, -1 is + returned. Otherwise the digit's numeric value is returned. + + The results will be odd if you use a radix < 2 or > 62, you are + expected to know what you're up to. + */ +int s_mp_tovalue(char ch, int r) +{ + int val, xch; + + if(r > 36) + xch = ch; + else + xch = toupper(ch); + + if(isdigit(xch)) + val = xch - '0'; + else if(isupper(xch)) + val = xch - 'A' + 10; + else if(islower(xch)) + val = xch - 'a' + 36; + else if(xch == '+') + val = 62; + else if(xch == '/') + val = 63; + else + return -1; + + if(val < 0 || val >= r) + return -1; + + return val; + +} /* end s_mp_tovalue() */ + +/* }}} */ + +/* {{{ s_mp_todigit(val, r, low) */ + +/* + Convert val to a radix-r digit, if possible. If val is out of range + for r, returns zero. Otherwise, returns an ASCII character denoting + the value in the given radix. + + The results may be odd if you use a radix < 2 or > 64, you are + expected to know what you're doing. + */ + +char s_mp_todigit(int val, int r, int low) +{ + char ch; + + if(val < 0 || val >= r) + return 0; + + ch = s_dmap_1[val]; + + if(r <= 36 && low) + ch = tolower(ch); + + return ch; + +} /* end s_mp_todigit() */ + +/* }}} */ + +/* {{{ s_mp_outlen(bits, radix) */ + +/* + Return an estimate for how long a string is needed to hold a radix + r representation of a number with 'bits' significant bits. + + Does not include space for a sign or a NUL terminator. + */ +int s_mp_outlen(int bits, int r) +{ + return (int)((double)bits * LOG_V_2(r)); + +} /* end s_mp_outlen() */ + +/* }}} */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* HERE THERE BE DRAGONS */ +/* crc==4242132123, version==2, Sat Feb 02 06:43:52 2002 */ + +/* $Source: /cvs/libtom/libtommath/mtest/mpi.c,v $ */ +/* $Revision: 1.2 $ */ +/* $Date: 2005/05/05 14:38:47 $ */ diff --git a/libtommath/mtest/mpi.h b/libtommath/mtest/mpi.h new file mode 100644 index 0000000..66ae873 --- /dev/null +++ b/libtommath/mtest/mpi.h @@ -0,0 +1,231 @@ +/* + mpi.h + + by Michael J. Fromberger <sting@linguist.dartmouth.edu> + Copyright (C) 1998 Michael J. Fromberger, All Rights Reserved + + Arbitrary precision integer arithmetic library + + $Id: mpi.h,v 1.2 2005/05/05 14:38:47 tom Exp $ + */ + +#ifndef _H_MPI_ +#define _H_MPI_ + +#include "mpi-config.h" + +#define MP_LT -1 +#define MP_EQ 0 +#define MP_GT 1 + +#if MP_DEBUG +#undef MP_IOFUNC +#define MP_IOFUNC 1 +#endif + +#if MP_IOFUNC +#include <stdio.h> +#include <ctype.h> +#endif + +#include <limits.h> + +#define MP_NEG 1 +#define MP_ZPOS 0 + +/* Included for compatibility... */ +#define NEG MP_NEG +#define ZPOS MP_ZPOS + +#define MP_OKAY 0 /* no error, all is well */ +#define MP_YES 0 /* yes (boolean result) */ +#define MP_NO -1 /* no (boolean result) */ +#define MP_MEM -2 /* out of memory */ +#define MP_RANGE -3 /* argument out of range */ +#define MP_BADARG -4 /* invalid parameter */ +#define MP_UNDEF -5 /* answer is undefined */ +#define MP_LAST_CODE MP_UNDEF + +#include "mpi-types.h" + +/* Included for compatibility... */ +#define DIGIT_BIT MP_DIGIT_BIT +#define DIGIT_MAX MP_DIGIT_MAX + +/* Macros for accessing the mp_int internals */ +#define SIGN(MP) ((MP)->sign) +#define USED(MP) ((MP)->used) +#define ALLOC(MP) ((MP)->alloc) +#define DIGITS(MP) ((MP)->dp) +#define DIGIT(MP,N) (MP)->dp[(N)] + +#if MP_ARGCHK == 1 +#define ARGCHK(X,Y) {if(!(X)){return (Y);}} +#elif MP_ARGCHK == 2 +#include <assert.h> +#define ARGCHK(X,Y) assert(X) +#else +#define ARGCHK(X,Y) /* */ +#endif + +/* This defines the maximum I/O base (minimum is 2) */ +#define MAX_RADIX 64 + +typedef struct { + mp_sign sign; /* sign of this quantity */ + mp_size alloc; /* how many digits allocated */ + mp_size used; /* how many digits used */ + mp_digit *dp; /* the digits themselves */ +} mp_int; + +/*------------------------------------------------------------------------*/ +/* Default precision */ + +unsigned int mp_get_prec(void); +void mp_set_prec(unsigned int prec); + +/*------------------------------------------------------------------------*/ +/* Memory management */ + +mp_err mp_init(mp_int *mp); +mp_err mp_init_array(mp_int mp[], int count); +mp_err mp_init_size(mp_int *mp, mp_size prec); +mp_err mp_init_copy(mp_int *mp, mp_int *from); +mp_err mp_copy(mp_int *from, mp_int *to); +void mp_exch(mp_int *mp1, mp_int *mp2); +void mp_clear(mp_int *mp); +void mp_clear_array(mp_int mp[], int count); +void mp_zero(mp_int *mp); +void mp_set(mp_int *mp, mp_digit d); +mp_err mp_set_int(mp_int *mp, long z); +mp_err mp_shrink(mp_int *a); + + +/*------------------------------------------------------------------------*/ +/* Single digit arithmetic */ + +mp_err mp_add_d(mp_int *a, mp_digit d, mp_int *b); +mp_err mp_sub_d(mp_int *a, mp_digit d, mp_int *b); +mp_err mp_mul_d(mp_int *a, mp_digit d, mp_int *b); +mp_err mp_mul_2(mp_int *a, mp_int *c); +mp_err mp_div_d(mp_int *a, mp_digit d, mp_int *q, mp_digit *r); +mp_err mp_div_2(mp_int *a, mp_int *c); +mp_err mp_expt_d(mp_int *a, mp_digit d, mp_int *c); + +/*------------------------------------------------------------------------*/ +/* Sign manipulations */ + +mp_err mp_abs(mp_int *a, mp_int *b); +mp_err mp_neg(mp_int *a, mp_int *b); + +/*------------------------------------------------------------------------*/ +/* Full arithmetic */ + +mp_err mp_add(mp_int *a, mp_int *b, mp_int *c); +mp_err mp_sub(mp_int *a, mp_int *b, mp_int *c); +mp_err mp_mul(mp_int *a, mp_int *b, mp_int *c); +mp_err mp_mul_2d(mp_int *a, mp_digit d, mp_int *c); +#if MP_SQUARE +mp_err mp_sqr(mp_int *a, mp_int *b); +#else +#define mp_sqr(a, b) mp_mul(a, a, b) +#endif +mp_err mp_div(mp_int *a, mp_int *b, mp_int *q, mp_int *r); +mp_err mp_div_2d(mp_int *a, mp_digit d, mp_int *q, mp_int *r); +mp_err mp_expt(mp_int *a, mp_int *b, mp_int *c); +mp_err mp_2expt(mp_int *a, mp_digit k); +mp_err mp_sqrt(mp_int *a, mp_int *b); + +/*------------------------------------------------------------------------*/ +/* Modular arithmetic */ + +#if MP_MODARITH +mp_err mp_mod(mp_int *a, mp_int *m, mp_int *c); +mp_err mp_mod_d(mp_int *a, mp_digit d, mp_digit *c); +mp_err mp_addmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c); +mp_err mp_submod(mp_int *a, mp_int *b, mp_int *m, mp_int *c); +mp_err mp_mulmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c); +#if MP_SQUARE +mp_err mp_sqrmod(mp_int *a, mp_int *m, mp_int *c); +#else +#define mp_sqrmod(a, m, c) mp_mulmod(a, a, m, c) +#endif +mp_err mp_exptmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c); +mp_err mp_exptmod_d(mp_int *a, mp_digit d, mp_int *m, mp_int *c); +#endif /* MP_MODARITH */ + +/*------------------------------------------------------------------------*/ +/* Comparisons */ + +int mp_cmp_z(mp_int *a); +int mp_cmp_d(mp_int *a, mp_digit d); +int mp_cmp(mp_int *a, mp_int *b); +int mp_cmp_mag(mp_int *a, mp_int *b); +int mp_cmp_int(mp_int *a, long z); +int mp_isodd(mp_int *a); +int mp_iseven(mp_int *a); + +/*------------------------------------------------------------------------*/ +/* Number theoretic */ + +#if MP_NUMTH +mp_err mp_gcd(mp_int *a, mp_int *b, mp_int *c); +mp_err mp_lcm(mp_int *a, mp_int *b, mp_int *c); +mp_err mp_xgcd(mp_int *a, mp_int *b, mp_int *g, mp_int *x, mp_int *y); +mp_err mp_invmod(mp_int *a, mp_int *m, mp_int *c); +#endif /* end MP_NUMTH */ + +/*------------------------------------------------------------------------*/ +/* Input and output */ + +#if MP_IOFUNC +void mp_print(mp_int *mp, FILE *ofp); +#endif /* end MP_IOFUNC */ + +/*------------------------------------------------------------------------*/ +/* Base conversion */ + +#define BITS 1 +#define BYTES CHAR_BIT + +mp_err mp_read_signed_bin(mp_int *mp, unsigned char *str, int len); +int mp_signed_bin_size(mp_int *mp); +mp_err mp_to_signed_bin(mp_int *mp, unsigned char *str); + +mp_err mp_read_unsigned_bin(mp_int *mp, unsigned char *str, int len); +int mp_unsigned_bin_size(mp_int *mp); +mp_err mp_to_unsigned_bin(mp_int *mp, unsigned char *str); + +int mp_count_bits(mp_int *mp); + +#if MP_COMPAT_MACROS +#define mp_read_raw(mp, str, len) mp_read_signed_bin((mp), (str), (len)) +#define mp_raw_size(mp) mp_signed_bin_size(mp) +#define mp_toraw(mp, str) mp_to_signed_bin((mp), (str)) +#define mp_read_mag(mp, str, len) mp_read_unsigned_bin((mp), (str), (len)) +#define mp_mag_size(mp) mp_unsigned_bin_size(mp) +#define mp_tomag(mp, str) mp_to_unsigned_bin((mp), (str)) +#endif + +mp_err mp_read_radix(mp_int *mp, unsigned char *str, int radix); +int mp_radix_size(mp_int *mp, int radix); +int mp_value_radix_size(int num, int qty, int radix); +mp_err mp_toradix(mp_int *mp, unsigned char *str, int radix); + +int mp_char2value(char ch, int r); + +#define mp_tobinary(M, S) mp_toradix((M), (S), 2) +#define mp_tooctal(M, S) mp_toradix((M), (S), 8) +#define mp_todecimal(M, S) mp_toradix((M), (S), 10) +#define mp_tohex(M, S) mp_toradix((M), (S), 16) + +/*------------------------------------------------------------------------*/ +/* Error strings */ + +const char *mp_strerror(mp_err ec); + +#endif /* end _H_MPI_ */ + +/* $Source: /cvs/libtom/libtommath/mtest/mpi.h,v $ */ +/* $Revision: 1.2 $ */ +/* $Date: 2005/05/05 14:38:47 $ */ diff --git a/libtommath/mtest/mtest.c b/libtommath/mtest/mtest.c new file mode 100644 index 0000000..bdfe612 --- /dev/null +++ b/libtommath/mtest/mtest.c @@ -0,0 +1,308 @@ +/* makes a bignum test harness with NUM tests per operation + * + * the output is made in the following format [one parameter per line] + +operation +operand1 +operand2 +[... operandN] +result1 +result2 +[... resultN] + +So for example "a * b mod n" would be + +mulmod +a +b +n +a*b mod n + +e.g. if a=3, b=4 n=11 then + +mulmod +3 +4 +11 +1 + + */ + +#ifdef MP_8BIT +#define THE_MASK 127 +#else +#define THE_MASK 32767 +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include "mpi.c" + +FILE *rng; + +void rand_num(mp_int *a) +{ + int n, size; + unsigned char buf[2048]; + + size = 1 + ((fgetc(rng)<<8) + fgetc(rng)) % 101; + buf[0] = (fgetc(rng)&1)?1:0; + fread(buf+1, 1, size, rng); + while (buf[1] == 0) buf[1] = fgetc(rng); + mp_read_raw(a, buf, 1+size); +} + +void rand_num2(mp_int *a) +{ + int n, size; + unsigned char buf[2048]; + + size = 10 + ((fgetc(rng)<<8) + fgetc(rng)) % 101; + buf[0] = (fgetc(rng)&1)?1:0; + fread(buf+1, 1, size, rng); + while (buf[1] == 0) buf[1] = fgetc(rng); + mp_read_raw(a, buf, 1+size); +} + +#define mp_to64(a, b) mp_toradix(a, b, 64) + +int main(void) +{ + int n, tmp; + mp_int a, b, c, d, e; + clock_t t1; + char buf[4096]; + + mp_init(&a); + mp_init(&b); + mp_init(&c); + mp_init(&d); + mp_init(&e); + + + /* initial (2^n - 1)^2 testing, makes sure the comba multiplier works [it has the new carry code] */ +/* + mp_set(&a, 1); + for (n = 1; n < 8192; n++) { + mp_mul(&a, &a, &c); + printf("mul\n"); + mp_to64(&a, buf); + printf("%s\n%s\n", buf, buf); + mp_to64(&c, buf); + printf("%s\n", buf); + + mp_add_d(&a, 1, &a); + mp_mul_2(&a, &a); + mp_sub_d(&a, 1, &a); + } +*/ + + rng = fopen("/dev/urandom", "rb"); + if (rng == NULL) { + rng = fopen("/dev/random", "rb"); + if (rng == NULL) { + fprintf(stderr, "\nWarning: stdin used as random source\n\n"); + rng = stdin; + } + } + + t1 = clock(); + for (;;) { +#if 0 + if (clock() - t1 > CLOCKS_PER_SEC) { + sleep(2); + t1 = clock(); + } +#endif + n = fgetc(rng) % 15; + + if (n == 0) { + /* add tests */ + rand_num(&a); + rand_num(&b); + mp_add(&a, &b, &c); + printf("add\n"); + mp_to64(&a, buf); + printf("%s\n", buf); + mp_to64(&b, buf); + printf("%s\n", buf); + mp_to64(&c, buf); + printf("%s\n", buf); + } else if (n == 1) { + /* sub tests */ + rand_num(&a); + rand_num(&b); + mp_sub(&a, &b, &c); + printf("sub\n"); + mp_to64(&a, buf); + printf("%s\n", buf); + mp_to64(&b, buf); + printf("%s\n", buf); + mp_to64(&c, buf); + printf("%s\n", buf); + } else if (n == 2) { + /* mul tests */ + rand_num(&a); + rand_num(&b); + mp_mul(&a, &b, &c); + printf("mul\n"); + mp_to64(&a, buf); + printf("%s\n", buf); + mp_to64(&b, buf); + printf("%s\n", buf); + mp_to64(&c, buf); + printf("%s\n", buf); + } else if (n == 3) { + /* div tests */ + rand_num(&a); + rand_num(&b); + mp_div(&a, &b, &c, &d); + printf("div\n"); + mp_to64(&a, buf); + printf("%s\n", buf); + mp_to64(&b, buf); + printf("%s\n", buf); + mp_to64(&c, buf); + printf("%s\n", buf); + mp_to64(&d, buf); + printf("%s\n", buf); + } else if (n == 4) { + /* sqr tests */ + rand_num(&a); + mp_sqr(&a, &b); + printf("sqr\n"); + mp_to64(&a, buf); + printf("%s\n", buf); + mp_to64(&b, buf); + printf("%s\n", buf); + } else if (n == 5) { + /* mul_2d test */ + rand_num(&a); + mp_copy(&a, &b); + n = fgetc(rng) & 63; + mp_mul_2d(&b, n, &b); + mp_to64(&a, buf); + printf("mul2d\n"); + printf("%s\n", buf); + printf("%d\n", n); + mp_to64(&b, buf); + printf("%s\n", buf); + } else if (n == 6) { + /* div_2d test */ + rand_num(&a); + mp_copy(&a, &b); + n = fgetc(rng) & 63; + mp_div_2d(&b, n, &b, NULL); + mp_to64(&a, buf); + printf("div2d\n"); + printf("%s\n", buf); + printf("%d\n", n); + mp_to64(&b, buf); + printf("%s\n", buf); + } else if (n == 7) { + /* gcd test */ + rand_num(&a); + rand_num(&b); + a.sign = MP_ZPOS; + b.sign = MP_ZPOS; + mp_gcd(&a, &b, &c); + printf("gcd\n"); + mp_to64(&a, buf); + printf("%s\n", buf); + mp_to64(&b, buf); + printf("%s\n", buf); + mp_to64(&c, buf); + printf("%s\n", buf); + } else if (n == 8) { + /* lcm test */ + rand_num(&a); + rand_num(&b); + a.sign = MP_ZPOS; + b.sign = MP_ZPOS; + mp_lcm(&a, &b, &c); + printf("lcm\n"); + mp_to64(&a, buf); + printf("%s\n", buf); + mp_to64(&b, buf); + printf("%s\n", buf); + mp_to64(&c, buf); + printf("%s\n", buf); + } else if (n == 9) { + /* exptmod test */ + rand_num2(&a); + rand_num2(&b); + rand_num2(&c); +// if (c.dp[0]&1) mp_add_d(&c, 1, &c); + a.sign = b.sign = c.sign = 0; + mp_exptmod(&a, &b, &c, &d); + printf("expt\n"); + mp_to64(&a, buf); + printf("%s\n", buf); + mp_to64(&b, buf); + printf("%s\n", buf); + mp_to64(&c, buf); + printf("%s\n", buf); + mp_to64(&d, buf); + printf("%s\n", buf); + } else if (n == 10) { + /* invmod test */ + rand_num2(&a); + rand_num2(&b); + b.sign = MP_ZPOS; + a.sign = MP_ZPOS; + mp_gcd(&a, &b, &c); + if (mp_cmp_d(&c, 1) != 0) continue; + if (mp_cmp_d(&b, 1) == 0) continue; + mp_invmod(&a, &b, &c); + printf("invmod\n"); + mp_to64(&a, buf); + printf("%s\n", buf); + mp_to64(&b, buf); + printf("%s\n", buf); + mp_to64(&c, buf); + printf("%s\n", buf); + } else if (n == 11) { + rand_num(&a); + mp_mul_2(&a, &a); + mp_div_2(&a, &b); + printf("div2\n"); + mp_to64(&a, buf); + printf("%s\n", buf); + mp_to64(&b, buf); + printf("%s\n", buf); + } else if (n == 12) { + rand_num2(&a); + mp_mul_2(&a, &b); + printf("mul2\n"); + mp_to64(&a, buf); + printf("%s\n", buf); + mp_to64(&b, buf); + printf("%s\n", buf); + } else if (n == 13) { + rand_num2(&a); + tmp = abs(rand()) & THE_MASK; + mp_add_d(&a, tmp, &b); + printf("add_d\n"); + mp_to64(&a, buf); + printf("%s\n%d\n", buf, tmp); + mp_to64(&b, buf); + printf("%s\n", buf); + } else if (n == 14) { + rand_num2(&a); + tmp = abs(rand()) & THE_MASK; + mp_sub_d(&a, tmp, &b); + printf("sub_d\n"); + mp_to64(&a, buf); + printf("%s\n%d\n", buf, tmp); + mp_to64(&b, buf); + printf("%s\n", buf); + } + } + fclose(rng); + return 0; +} + +/* $Source: /cvs/libtom/libtommath/mtest/mtest.c,v $ */ +/* $Revision: 1.2 $ */ +/* $Date: 2005/05/05 14:38:47 $ */ diff --git a/libtommath/pics/design_process.sxd b/libtommath/pics/design_process.sxd Binary files differnew file mode 100644 index 0000000..7414dbb --- /dev/null +++ b/libtommath/pics/design_process.sxd diff --git a/libtommath/pics/design_process.tif b/libtommath/pics/design_process.tif Binary files differnew file mode 100644 index 0000000..4a0c012 --- /dev/null +++ b/libtommath/pics/design_process.tif diff --git a/libtommath/pics/expt_state.sxd b/libtommath/pics/expt_state.sxd Binary files differnew file mode 100644 index 0000000..6518404 --- /dev/null +++ b/libtommath/pics/expt_state.sxd diff --git a/libtommath/pics/expt_state.tif b/libtommath/pics/expt_state.tif Binary files differnew file mode 100644 index 0000000..cb06e8e --- /dev/null +++ b/libtommath/pics/expt_state.tif diff --git a/libtommath/pics/makefile b/libtommath/pics/makefile new file mode 100644 index 0000000..3ecb02f --- /dev/null +++ b/libtommath/pics/makefile @@ -0,0 +1,35 @@ +# makes the images... yeah + +default: pses + +design_process.ps: design_process.tif + tiff2ps -s -e design_process.tif > design_process.ps + +sliding_window.ps: sliding_window.tif + tiff2ps -s -e sliding_window.tif > sliding_window.ps + +expt_state.ps: expt_state.tif + tiff2ps -s -e expt_state.tif > expt_state.ps + +primality.ps: primality.tif + tiff2ps -s -e primality.tif > primality.ps + +design_process.pdf: design_process.ps + epstopdf design_process.ps + +sliding_window.pdf: sliding_window.ps + epstopdf sliding_window.ps + +expt_state.pdf: expt_state.ps + epstopdf expt_state.ps + +primality.pdf: primality.ps + epstopdf primality.ps + + +pses: sliding_window.ps expt_state.ps primality.ps design_process.ps +pdfes: sliding_window.pdf expt_state.pdf primality.pdf design_process.pdf + +clean: + rm -rf *.ps *.pdf .xvpics +
\ No newline at end of file diff --git a/libtommath/pics/primality.tif b/libtommath/pics/primality.tif Binary files differnew file mode 100644 index 0000000..76d6be3 --- /dev/null +++ b/libtommath/pics/primality.tif diff --git a/libtommath/pics/radix.sxd b/libtommath/pics/radix.sxd Binary files differnew file mode 100644 index 0000000..b9eb9a0 --- /dev/null +++ b/libtommath/pics/radix.sxd diff --git a/libtommath/pics/sliding_window.sxd b/libtommath/pics/sliding_window.sxd Binary files differnew file mode 100644 index 0000000..91e7c0d --- /dev/null +++ b/libtommath/pics/sliding_window.sxd diff --git a/libtommath/pics/sliding_window.tif b/libtommath/pics/sliding_window.tif Binary files differnew file mode 100644 index 0000000..bb4cb96 --- /dev/null +++ b/libtommath/pics/sliding_window.tif diff --git a/libtommath/poster.out b/libtommath/poster.out new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libtommath/poster.out diff --git a/libtommath/poster.tex b/libtommath/poster.tex new file mode 100644 index 0000000..e7388f4 --- /dev/null +++ b/libtommath/poster.tex @@ -0,0 +1,35 @@ +\documentclass[landscape,11pt]{article} +\usepackage{amsmath, amssymb} +\usepackage{hyperref} +\begin{document} +\hspace*{-3in} +\begin{tabular}{llllll} +$c = a + b$ & {\tt mp\_add(\&a, \&b, \&c)} & $b = 2a$ & {\tt mp\_mul\_2(\&a, \&b)} & \\ +$c = a - b$ & {\tt mp\_sub(\&a, \&b, \&c)} & $b = a/2$ & {\tt mp\_div\_2(\&a, \&b)} & \\ +$c = ab $ & {\tt mp\_mul(\&a, \&b, \&c)} & $c = 2^ba$ & {\tt mp\_mul\_2d(\&a, b, \&c)} \\ +$b = a^2 $ & {\tt mp\_sqr(\&a, \&b)} & $c = a/2^b, d = a \mod 2^b$ & {\tt mp\_div\_2d(\&a, b, \&c, \&d)} \\ +$c = \lfloor a/b \rfloor, d = a \mod b$ & {\tt mp\_div(\&a, \&b, \&c, \&d)} & $c = a \mod 2^b $ & {\tt mp\_mod\_2d(\&a, b, \&c)} \\ + && \\ +$a = b $ & {\tt mp\_set\_int(\&a, b)} & $c = a \vee b$ & {\tt mp\_or(\&a, \&b, \&c)} \\ +$b = a $ & {\tt mp\_copy(\&a, \&b)} & $c = a \wedge b$ & {\tt mp\_and(\&a, \&b, \&c)} \\ + && $c = a \oplus b$ & {\tt mp\_xor(\&a, \&b, \&c)} \\ + & \\ +$b = -a $ & {\tt mp\_neg(\&a, \&b)} & $d = a + b \mod c$ & {\tt mp\_addmod(\&a, \&b, \&c, \&d)} \\ +$b = |a| $ & {\tt mp\_abs(\&a, \&b)} & $d = a - b \mod c$ & {\tt mp\_submod(\&a, \&b, \&c, \&d)} \\ + && $d = ab \mod c$ & {\tt mp\_mulmod(\&a, \&b, \&c, \&d)} \\ +Compare $a$ and $b$ & {\tt mp\_cmp(\&a, \&b)} & $c = a^2 \mod b$ & {\tt mp\_sqrmod(\&a, \&b, \&c)} \\ +Is Zero? & {\tt mp\_iszero(\&a)} & $c = a^{-1} \mod b$ & {\tt mp\_invmod(\&a, \&b, \&c)} \\ +Is Even? & {\tt mp\_iseven(\&a)} & $d = a^b \mod c$ & {\tt mp\_exptmod(\&a, \&b, \&c, \&d)} \\ +Is Odd ? & {\tt mp\_isodd(\&a)} \\ +&\\ +$\vert \vert a \vert \vert$ & {\tt mp\_unsigned\_bin\_size(\&a)} & $res$ = 1 if $a$ prime to $t$ rounds? & {\tt mp\_prime\_is\_prime(\&a, t, \&res)} \\ +$buf \leftarrow a$ & {\tt mp\_to\_unsigned\_bin(\&a, buf)} & Next prime after $a$ to $t$ rounds. & {\tt mp\_prime\_next\_prime(\&a, t, bbs\_style)} \\ +$a \leftarrow buf[0..len-1]$ & {\tt mp\_read\_unsigned\_bin(\&a, buf, len)} \\ +&\\ +$b = \sqrt{a}$ & {\tt mp\_sqrt(\&a, \&b)} & $c = \mbox{gcd}(a, b)$ & {\tt mp\_gcd(\&a, \&b, \&c)} \\ +$c = a^{1/b}$ & {\tt mp\_n\_root(\&a, b, \&c)} & $c = \mbox{lcm}(a, b)$ & {\tt mp\_lcm(\&a, \&b, \&c)} \\ +&\\ +Greater Than & MP\_GT & Equal To & MP\_EQ \\ +Less Than & MP\_LT & Bits per digit & DIGIT\_BIT \\ +\end{tabular} +\end{document} diff --git a/libtommath/pre_gen/mpi.c b/libtommath/pre_gen/mpi.c new file mode 100644 index 0000000..f651138 --- /dev/null +++ b/libtommath/pre_gen/mpi.c @@ -0,0 +1,9514 @@ +/* Start: bn_error.c */ +#include <tommath.h> +#ifdef BN_ERROR_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +static const struct { + int code; + char *msg; +} msgs[] = { + { MP_OKAY, "Successful" }, + { MP_MEM, "Out of heap" }, + { MP_VAL, "Value out of range" } +}; + +/* return a char * string for a given code */ +char *mp_error_to_string(int code) +{ + int x; + + /* scan the lookup table for the given message */ + for (x = 0; x < (int)(sizeof(msgs) / sizeof(msgs[0])); x++) { + if (msgs[x].code == code) { + return msgs[x].msg; + } + } + + /* generic reply for invalid code */ + return "Invalid error code"; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_error.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_error.c */ + +/* Start: bn_fast_mp_invmod.c */ +#include <tommath.h> +#ifdef BN_FAST_MP_INVMOD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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 + */ +int fast_mp_invmod (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int x, y, u, v, B, D; + int res, neg; + + /* 2. [modified] b must be odd */ + if (mp_iseven (b) == 1) { + return MP_VAL; + } + + /* init all our temps */ + if ((res = mp_init_multi(&x, &y, &u, &v, &B, &D, NULL)) != MP_OKAY) { + return res; + } + + /* x == modulus, y == value to invert */ + if ((res = mp_copy (b, &x)) != MP_OKAY) { + goto LBL_ERR; + } + + /* we need y = |a| */ + if ((res = mp_mod (a, b, &y)) != MP_OKAY) { + goto LBL_ERR; + } + + /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ + if ((res = mp_copy (&x, &u)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_copy (&y, &v)) != MP_OKAY) { + goto LBL_ERR; + } + mp_set (&D, 1); + +top: + /* 4. while u is even do */ + while (mp_iseven (&u) == 1) { + /* 4.1 u = u/2 */ + if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { + goto LBL_ERR; + } + /* 4.2 if B is odd then */ + if (mp_isodd (&B) == 1) { + if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } + /* B = B/2 */ + if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* 5. while v is even do */ + while (mp_iseven (&v) == 1) { + /* 5.1 v = v/2 */ + if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { + goto LBL_ERR; + } + /* 5.2 if D is odd then */ + if (mp_isodd (&D) == 1) { + /* D = (D-x)/2 */ + if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + /* D = D/2 */ + if ((res = 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 ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } else { + /* v - v - u, D = D - B */ + if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* if not zero goto step 4 */ + if (mp_iszero (&u) == 0) { + goto top; + } + + /* now a = C, b = D, gcd == g*v */ + + /* if v != 1 then there is no inverse */ + if (mp_cmp_d (&v, 1) != MP_EQ) { + res = MP_VAL; + goto LBL_ERR; + } + + /* b is now the inverse */ + neg = a->sign; + while (D.sign == MP_NEG) { + if ((res = mp_add (&D, b, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + mp_exch (&D, c); + c->sign = neg; + res = MP_OKAY; + +LBL_ERR:mp_clear_multi (&x, &y, &u, &v, &B, &D, NULL); + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_fast_mp_invmod.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_fast_mp_invmod.c */ + +/* Start: bn_fast_mp_montgomery_reduce.c */ +#include <tommath.h> +#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* computes xR**-1 == x (mod N) via Montgomery Reduction + * + * This is an optimized implementation of montgomery_reduce + * which uses the comba method to quickly calculate the columns of the + * reduction. + * + * Based on Algorithm 14.32 on pp.601 of HAC. +*/ +int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho) +{ + int ix, res, olduse; + mp_word W[MP_WARRAY]; + + /* get old used count */ + olduse = x->used; + + /* grow a as required */ + if (x->alloc < n->used + 1) { + if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) { + return res; + } + } + + /* first we have to get the digits of the input into + * an array of double precision words W[...] + */ + { + register mp_word *_W; + register 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] */ + for (; ix < n->used * 2 + 1; ix++) { + *_W++ = 0; + } + } + + /* 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) + */ + register mp_digit mu; + mu = (mp_digit) (((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 + */ + { + register int iy; + register mp_digit *tmpn; + register 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) DIGIT_BIT); + } + + /* now we have to propagate the carries and + * shift the words downward [all those least + * significant digits we zeroed]. + */ + { + register mp_digit *tmpx; + register 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); + } + + /* 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++ = (mp_digit)(*_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 + */ + for (; ix < olduse; ix++) { + *tmpx++ = 0; + } + } + + /* 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 + +/* $Source: /cvs/libtom/libtommath/bn_fast_mp_montgomery_reduce.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_fast_mp_montgomery_reduce.c */ + +/* Start: bn_fast_s_mp_mul_digs.c */ +#include <tommath.h> +#ifdef BN_FAST_S_MP_MUL_DIGS_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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. + * + */ +int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + int olduse, res, pa, ix, iz; + mp_digit W[MP_WARRAY]; + register mp_word _W; + + /* grow the destination as required */ + if (c->alloc < digs) { + if ((res = mp_grow (c, digs)) != MP_OKAY) { + return res; + } + } + + /* number of output digits to produce */ + pa = 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 = 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 = 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)DIGIT_BIT); + } + + /* setup dest */ + olduse = c->used; + c->used = pa; + + { + register mp_digit *tmpc; + tmpc = c->dp; + for (ix = 0; ix < pa+1; ix++) { + /* now extract the previous digit [below the carry] */ + *tmpc++ = W[ix]; + } + + /* clear unused digits [that existed in the old copy of c] */ + for (; ix < olduse; ix++) { + *tmpc++ = 0; + } + } + mp_clamp (c); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_fast_s_mp_mul_digs.c,v $ */ +/* $Revision: 1.7 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_fast_s_mp_mul_digs.c */ + +/* Start: bn_fast_s_mp_mul_high_digs.c */ +#include <tommath.h> +#ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* this is a modified version of fast_s_mul_digs that only produces + * output digits *above* digs. See the comments for fast_s_mul_digs + * 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. + */ +int fast_s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + int olduse, res, pa, ix, iz; + mp_digit W[MP_WARRAY]; + mp_word _W; + + /* grow the destination as required */ + pa = a->used + b->used; + if (c->alloc < pa) { + if ((res = mp_grow (c, pa)) != MP_OKAY) { + return res; + } + } + + /* 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 = 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 = 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)DIGIT_BIT); + } + + /* setup dest */ + olduse = c->used; + c->used = pa; + + { + register 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] */ + for (; ix < olduse; ix++) { + *tmpc++ = 0; + } + } + mp_clamp (c); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_fast_s_mp_mul_high_digs.c,v $ */ +/* $Revision: 1.5 $ */ +/* $Date: 2006/11/14 03:46:25 $ */ + +/* End: bn_fast_s_mp_mul_high_digs.c */ + +/* Start: bn_fast_s_mp_sqr.c */ +#include <tommath.h> +#ifdef BN_FAST_S_MP_SQR_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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. +*/ + +int fast_s_mp_sqr (mp_int * a, mp_int * b) +{ + int olduse, res, pa, ix, iz; + mp_digit W[MP_WARRAY], *tmpx; + mp_word W1; + + /* grow the destination as required */ + pa = a->used + a->used; + if (b->alloc < pa) { + if ((res = mp_grow (b, pa)) != MP_OKAY) { + return res; + } + } + + /* 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 = 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 = 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 = 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 ((ix&1) == 0) { + _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)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] */ + for (; ix < olduse; ix++) { + *tmpb++ = 0; + } + } + mp_clamp (b); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_fast_s_mp_sqr.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_fast_s_mp_sqr.c */ + +/* Start: bn_mp_2expt.c */ +#include <tommath.h> +#ifdef BN_MP_2EXPT_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* computes a = 2**b + * + * Simple algorithm which zeroes the int, grows it then just sets one bit + * as required. + */ +int +mp_2expt (mp_int * a, int b) +{ + int res; + + /* zero a as per default */ + mp_zero (a); + + /* grow a to accomodate the single bit */ + if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) { + return res; + } + + /* set the used count of where the bit will go */ + a->used = b / DIGIT_BIT + 1; + + /* put the single bit in its place */ + a->dp[b / DIGIT_BIT] = ((mp_digit)1) << (b % DIGIT_BIT); + + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_2expt.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_2expt.c */ + +/* Start: bn_mp_abs.c */ +#include <tommath.h> +#ifdef BN_MP_ABS_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* b = |a| + * + * Simple function copies the input and fixes the sign to positive + */ +int +mp_abs (mp_int * a, mp_int * b) +{ + int res; + + /* copy a to b */ + if (a != b) { + if ((res = mp_copy (a, b)) != MP_OKAY) { + return res; + } + } + + /* force the sign of b to positive */ + b->sign = MP_ZPOS; + + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_abs.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_abs.c */ + +/* Start: bn_mp_add.c */ +#include <tommath.h> +#ifdef BN_MP_ADD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* high level addition (handles signs) */ +int mp_add (mp_int * a, mp_int * b, mp_int * c) +{ + int sa, sb, res; + + /* 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; + res = 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; + res = s_mp_sub (b, a, c); + } else { + c->sign = sa; + res = s_mp_sub (a, b, c); + } + } + return res; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_add.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_add.c */ + +/* Start: bn_mp_add_d.c */ +#include <tommath.h> +#ifdef BN_MP_ADD_D_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* single digit addition */ +int +mp_add_d (mp_int * a, mp_digit b, mp_int * c) +{ + int res, ix, oldused; + mp_digit *tmpa, *tmpc, mu; + + /* grow c as required */ + if (c->alloc < a->used + 1) { + if ((res = mp_grow(c, a->used + 1)) != MP_OKAY) { + return res; + } + } + + /* if a is negative and |a| >= b, call c = |a| - b */ + if (a->sign == MP_NEG && (a->used > 1 || a->dp[0] >= b)) { + /* temporarily fix sign of a */ + a->sign = MP_ZPOS; + + /* c = |a| - b */ + res = mp_sub_d(a, b, c); + + /* fix sign */ + a->sign = c->sign = MP_NEG; + + /* clamp */ + mp_clamp(c); + + return res; + } + + /* old number of used digits in c */ + oldused = c->used; + + /* sign always positive */ + c->sign = MP_ZPOS; + + /* source alias */ + tmpa = a->dp; + + /* destination alias */ + tmpc = c->dp; + + /* if a is positive */ + if (a->sign == MP_ZPOS) { + /* 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; + } + /* 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; + } + + /* now zero to oldused */ + while (ix++ < oldused) { + *tmpc++ = 0; + } + mp_clamp(c); + + return MP_OKAY; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_add_d.c,v $ */ +/* $Revision: 1.4 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_add_d.c */ + +/* Start: bn_mp_addmod.c */ +#include <tommath.h> +#ifdef BN_MP_ADDMOD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* d = a + b (mod c) */ +int +mp_addmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + int res; + mp_int t; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_add (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, c, d); + mp_clear (&t); + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_addmod.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_addmod.c */ + +/* Start: bn_mp_and.c */ +#include <tommath.h> +#ifdef BN_MP_AND_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* AND two ints together */ +int +mp_and (mp_int * a, mp_int * b, mp_int * c) +{ + int res, ix, px; + mp_int t, *x; + + if (a->used > b->used) { + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + px = b->used; + x = b; + } else { + if ((res = mp_init_copy (&t, b)) != MP_OKAY) { + return res; + } + px = a->used; + x = a; + } + + for (ix = 0; ix < px; ix++) { + t.dp[ix] &= x->dp[ix]; + } + + /* zero digits above the last from the smallest mp_int */ + for (; ix < t.used; ix++) { + t.dp[ix] = 0; + } + + mp_clamp (&t); + mp_exch (c, &t); + mp_clear (&t); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_and.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_and.c */ + +/* Start: bn_mp_clamp.c */ +#include <tommath.h> +#ifdef BN_MP_CLAMP_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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] == 0) { + --(a->used); + } + + /* reset the sign flag if used == 0 */ + if (a->used == 0) { + a->sign = MP_ZPOS; + } +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_clamp.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_clamp.c */ + +/* Start: bn_mp_clear.c */ +#include <tommath.h> +#ifdef BN_MP_CLEAR_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* clear one (frees) */ +void +mp_clear (mp_int * a) +{ + int i; + + /* only do anything if a hasn't been freed previously */ + if (a->dp != NULL) { + /* first zero the digits */ + for (i = 0; i < a->used; i++) { + a->dp[i] = 0; + } + + /* free ram */ + XFREE(a->dp); + + /* reset members to make debugging easier */ + a->dp = NULL; + a->alloc = a->used = 0; + a->sign = MP_ZPOS; + } +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_clear.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_clear.c */ + +/* Start: bn_mp_clear_multi.c */ +#include <tommath.h> +#ifdef BN_MP_CLEAR_MULTI_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ +#include <stdarg.h> + +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 + +/* $Source: /cvs/libtom/libtommath/bn_mp_clear_multi.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_clear_multi.c */ + +/* Start: bn_mp_cmp.c */ +#include <tommath.h> +#ifdef BN_MP_CMP_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* compare two ints (signed)*/ +int +mp_cmp (mp_int * a, 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 + +/* $Source: /cvs/libtom/libtommath/bn_mp_cmp.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_cmp.c */ + +/* Start: bn_mp_cmp_d.c */ +#include <tommath.h> +#ifdef BN_MP_CMP_D_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* compare a digit */ +int mp_cmp_d(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 + +/* $Source: /cvs/libtom/libtommath/bn_mp_cmp_d.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_cmp_d.c */ + +/* Start: bn_mp_cmp_mag.c */ +#include <tommath.h> +#ifdef BN_MP_CMP_MAG_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* compare maginitude of two ints (unsigned) */ +int mp_cmp_mag (mp_int * a, mp_int * b) +{ + int n; + 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 + +/* $Source: /cvs/libtom/libtommath/bn_mp_cmp_mag.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_cmp_mag.c */ + +/* Start: bn_mp_cnt_lsb.c */ +#include <tommath.h> +#ifdef BN_MP_CNT_LSB_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +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(mp_int *a) +{ + int x; + mp_digit q, qq; + + /* easy out */ + if (mp_iszero(a) == 1) { + return 0; + } + + /* scan lower digits until non-zero */ + for (x = 0; x < a->used && a->dp[x] == 0; x++); + q = a->dp[x]; + x *= DIGIT_BIT; + + /* now scan this digit until a 1 is found */ + if ((q & 1) == 0) { + do { + qq = q & 15; + x += lnz[qq]; + q >>= 4; + } while (qq == 0); + } + return x; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_cnt_lsb.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_cnt_lsb.c */ + +/* Start: bn_mp_copy.c */ +#include <tommath.h> +#ifdef BN_MP_COPY_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* copy, b = a */ +int +mp_copy (mp_int * a, mp_int * b) +{ + int res, n; + + /* if dst == src do nothing */ + if (a == b) { + return MP_OKAY; + } + + /* grow dest */ + if (b->alloc < a->used) { + if ((res = mp_grow (b, a->used)) != MP_OKAY) { + return res; + } + } + + /* zero b and copy the parameters over */ + { + register mp_digit *tmpa, *tmpb; + + /* 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 */ + for (; n < b->used; n++) { + *tmpb++ = 0; + } + } + + /* copy used count and sign */ + b->used = a->used; + b->sign = a->sign; + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_copy.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_copy.c */ + +/* Start: bn_mp_count_bits.c */ +#include <tommath.h> +#ifdef BN_MP_COUNT_BITS_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* returns the number of bits in an int */ +int +mp_count_bits (mp_int * a) +{ + int r; + mp_digit q; + + /* shortcut */ + if (a->used == 0) { + return 0; + } + + /* get number of digits and add that */ + r = (a->used - 1) * DIGIT_BIT; + + /* take the last digit and count the bits in it */ + q = a->dp[a->used - 1]; + while (q > ((mp_digit) 0)) { + ++r; + q >>= ((mp_digit) 1); + } + return r; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_count_bits.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_count_bits.c */ + +/* Start: bn_mp_div.c */ +#include <tommath.h> +#ifdef BN_MP_DIV_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +#ifdef BN_MP_DIV_SMALL + +/* slower bit-bang division... also smaller */ +int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + mp_int ta, tb, tq, q; + int res, n, n2; + + /* is divisor zero ? */ + if (mp_iszero (b) == 1) { + return MP_VAL; + } + + /* if a < b then q=0, r = a */ + if (mp_cmp_mag (a, b) == MP_LT) { + if (d != NULL) { + res = mp_copy (a, d); + } else { + res = MP_OKAY; + } + if (c != NULL) { + mp_zero (c); + } + return res; + } + + /* init our temps */ + if ((res = mp_init_multi(&ta, &tb, &tq, &q, NULL) != MP_OKAY)) { + return res; + } + + + mp_set(&tq, 1); + n = mp_count_bits(a) - mp_count_bits(b); + if (((res = mp_abs(a, &ta)) != MP_OKAY) || + ((res = mp_abs(b, &tb)) != MP_OKAY) || + ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) || + ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) { + goto LBL_ERR; + } + + while (n-- >= 0) { + if (mp_cmp(&tb, &ta) != MP_GT) { + if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) || + ((res = mp_add(&q, &tq, &q)) != MP_OKAY)) { + goto LBL_ERR; + } + } + if (((res = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) || + ((res = 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_iszero(c) == MP_YES) ? MP_ZPOS : n2; + } + if (d != NULL) { + mp_exch(d, &ta); + d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n; + } +LBL_ERR: + mp_clear_multi(&ta, &tb, &tq, &q, NULL); + return res; +} + +#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. +*/ +int mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + mp_int q, x, y, t1, t2; + int res, n, t, i, norm, neg; + + /* is divisor zero ? */ + if (mp_iszero (b) == 1) { + return MP_VAL; + } + + /* if a < b then q=0, r = a */ + if (mp_cmp_mag (a, b) == MP_LT) { + if (d != NULL) { + res = mp_copy (a, d); + } else { + res = MP_OKAY; + } + if (c != NULL) { + mp_zero (c); + } + return res; + } + + if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) { + return res; + } + q.used = a->used + 2; + + if ((res = mp_init (&t1)) != MP_OKAY) { + goto LBL_Q; + } + + if ((res = mp_init (&t2)) != MP_OKAY) { + goto LBL_T1; + } + + if ((res = mp_init_copy (&x, a)) != MP_OKAY) { + goto LBL_T2; + } + + if ((res = 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**DIGIT_BIT] */ + norm = mp_count_bits(&y) % DIGIT_BIT; + if (norm < (int)(DIGIT_BIT-1)) { + norm = (DIGIT_BIT-1) - norm; + if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) { + goto LBL_Y; + } + if ((res = 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} } */ + if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b**{n-t} */ + goto LBL_Y; + } + + while (mp_cmp (&x, &y) != MP_LT) { + ++(q.dp[n - t]); + if ((res = 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) << DIGIT_BIT) - 1); + } else { + mp_word tmp; + tmp = ((mp_word) x.dp[i]) << ((mp_word) 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] + 1) & MP_MASK; + do { + q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK; + + /* find left hand */ + mp_zero (&t1); + t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1]; + t1.dp[1] = y.dp[t]; + t1.used = 2; + if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) { + goto LBL_Y; + } + + /* find right hand */ + t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2]; + t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1]; + 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 ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) { + goto LBL_Y; + } + + if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { + goto LBL_Y; + } + + if ((res = 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 ((res = mp_copy (&y, &t1)) != MP_OKAY) { + goto LBL_Y; + } + if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { + goto LBL_Y; + } + if ((res = 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) { + mp_div_2d (&x, norm, &x, NULL); + mp_exch (&x, d); + } + + res = 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 res; +} + +#endif + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_div.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_div.c */ + +/* Start: bn_mp_div_2.c */ +#include <tommath.h> +#ifdef BN_MP_DIV_2_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* b = a/2 */ +int mp_div_2(mp_int * a, mp_int * b) +{ + int x, res, oldused; + + /* copy */ + if (b->alloc < a->used) { + if ((res = mp_grow (b, a->used)) != MP_OKAY) { + return res; + } + } + + oldused = b->used; + b->used = a->used; + { + register mp_digit r, rr, *tmpa, *tmpb; + + /* 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 & 1; + + /* shift the current digit, add in carry and store */ + *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1)); + + /* forward carry to next iteration */ + r = rr; + } + + /* zero excess digits */ + tmpb = b->dp + b->used; + for (x = b->used; x < oldused; x++) { + *tmpb++ = 0; + } + } + b->sign = a->sign; + mp_clamp (b); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_div_2.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_div_2.c */ + +/* Start: bn_mp_div_2d.c */ +#include <tommath.h> +#ifdef BN_MP_DIV_2D_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* shift right by a certain bit count (store quotient in c, optional remainder in d) */ +int mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d) +{ + mp_digit D, r, rr; + int x, res; + mp_int t; + + + /* if the shift count is <= 0 then we do no work */ + if (b <= 0) { + res = mp_copy (a, c); + if (d != NULL) { + mp_zero (d); + } + return res; + } + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + /* get the remainder */ + if (d != NULL) { + if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + } + + /* copy */ + if ((res = mp_copy (a, c)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + /* shift by as many digits in the bit count */ + if (b >= (int)DIGIT_BIT) { + mp_rshd (c, b / DIGIT_BIT); + } + + /* shift any bit count < DIGIT_BIT */ + D = (mp_digit) (b % DIGIT_BIT); + if (D != 0) { + register mp_digit *tmpc, mask, shift; + + /* mask */ + mask = (((mp_digit)1) << D) - 1; + + /* shift for lsb */ + shift = 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); + if (d != NULL) { + mp_exch (&t, d); + } + mp_clear (&t); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_div_2d.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_div_2d.c */ + +/* Start: bn_mp_div_3.c */ +#include <tommath.h> +#ifdef BN_MP_DIV_3_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* divide by three (based on routine from MPI and the GMP manual) */ +int +mp_div_3 (mp_int * a, mp_int *c, mp_digit * d) +{ + mp_int q; + mp_word w, t; + mp_digit b; + int res, ix; + + /* b = 2**DIGIT_BIT / 3 */ + b = (((mp_word)1) << ((mp_word)DIGIT_BIT)) / ((mp_word)3); + + if ((res = mp_init_size(&q, a->used)) != MP_OKAY) { + return res; + } + + q.used = a->used; + q.sign = a->sign; + w = 0; + for (ix = a->used - 1; ix >= 0; ix--) { + w = (w << ((mp_word)DIGIT_BIT)) | ((mp_word)a->dp[ix]); + + if (w >= 3) { + /* multiply w by [1/3] */ + t = (w * ((mp_word)b)) >> ((mp_word)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 >= 3) { + t += 1; + w -= 3; + } + } 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 res; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_div_3.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_div_3.c */ + +/* Start: bn_mp_div_d.c */ +#include <tommath.h> +#ifdef BN_MP_DIV_D_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +static int s_is_power_of_two(mp_digit b, int *p) +{ + int x; + + for (x = 1; x < DIGIT_BIT; x++) { + if (b == (((mp_digit)1)<<x)) { + *p = x; + return 1; + } + } + return 0; +} + +/* single digit division (based on routine from MPI) */ +int mp_div_d (mp_int * a, mp_digit b, mp_int * c, mp_digit * d) +{ + mp_int q; + mp_word w; + mp_digit t; + int res, ix; + + /* cannot divide by zero */ + if (b == 0) { + return MP_VAL; + } + + /* quick outs */ + if (b == 1 || mp_iszero(a) == 1) { + if (d != NULL) { + *d = 0; + } + if (c != NULL) { + return mp_copy(a, c); + } + return MP_OKAY; + } + + /* power of two ? */ + if (s_is_power_of_two(b, &ix) == 1) { + if (d != NULL) { + *d = a->dp[0] & ((((mp_digit)1)<<ix) - 1); + } + if (c != NULL) { + return mp_div_2d(a, ix, c, NULL); + } + return MP_OKAY; + } + +#ifdef BN_MP_DIV_3_C + /* three? */ + if (b == 3) { + return mp_div_3(a, c, d); + } +#endif + + /* no easy answer [c'est la vie]. Just division */ + if ((res = mp_init_size(&q, a->used)) != MP_OKAY) { + return res; + } + + q.used = a->used; + q.sign = a->sign; + w = 0; + for (ix = a->used - 1; ix >= 0; ix--) { + w = (w << ((mp_word)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] = (mp_digit)t; + } + + if (d != NULL) { + *d = (mp_digit)w; + } + + if (c != NULL) { + mp_clamp(&q); + mp_exch(&q, c); + } + mp_clear(&q); + + return res; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_div_d.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_div_d.c */ + +/* Start: bn_mp_dr_is_modulus.c */ +#include <tommath.h> +#ifdef BN_MP_DR_IS_MODULUS_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* determines if a number is a valid DR modulus */ +int mp_dr_is_modulus(mp_int *a) +{ + int ix; + + /* must be at least two digits */ + if (a->used < 2) { + return 0; + } + + /* 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 0; + } + } + return 1; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_dr_is_modulus.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_dr_is_modulus.c */ + +/* Start: bn_mp_dr_reduce.c */ +#include <tommath.h> +#ifdef BN_MP_DR_REDUCE_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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 + */ +int +mp_dr_reduce (mp_int * x, mp_int * n, mp_digit k) +{ + int err, 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)DIGIT_BIT)); + } + + /* set final carry */ + *tmpx1++ = mu; + + /* zero words above m */ + for (i = m + 1; i < x->used; i++) { + *tmpx1++ = 0; + } + + /* 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) { + s_mp_sub(x, n, x); + goto top; + } + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_dr_reduce.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_dr_reduce.c */ + +/* Start: bn_mp_dr_setup.c */ +#include <tommath.h> +#ifdef BN_MP_DR_SETUP_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* determines the setup value */ +void mp_dr_setup(mp_int *a, mp_digit *d) +{ + /* the casts are required if DIGIT_BIT is one less than + * the number of bits in a mp_digit [e.g. DIGIT_BIT==31] + */ + *d = (mp_digit)((((mp_word)1) << ((mp_word)DIGIT_BIT)) - + ((mp_word)a->dp[0])); +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_dr_setup.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_dr_setup.c */ + +/* Start: bn_mp_exch.c */ +#include <tommath.h> +#ifdef BN_MP_EXCH_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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 + +/* $Source: /cvs/libtom/libtommath/bn_mp_exch.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_exch.c */ + +/* Start: bn_mp_expt_d.c */ +#include <tommath.h> +#ifdef BN_MP_EXPT_D_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* calculate c = a**b using a square-multiply algorithm */ +int mp_expt_d (mp_int * a, mp_digit b, mp_int * c) +{ + int res, x; + mp_int g; + + if ((res = mp_init_copy (&g, a)) != MP_OKAY) { + return res; + } + + /* set initial result */ + mp_set (c, 1); + + for (x = 0; x < (int) DIGIT_BIT; x++) { + /* square */ + if ((res = mp_sqr (c, c)) != MP_OKAY) { + mp_clear (&g); + return res; + } + + /* if the bit is set multiply */ + if ((b & (mp_digit) (((mp_digit)1) << (DIGIT_BIT - 1))) != 0) { + if ((res = mp_mul (c, &g, c)) != MP_OKAY) { + mp_clear (&g); + return res; + } + } + + /* shift to next bit */ + b <<= 1; + } + + mp_clear (&g); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_expt_d.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_expt_d.c */ + +/* Start: bn_mp_exptmod.c */ +#include <tommath.h> +#ifdef BN_MP_EXPTMOD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + + +/* 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) + */ +int mp_exptmod (mp_int * G, mp_int * X, 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) { +#ifdef BN_MP_INVMOD_C + mp_int tmpG, tmpX; + int err; + + /* first compute 1/G mod P */ + if ((err = mp_init(&tmpG)) != MP_OKAY) { + return err; + } + if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) { + mp_clear(&tmpG); + return err; + } + + /* now get |X| */ + if ((err = mp_init(&tmpX)) != MP_OKAY) { + mp_clear(&tmpG); + return err; + } + if ((err = mp_abs(X, &tmpX)) != MP_OKAY) { + mp_clear_multi(&tmpG, &tmpX, NULL); + return err; + } + + /* and now compute (1/G)**|X| instead of G**X [X < 0] */ + err = mp_exptmod(&tmpG, &tmpX, P, Y); + mp_clear_multi(&tmpG, &tmpX, NULL); + return err; +#else + /* no invmod */ + return MP_VAL; +#endif + } + +/* modified diminished radix reduction */ +#if defined(BN_MP_REDUCE_IS_2K_L_C) && defined(BN_MP_REDUCE_2K_L_C) && defined(BN_S_MP_EXPTMOD_C) + if (mp_reduce_is_2k_l(P) == MP_YES) { + return s_mp_exptmod(G, X, P, Y, 1); + } +#endif + +#ifdef BN_MP_DR_IS_MODULUS_C + /* is it a DR modulus? */ + dr = mp_dr_is_modulus(P); +#else + /* default to no */ + dr = 0; +#endif + +#ifdef BN_MP_REDUCE_IS_2K_C + /* if not, is it a unrestricted DR modulus? */ + if (dr == 0) { + dr = mp_reduce_is_2k(P) << 1; + } +#endif + + /* if the modulus is odd or dr != 0 use the montgomery method */ +#ifdef BN_MP_EXPTMOD_FAST_C + if (mp_isodd (P) == 1 || dr != 0) { + return mp_exptmod_fast (G, X, P, Y, dr); + } else { +#endif +#ifdef BN_S_MP_EXPTMOD_C + /* 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 +#ifdef BN_MP_EXPTMOD_FAST_C + } +#endif +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_exptmod.c,v $ */ +/* $Revision: 1.4 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_exptmod.c */ + +/* Start: bn_mp_exptmod_fast.c */ +#include <tommath.h> +#ifdef BN_MP_EXPTMOD_FAST_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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 +#else + #define TAB_SIZE 256 +#endif + +int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) +{ + mp_int M[TAB_SIZE], res; + mp_digit buf, mp; + int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + + /* 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. + */ + int (*redux)(mp_int*,mp_int*,mp_digit); + + /* 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; + } + +#ifdef MP_LOW_MEM + if (winsize > 5) { + winsize = 5; + } +#endif + + /* 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; + } + } + + /* determine and setup reduction code */ + if (redmode == 0) { +#ifdef BN_MP_MONTGOMERY_SETUP_C + /* now setup montgomery */ + if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) { + goto LBL_M; + } +#else + err = MP_VAL; + goto LBL_M; +#endif + + /* automatically pick the comba one if available (saves quite a few calls/ifs) */ +#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C + if (((P->used * 2 + 1) < MP_WARRAY) && + P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + redux = fast_mp_montgomery_reduce; + } else +#endif + { +#ifdef BN_MP_MONTGOMERY_REDUCE_C + /* use slower baseline Montgomery method */ + redux = mp_montgomery_reduce; +#else + err = MP_VAL; + goto LBL_M; +#endif + } + } else if (redmode == 1) { +#if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C) + /* 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; +#endif + } else { +#if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C) + /* 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; +#endif + } + + /* setup result */ + if ((err = mp_init (&res)) != 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) { +#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 + + /* now set M[1] to G * R mod m */ + if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) { + goto LBL_RES; + } + } else { + mp_set(&res, 1); + 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[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_RES; + } + + for (x = 0; x < (winsize - 1); x++) { + if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&M[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)DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1; + 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 + + +/* $Source: /cvs/libtom/libtommath/bn_mp_exptmod_fast.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_exptmod_fast.c */ + +/* Start: bn_mp_exteuclid.c */ +#include <tommath.h> +#ifdef BN_MP_EXTEUCLID_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* Extended euclidean algorithm of (a, b) produces + a*u1 + b*u2 = u3 + */ +int mp_exteuclid(mp_int *a, 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; + int 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, 1); + if ((err = mp_copy(a, &u3)) != MP_OKAY) { goto _ERR; } + + /* initialize, (v1,v2,v3) = (0,1,b) */ + mp_set(&v2, 1); + if ((err = mp_copy(b, &v3)) != MP_OKAY) { goto _ERR; } + + /* loop while v3 != 0 */ + while (mp_iszero(&v3) == MP_NO) { + /* q = u3/v3 */ + if ((err = mp_div(&u3, &v3, &q, NULL)) != MP_OKAY) { goto _ERR; } + + /* (t1,t2,t3) = (u1,u2,u3) - (v1,v2,v3)q */ + if ((err = mp_mul(&v1, &q, &tmp)) != MP_OKAY) { goto _ERR; } + if ((err = mp_sub(&u1, &tmp, &t1)) != MP_OKAY) { goto _ERR; } + if ((err = mp_mul(&v2, &q, &tmp)) != MP_OKAY) { goto _ERR; } + if ((err = mp_sub(&u2, &tmp, &t2)) != MP_OKAY) { goto _ERR; } + if ((err = mp_mul(&v3, &q, &tmp)) != MP_OKAY) { goto _ERR; } + if ((err = mp_sub(&u3, &tmp, &t3)) != MP_OKAY) { goto _ERR; } + + /* (u1,u2,u3) = (v1,v2,v3) */ + if ((err = mp_copy(&v1, &u1)) != MP_OKAY) { goto _ERR; } + if ((err = mp_copy(&v2, &u2)) != MP_OKAY) { goto _ERR; } + if ((err = mp_copy(&v3, &u3)) != MP_OKAY) { goto _ERR; } + + /* (v1,v2,v3) = (t1,t2,t3) */ + if ((err = mp_copy(&t1, &v1)) != MP_OKAY) { goto _ERR; } + if ((err = mp_copy(&t2, &v2)) != MP_OKAY) { goto _ERR; } + if ((err = mp_copy(&t3, &v3)) != MP_OKAY) { goto _ERR; } + } + + /* make sure U3 >= 0 */ + if (u3.sign == MP_NEG) { + mp_neg(&u1, &u1); + mp_neg(&u2, &u2); + mp_neg(&u3, &u3); + } + + /* 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; +_ERR: mp_clear_multi(&u1, &u2, &u3, &v1, &v2, &v3, &t1, &t2, &t3, &q, &tmp, NULL); + return err; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_exteuclid.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_exteuclid.c */ + +/* Start: bn_mp_fread.c */ +#include <tommath.h> +#ifdef BN_MP_FREAD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* read a bigint from a file stream in ASCII */ +int mp_fread(mp_int *a, int radix, FILE *stream) +{ + int err, ch, neg, y; + + /* clear a */ + mp_zero(a); + + /* if first digit is - then set negative */ + ch = fgetc(stream); + if (ch == '-') { + neg = MP_NEG; + ch = fgetc(stream); + } else { + neg = MP_ZPOS; + } + + for (;;) { + /* find y in the radix map */ + for (y = 0; y < radix; y++) { + if (mp_s_rmap[y] == ch) { + break; + } + } + if (y == radix) { + break; + } + + /* shift up and add */ + if ((err = mp_mul_d(a, radix, a)) != MP_OKAY) { + return err; + } + if ((err = mp_add_d(a, y, a)) != MP_OKAY) { + return err; + } + + ch = fgetc(stream); + } + if (mp_cmp_d(a, 0) != MP_EQ) { + a->sign = neg; + } + + return MP_OKAY; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_fread.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_fread.c */ + +/* Start: bn_mp_fwrite.c */ +#include <tommath.h> +#ifdef BN_MP_FWRITE_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +int mp_fwrite(mp_int *a, int radix, FILE *stream) +{ + char *buf; + int err, len, x; + + if ((err = mp_radix_size(a, radix, &len)) != MP_OKAY) { + return err; + } + + buf = OPT_CAST(char) XMALLOC (len); + if (buf == NULL) { + return MP_MEM; + } + + if ((err = mp_toradix(a, buf, radix)) != MP_OKAY) { + XFREE (buf); + return err; + } + + for (x = 0; x < len; x++) { + if (fputc(buf[x], stream) == EOF) { + XFREE (buf); + return MP_VAL; + } + } + + XFREE (buf); + return MP_OKAY; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_fwrite.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_fwrite.c */ + +/* Start: bn_mp_gcd.c */ +#include <tommath.h> +#ifdef BN_MP_GCD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* Greatest Common Divisor using the binary method */ +int mp_gcd (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int u, v; + int k, u_lsb, v_lsb, res; + + /* either zero than gcd is the largest */ + if (mp_iszero (a) == MP_YES) { + return mp_abs (b, c); + } + if (mp_iszero (b) == MP_YES) { + return mp_abs (a, c); + } + + /* get copies of a and b we can modify */ + if ((res = mp_init_copy (&u, a)) != MP_OKAY) { + return res; + } + + if ((res = 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 = MIN(u_lsb, v_lsb); + + if (k > 0) { + /* divide the power of two out */ + if ((res = mp_div_2d(&u, k, &u, NULL)) != MP_OKAY) { + goto LBL_V; + } + + if ((res = mp_div_2d(&v, k, &v, NULL)) != MP_OKAY) { + goto LBL_V; + } + } + + /* divide any remaining factors of two out */ + if (u_lsb != k) { + if ((res = mp_div_2d(&u, u_lsb - k, &u, NULL)) != MP_OKAY) { + goto LBL_V; + } + } + + if (v_lsb != k) { + if ((res = mp_div_2d(&v, v_lsb - k, &v, NULL)) != MP_OKAY) { + goto LBL_V; + } + } + + while (mp_iszero(&v) == 0) { + /* 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 ((res = s_mp_sub(&v, &u, &v)) != MP_OKAY) { + goto LBL_V; + } + + /* Divide out all factors of two */ + if ((res = 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 ((res = mp_mul_2d (&u, k, c)) != MP_OKAY) { + goto LBL_V; + } + c->sign = MP_ZPOS; + res = MP_OKAY; +LBL_V:mp_clear (&u); +LBL_U:mp_clear (&v); + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_gcd.c,v $ */ +/* $Revision: 1.4 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_gcd.c */ + +/* Start: bn_mp_get_int.c */ +#include <tommath.h> +#ifdef BN_MP_GET_INT_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* get the lower 32-bits of an mp_int */ +unsigned long mp_get_int(mp_int * a) +{ + int i; + unsigned long res; + + if (a->used == 0) { + return 0; + } + + /* get number of digits of the lsb we have to read */ + i = MIN(a->used,(int)((sizeof(unsigned long)*CHAR_BIT+DIGIT_BIT-1)/DIGIT_BIT))-1; + + /* get most significant digit of result */ + res = DIGIT(a,i); + + while (--i >= 0) { + res = (res << DIGIT_BIT) | DIGIT(a,i); + } + + /* force result to 32-bits always so it is consistent on non 32-bit platforms */ + return res & 0xFFFFFFFFUL; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_get_int.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_get_int.c */ + +/* Start: bn_mp_grow.c */ +#include <tommath.h> +#ifdef BN_MP_GROW_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* grow as required */ +int mp_grow (mp_int * a, int size) +{ + int i; + mp_digit *tmp; + + /* if the alloc size is smaller alloc more ram */ + if (a->alloc < size) { + /* ensure there are always at least MP_PREC digits extra on top */ + size += (MP_PREC * 2) - (size % MP_PREC); + + /* 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 = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * size); + 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; + for (; i < a->alloc; i++) { + a->dp[i] = 0; + } + } + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_grow.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_grow.c */ + +/* Start: bn_mp_init.c */ +#include <tommath.h> +#ifdef BN_MP_INIT_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* init a new mp_int */ +int mp_init (mp_int * a) +{ + int i; + + /* allocate memory required and clear it */ + a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * MP_PREC); + if (a->dp == NULL) { + return MP_MEM; + } + + /* set the digits to zero */ + for (i = 0; i < MP_PREC; i++) { + a->dp[i] = 0; + } + + /* 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 + +/* $Source: /cvs/libtom/libtommath/bn_mp_init.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_init.c */ + +/* Start: bn_mp_init_copy.c */ +#include <tommath.h> +#ifdef BN_MP_INIT_COPY_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* creates "a" then copies b into it */ +int mp_init_copy (mp_int * a, mp_int * b) +{ + int res; + + if ((res = mp_init (a)) != MP_OKAY) { + return res; + } + return mp_copy (b, a); +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_init_copy.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_init_copy.c */ + +/* Start: bn_mp_init_multi.c */ +#include <tommath.h> +#ifdef BN_MP_INIT_MULTI_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ +#include <stdarg.h> + +int mp_init_multi(mp_int *mp, ...) +{ + mp_err res = 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; + + /* end the current list */ + va_end(args); + + /* now start cleaning up */ + cur_arg = mp; + va_start(clean_args, mp); + while (n--) { + mp_clear(cur_arg); + cur_arg = va_arg(clean_args, mp_int*); + } + va_end(clean_args); + res = MP_MEM; + break; + } + n++; + cur_arg = va_arg(args, mp_int*); + } + va_end(args); + return res; /* Assumed ok, if error flagged above. */ +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_init_multi.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_init_multi.c */ + +/* Start: bn_mp_init_set.c */ +#include <tommath.h> +#ifdef BN_MP_INIT_SET_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* initialize and set a digit */ +int mp_init_set (mp_int * a, mp_digit b) +{ + int err; + if ((err = mp_init(a)) != MP_OKAY) { + return err; + } + mp_set(a, b); + return err; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_init_set.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_init_set.c */ + +/* Start: bn_mp_init_set_int.c */ +#include <tommath.h> +#ifdef BN_MP_INIT_SET_INT_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* initialize and set a digit */ +int mp_init_set_int (mp_int * a, unsigned long b) +{ + int err; + if ((err = mp_init(a)) != MP_OKAY) { + return err; + } + return mp_set_int(a, b); +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_init_set_int.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_init_set_int.c */ + +/* Start: bn_mp_init_size.c */ +#include <tommath.h> +#ifdef BN_MP_INIT_SIZE_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* init an mp_init for a given size */ +int mp_init_size (mp_int * a, int size) +{ + int x; + + /* pad size so there are always extra digits */ + size += (MP_PREC * 2) - (size % MP_PREC); + + /* alloc mem */ + a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * size); + if (a->dp == NULL) { + return MP_MEM; + } + + /* set the members */ + a->used = 0; + a->alloc = size; + a->sign = MP_ZPOS; + + /* zero the digits */ + for (x = 0; x < size; x++) { + a->dp[x] = 0; + } + + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_init_size.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_init_size.c */ + +/* Start: bn_mp_invmod.c */ +#include <tommath.h> +#ifdef BN_MP_INVMOD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* hac 14.61, pp608 */ +int mp_invmod (mp_int * a, mp_int * b, mp_int * c) +{ + /* b cannot be negative */ + if (b->sign == MP_NEG || mp_iszero(b) == 1) { + return MP_VAL; + } + +#ifdef BN_FAST_MP_INVMOD_C + /* if the modulus is odd we can use a faster routine instead */ + if (mp_isodd (b) == 1) { + return fast_mp_invmod (a, b, c); + } +#endif + +#ifdef BN_MP_INVMOD_SLOW_C + return mp_invmod_slow(a, b, c); +#endif + + return MP_VAL; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_invmod.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_invmod.c */ + +/* Start: bn_mp_invmod_slow.c */ +#include <tommath.h> +#ifdef BN_MP_INVMOD_SLOW_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* hac 14.61, pp608 */ +int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int x, y, u, v, A, B, C, D; + int res; + + /* b cannot be negative */ + if (b->sign == MP_NEG || mp_iszero(b) == 1) { + return MP_VAL; + } + + /* init temps */ + if ((res = mp_init_multi(&x, &y, &u, &v, + &A, &B, &C, &D, NULL)) != MP_OKAY) { + return res; + } + + /* x = a, y = b */ + if ((res = mp_mod(a, b, &x)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_copy (b, &y)) != MP_OKAY) { + goto LBL_ERR; + } + + /* 2. [modified] if x,y are both even then return an error! */ + if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) { + res = MP_VAL; + goto LBL_ERR; + } + + /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ + if ((res = mp_copy (&x, &u)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_copy (&y, &v)) != MP_OKAY) { + goto LBL_ERR; + } + mp_set (&A, 1); + mp_set (&D, 1); + +top: + /* 4. while u is even do */ + while (mp_iseven (&u) == 1) { + /* 4.1 u = u/2 */ + if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { + goto LBL_ERR; + } + /* 4.2 if A or B is odd then */ + if (mp_isodd (&A) == 1 || mp_isodd (&B) == 1) { + /* A = (A+y)/2, B = (B-x)/2 */ + if ((res = mp_add (&A, &y, &A)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } + /* A = A/2, B = B/2 */ + if ((res = mp_div_2 (&A, &A)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* 5. while v is even do */ + while (mp_iseven (&v) == 1) { + /* 5.1 v = v/2 */ + if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { + goto LBL_ERR; + } + /* 5.2 if C or D is odd then */ + if (mp_isodd (&C) == 1 || mp_isodd (&D) == 1) { + /* C = (C+y)/2, D = (D-x)/2 */ + if ((res = mp_add (&C, &y, &C)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + /* C = C/2, D = D/2 */ + if ((res = mp_div_2 (&C, &C)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = 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 ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } else { + /* v - v - u, C = C - A, D = D - B */ + if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* if not zero goto step 4 */ + if (mp_iszero (&u) == 0) + goto top; + + /* now a = C, b = D, gcd == g*v */ + + /* if v != 1 then there is no inverse */ + if (mp_cmp_d (&v, 1) != MP_EQ) { + res = MP_VAL; + goto LBL_ERR; + } + + /* if its too low */ + while (mp_cmp_d(&C, 0) == MP_LT) { + if ((res = mp_add(&C, b, &C)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* too big */ + while (mp_cmp_mag(&C, b) != MP_LT) { + if ((res = mp_sub(&C, b, &C)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* C is now the inverse */ + mp_exch (&C, c); + res = MP_OKAY; +LBL_ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL); + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_invmod_slow.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_invmod_slow.c */ + +/* Start: bn_mp_is_square.c */ +#include <tommath.h> +#ifdef BN_MP_IS_SQUARE_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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 */ +int mp_is_square(mp_int *arg,int *ret) +{ + int res; + mp_digit c; + mp_int t; + unsigned long r; + + /* Default to Non-square :) */ + *ret = MP_NO; + + if (arg->sign == MP_NEG) { + return MP_VAL; + } + + /* digits used? (TSD) */ + if (arg->used == 0) { + return MP_OKAY; + } + + /* First check mod 128 (suppose that DIGIT_BIT is at least 7) */ + if (rem_128[127 & DIGIT(arg,0)] == 1) { + return MP_OKAY; + } + + /* Next check mod 105 (3*5*7) */ + if ((res = mp_mod_d(arg,105,&c)) != MP_OKAY) { + return res; + } + if (rem_105[c] == 1) { + return MP_OKAY; + } + + + if ((res = mp_init_set_int(&t,11L*13L*17L*19L*23L*29L*31L)) != MP_OKAY) { + return res; + } + if ((res = mp_mod(arg,&t,&t)) != MP_OKAY) { + goto ERR; + } + r = mp_get_int(&t); + /* Check for other prime modules, note it's not an ERROR but we must + * free "t" so the easiest way is to goto ERR. We know that res + * is already equal to MP_OKAY from the mp_mod call + */ + if ( (1L<<(r%11)) & 0x5C4L ) goto ERR; + if ( (1L<<(r%13)) & 0x9E4L ) goto ERR; + if ( (1L<<(r%17)) & 0x5CE8L ) goto ERR; + if ( (1L<<(r%19)) & 0x4F50CL ) goto ERR; + if ( (1L<<(r%23)) & 0x7ACCA0L ) goto ERR; + if ( (1L<<(r%29)) & 0xC2EDD0CL ) goto ERR; + if ( (1L<<(r%31)) & 0x6DE2B848L ) goto ERR; + + /* Final check - is sqr(sqrt(arg)) == arg ? */ + if ((res = mp_sqrt(arg,&t)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sqr(&t,&t)) != MP_OKAY) { + goto ERR; + } + + *ret = (mp_cmp_mag(&t,arg) == MP_EQ) ? MP_YES : MP_NO; +ERR:mp_clear(&t); + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_is_square.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_is_square.c */ + +/* Start: bn_mp_jacobi.c */ +#include <tommath.h> +#ifdef BN_MP_JACOBI_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* computes the jacobi c = (a | n) (or Legendre if n is prime) + * HAC pp. 73 Algorithm 2.149 + */ +int mp_jacobi (mp_int * a, mp_int * p, int *c) +{ + mp_int a1, p1; + int k, s, r, res; + mp_digit residue; + + /* if p <= 0 return MP_VAL */ + if (mp_cmp_d(p, 0) != MP_GT) { + return MP_VAL; + } + + /* step 1. if a == 0, return 0 */ + if (mp_iszero (a) == 1) { + *c = 0; + return MP_OKAY; + } + + /* step 2. if a == 1, return 1 */ + if (mp_cmp_d (a, 1) == MP_EQ) { + *c = 1; + return MP_OKAY; + } + + /* default */ + s = 0; + + /* step 3. write a = a1 * 2**k */ + if ((res = mp_init_copy (&a1, a)) != MP_OKAY) { + return res; + } + + if ((res = mp_init (&p1)) != MP_OKAY) { + goto LBL_A1; + } + + /* divide out larger power of two */ + k = mp_cnt_lsb(&a1); + if ((res = mp_div_2d(&a1, k, &a1, NULL)) != MP_OKAY) { + goto LBL_P1; + } + + /* step 4. if e is even set s=1 */ + if ((k & 1) == 0) { + s = 1; + } else { + /* else set s=1 if p = 1/7 (mod 8) or s=-1 if p = 3/5 (mod 8) */ + residue = p->dp[0] & 7; + + if (residue == 1 || residue == 7) { + s = 1; + } else if (residue == 3 || residue == 5) { + s = -1; + } + } + + /* step 5. if p == 3 (mod 4) *and* a1 == 3 (mod 4) then s = -s */ + if ( ((p->dp[0] & 3) == 3) && ((a1.dp[0] & 3) == 3)) { + s = -s; + } + + /* if a1 == 1 we're done */ + if (mp_cmp_d (&a1, 1) == MP_EQ) { + *c = s; + } else { + /* n1 = n mod a1 */ + if ((res = mp_mod (p, &a1, &p1)) != MP_OKAY) { + goto LBL_P1; + } + if ((res = mp_jacobi (&p1, &a1, &r)) != MP_OKAY) { + goto LBL_P1; + } + *c = s * r; + } + + /* done */ + res = MP_OKAY; +LBL_P1:mp_clear (&p1); +LBL_A1:mp_clear (&a1); + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_jacobi.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_jacobi.c */ + +/* Start: bn_mp_karatsuba_mul.c */ +#include <tommath.h> +#ifdef BN_MP_KARATSUBA_MUL_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* c = |a| * |b| using Karatsuba Multiplication using + * three half size multiplications + * + * Let B represent the radix [e.g. 2**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. + */ +int mp_karatsuba_mul (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int x0, x1, y0, y1, t1, x0y0, x1y1; + int B, err; + + /* default the return code to an error */ + err = MP_MEM; + + /* min # of digits */ + B = 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 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; + + { + register int x; + register 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))<<B */ + if (mp_lshd (&x1y1, B * 2) != MP_OKAY) + goto X1Y1; /* x1y1 = x1y1 << 2*B */ + + if (mp_add (&x0y0, &t1, &t1) != MP_OKAY) + goto X1Y1; /* t1 = x0y0 + t1 */ + if (mp_add (&t1, &x1y1, c) != MP_OKAY) + goto X1Y1; /* t1 = x0y0 + t1 + x1y1 */ + + /* Algorithm succeeded set the return code to MP_OKAY */ + err = MP_OKAY; + +X1Y1:mp_clear (&x1y1); +X0Y0:mp_clear (&x0y0); +T1:mp_clear (&t1); +Y1:mp_clear (&y1); +Y0:mp_clear (&y0); +X1:mp_clear (&x1); +X0:mp_clear (&x0); +ERR: + return err; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_karatsuba_mul.c,v $ */ +/* $Revision: 1.5 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_karatsuba_mul.c */ + +/* Start: bn_mp_karatsuba_sqr.c */ +#include <tommath.h> +#ifdef BN_MP_KARATSUBA_SQR_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* Karatsuba squaring, computes b = a*a using three + * half size squarings + * + * See comments of karatsuba_mul for details. It + * is essentially the same algorithm but merely + * tuned to perform recursive squarings. + */ +int mp_karatsuba_sqr (mp_int * a, mp_int * b) +{ + mp_int x0, x1, t1, t2, x0x0, x1x1; + int B, err; + + err = MP_MEM; + + /* min # of digits */ + B = a->used; + + /* now divide in two */ + B = B >> 1; + + /* init copy all the temps */ + if (mp_init_size (&x0, B) != MP_OKAY) + goto 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; + + { + register int x; + register 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))<<B */ + if (mp_lshd (&x1x1, B * 2) != MP_OKAY) + goto X1X1; /* x1x1 = x1x1 << 2*B */ + + if (mp_add (&x0x0, &t1, &t1) != MP_OKAY) + goto X1X1; /* t1 = x0x0 + t1 */ + if (mp_add (&t1, &x1x1, b) != MP_OKAY) + goto X1X1; /* t1 = x0x0 + t1 + x1x1 */ + + err = MP_OKAY; + +X1X1:mp_clear (&x1x1); +X0X0:mp_clear (&x0x0); +T2:mp_clear (&t2); +T1:mp_clear (&t1); +X1:mp_clear (&x1); +X0:mp_clear (&x0); +ERR: + return err; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_karatsuba_sqr.c,v $ */ +/* $Revision: 1.5 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_karatsuba_sqr.c */ + +/* Start: bn_mp_lcm.c */ +#include <tommath.h> +#ifdef BN_MP_LCM_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* computes least common multiple as |a*b|/(a, b) */ +int mp_lcm (mp_int * a, mp_int * b, mp_int * c) +{ + int res; + mp_int t1, t2; + + + if ((res = mp_init_multi (&t1, &t2, NULL)) != MP_OKAY) { + return res; + } + + /* t1 = get the GCD of the two inputs */ + if ((res = 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 ((res = mp_div(a, &t1, &t2, NULL)) != MP_OKAY) { + goto LBL_T; + } + res = mp_mul(b, &t2, c); + } else { + /* store quotient in t2 such that t2 * a is the LCM */ + if ((res = mp_div(b, &t1, &t2, NULL)) != MP_OKAY) { + goto LBL_T; + } + res = mp_mul(a, &t2, c); + } + + /* fix the sign to positive */ + c->sign = MP_ZPOS; + +LBL_T: + mp_clear_multi (&t1, &t2, NULL); + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_lcm.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_lcm.c */ + +/* Start: bn_mp_lshd.c */ +#include <tommath.h> +#ifdef BN_MP_LSHD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* shift left a certain amount of digits */ +int mp_lshd (mp_int * a, int b) +{ + int x, res; + + /* if its less than zero return */ + if (b <= 0) { + return MP_OKAY; + } + + /* grow to fit the new digits */ + if (a->alloc < a->used + b) { + if ((res = mp_grow (a, a->used + b)) != MP_OKAY) { + return res; + } + } + + { + register mp_digit *top, *bottom; + + /* 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 */ + top = a->dp; + for (x = 0; x < b; x++) { + *top++ = 0; + } + } + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_lshd.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_lshd.c */ + +/* Start: bn_mp_mod.c */ +#include <tommath.h> +#ifdef BN_MP_MOD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* c = a mod b, 0 <= c < b */ +int +mp_mod (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int t; + int res; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + if (t.sign != b->sign) { + res = mp_add (b, &t, c); + } else { + res = MP_OKAY; + mp_exch (&t, c); + } + + mp_clear (&t); + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_mod.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_mod.c */ + +/* Start: bn_mp_mod_2d.c */ +#include <tommath.h> +#ifdef BN_MP_MOD_2D_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* calc a value mod 2**b */ +int +mp_mod_2d (mp_int * a, int b, mp_int * c) +{ + int x, res; + + /* 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 >= (int) (a->used * DIGIT_BIT)) { + res = mp_copy (a, c); + return res; + } + + /* copy */ + if ((res = mp_copy (a, c)) != MP_OKAY) { + return res; + } + + /* zero digits above the last digit of the modulus */ + for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) { + c->dp[x] = 0; + } + /* clear the digit that is not completely outside/inside the modulus */ + c->dp[b / DIGIT_BIT] &= + (mp_digit) ((((mp_digit) 1) << (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1)); + mp_clamp (c); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_mod_2d.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_mod_2d.c */ + +/* Start: bn_mp_mod_d.c */ +#include <tommath.h> +#ifdef BN_MP_MOD_D_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +int +mp_mod_d (mp_int * a, mp_digit b, mp_digit * c) +{ + return mp_div_d(a, b, NULL, c); +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_mod_d.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_mod_d.c */ + +/* Start: bn_mp_montgomery_calc_normalization.c */ +#include <tommath.h> +#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* + * 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. + */ +int mp_montgomery_calc_normalization (mp_int * a, mp_int * b) +{ + int x, bits, res; + + /* how many bits of last digit does b use */ + bits = mp_count_bits (b) % DIGIT_BIT; + + if (b->used > 1) { + if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) { + return res; + } + } else { + mp_set(a, 1); + bits = 1; + } + + + /* now compute C = A * B mod b */ + for (x = bits - 1; x < (int)DIGIT_BIT; x++) { + if ((res = mp_mul_2 (a, a)) != MP_OKAY) { + return res; + } + if (mp_cmp_mag (a, b) != MP_LT) { + if ((res = s_mp_sub (a, b, a)) != MP_OKAY) { + return res; + } + } + } + + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_montgomery_calc_normalization.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_montgomery_calc_normalization.c */ + +/* Start: bn_mp_montgomery_reduce.c */ +#include <tommath.h> +#ifdef BN_MP_MONTGOMERY_REDUCE_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* computes xR**-1 == x (mod N) via Montgomery Reduction */ +int +mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho) +{ + int ix, res, digs; + 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) && + n->used < + (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_mp_montgomery_reduce (x, n, rho); + } + + /* grow the input as required */ + if (x->alloc < digs) { + if ((res = mp_grow (x, digs)) != MP_OKAY) { + return res; + } + } + 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 */ + { + register int iy; + register mp_digit *tmpn, *tmpx, u; + register 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) 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) { + *tmpx += u; + u = *tmpx >> 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 + +/* $Source: /cvs/libtom/libtommath/bn_mp_montgomery_reduce.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_montgomery_reduce.c */ + +/* Start: bn_mp_montgomery_setup.c */ +#include <tommath.h> +#ifdef BN_MP_MONTGOMERY_SETUP_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* setups the montgomery reduction stuff */ +int +mp_montgomery_setup (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 & 1) == 0) { + return MP_VAL; + } + + x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */ + x *= 2 - b * x; /* here x*a==1 mod 2**8 */ +#if !defined(MP_8BIT) + x *= 2 - b * x; /* here x*a==1 mod 2**16 */ +#endif +#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT)) + x *= 2 - b * x; /* here x*a==1 mod 2**32 */ +#endif +#ifdef MP_64BIT + x *= 2 - b * x; /* here x*a==1 mod 2**64 */ +#endif + + /* rho = -1/m mod b */ + *rho = (unsigned long)(((mp_word)1 << ((mp_word) DIGIT_BIT)) - x) & MP_MASK; + + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_montgomery_setup.c,v $ */ +/* $Revision: 1.4 $ */ +/* $Date: 2006/12/04 21:34:03 $ */ + +/* End: bn_mp_montgomery_setup.c */ + +/* Start: bn_mp_mul.c */ +#include <tommath.h> +#ifdef BN_MP_MUL_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* high level multiplication (handles sign) */ +int mp_mul (mp_int * a, mp_int * b, mp_int * c) +{ + int res, neg; + neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; + + /* use Toom-Cook? */ +#ifdef BN_MP_TOOM_MUL_C + if (MIN (a->used, b->used) >= TOOM_MUL_CUTOFF) { + res = mp_toom_mul(a, b, c); + } else +#endif +#ifdef BN_MP_KARATSUBA_MUL_C + /* use Karatsuba? */ + if (MIN (a->used, b->used) >= KARATSUBA_MUL_CUTOFF) { + res = mp_karatsuba_mul (a, b, c); + } else +#endif + { + /* 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 + */ + int digs = a->used + b->used + 1; + +#ifdef BN_FAST_S_MP_MUL_DIGS_C + if ((digs < MP_WARRAY) && + MIN(a->used, b->used) <= + (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + res = fast_s_mp_mul_digs (a, b, c, digs); + } else +#endif +#ifdef BN_S_MP_MUL_DIGS_C + res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */ +#else + res = MP_VAL; +#endif + + } + c->sign = (c->used > 0) ? neg : MP_ZPOS; + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_mul.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_mul.c */ + +/* Start: bn_mp_mul_2.c */ +#include <tommath.h> +#ifdef BN_MP_MUL_2_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* b = a*2 */ +int mp_mul_2(mp_int * a, mp_int * b) +{ + int x, res, oldused; + + /* grow to accomodate result */ + if (b->alloc < a->used + 1) { + if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) { + return res; + } + } + + oldused = b->used; + b->used = a->used; + + { + register 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)(DIGIT_BIT - 1)); + + /* now shift up this digit, add in the carry [from the previous] */ + *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK; + + /* copy the carry that would be from the source + * digit into the next iteration + */ + r = rr; + } + + /* new leading digit? */ + if (r != 0) { + /* 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 + */ + tmpb = b->dp + b->used; + for (x = b->used; x < oldused; x++) { + *tmpb++ = 0; + } + } + b->sign = a->sign; + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_mul_2.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_mul_2.c */ + +/* Start: bn_mp_mul_2d.c */ +#include <tommath.h> +#ifdef BN_MP_MUL_2D_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* shift left by a certain bit count */ +int mp_mul_2d (mp_int * a, int b, mp_int * c) +{ + mp_digit d; + int res; + + /* copy */ + if (a != c) { + if ((res = mp_copy (a, c)) != MP_OKAY) { + return res; + } + } + + if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) { + if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) { + return res; + } + } + + /* shift by as many digits in the bit count */ + if (b >= (int)DIGIT_BIT) { + if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) { + return res; + } + } + + /* shift any bit count < DIGIT_BIT */ + d = (mp_digit) (b % DIGIT_BIT); + if (d != 0) { + register mp_digit *tmpc, shift, mask, r, rr; + register int x; + + /* bitmask for carries */ + mask = (((mp_digit)1) << d) - 1; + + /* shift for msbs */ + shift = 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 != 0) { + c->dp[(c->used)++] = r; + } + } + mp_clamp (c); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_mul_2d.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_mul_2d.c */ + +/* Start: bn_mp_mul_d.c */ +#include <tommath.h> +#ifdef BN_MP_MUL_D_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* multiply by a digit */ +int +mp_mul_d (mp_int * a, mp_digit b, mp_int * c) +{ + mp_digit u, *tmpa, *tmpc; + mp_word r; + int ix, res, olduse; + + /* make sure c is big enough to hold a*b */ + if (c->alloc < a->used + 1) { + if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) { + return res; + } + } + + /* 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) DIGIT_BIT)); + } + + /* store final carry [if any] and increment ix offset */ + *tmpc++ = u; + ++ix; + + /* now zero digits above the top */ + while (ix++ < olduse) { + *tmpc++ = 0; + } + + /* set used count */ + c->used = a->used + 1; + mp_clamp(c); + + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_mul_d.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_mul_d.c */ + +/* Start: bn_mp_mulmod.c */ +#include <tommath.h> +#ifdef BN_MP_MULMOD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* d = a * b (mod c) */ +int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + int res; + mp_int t; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_mul (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, c, d); + mp_clear (&t); + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_mulmod.c,v $ */ +/* $Revision: 1.4 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_mulmod.c */ + +/* Start: bn_mp_n_root.c */ +#include <tommath.h> +#ifdef BN_MP_N_ROOT_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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. This is not meant to + * find huge roots [square and cube, etc]. + */ +int mp_n_root (mp_int * a, mp_digit b, mp_int * c) +{ + mp_int t1, t2, t3; + int res, neg; + + /* input must be positive if b is even */ + if ((b & 1) == 0 && a->sign == MP_NEG) { + return MP_VAL; + } + + if ((res = mp_init (&t1)) != MP_OKAY) { + return res; + } + + if ((res = mp_init (&t2)) != MP_OKAY) { + goto LBL_T1; + } + + if ((res = mp_init (&t3)) != MP_OKAY) { + goto LBL_T2; + } + + /* if a is negative fudge the sign but keep track */ + neg = a->sign; + a->sign = MP_ZPOS; + + /* t2 = 2 */ + mp_set (&t2, 2); + + do { + /* t1 = t2 */ + if ((res = mp_copy (&t2, &t1)) != MP_OKAY) { + goto LBL_T3; + } + + /* t2 = t1 - ((t1**b - a) / (b * t1**(b-1))) */ + + /* t3 = t1**(b-1) */ + if ((res = mp_expt_d (&t1, b - 1, &t3)) != MP_OKAY) { + goto LBL_T3; + } + + /* numerator */ + /* t2 = t1**b */ + if ((res = mp_mul (&t3, &t1, &t2)) != MP_OKAY) { + goto LBL_T3; + } + + /* t2 = t1**b - a */ + if ((res = mp_sub (&t2, a, &t2)) != MP_OKAY) { + goto LBL_T3; + } + + /* denominator */ + /* t3 = t1**(b-1) * b */ + if ((res = mp_mul_d (&t3, b, &t3)) != MP_OKAY) { + goto LBL_T3; + } + + /* t3 = (t1**b - a)/(b * t1**(b-1)) */ + if ((res = mp_div (&t2, &t3, &t3, NULL)) != MP_OKAY) { + goto LBL_T3; + } + + if ((res = mp_sub (&t1, &t3, &t2)) != MP_OKAY) { + goto LBL_T3; + } + } while (mp_cmp (&t1, &t2) != MP_EQ); + + /* result can be off by a few so check */ + for (;;) { + if ((res = mp_expt_d (&t1, b, &t2)) != MP_OKAY) { + goto LBL_T3; + } + + if (mp_cmp (&t2, a) == MP_GT) { + if ((res = mp_sub_d (&t1, 1, &t1)) != MP_OKAY) { + goto LBL_T3; + } + } else { + break; + } + } + + /* reset the sign of a first */ + a->sign = neg; + + /* set the result */ + mp_exch (&t1, c); + + /* set the sign of the result */ + c->sign = neg; + + res = MP_OKAY; + +LBL_T3:mp_clear (&t3); +LBL_T2:mp_clear (&t2); +LBL_T1:mp_clear (&t1); + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_n_root.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_n_root.c */ + +/* Start: bn_mp_neg.c */ +#include <tommath.h> +#ifdef BN_MP_NEG_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* b = -a */ +int mp_neg (mp_int * a, mp_int * b) +{ + int res; + if (a != b) { + if ((res = mp_copy (a, b)) != MP_OKAY) { + return res; + } + } + + if (mp_iszero(b) != MP_YES) { + b->sign = (a->sign == MP_ZPOS) ? MP_NEG : MP_ZPOS; + } else { + b->sign = MP_ZPOS; + } + + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_neg.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_neg.c */ + +/* Start: bn_mp_or.c */ +#include <tommath.h> +#ifdef BN_MP_OR_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* OR two ints together */ +int mp_or (mp_int * a, mp_int * b, mp_int * c) +{ + int res, ix, px; + mp_int t, *x; + + if (a->used > b->used) { + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + px = b->used; + x = b; + } else { + if ((res = mp_init_copy (&t, b)) != MP_OKAY) { + return res; + } + px = a->used; + x = a; + } + + for (ix = 0; ix < px; ix++) { + t.dp[ix] |= x->dp[ix]; + } + mp_clamp (&t); + mp_exch (c, &t); + mp_clear (&t); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_or.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_or.c */ + +/* Start: bn_mp_prime_fermat.c */ +#include <tommath.h> +#ifdef BN_MP_PRIME_FERMAT_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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. + */ +int mp_prime_fermat (mp_int * a, mp_int * b, int *result) +{ + mp_int t; + int err; + + /* default to composite */ + *result = MP_NO; + + /* ensure b > 1 */ + if (mp_cmp_d(b, 1) != 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 + +/* $Source: /cvs/libtom/libtommath/bn_mp_prime_fermat.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_prime_fermat.c */ + +/* Start: bn_mp_prime_is_divisible.c */ +#include <tommath.h> +#ifdef BN_MP_PRIME_IS_DIVISIBLE_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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 + */ +int mp_prime_is_divisible (mp_int * a, int *result) +{ + int err, ix; + mp_digit res; + + /* default to not */ + *result = MP_NO; + + for (ix = 0; ix < PRIME_SIZE; ix++) { + /* what is a mod LBL_prime_tab[ix] */ + if ((err = mp_mod_d (a, ltm_prime_tab[ix], &res)) != MP_OKAY) { + return err; + } + + /* is the residue zero? */ + if (res == 0) { + *result = MP_YES; + return MP_OKAY; + } + } + + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_prime_is_divisible.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_prime_is_divisible.c */ + +/* Start: bn_mp_prime_is_prime.c */ +#include <tommath.h> +#ifdef BN_MP_PRIME_IS_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* performs a variable number of rounds of Miller-Rabin + * + * Probability of error after t rounds is no more than + + * + * Sets result to 1 if probably prime, 0 otherwise + */ +int mp_prime_is_prime (mp_int * a, int t, int *result) +{ + mp_int b; + int ix, err, res; + + /* default to no */ + *result = MP_NO; + + /* valid value of t? */ + if (t <= 0 || t > PRIME_SIZE) { + return MP_VAL; + } + + /* is the input equal to one of the primes in the table? */ + for (ix = 0; ix < PRIME_SIZE; ix++) { + if (mp_cmp_d(a, ltm_prime_tab[ix]) == MP_EQ) { + *result = 1; + return MP_OKAY; + } + } + + /* first perform trial division */ + if ((err = mp_prime_is_divisible (a, &res)) != MP_OKAY) { + return err; + } + + /* return if it was trivially divisible */ + if (res == MP_YES) { + return MP_OKAY; + } + + /* now perform the miller-rabin rounds */ + if ((err = mp_init (&b)) != MP_OKAY) { + return err; + } + + for (ix = 0; ix < t; ix++) { + /* set the prime */ + mp_set (&b, ltm_prime_tab[ix]); + + 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 + +/* $Source: /cvs/libtom/libtommath/bn_mp_prime_is_prime.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_prime_is_prime.c */ + +/* Start: bn_mp_prime_miller_rabin.c */ +#include <tommath.h> +#ifdef BN_MP_PRIME_MILLER_RABIN_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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. + */ +int mp_prime_miller_rabin (mp_int * a, mp_int * b, int *result) +{ + mp_int n1, y, r; + int s, j, err; + + /* default */ + *result = MP_NO; + + /* ensure b > 1 */ + if (mp_cmp_d(b, 1) != 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, 1, &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, 1) != 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, 1) == 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 + +/* $Source: /cvs/libtom/libtommath/bn_mp_prime_miller_rabin.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_prime_miller_rabin.c */ + +/* Start: bn_mp_prime_next_prime.c */ +#include <tommath.h> +#ifdef BN_MP_PRIME_NEXT_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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 + */ +int mp_prime_next_prime(mp_int *a, int t, int bbs_style) +{ + int err, res, x, y; + mp_digit res_tab[PRIME_SIZE], step, kstep; + mp_int b; + + /* ensure t is valid */ + if (t <= 0 || t > PRIME_SIZE) { + return MP_VAL; + } + + /* force positive */ + a->sign = MP_ZPOS; + + /* simple algo if a is less than the largest prime in the table */ + if (mp_cmp_d(a, ltm_prime_tab[PRIME_SIZE-1]) == MP_LT) { + /* find which prime it is bigger than */ + for (x = PRIME_SIZE - 2; x >= 0; x--) { + if (mp_cmp_d(a, ltm_prime_tab[x]) != MP_LT) { + if (bbs_style == 1) { + /* ok we found a prime smaller or + * equal [so the next is larger] + * + * however, the prime must be + * congruent to 3 mod 4 + */ + if ((ltm_prime_tab[x + 1] & 3) != 3) { + /* scan upwards for a prime congruent to 3 mod 4 */ + for (y = x + 1; y < PRIME_SIZE; y++) { + if ((ltm_prime_tab[y] & 3) == 3) { + mp_set(a, ltm_prime_tab[y]); + return MP_OKAY; + } + } + } + } else { + mp_set(a, ltm_prime_tab[x + 1]); + return MP_OKAY; + } + } + } + /* at this point a maybe 1 */ + if (mp_cmp_d(a, 1) == MP_EQ) { + mp_set(a, 2); + 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] & 3) != 3) { + if ((err = mp_sub_d(a, (a->dp[0] & 3) + 1, a)) != MP_OKAY) { return err; }; + } + } else { + if (mp_iseven(a) == 1) { + /* force odd */ + if ((err = mp_sub_d(a, 1, a)) != MP_OKAY) { + return err; + } + } + } + + /* generate the restable */ + for (x = 1; x < PRIME_SIZE; x++) { + if ((err = mp_mod_d(a, ltm_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 < PRIME_SIZE; x++) { + /* add the step to each residue */ + res_tab[x] += kstep; + + /* subtract the modulus [instead of using division] */ + if (res_tab[x] >= ltm_prime_tab[x]) { + res_tab[x] -= ltm_prime_tab[x]; + } + + /* set flag if zero */ + if (res_tab[x] == 0) { + y = 1; + } + } + } while (y == 1 && step < ((((mp_digit)1)<<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 == MAX then skip test */ + if (y == 1 && step >= ((((mp_digit)1)<<DIGIT_BIT) - kstep)) { + continue; + } + + /* is this prime? */ + for (x = 0; x < t; x++) { + mp_set(&b, ltm_prime_tab[t]); + if ((err = mp_prime_miller_rabin(a, &b, &res)) != MP_OKAY) { + goto LBL_ERR; + } + if (res == MP_NO) { + break; + } + } + + if (res == MP_YES) { + break; + } + } + + err = MP_OKAY; +LBL_ERR: + mp_clear(&b); + return err; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_prime_next_prime.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_prime_next_prime.c */ + +/* Start: bn_mp_prime_rabin_miller_trials.c */ +#include <tommath.h> +#ifdef BN_MP_PRIME_RABIN_MILLER_TRIALS_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + + +static const struct { + int k, t; +} sizes[] = { +{ 128, 28 }, +{ 256, 16 }, +{ 384, 10 }, +{ 512, 7 }, +{ 640, 6 }, +{ 768, 5 }, +{ 896, 4 }, +{ 1024, 4 } +}; + +/* 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 + 1; +} + + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_prime_rabin_miller_trials.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_prime_rabin_miller_trials.c */ + +/* Start: bn_mp_prime_random_ex.c */ +#include <tommath.h> +#ifdef BN_MP_PRIME_RANDOM_EX_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* makes a truly random prime of a given size (bits), + * + * Flags are as follows: + * + * LTM_PRIME_BBS - make prime congruent to 3 mod 4 + * LTM_PRIME_SAFE - make sure (p-1)/2 is prime as well (implies LTM_PRIME_BBS) + * LTM_PRIME_2MSB_OFF - make the 2nd highest bit zero + * LTM_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! */ +int mp_prime_random_ex(mp_int *a, int t, int size, int flags, ltm_prime_callback cb, void *dat) +{ + unsigned char *tmp, maskAND, maskOR_msb, maskOR_lsb; + int res, err, bsize, maskOR_msb_offset; + + /* sanity check the input */ + if (size <= 1 || t <= 0) { + return MP_VAL; + } + + /* LTM_PRIME_SAFE implies LTM_PRIME_BBS */ + if (flags & LTM_PRIME_SAFE) { + flags |= LTM_PRIME_BBS; + } + + /* calc the byte size */ + bsize = (size>>3) + ((size&7)?1:0); + + /* we need a buffer of bsize bytes */ + tmp = OPT_CAST(unsigned char) XMALLOC(bsize); + if (tmp == NULL) { + return MP_MEM; + } + + /* calc the maskAND value for the MSbyte*/ + maskAND = ((size&7) == 0) ? 0xFF : (0xFF >> (8 - (size & 7))); + + /* calc the maskOR_msb */ + maskOR_msb = 0; + maskOR_msb_offset = ((size & 7) == 1) ? 1 : 0; + if (flags & LTM_PRIME_2MSB_ON) { + maskOR_msb |= 0x80 >> ((9 - size) & 7); + } + + /* get the maskOR_lsb */ + maskOR_lsb = 1; + if (flags & LTM_PRIME_BBS) { + maskOR_lsb |= 3; + } + + do { + /* read the bytes */ + if (cb(tmp, bsize, dat) != bsize) { + err = MP_VAL; + goto error; + } + + /* work over the MSbyte */ + tmp[0] &= maskAND; + tmp[0] |= 1 << ((size - 1) & 7); + + /* mix in the maskORs */ + tmp[maskOR_msb_offset] |= maskOR_msb; + tmp[bsize-1] |= maskOR_lsb; + + /* read it in */ + if ((err = mp_read_unsigned_bin(a, tmp, 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 & LTM_PRIME_SAFE) { + /* see if (a-1)/2 is prime */ + if ((err = mp_sub_d(a, 1, 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 & LTM_PRIME_SAFE) { + /* restore a to the original value */ + if ((err = mp_mul_2(a, a)) != MP_OKAY) { goto error; } + if ((err = mp_add_d(a, 1, a)) != MP_OKAY) { goto error; } + } + + err = MP_OKAY; +error: + XFREE(tmp); + return err; +} + + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_prime_random_ex.c,v $ */ +/* $Revision: 1.4 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_prime_random_ex.c */ + +/* Start: bn_mp_radix_size.c */ +#include <tommath.h> +#ifdef BN_MP_RADIX_SIZE_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* returns size of ASCII reprensentation */ +int mp_radix_size (mp_int * a, int radix, int *size) +{ + int res, digs; + mp_int t; + mp_digit d; + + *size = 0; + + /* special case for binary */ + if (radix == 2) { + *size = mp_count_bits (a) + (a->sign == MP_NEG ? 1 : 0) + 1; + return MP_OKAY; + } + + /* make sure the radix is in range */ + if (radix < 2 || radix > 64) { + return MP_VAL; + } + + if (mp_iszero(a) == MP_YES) { + *size = 2; + 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 ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + + /* force temp to positive */ + t.sign = MP_ZPOS; + + /* fetch out all of the digits */ + 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); + + /* return digs + 1, the 1 is for the NULL byte that would be required. */ + *size = digs + 1; + return MP_OKAY; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_radix_size.c,v $ */ +/* $Revision: 1.4 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_radix_size.c */ + +/* Start: bn_mp_radix_smap.c */ +#include <tommath.h> +#ifdef BN_MP_RADIX_SMAP_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* chars used in radix conversions */ +const char *mp_s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_radix_smap.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_radix_smap.c */ + +/* Start: bn_mp_rand.c */ +#include <tommath.h> +#ifdef BN_MP_RAND_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* makes a pseudo-random int of a given size */ +int +mp_rand (mp_int * a, int digits) +{ + int res; + mp_digit d; + + mp_zero (a); + if (digits <= 0) { + return MP_OKAY; + } + + /* first place a random non-zero digit */ + do { + d = ((mp_digit) abs (rand ())) & MP_MASK; + } while (d == 0); + + if ((res = mp_add_d (a, d, a)) != MP_OKAY) { + return res; + } + + while (--digits > 0) { + if ((res = mp_lshd (a, 1)) != MP_OKAY) { + return res; + } + + if ((res = mp_add_d (a, ((mp_digit) abs (rand ())), a)) != MP_OKAY) { + return res; + } + } + + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_rand.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_rand.c */ + +/* Start: bn_mp_read_radix.c */ +#include <tommath.h> +#ifdef BN_MP_READ_RADIX_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* read a string [ASCII] in a given radix */ +int mp_read_radix (mp_int * a, const char *str, int radix) +{ + int y, res, neg; + 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) { + /* 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 = (char) ((radix < 36) ? toupper (*str) : *str); + for (y = 0; y < 64; y++) { + if (ch == mp_s_rmap[y]) { + break; + } + } + + /* 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 < radix) { + if ((res = mp_mul_d (a, (mp_digit) radix, a)) != MP_OKAY) { + return res; + } + if ((res = mp_add_d (a, (mp_digit) y, a)) != MP_OKAY) { + return res; + } + } else { + break; + } + ++str; + } + + /* set the sign only if a != 0 */ + if (mp_iszero(a) != 1) { + a->sign = neg; + } + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_read_radix.c,v $ */ +/* $Revision: 1.4 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_read_radix.c */ + +/* Start: bn_mp_read_signed_bin.c */ +#include <tommath.h> +#ifdef BN_MP_READ_SIGNED_BIN_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* read signed bin, big endian, first byte is 0==positive or 1==negative */ +int mp_read_signed_bin (mp_int * a, const unsigned char *b, int c) +{ + int res; + + /* read magnitude */ + if ((res = mp_read_unsigned_bin (a, b + 1, c - 1)) != MP_OKAY) { + return res; + } + + /* first byte is 0 for positive, non-zero for negative */ + if (b[0] == 0) { + a->sign = MP_ZPOS; + } else { + a->sign = MP_NEG; + } + + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_read_signed_bin.c,v $ */ +/* $Revision: 1.4 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_read_signed_bin.c */ + +/* Start: bn_mp_read_unsigned_bin.c */ +#include <tommath.h> +#ifdef BN_MP_READ_UNSIGNED_BIN_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* reads a unsigned char array, assumes the msb is stored first [big endian] */ +int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c) +{ + int res; + + /* make sure there are at least two digits */ + if (a->alloc < 2) { + if ((res = mp_grow(a, 2)) != MP_OKAY) { + return res; + } + } + + /* zero the int */ + mp_zero (a); + + /* read the bytes in */ + while (c-- > 0) { + if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) { + return res; + } + +#ifndef MP_8BIT + a->dp[0] |= *b++; + a->used += 1; +#else + a->dp[0] = (*b & MP_MASK); + a->dp[1] |= ((*b++ >> 7U) & 1); + a->used += 2; +#endif + } + mp_clamp (a); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_read_unsigned_bin.c,v $ */ +/* $Revision: 1.4 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_read_unsigned_bin.c */ + +/* Start: bn_mp_reduce.c */ +#include <tommath.h> +#ifdef BN_MP_REDUCE_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* reduces x mod m, assumes 0 < x < m**2, mu is + * precomputed via mp_reduce_setup. + * From HAC pp.604 Algorithm 14.42 + */ +int mp_reduce (mp_int * x, mp_int * m, mp_int * mu) +{ + mp_int q; + int res, um = m->used; + + /* q = x */ + if ((res = mp_init_copy (&q, x)) != MP_OKAY) { + return res; + } + + /* q1 = x / b**(k-1) */ + mp_rshd (&q, um - 1); + + /* according to HAC this optimization is ok */ + if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) { + if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) { + goto CLEANUP; + } + } else { +#ifdef BN_S_MP_MUL_HIGH_DIGS_C + if ((res = s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) { + goto CLEANUP; + } +#elif defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C) + if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) { + goto CLEANUP; + } +#else + { + res = MP_VAL; + goto CLEANUP; + } +#endif + } + + /* q3 = q2 / b**(k+1) */ + mp_rshd (&q, um + 1); + + /* x = x mod b**(k+1), quick (no division) */ + if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) { + goto CLEANUP; + } + + /* q = q * m mod b**(k+1), quick (no division) */ + if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) { + goto CLEANUP; + } + + /* x = x - q */ + if ((res = mp_sub (x, &q, x)) != MP_OKAY) { + goto CLEANUP; + } + + /* If x < 0, add b**(k+1) to it */ + if (mp_cmp_d (x, 0) == MP_LT) { + mp_set (&q, 1); + if ((res = mp_lshd (&q, um + 1)) != MP_OKAY) + goto CLEANUP; + if ((res = mp_add (x, &q, x)) != MP_OKAY) + goto CLEANUP; + } + + /* Back off if it's too big */ + while (mp_cmp (x, m) != MP_LT) { + if ((res = s_mp_sub (x, m, x)) != MP_OKAY) { + goto CLEANUP; + } + } + +CLEANUP: + mp_clear (&q); + + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_reduce.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_reduce.c */ + +/* Start: bn_mp_reduce_2k.c */ +#include <tommath.h> +#ifdef BN_MP_REDUCE_2K_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* reduces a modulo n where n is of the form 2**p - d */ +int mp_reduce_2k(mp_int *a, mp_int *n, mp_digit d) +{ + mp_int q; + int p, res; + + if ((res = mp_init(&q)) != MP_OKAY) { + return res; + } + + p = mp_count_bits(n); +top: + /* q = a/2**p, a = a mod 2**p */ + if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) { + goto ERR; + } + + if (d != 1) { + /* q = q * d */ + if ((res = mp_mul_d(&q, d, &q)) != MP_OKAY) { + goto ERR; + } + } + + /* a = a + q */ + if ((res = s_mp_add(a, &q, a)) != MP_OKAY) { + goto ERR; + } + + if (mp_cmp_mag(a, n) != MP_LT) { + s_mp_sub(a, n, a); + goto top; + } + +ERR: + mp_clear(&q); + return res; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_reduce_2k.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_reduce_2k.c */ + +/* Start: bn_mp_reduce_2k_l.c */ +#include <tommath.h> +#ifdef BN_MP_REDUCE_2K_L_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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. +*/ +int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d) +{ + mp_int q; + int p, res; + + if ((res = mp_init(&q)) != MP_OKAY) { + return res; + } + + p = mp_count_bits(n); +top: + /* q = a/2**p, a = a mod 2**p */ + if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) { + goto ERR; + } + + /* q = q * d */ + if ((res = mp_mul(&q, d, &q)) != MP_OKAY) { + goto ERR; + } + + /* a = a + q */ + if ((res = s_mp_add(a, &q, a)) != MP_OKAY) { + goto ERR; + } + + if (mp_cmp_mag(a, n) != MP_LT) { + s_mp_sub(a, n, a); + goto top; + } + +ERR: + mp_clear(&q); + return res; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_reduce_2k_l.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_reduce_2k_l.c */ + +/* Start: bn_mp_reduce_2k_setup.c */ +#include <tommath.h> +#ifdef BN_MP_REDUCE_2K_SETUP_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* determines the setup value */ +int mp_reduce_2k_setup(mp_int *a, mp_digit *d) +{ + int res, p; + mp_int tmp; + + if ((res = mp_init(&tmp)) != MP_OKAY) { + return res; + } + + p = mp_count_bits(a); + if ((res = mp_2expt(&tmp, p)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + + if ((res = s_mp_sub(&tmp, a, &tmp)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + + *d = tmp.dp[0]; + mp_clear(&tmp); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_reduce_2k_setup.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_reduce_2k_setup.c */ + +/* Start: bn_mp_reduce_2k_setup_l.c */ +#include <tommath.h> +#ifdef BN_MP_REDUCE_2K_SETUP_L_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* determines the setup value */ +int mp_reduce_2k_setup_l(mp_int *a, mp_int *d) +{ + int res; + mp_int tmp; + + if ((res = mp_init(&tmp)) != MP_OKAY) { + return res; + } + + if ((res = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) { + goto ERR; + } + + if ((res = s_mp_sub(&tmp, a, d)) != MP_OKAY) { + goto ERR; + } + +ERR: + mp_clear(&tmp); + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_reduce_2k_setup_l.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_reduce_2k_setup_l.c */ + +/* Start: bn_mp_reduce_is_2k.c */ +#include <tommath.h> +#ifdef BN_MP_REDUCE_IS_2K_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* determines if mp_reduce_2k can be used */ +int mp_reduce_is_2k(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 = DIGIT_BIT; ix < iy; ix++) { + if ((a->dp[iw] & iz) == 0) { + return MP_NO; + } + iz <<= 1; + if (iz > (mp_digit)MP_MASK) { + ++iw; + iz = 1; + } + } + } + return MP_YES; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_reduce_is_2k.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_reduce_is_2k.c */ + +/* Start: bn_mp_reduce_is_2k_l.c */ +#include <tommath.h> +#ifdef BN_MP_REDUCE_IS_2K_L_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* determines if reduce_2k_l can be used */ +int mp_reduce_is_2k_l(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_MASK) { + ++iy; + } + } + return (iy >= (a->used/2)) ? MP_YES : MP_NO; + + } + return MP_NO; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_reduce_is_2k_l.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_reduce_is_2k_l.c */ + +/* Start: bn_mp_reduce_setup.c */ +#include <tommath.h> +#ifdef BN_MP_REDUCE_SETUP_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* pre-calculate the value required for Barrett reduction + * For a given modulus "b" it calulates the value required in "a" + */ +int mp_reduce_setup (mp_int * a, mp_int * b) +{ + int res; + + if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) { + return res; + } + return mp_div (a, b, a, NULL); +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_reduce_setup.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_reduce_setup.c */ + +/* Start: bn_mp_rshd.c */ +#include <tommath.h> +#ifdef BN_MP_RSHD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* shift right a certain amount of digits */ +void mp_rshd (mp_int * a, int b) +{ + int x; + + /* 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; + } + + { + register mp_digit *bottom, *top; + + /* 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 */ + for (; x < a->used; x++) { + *bottom++ = 0; + } + } + + /* remove excess digits */ + a->used -= b; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_rshd.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_rshd.c */ + +/* Start: bn_mp_set.c */ +#include <tommath.h> +#ifdef BN_MP_SET_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* set to a digit */ +void mp_set (mp_int * a, mp_digit b) +{ + mp_zero (a); + a->dp[0] = b & MP_MASK; + a->used = (a->dp[0] != 0) ? 1 : 0; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_set.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_set.c */ + +/* Start: bn_mp_set_int.c */ +#include <tommath.h> +#ifdef BN_MP_SET_INT_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* set a 32-bit const */ +int mp_set_int (mp_int * a, unsigned long b) +{ + int x, res; + + mp_zero (a); + + /* set four bits at a time */ + for (x = 0; x < 8; x++) { + /* shift the number up four bits */ + if ((res = mp_mul_2d (a, 4, a)) != MP_OKAY) { + return res; + } + + /* OR in the top four bits of the source */ + a->dp[0] |= (b >> 28) & 15; + + /* shift the source up to the next four bits */ + b <<= 4; + + /* ensure that digits are not clamped off */ + a->used += 1; + } + mp_clamp (a); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_set_int.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_set_int.c */ + +/* Start: bn_mp_shrink.c */ +#include <tommath.h> +#ifdef BN_MP_SHRINK_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* shrink a bignum */ +int mp_shrink (mp_int * a) +{ + mp_digit *tmp; + if (a->alloc != a->used && a->used > 0) { + if ((tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * a->used)) == NULL) { + return MP_MEM; + } + a->dp = tmp; + a->alloc = a->used; + } + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_shrink.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_shrink.c */ + +/* Start: bn_mp_signed_bin_size.c */ +#include <tommath.h> +#ifdef BN_MP_SIGNED_BIN_SIZE_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* get the size for an signed equivalent */ +int mp_signed_bin_size (mp_int * a) +{ + return 1 + mp_unsigned_bin_size (a); +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_signed_bin_size.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_signed_bin_size.c */ + +/* Start: bn_mp_sqr.c */ +#include <tommath.h> +#ifdef BN_MP_SQR_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* computes b = a*a */ +int +mp_sqr (mp_int * a, mp_int * b) +{ + int res; + +#ifdef BN_MP_TOOM_SQR_C + /* use Toom-Cook? */ + if (a->used >= TOOM_SQR_CUTOFF) { + res = mp_toom_sqr(a, b); + /* Karatsuba? */ + } else +#endif +#ifdef BN_MP_KARATSUBA_SQR_C +if (a->used >= KARATSUBA_SQR_CUTOFF) { + res = mp_karatsuba_sqr (a, b); + } else +#endif + { +#ifdef BN_FAST_S_MP_SQR_C + /* can we use the fast comba multiplier? */ + if ((a->used * 2 + 1) < MP_WARRAY && + a->used < + (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) { + res = fast_s_mp_sqr (a, b); + } else +#endif +#ifdef BN_S_MP_SQR_C + res = s_mp_sqr (a, b); +#else + res = MP_VAL; +#endif + } + b->sign = MP_ZPOS; + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_sqr.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_sqr.c */ + +/* Start: bn_mp_sqrmod.c */ +#include <tommath.h> +#ifdef BN_MP_SQRMOD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* c = a * a (mod b) */ +int +mp_sqrmod (mp_int * a, mp_int * b, mp_int * c) +{ + int res; + mp_int t; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_sqr (a, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, b, c); + mp_clear (&t); + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_sqrmod.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_sqrmod.c */ + +/* Start: bn_mp_sqrt.c */ +#include <tommath.h> +#ifdef BN_MP_SQRT_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* this function is less generic than mp_n_root, simpler and faster */ +int mp_sqrt(mp_int *arg, mp_int *ret) +{ + int res; + mp_int t1,t2; + + /* must be positive */ + if (arg->sign == MP_NEG) { + return MP_VAL; + } + + /* easy out */ + if (mp_iszero(arg) == MP_YES) { + mp_zero(ret); + return MP_OKAY; + } + + if ((res = mp_init_copy(&t1, arg)) != MP_OKAY) { + return res; + } + + if ((res = mp_init(&t2)) != MP_OKAY) { + goto E2; + } + + /* First approx. (not very bad for large arg) */ + mp_rshd (&t1,t1.used/2); + + /* t1 > 0 */ + if ((res = mp_div(arg,&t1,&t2,NULL)) != MP_OKAY) { + goto E1; + } + if ((res = mp_add(&t1,&t2,&t1)) != MP_OKAY) { + goto E1; + } + if ((res = mp_div_2(&t1,&t1)) != MP_OKAY) { + goto E1; + } + /* And now t1 > sqrt(arg) */ + do { + if ((res = mp_div(arg,&t1,&t2,NULL)) != MP_OKAY) { + goto E1; + } + if ((res = mp_add(&t1,&t2,&t1)) != MP_OKAY) { + goto E1; + } + if ((res = 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 res; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_sqrt.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_sqrt.c */ + +/* Start: bn_mp_sub.c */ +#include <tommath.h> +#ifdef BN_MP_SUB_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* high level subtraction (handles signs) */ +int +mp_sub (mp_int * a, mp_int * b, mp_int * c) +{ + int sa, sb, res; + + sa = a->sign; + sb = b->sign; + + 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; + res = 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 */ + res = 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 */ + res = s_mp_sub (b, a, c); + } + } + return res; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_sub.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_sub.c */ + +/* Start: bn_mp_sub_d.c */ +#include <tommath.h> +#ifdef BN_MP_SUB_D_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* single digit subtraction */ +int +mp_sub_d (mp_int * a, mp_digit b, mp_int * c) +{ + mp_digit *tmpa, *tmpc, mu; + int res, ix, oldused; + + /* grow c as required */ + if (c->alloc < a->used + 1) { + if ((res = mp_grow(c, a->used + 1)) != MP_OKAY) { + return res; + } + } + + /* if a is negative just do an unsigned + * addition [with fudged signs] + */ + if (a->sign == MP_NEG) { + a->sign = MP_ZPOS; + res = mp_add_d(a, b, c); + a->sign = c->sign = MP_NEG; + + /* clamp */ + mp_clamp(c); + + return res; + } + + /* 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 { + /* positive/size */ + c->sign = MP_ZPOS; + c->used = a->used; + + /* subtract first digit */ + *tmpc = *tmpa++ - b; + mu = *tmpc >> (sizeof(mp_digit) * CHAR_BIT - 1); + *tmpc++ &= MP_MASK; + + /* handle rest of the digits */ + for (ix = 1; ix < a->used; ix++) { + *tmpc = *tmpa++ - mu; + mu = *tmpc >> (sizeof(mp_digit) * CHAR_BIT - 1); + *tmpc++ &= MP_MASK; + } + } + + /* zero excess digits */ + while (ix++ < oldused) { + *tmpc++ = 0; + } + mp_clamp(c); + return MP_OKAY; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_sub_d.c,v $ */ +/* $Revision: 1.5 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_sub_d.c */ + +/* Start: bn_mp_submod.c */ +#include <tommath.h> +#ifdef BN_MP_SUBMOD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* d = a - b (mod c) */ +int +mp_submod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + int res; + mp_int t; + + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_sub (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, c, d); + mp_clear (&t); + return res; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_submod.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_submod.c */ + +/* Start: bn_mp_to_signed_bin.c */ +#include <tommath.h> +#ifdef BN_MP_TO_SIGNED_BIN_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* store in signed [big endian] format */ +int mp_to_signed_bin (mp_int * a, unsigned char *b) +{ + int res; + + if ((res = mp_to_unsigned_bin (a, b + 1)) != MP_OKAY) { + return res; + } + b[0] = (unsigned char) ((a->sign == MP_ZPOS) ? 0 : 1); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_to_signed_bin.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_to_signed_bin.c */ + +/* Start: bn_mp_to_signed_bin_n.c */ +#include <tommath.h> +#ifdef BN_MP_TO_SIGNED_BIN_N_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* store in signed [big endian] format */ +int mp_to_signed_bin_n (mp_int * a, unsigned char *b, unsigned long *outlen) +{ + if (*outlen < (unsigned long)mp_signed_bin_size(a)) { + return MP_VAL; + } + *outlen = mp_signed_bin_size(a); + return mp_to_signed_bin(a, b); +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_to_signed_bin_n.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_to_signed_bin_n.c */ + +/* Start: bn_mp_to_unsigned_bin.c */ +#include <tommath.h> +#ifdef BN_MP_TO_UNSIGNED_BIN_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* store in unsigned [big endian] format */ +int mp_to_unsigned_bin (mp_int * a, unsigned char *b) +{ + int x, res; + mp_int t; + + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + + x = 0; + while (mp_iszero (&t) == 0) { +#ifndef MP_8BIT + b[x++] = (unsigned char) (t.dp[0] & 255); +#else + b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7)); +#endif + if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) { + mp_clear (&t); + return res; + } + } + bn_reverse (b, x); + mp_clear (&t); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_to_unsigned_bin.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_to_unsigned_bin.c */ + +/* Start: bn_mp_to_unsigned_bin_n.c */ +#include <tommath.h> +#ifdef BN_MP_TO_UNSIGNED_BIN_N_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* store in unsigned [big endian] format */ +int mp_to_unsigned_bin_n (mp_int * a, unsigned char *b, unsigned long *outlen) +{ + if (*outlen < (unsigned long)mp_unsigned_bin_size(a)) { + return MP_VAL; + } + *outlen = mp_unsigned_bin_size(a); + return mp_to_unsigned_bin(a, b); +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_to_unsigned_bin_n.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_to_unsigned_bin_n.c */ + +/* Start: bn_mp_toom_mul.c */ +#include <tommath.h> +#ifdef BN_MP_TOOM_MUL_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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...). +*/ +int mp_toom_mul(mp_int *a, mp_int *b, mp_int *c) +{ + mp_int w0, w1, w2, w3, w4, tmp1, tmp2, a0, a1, a2, b0, b1, b2; + int res, B; + + /* init temps */ + if ((res = mp_init_multi(&w0, &w1, &w2, &w3, &w4, + &a0, &a1, &a2, &b0, &b1, + &b2, &tmp1, &tmp2, NULL)) != MP_OKAY) { + return res; + } + + /* B */ + B = MIN(a->used, b->used) / 3; + + /* a = a2 * B**2 + a1 * B + a0 */ + if ((res = mp_mod_2d(a, DIGIT_BIT * B, &a0)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_copy(a, &a1)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&a1, B); + mp_mod_2d(&a1, DIGIT_BIT * B, &a1); + + if ((res = mp_copy(a, &a2)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&a2, B*2); + + /* b = b2 * B**2 + b1 * B + b0 */ + if ((res = mp_mod_2d(b, DIGIT_BIT * B, &b0)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_copy(b, &b1)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&b1, B); + mp_mod_2d(&b1, DIGIT_BIT * B, &b1); + + if ((res = mp_copy(b, &b2)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&b2, B*2); + + /* w0 = a0*b0 */ + if ((res = mp_mul(&a0, &b0, &w0)) != MP_OKAY) { + goto ERR; + } + + /* w4 = a2 * b2 */ + if ((res = mp_mul(&a2, &b2, &w4)) != MP_OKAY) { + goto ERR; + } + + /* w1 = (a2 + 2(a1 + 2a0))(b2 + 2(b1 + 2b0)) */ + if ((res = mp_mul_2(&a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a2, &tmp1)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_mul_2(&b0, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b1, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp2, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b2, &tmp2)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_mul(&tmp1, &tmp2, &w1)) != MP_OKAY) { + goto ERR; + } + + /* w3 = (a0 + 2(a1 + 2a2))(b0 + 2(b1 + 2b2)) */ + if ((res = mp_mul_2(&a2, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_mul_2(&b2, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b1, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp2, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b0, &tmp2)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_mul(&tmp1, &tmp2, &w3)) != MP_OKAY) { + goto ERR; + } + + + /* w2 = (a2 + a1 + a0)(b2 + b1 + b0) */ + if ((res = mp_add(&a2, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&b2, &b1, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b0, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul(&tmp1, &tmp2, &w2)) != MP_OKAY) { + goto ERR; + } + + /* now solve the matrix + + 0 0 0 0 1 + 1 2 4 8 16 + 1 1 1 1 1 + 16 8 4 2 1 + 1 0 0 0 0 + + using 12 subtractions, 4 shifts, + 2 small divisions and 1 small multiplication + */ + + /* r1 - r4 */ + if ((res = mp_sub(&w1, &w4, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r0 */ + if ((res = mp_sub(&w3, &w0, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1/2 */ + if ((res = mp_div_2(&w1, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3/2 */ + if ((res = mp_div_2(&w3, &w3)) != MP_OKAY) { + goto ERR; + } + /* r2 - r0 - r4 */ + if ((res = mp_sub(&w2, &w0, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w4, &w2)) != MP_OKAY) { + goto ERR; + } + /* r1 - r2 */ + if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r2 */ + if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1 - 8r0 */ + if ((res = mp_mul_2d(&w0, 3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w1, &tmp1, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - 8r4 */ + if ((res = mp_mul_2d(&w4, 3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w3, &tmp1, &w3)) != MP_OKAY) { + goto ERR; + } + /* 3r2 - r1 - r3 */ + if ((res = mp_mul_d(&w2, 3, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w1, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w3, &w2)) != MP_OKAY) { + goto ERR; + } + /* r1 - r2 */ + if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r2 */ + if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1/3 */ + if ((res = mp_div_3(&w1, &w1, NULL)) != MP_OKAY) { + goto ERR; + } + /* r3/3 */ + if ((res = mp_div_3(&w3, &w3, NULL)) != MP_OKAY) { + goto ERR; + } + + /* at this point shift W[n] by B*n */ + if ((res = mp_lshd(&w1, 1*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w2, 2*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w3, 3*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w4, 4*B)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_add(&w0, &w1, c)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&w2, &w3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&w4, &tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, c, c)) != MP_OKAY) { + goto ERR; + } + +ERR: + mp_clear_multi(&w0, &w1, &w2, &w3, &w4, + &a0, &a1, &a2, &b0, &b1, + &b2, &tmp1, &tmp2, NULL); + return res; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_toom_mul.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_toom_mul.c */ + +/* Start: bn_mp_toom_sqr.c */ +#include <tommath.h> +#ifdef BN_MP_TOOM_SQR_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* squaring using Toom-Cook 3-way algorithm */ +int +mp_toom_sqr(mp_int *a, mp_int *b) +{ + mp_int w0, w1, w2, w3, w4, tmp1, a0, a1, a2; + int res, B; + + /* init temps */ + if ((res = mp_init_multi(&w0, &w1, &w2, &w3, &w4, &a0, &a1, &a2, &tmp1, NULL)) != MP_OKAY) { + return res; + } + + /* B */ + B = a->used / 3; + + /* a = a2 * B**2 + a1 * B + a0 */ + if ((res = mp_mod_2d(a, DIGIT_BIT * B, &a0)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_copy(a, &a1)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&a1, B); + mp_mod_2d(&a1, DIGIT_BIT * B, &a1); + + if ((res = mp_copy(a, &a2)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&a2, B*2); + + /* w0 = a0*a0 */ + if ((res = mp_sqr(&a0, &w0)) != MP_OKAY) { + goto ERR; + } + + /* w4 = a2 * a2 */ + if ((res = mp_sqr(&a2, &w4)) != MP_OKAY) { + goto ERR; + } + + /* w1 = (a2 + 2(a1 + 2a0))**2 */ + if ((res = mp_mul_2(&a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a2, &tmp1)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_sqr(&tmp1, &w1)) != MP_OKAY) { + goto ERR; + } + + /* w3 = (a0 + 2(a1 + 2a2))**2 */ + if ((res = mp_mul_2(&a2, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_sqr(&tmp1, &w3)) != MP_OKAY) { + goto ERR; + } + + + /* w2 = (a2 + a1 + a0)**2 */ + if ((res = mp_add(&a2, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sqr(&tmp1, &w2)) != MP_OKAY) { + goto ERR; + } + + /* now solve the matrix + + 0 0 0 0 1 + 1 2 4 8 16 + 1 1 1 1 1 + 16 8 4 2 1 + 1 0 0 0 0 + + using 12 subtractions, 4 shifts, 2 small divisions and 1 small multiplication. + */ + + /* r1 - r4 */ + if ((res = mp_sub(&w1, &w4, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r0 */ + if ((res = mp_sub(&w3, &w0, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1/2 */ + if ((res = mp_div_2(&w1, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3/2 */ + if ((res = mp_div_2(&w3, &w3)) != MP_OKAY) { + goto ERR; + } + /* r2 - r0 - r4 */ + if ((res = mp_sub(&w2, &w0, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w4, &w2)) != MP_OKAY) { + goto ERR; + } + /* r1 - r2 */ + if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r2 */ + if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1 - 8r0 */ + if ((res = mp_mul_2d(&w0, 3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w1, &tmp1, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - 8r4 */ + if ((res = mp_mul_2d(&w4, 3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w3, &tmp1, &w3)) != MP_OKAY) { + goto ERR; + } + /* 3r2 - r1 - r3 */ + if ((res = mp_mul_d(&w2, 3, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w1, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w3, &w2)) != MP_OKAY) { + goto ERR; + } + /* r1 - r2 */ + if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r2 */ + if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1/3 */ + if ((res = mp_div_3(&w1, &w1, NULL)) != MP_OKAY) { + goto ERR; + } + /* r3/3 */ + if ((res = mp_div_3(&w3, &w3, NULL)) != MP_OKAY) { + goto ERR; + } + + /* at this point shift W[n] by B*n */ + if ((res = mp_lshd(&w1, 1*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w2, 2*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w3, 3*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w4, 4*B)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_add(&w0, &w1, b)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&w2, &w3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&w4, &tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, b, b)) != MP_OKAY) { + goto ERR; + } + +ERR: + mp_clear_multi(&w0, &w1, &w2, &w3, &w4, &a0, &a1, &a2, &tmp1, NULL); + return res; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_toom_sqr.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_toom_sqr.c */ + +/* Start: bn_mp_toradix.c */ +#include <tommath.h> +#ifdef BN_MP_TORADIX_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* stores a bignum as a ASCII string in a given radix (2..64) */ +int mp_toradix (mp_int * a, char *str, int radix) +{ + int res, digs; + mp_int t; + mp_digit d; + char *_s = str; + + /* check range of the radix */ + if (radix < 2 || radix > 64) { + return MP_VAL; + } + + /* quick out if its zero */ + if (mp_iszero(a) == 1) { + *str++ = '0'; + *str = '\0'; + return MP_OKAY; + } + + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + + /* if it is negative output a - */ + if (t.sign == MP_NEG) { + ++_s; + *str++ = '-'; + t.sign = MP_ZPOS; + } + + digs = 0; + while (mp_iszero (&t) == 0) { + if ((res = mp_div_d (&t, (mp_digit) radix, &t, &d)) != MP_OKAY) { + mp_clear (&t); + return res; + } + *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] + */ + bn_reverse ((unsigned char *)_s, digs); + + /* append a NULL so the string is properly terminated */ + *str = '\0'; + + mp_clear (&t); + return MP_OKAY; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_toradix.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_toradix.c */ + +/* Start: bn_mp_toradix_n.c */ +#include <tommath.h> +#ifdef BN_MP_TORADIX_N_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* stores a bignum as a ASCII string in a given radix (2..64) + * + * Stores upto maxlen-1 chars and always a NULL byte + */ +int mp_toradix_n(mp_int * a, char *str, int radix, int maxlen) +{ + int res, digs; + mp_int t; + mp_digit d; + char *_s = str; + + /* check range of the maxlen, radix */ + if (maxlen < 2 || radix < 2 || radix > 64) { + return MP_VAL; + } + + /* quick out if its zero */ + if (mp_iszero(a) == MP_YES) { + *str++ = '0'; + *str = '\0'; + return MP_OKAY; + } + + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + + /* 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 = 0; + while (mp_iszero (&t) == 0) { + if (--maxlen < 1) { + /* no more room */ + break; + } + if ((res = mp_div_d (&t, (mp_digit) radix, &t, &d)) != MP_OKAY) { + mp_clear (&t); + return res; + } + *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 + */ + bn_reverse ((unsigned char *)_s, digs); + + /* append a NULL so the string is properly terminated */ + *str = '\0'; + + mp_clear (&t); + return MP_OKAY; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_toradix_n.c,v $ */ +/* $Revision: 1.4 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_toradix_n.c */ + +/* Start: bn_mp_unsigned_bin_size.c */ +#include <tommath.h> +#ifdef BN_MP_UNSIGNED_BIN_SIZE_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* get the size for an unsigned equivalent */ +int mp_unsigned_bin_size (mp_int * a) +{ + int size = mp_count_bits (a); + return (size / 8 + ((size & 7) != 0 ? 1 : 0)); +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_unsigned_bin_size.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_unsigned_bin_size.c */ + +/* Start: bn_mp_xor.c */ +#include <tommath.h> +#ifdef BN_MP_XOR_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* XOR two ints together */ +int +mp_xor (mp_int * a, mp_int * b, mp_int * c) +{ + int res, ix, px; + mp_int t, *x; + + if (a->used > b->used) { + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + px = b->used; + x = b; + } else { + if ((res = mp_init_copy (&t, b)) != MP_OKAY) { + return res; + } + px = a->used; + x = a; + } + + for (ix = 0; ix < px; ix++) { + t.dp[ix] ^= x->dp[ix]; + } + mp_clamp (&t); + mp_exch (c, &t); + mp_clear (&t); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_xor.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_xor.c */ + +/* Start: bn_mp_zero.c */ +#include <tommath.h> +#ifdef BN_MP_ZERO_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* set to zero */ +void mp_zero (mp_int * a) +{ + int n; + mp_digit *tmp; + + a->sign = MP_ZPOS; + a->used = 0; + + tmp = a->dp; + for (n = 0; n < a->alloc; n++) { + *tmp++ = 0; + } +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_zero.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_mp_zero.c */ + +/* Start: bn_prime_tab.c */ +#include <tommath.h> +#ifdef BN_PRIME_TAB_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ +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 +}; +#endif + +/* $Source: /cvs/libtom/libtommath/bn_prime_tab.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_prime_tab.c */ + +/* Start: bn_reverse.c */ +#include <tommath.h> +#ifdef BN_REVERSE_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* reverse an array, used for radix code */ +void +bn_reverse (unsigned char *s, int len) +{ + int ix, iy; + unsigned char t; + + ix = 0; + iy = len - 1; + while (ix < iy) { + t = s[ix]; + s[ix] = s[iy]; + s[iy] = t; + ++ix; + --iy; + } +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_reverse.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_reverse.c */ + +/* Start: bn_s_mp_add.c */ +#include <tommath.h> +#ifdef BN_S_MP_ADD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* low level addition, based on HAC pp.594, Algorithm 14.7 */ +int +s_mp_add (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int *x; + int olduse, res, 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 ((res = mp_grow (c, max + 1)) != MP_OKAY) { + return res; + } + } + + /* get old used digit count and set new one */ + olduse = c->used; + c->used = max + 1; + + { + register mp_digit u, *tmpa, *tmpb, *tmpc; + register 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)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)DIGIT_BIT); + + /* take away carry bit from T[i] */ + *tmpc++ &= MP_MASK; + } + } + + /* add carry */ + *tmpc++ = u; + + /* clear digits above oldused */ + for (i = c->used; i < olduse; i++) { + *tmpc++ = 0; + } + } + + mp_clamp (c); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_s_mp_add.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_s_mp_add.c */ + +/* Start: bn_s_mp_exptmod.c */ +#include <tommath.h> +#ifdef BN_S_MP_EXPTMOD_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ +#ifdef MP_LOW_MEM + #define TAB_SIZE 32 +#else + #define TAB_SIZE 256 +#endif + +int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) +{ + mp_int M[TAB_SIZE], res, mu; + mp_digit buf; + int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + int (*redux)(mp_int*,mp_int*,mp_int*); + + /* 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; + } + +#ifdef MP_LOW_MEM + if (winsize > 5) { + winsize = 5; + } +#endif + + /* 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[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_MU; + } + + for (x = 0; x < (winsize - 1); x++) { + /* square it */ + if ((err = mp_sqr (&M[1 << (winsize - 1)], + &M[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_MU; + } + + /* reduce modulo P */ + if ((err = redux (&M[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, 1); + + /* 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) DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1; + 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 + +/* $Source: /cvs/libtom/libtommath/bn_s_mp_exptmod.c,v $ */ +/* $Revision: 1.4 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_s_mp_exptmod.c */ + +/* Start: bn_s_mp_mul_digs.c */ +#include <tommath.h> +#ifdef BN_S_MP_MUL_DIGS_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* 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. + */ +int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + mp_int t; + int res, pa, pb, ix, iy; + mp_digit u; + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + + /* can we use the fast multiplier? */ + if (((digs) < MP_WARRAY) && + MIN (a->used, b->used) < + (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_s_mp_mul_digs (a, b, c, digs); + } + + if ((res = mp_init_size (&t, digs)) != MP_OKAY) { + return res; + } + 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 = 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) 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 + +/* $Source: /cvs/libtom/libtommath/bn_s_mp_mul_digs.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_s_mp_mul_digs.c */ + +/* Start: bn_s_mp_mul_high_digs.c */ +#include <tommath.h> +#ifdef BN_S_MP_MUL_HIGH_DIGS_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* multiplies |a| * |b| and does not compute the lower digs digits + * [meant to get the higher part of the product] + */ +int +s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + mp_int t; + int res, pa, pb, ix, iy; + mp_digit u; + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + + /* can we use the fast multiplier? */ +#ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C + if (((a->used + b->used + 1) < MP_WARRAY) + && MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_s_mp_mul_high_digs (a, b, c, digs); + } +#endif + + if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) { + return res; + } + 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) DIGIT_BIT)); + } + *tmpt = u; + } + mp_clamp (&t); + mp_exch (&t, c); + mp_clear (&t); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_s_mp_mul_high_digs.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_s_mp_mul_high_digs.c */ + +/* Start: bn_s_mp_sqr.c */ +#include <tommath.h> +#ifdef BN_S_MP_SQR_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */ +int s_mp_sqr (mp_int * a, mp_int * b) +{ + mp_int t; + int res, ix, iy, pa; + mp_word r; + mp_digit u, tmpx, *tmpt; + + pa = a->used; + if ((res = mp_init_size (&t, 2*pa + 1)) != MP_OKAY) { + return res; + } + + /* 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) 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) DIGIT_BIT)); + } + /* propagate upwards */ + while (u != ((mp_digit) 0)) { + r = ((mp_word) *tmpt) + ((mp_word) u); + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + } + } + + mp_clamp (&t); + mp_exch (&t, b); + mp_clear (&t); + return MP_OKAY; +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_s_mp_sqr.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_s_mp_sqr.c */ + +/* Start: bn_s_mp_sub.c */ +#include <tommath.h> +#ifdef BN_S_MP_SUB_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */ +int +s_mp_sub (mp_int * a, mp_int * b, mp_int * c) +{ + int olduse, res, min, max; + + /* find sizes */ + min = b->used; + max = a->used; + + /* init result */ + if (c->alloc < max) { + if ((res = mp_grow (c, max)) != MP_OKAY) { + return res; + } + } + olduse = c->used; + c->used = max; + + { + register mp_digit u, *tmpa, *tmpb, *tmpc; + register 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_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); + + /* 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_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); + + /* Clear carry from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* clear digits above used (since we may not have grown result above) */ + for (i = c->used; i < olduse; i++) { + *tmpc++ = 0; + } + } + + mp_clamp (c); + return MP_OKAY; +} + +#endif + +/* $Source: /cvs/libtom/libtommath/bn_s_mp_sub.c,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bn_s_mp_sub.c */ + +/* Start: bncore.c */ +#include <tommath.h> +#ifdef BNCORE_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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ + +/* Known optimal configurations + + CPU /Compiler /MUL CUTOFF/SQR CUTOFF +------------------------------------------------------------- + Intel P4 Northwood /GCC v3.4.1 / 88/ 128/LTM 0.32 ;-) + AMD Athlon64 /GCC v3.4.4 / 80/ 120/LTM 0.35 + +*/ + +int KARATSUBA_MUL_CUTOFF = 80, /* Min. number of digits before Karatsuba multiplication is used. */ + KARATSUBA_SQR_CUTOFF = 120, /* Min. number of digits before Karatsuba squaring is used. */ + + TOOM_MUL_CUTOFF = 350, /* no optimal values of these are known yet so set em high */ + TOOM_SQR_CUTOFF = 400; +#endif + +/* $Source: /cvs/libtom/libtommath/bncore.c,v $ */ +/* $Revision: 1.4 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ + +/* End: bncore.c */ + + +/* EOF */ diff --git a/libtommath/pretty.build b/libtommath/pretty.build new file mode 100644 index 0000000..a708b8a --- /dev/null +++ b/libtommath/pretty.build @@ -0,0 +1,66 @@ +#!/bin/perl -w +# +# Cute little builder for perl +# Total waste of development time... +# +# This will build all the object files and then the archive .a file +# requires GCC, GNU make and a sense of humour. +# +# Tom St Denis +use strict; + +my $count = 0; +my $starttime = time; +my $rate = 0; +print "Scanning for source files...\n"; +foreach my $filename (glob "*.c") { + ++$count; +} +print "Source files to build: $count\nBuilding...\n"; +my $i = 0; +my $lines = 0; +my $filesbuilt = 0; +foreach my $filename (glob "*.c") { + printf("Building %3.2f%%, ", (++$i/$count)*100.0); + if ($i % 4 == 0) { print "/, "; } + if ($i % 4 == 1) { print "-, "; } + if ($i % 4 == 2) { print "\\, "; } + if ($i % 4 == 3) { print "|, "; } + if ($rate > 0) { + my $tleft = ($count - $i) / $rate; + my $tsec = $tleft%60; + my $tmin = ($tleft/60)%60; + my $thour = ($tleft/3600)%60; + printf("%2d:%02d:%02d left, ", $thour, $tmin, $tsec); + } + my $cnt = ($i/$count)*30.0; + my $x = 0; + print "["; + for (; $x < $cnt; $x++) { print "#"; } + for (; $x < 30; $x++) { print " "; } + print "]\r"; + my $tmp = $filename; + $tmp =~ s/\.c/".o"/ge; + if (open(SRC, "<$tmp")) { + close SRC; + } else { + !system("make $tmp > /dev/null 2>/dev/null") or die "\nERROR: Failed to make $tmp!!!\n"; + open( SRC, "<$filename" ) or die "Couldn't open $filename for reading: $!"; + ++$lines while (<SRC>); + close SRC or die "Error closing $filename after reading: $!"; + ++$filesbuilt; + } + + # update timer + if (time != $starttime) { + my $delay = time - $starttime; + $rate = $i/$delay; + } +} + +# finish building the library +printf("\nFinished building source (%d seconds, %3.2f files per second).\n", time - $starttime, $rate); +print "Compiled approximately $filesbuilt files and $lines lines of code.\n"; +print "Doing final make (building archive...)\n"; +!system("make > /dev/null 2>/dev/null") or die "\nERROR: Failed to perform last make command!!!\n"; +print "done.\n";
\ No newline at end of file diff --git a/libtommath/tombc/grammar.txt b/libtommath/tombc/grammar.txt new file mode 100644 index 0000000..a780e75 --- /dev/null +++ b/libtommath/tombc/grammar.txt @@ -0,0 +1,35 @@ +program := program statement | statement | empty +statement := { statement } | + identifier = numexpression; | + identifier[numexpression] = numexpression; | + function(expressionlist); | + for (identifer = numexpression; numexpression; identifier = numexpression) { statement } | + while (numexpression) { statement } | + if (numexpresion) { statement } elif | + break; | + continue; + +elif := else statement | empty +function := abs | countbits | exptmod | jacobi | print | isprime | nextprime | issquare | readinteger | exit +expressionlist := expressionlist, expression | expression + +// LR(1) !!!? +expression := string | numexpression +numexpression := cmpexpr && cmpexpr | cmpexpr \|\| cmpexpr | cmpexpr +cmpexpr := boolexpr < boolexpr | boolexpr > boolexpr | boolexpr == boolexpr | + boolexpr <= boolexpr | boolexpr >= boolexpr | boolexpr +boolexpr := shiftexpr & shiftexpr | shiftexpr ^ shiftexpr | shiftexpr \| shiftexpr | shiftexpr +shiftexpr := addsubexpr << addsubexpr | addsubexpr >> addsubexpr | addsubexpr +addsubexpr := mulexpr + mulexpr | mulexpr - mulexpr | mulexpr +mulexpr := expr * expr | expr / expr | expr % expr | expr +expr := -nexpr | nexpr +nexpr := integer | identifier | ( numexpression ) | identifier[numexpression] + +identifier := identifer digits | identifier alpha | alpha +alpha := a ... z | A ... Z +integer := hexnumber | digits +hexnumber := 0xhexdigits +hexdigits := hexdigits hexdigit | hexdigit +hexdigit := 0 ... 9 | a ... f | A ... F +digits := digits digit | digit +digit := 0 ... 9 diff --git a/libtommath/tommath.h b/libtommath/tommath.h new file mode 100644 index 0000000..1ead3d0 --- /dev/null +++ b/libtommath/tommath.h @@ -0,0 +1,584 @@ +/* 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 was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com + */ +#ifndef BN_H_ +#define BN_H_ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <limits.h> + +#include "tommath_class.h" + +#ifndef MIN + #define MIN(x,y) ((x)<(y)?(x):(y)) +#endif + +#ifndef MAX + #define MAX(x,y) ((x)>(y)?(x):(y)) +#endif + +#ifdef __cplusplus +extern "C" { + +/* C++ compilers don't like assigning void * to mp_digit * */ +#define OPT_CAST(x) (x *) + +#else + +/* C on the other hand doesn't care */ +#define OPT_CAST(x) + +#endif + + +/* detect 64-bit mode if possible */ +#if defined(__x86_64__) + #if !(defined(MP_64BIT) && defined(MP_16BIT) && defined(MP_8BIT)) + #define MP_64BIT + #endif +#endif + +/* some default configurations. + * + * A "mp_digit" must be able to hold DIGIT_BIT + 1 bits + * A "mp_word" must be able to hold 2*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 unsigned char mp_digit; + typedef unsigned short mp_word; +#elif defined(MP_16BIT) + typedef unsigned short mp_digit; + typedef unsigned long mp_word; +#elif defined(MP_64BIT) + /* for GCC only on supported platforms */ +#ifndef CRYPT + typedef unsigned long long ulong64; + typedef signed long long long64; +#endif + + typedef unsigned long mp_digit; + typedef unsigned long mp_word __attribute__ ((mode(TI))); + + #define DIGIT_BIT 60 +#else + /* this is the default case, 28-bit digits */ + + /* this is to make porting into LibTomCrypt easier :-) */ +#ifndef CRYPT + #if defined(_MSC_VER) || defined(__BORLANDC__) + typedef unsigned __int64 ulong64; + typedef signed __int64 long64; + #else + typedef unsigned long long ulong64; + typedef signed long long long64; + #endif +#endif + + typedef unsigned long mp_digit; + typedef ulong64 mp_word; + +#ifdef MP_31BIT + /* this is an extension that uses 31-bit digits */ + #define DIGIT_BIT 31 +#else + /* default case is 28-bit digits, defines MP_28BIT as a handy macro to test */ + #define DIGIT_BIT 28 + #define MP_28BIT +#endif +#endif + +/* define heap macros */ +#ifndef CRYPT + /* default to libc stuff */ + #ifndef XMALLOC + #define XMALLOC malloc + #define XFREE free + #define XREALLOC realloc + #define XCALLOC calloc + #else + /* prototypes for our heap functions */ + extern void *XMALLOC(size_t n); + extern void *XREALLOC(void *p, size_t n); + extern void *XCALLOC(size_t n, size_t s); + extern void XFREE(void *p); + #endif +#endif + + +/* otherwise the bits per digit is calculated automatically from the size of a mp_digit */ +#ifndef DIGIT_BIT + #define DIGIT_BIT ((int)((CHAR_BIT * sizeof(mp_digit) - 1))) /* bits per digit */ +#endif + +#define MP_DIGIT_BIT DIGIT_BIT +#define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1)) +#define MP_DIGIT_MAX MP_MASK + +/* equalities */ +#define MP_LT -1 /* less than */ +#define MP_EQ 0 /* equal to */ +#define MP_GT 1 /* greater than */ + +#define MP_ZPOS 0 /* positive integer */ +#define MP_NEG 1 /* negative */ + +#define MP_OKAY 0 /* ok result */ +#define MP_MEM -2 /* out of mem */ +#define MP_VAL -3 /* invalid input */ +#define MP_RANGE MP_VAL + +#define MP_YES 1 /* yes response */ +#define MP_NO 0 /* no response */ + +/* Primality generation flags */ +#define LTM_PRIME_BBS 0x0001 /* BBS style prime */ +#define LTM_PRIME_SAFE 0x0002 /* Safe prime (p-1)/2 == prime */ +#define LTM_PRIME_2MSB_ON 0x0008 /* force 2nd MSB to 1 */ + +typedef int mp_err; + +/* you'll have to tune these... */ +extern int KARATSUBA_MUL_CUTOFF, + KARATSUBA_SQR_CUTOFF, + TOOM_MUL_CUTOFF, + TOOM_SQR_CUTOFF; + +/* define this to use lower memory usage routines (exptmods mostly) */ +/* #define MP_LOW_MEM */ + +/* default precision */ +#ifndef MP_PREC + #ifndef MP_LOW_MEM + #define MP_PREC 32 /* default digits of precision */ + #else + #define MP_PREC 8 /* default digits of precision */ + #endif +#endif + +/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */ +#define MP_WARRAY (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1)) + +/* the infamous mp_int structure */ +typedef struct { + int used, alloc, 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 ltm_prime_callback(unsigned char *dst, int len, void *dat); + + +#define USED(m) ((m)->used) +#define DIGIT(m,k) ((m)->dp[(k)]) +#define SIGN(m) ((m)->sign) + +/* error code to char* string */ +char *mp_error_to_string(int code); + +/* ---> init and deinit bignum functions <--- */ +/* init a bignum */ +int mp_init(mp_int *a); + +/* free a bignum */ +void mp_clear(mp_int *a); + +/* init a null terminated series of arguments */ +int mp_init_multi(mp_int *mp, ...); + +/* clear a null terminated series of arguments */ +void mp_clear_multi(mp_int *mp, ...); + +/* exchange two ints */ +void mp_exch(mp_int *a, mp_int *b); + +/* shrink ram required for a bignum */ +int mp_shrink(mp_int *a); + +/* grow an int to a given size */ +int mp_grow(mp_int *a, int size); + +/* init to a given number of digits */ +int mp_init_size(mp_int *a, int size); + +/* ---> Basic Manipulations <--- */ +#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO) +#define mp_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO) +#define mp_isodd(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO) + +/* set to zero */ +void mp_zero(mp_int *a); + +/* set to a digit */ +void mp_set(mp_int *a, mp_digit b); + +/* set a 32-bit const */ +int mp_set_int(mp_int *a, unsigned long b); + +/* get a 32-bit value */ +unsigned long mp_get_int(mp_int * a); + +/* initialize and set a digit */ +int mp_init_set (mp_int * a, mp_digit b); + +/* initialize and set 32-bit value */ +int mp_init_set_int (mp_int * a, unsigned long b); + +/* copy, b = a */ +int mp_copy(mp_int *a, mp_int *b); + +/* inits and copies, a = b */ +int mp_init_copy(mp_int *a, mp_int *b); + +/* trim unused digits */ +void mp_clamp(mp_int *a); + +/* ---> digit manipulation <--- */ + +/* right shift by "b" digits */ +void mp_rshd(mp_int *a, int b); + +/* left shift by "b" digits */ +int mp_lshd(mp_int *a, int b); + +/* c = a / 2**b */ +int mp_div_2d(mp_int *a, int b, mp_int *c, mp_int *d); + +/* b = a/2 */ +int mp_div_2(mp_int *a, mp_int *b); + +/* c = a * 2**b */ +int mp_mul_2d(mp_int *a, int b, mp_int *c); + +/* b = a*2 */ +int mp_mul_2(mp_int *a, mp_int *b); + +/* c = a mod 2**d */ +int mp_mod_2d(mp_int *a, int b, mp_int *c); + +/* computes a = 2**b */ +int mp_2expt(mp_int *a, int b); + +/* Counts the number of lsbs which are zero before the first zero bit */ +int mp_cnt_lsb(mp_int *a); + +/* I Love Earth! */ + +/* makes a pseudo-random int of a given size */ +int mp_rand(mp_int *a, int digits); + +/* ---> binary operations <--- */ +/* c = a XOR b */ +int mp_xor(mp_int *a, mp_int *b, mp_int *c); + +/* c = a OR b */ +int mp_or(mp_int *a, mp_int *b, mp_int *c); + +/* c = a AND b */ +int mp_and(mp_int *a, mp_int *b, mp_int *c); + +/* ---> Basic arithmetic <--- */ + +/* b = -a */ +int mp_neg(mp_int *a, mp_int *b); + +/* b = |a| */ +int mp_abs(mp_int *a, mp_int *b); + +/* compare a to b */ +int mp_cmp(mp_int *a, mp_int *b); + +/* compare |a| to |b| */ +int mp_cmp_mag(mp_int *a, mp_int *b); + +/* c = a + b */ +int mp_add(mp_int *a, mp_int *b, mp_int *c); + +/* c = a - b */ +int mp_sub(mp_int *a, mp_int *b, mp_int *c); + +/* c = a * b */ +int mp_mul(mp_int *a, mp_int *b, mp_int *c); + +/* b = a*a */ +int mp_sqr(mp_int *a, mp_int *b); + +/* a/b => cb + d == a */ +int mp_div(mp_int *a, mp_int *b, mp_int *c, mp_int *d); + +/* c = a mod b, 0 <= c < b */ +int mp_mod(mp_int *a, mp_int *b, mp_int *c); + +/* ---> single digit functions <--- */ + +/* compare against a single digit */ +int mp_cmp_d(mp_int *a, mp_digit b); + +/* c = a + b */ +int mp_add_d(mp_int *a, mp_digit b, mp_int *c); + +/* c = a - b */ +int mp_sub_d(mp_int *a, mp_digit b, mp_int *c); + +/* c = a * b */ +int mp_mul_d(mp_int *a, mp_digit b, mp_int *c); + +/* a/b => cb + d == a */ +int mp_div_d(mp_int *a, mp_digit b, mp_int *c, mp_digit *d); + +/* a/3 => 3c + d == a */ +int mp_div_3(mp_int *a, mp_int *c, mp_digit *d); + +/* c = a**b */ +int mp_expt_d(mp_int *a, mp_digit b, mp_int *c); + +/* c = a mod b, 0 <= c < b */ +int mp_mod_d(mp_int *a, mp_digit b, mp_digit *c); + +/* ---> number theory <--- */ + +/* d = a + b (mod c) */ +int mp_addmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); + +/* d = a - b (mod c) */ +int mp_submod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); + +/* d = a * b (mod c) */ +int mp_mulmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); + +/* c = a * a (mod b) */ +int mp_sqrmod(mp_int *a, mp_int *b, mp_int *c); + +/* c = 1/a (mod b) */ +int mp_invmod(mp_int *a, mp_int *b, mp_int *c); + +/* c = (a, b) */ +int mp_gcd(mp_int *a, mp_int *b, mp_int *c); + +/* produces value such that U1*a + U2*b = U3 */ +int mp_exteuclid(mp_int *a, mp_int *b, mp_int *U1, mp_int *U2, mp_int *U3); + +/* c = [a, b] or (a*b)/(a, b) */ +int mp_lcm(mp_int *a, mp_int *b, mp_int *c); + +/* finds one of the b'th root of a, such that |c|**b <= |a| + * + * returns error if a < 0 and b is even + */ +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); + +/* is number a square? */ +int mp_is_square(mp_int *arg, int *ret); + +/* computes the jacobi c = (a | n) (or Legendre if b is prime) */ +int mp_jacobi(mp_int *a, mp_int *n, int *c); + +/* used to setup the Barrett reduction for a given modulus b */ +int mp_reduce_setup(mp_int *a, mp_int *b); + +/* Barrett Reduction, computes a (mod b) with a precomputed value c + * + * Assumes that 0 < a <= b*b, note if 0 > a > -(b*b) then you can merely + * compute the reduction as -1 * mp_reduce(mp_abs(a)) [pseudo code]. + */ +int mp_reduce(mp_int *a, mp_int *b, mp_int *c); + +/* setups the montgomery reduction */ +int mp_montgomery_setup(mp_int *a, mp_digit *mp); + +/* computes a = B**n mod b without division or multiplication useful for + * normalizing numbers in a Montgomery system. + */ +int mp_montgomery_calc_normalization(mp_int *a, mp_int *b); + +/* computes x/R == x (mod N) via Montgomery Reduction */ +int mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp); + +/* returns 1 if a is a valid DR modulus */ +int mp_dr_is_modulus(mp_int *a); + +/* sets the value of "d" required for mp_dr_reduce */ +void mp_dr_setup(mp_int *a, mp_digit *d); + +/* reduces a modulo b using the Diminished Radix method */ +int mp_dr_reduce(mp_int *a, mp_int *b, mp_digit mp); + +/* returns true if a can be reduced with mp_reduce_2k */ +int mp_reduce_is_2k(mp_int *a); + +/* determines k value for 2k reduction */ +int mp_reduce_2k_setup(mp_int *a, mp_digit *d); + +/* reduces a modulo b where b is of the form 2**p - k [0 <= a] */ +int mp_reduce_2k(mp_int *a, mp_int *n, mp_digit d); + +/* returns true if a can be reduced with mp_reduce_2k_l */ +int mp_reduce_is_2k_l(mp_int *a); + +/* determines k value for 2k reduction */ +int mp_reduce_2k_setup_l(mp_int *a, mp_int *d); + +/* reduces a modulo b where b is of the form 2**p - k [0 <= a] */ +int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d); + +/* d = a**b (mod c) */ +int mp_exptmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); + +/* ---> Primes <--- */ + +/* number of primes */ +#ifdef MP_8BIT + #define PRIME_SIZE 31 +#else + #define PRIME_SIZE 256 +#endif + +/* table of first PRIME_SIZE primes */ +extern const mp_digit ltm_prime_tab[]; + +/* result=1 if a is divisible by one of the first PRIME_SIZE primes */ +int mp_prime_is_divisible(mp_int *a, int *result); + +/* performs one Fermat test of "a" using base "b". + * Sets result to 0 if composite or 1 if probable prime + */ +int mp_prime_fermat(mp_int *a, mp_int *b, int *result); + +/* performs one Miller-Rabin test of "a" using base "b". + * Sets result to 0 if composite or 1 if probable prime + */ +int mp_prime_miller_rabin(mp_int *a, mp_int *b, int *result); + +/* 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); + +/* performs t rounds of Miller-Rabin on "a" using the first + * t prime bases. Also performs an initial sieve of trial + * division. Determines if "a" is prime with probability + * of error no more than (1/4)**t. + * + * Sets result to 1 if probably prime, 0 otherwise + */ +int mp_prime_is_prime(mp_int *a, int t, int *result); + +/* 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 + */ +int mp_prime_next_prime(mp_int *a, int t, int bbs_style); + +/* 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_prime_random_ex(a, t, ((size) * 8) + 1, (bbs==1)?LTM_PRIME_BBS:0, cb, dat) + +/* makes a truly random prime of a given size (bits), + * + * Flags are as follows: + * + * LTM_PRIME_BBS - make prime congruent to 3 mod 4 + * LTM_PRIME_SAFE - make sure (p-1)/2 is prime as well (implies LTM_PRIME_BBS) + * LTM_PRIME_2MSB_OFF - make the 2nd highest bit zero + * LTM_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 + * + */ +int mp_prime_random_ex(mp_int *a, int t, int size, int flags, ltm_prime_callback cb, void *dat); + +/* ---> radix conversion <--- */ +int mp_count_bits(mp_int *a); + +int mp_unsigned_bin_size(mp_int *a); +int mp_read_unsigned_bin(mp_int *a, const unsigned char *b, int c); +int mp_to_unsigned_bin(mp_int *a, unsigned char *b); +int mp_to_unsigned_bin_n (mp_int * a, unsigned char *b, unsigned long *outlen); + +int mp_signed_bin_size(mp_int *a); +int mp_read_signed_bin(mp_int *a, const unsigned char *b, int c); +int mp_to_signed_bin(mp_int *a, unsigned char *b); +int mp_to_signed_bin_n (mp_int * a, unsigned char *b, unsigned long *outlen); + +int mp_read_radix(mp_int *a, const char *str, int radix); +int mp_toradix(mp_int *a, char *str, int radix); +int mp_toradix_n(mp_int * a, char *str, int radix, int maxlen); +int mp_radix_size(mp_int *a, int radix, int *size); + +int mp_fread(mp_int *a, int radix, FILE *stream); +int mp_fwrite(mp_int *a, int radix, FILE *stream); + +#define mp_read_raw(mp, str, len) mp_read_signed_bin((mp), (str), (len)) +#define mp_raw_size(mp) mp_signed_bin_size(mp) +#define mp_toraw(mp, str) mp_to_signed_bin((mp), (str)) +#define mp_read_mag(mp, str, len) mp_read_unsigned_bin((mp), (str), (len)) +#define mp_mag_size(mp) mp_unsigned_bin_size(mp) +#define mp_tomag(mp, str) mp_to_unsigned_bin((mp), (str)) + +#define mp_tobinary(M, S) mp_toradix((M), (S), 2) +#define mp_tooctal(M, S) mp_toradix((M), (S), 8) +#define mp_todecimal(M, S) mp_toradix((M), (S), 10) +#define mp_tohex(M, S) mp_toradix((M), (S), 16) + +/* lowlevel functions, do not call! */ +int s_mp_add(mp_int *a, mp_int *b, mp_int *c); +int s_mp_sub(mp_int *a, mp_int *b, mp_int *c); +#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1) +int fast_s_mp_mul_digs(mp_int *a, mp_int *b, mp_int *c, int digs); +int s_mp_mul_digs(mp_int *a, mp_int *b, mp_int *c, int digs); +int fast_s_mp_mul_high_digs(mp_int *a, mp_int *b, mp_int *c, int digs); +int s_mp_mul_high_digs(mp_int *a, mp_int *b, mp_int *c, int digs); +int fast_s_mp_sqr(mp_int *a, mp_int *b); +int s_mp_sqr(mp_int *a, mp_int *b); +int mp_karatsuba_mul(mp_int *a, mp_int *b, mp_int *c); +int mp_toom_mul(mp_int *a, mp_int *b, mp_int *c); +int mp_karatsuba_sqr(mp_int *a, mp_int *b); +int mp_toom_sqr(mp_int *a, mp_int *b); +int fast_mp_invmod(mp_int *a, mp_int *b, mp_int *c); +int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c); +int fast_mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp); +int mp_exptmod_fast(mp_int *G, mp_int *X, mp_int *P, mp_int *Y, int mode); +int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int mode); +void bn_reverse(unsigned char *s, int len); + +extern const char *mp_s_rmap; + +#ifdef __cplusplus + } +#endif + +#endif + + +/* $Source: /cvs/libtom/libtommath/tommath.h,v $ */ +/* $Revision: 1.8 $ */ +/* $Date: 2006/03/31 14:18:44 $ */ diff --git a/libtommath/tommath.out b/libtommath/tommath.out new file mode 100644 index 0000000..9f62617 --- /dev/null +++ b/libtommath/tommath.out @@ -0,0 +1,139 @@ +\BOOKMARK [0][-]{chapter.1}{Introduction}{} +\BOOKMARK [1][-]{section.1.1}{Multiple Precision Arithmetic}{chapter.1} +\BOOKMARK [2][-]{subsection.1.1.1}{What is Multiple Precision Arithmetic?}{section.1.1} +\BOOKMARK [2][-]{subsection.1.1.2}{The Need for Multiple Precision Arithmetic}{section.1.1} +\BOOKMARK [2][-]{subsection.1.1.3}{Benefits of Multiple Precision Arithmetic}{section.1.1} +\BOOKMARK [1][-]{section.1.2}{Purpose of This Text}{chapter.1} +\BOOKMARK [1][-]{section.1.3}{Discussion and Notation}{chapter.1} +\BOOKMARK [2][-]{subsection.1.3.1}{Notation}{section.1.3} +\BOOKMARK [2][-]{subsection.1.3.2}{Precision Notation}{section.1.3} +\BOOKMARK [2][-]{subsection.1.3.3}{Algorithm Inputs and Outputs}{section.1.3} +\BOOKMARK [2][-]{subsection.1.3.4}{Mathematical Expressions}{section.1.3} +\BOOKMARK [2][-]{subsection.1.3.5}{Work Effort}{section.1.3} +\BOOKMARK [1][-]{section.1.4}{Exercises}{chapter.1} +\BOOKMARK [1][-]{section.1.5}{Introduction to LibTomMath}{chapter.1} +\BOOKMARK [2][-]{subsection.1.5.1}{What is LibTomMath?}{section.1.5} +\BOOKMARK [2][-]{subsection.1.5.2}{Goals of LibTomMath}{section.1.5} +\BOOKMARK [1][-]{section.1.6}{Choice of LibTomMath}{chapter.1} +\BOOKMARK [2][-]{subsection.1.6.1}{Code Base}{section.1.6} +\BOOKMARK [2][-]{subsection.1.6.2}{API Simplicity}{section.1.6} +\BOOKMARK [2][-]{subsection.1.6.3}{Optimizations}{section.1.6} +\BOOKMARK [2][-]{subsection.1.6.4}{Portability and Stability}{section.1.6} +\BOOKMARK [2][-]{subsection.1.6.5}{Choice}{section.1.6} +\BOOKMARK [0][-]{chapter.2}{Getting Started}{} +\BOOKMARK [1][-]{section.2.1}{Library Basics}{chapter.2} +\BOOKMARK [1][-]{section.2.2}{What is a Multiple Precision Integer?}{chapter.2} +\BOOKMARK [2][-]{subsection.2.2.1}{The mp\137int Structure}{section.2.2} +\BOOKMARK [1][-]{section.2.3}{Argument Passing}{chapter.2} +\BOOKMARK [1][-]{section.2.4}{Return Values}{chapter.2} +\BOOKMARK [1][-]{section.2.5}{Initialization and Clearing}{chapter.2} +\BOOKMARK [2][-]{subsection.2.5.1}{Initializing an mp\137int}{section.2.5} +\BOOKMARK [2][-]{subsection.2.5.2}{Clearing an mp\137int}{section.2.5} +\BOOKMARK [1][-]{section.2.6}{Maintenance Algorithms}{chapter.2} +\BOOKMARK [2][-]{subsection.2.6.1}{Augmenting an mp\137int's Precision}{section.2.6} +\BOOKMARK [2][-]{subsection.2.6.2}{Initializing Variable Precision mp\137ints}{section.2.6} +\BOOKMARK [2][-]{subsection.2.6.3}{Multiple Integer Initializations and Clearings}{section.2.6} +\BOOKMARK [2][-]{subsection.2.6.4}{Clamping Excess Digits}{section.2.6} +\BOOKMARK [0][-]{chapter.3}{Basic Operations}{} +\BOOKMARK [1][-]{section.3.1}{Introduction}{chapter.3} +\BOOKMARK [1][-]{section.3.2}{Assigning Values to mp\137int Structures}{chapter.3} +\BOOKMARK [2][-]{subsection.3.2.1}{Copying an mp\137int}{section.3.2} +\BOOKMARK [2][-]{subsection.3.2.2}{Creating a Clone}{section.3.2} +\BOOKMARK [1][-]{section.3.3}{Zeroing an Integer}{chapter.3} +\BOOKMARK [1][-]{section.3.4}{Sign Manipulation}{chapter.3} +\BOOKMARK [2][-]{subsection.3.4.1}{Absolute Value}{section.3.4} +\BOOKMARK [2][-]{subsection.3.4.2}{Integer Negation}{section.3.4} +\BOOKMARK [1][-]{section.3.5}{Small Constants}{chapter.3} +\BOOKMARK [2][-]{subsection.3.5.1}{Setting Small Constants}{section.3.5} +\BOOKMARK [2][-]{subsection.3.5.2}{Setting Large Constants}{section.3.5} +\BOOKMARK [1][-]{section.3.6}{Comparisons}{chapter.3} +\BOOKMARK [2][-]{subsection.3.6.1}{Unsigned Comparisions}{section.3.6} +\BOOKMARK [2][-]{subsection.3.6.2}{Signed Comparisons}{section.3.6} +\BOOKMARK [0][-]{chapter.4}{Basic Arithmetic}{} +\BOOKMARK [1][-]{section.4.1}{Introduction}{chapter.4} +\BOOKMARK [1][-]{section.4.2}{Addition and Subtraction}{chapter.4} +\BOOKMARK [2][-]{subsection.4.2.1}{Low Level Addition}{section.4.2} +\BOOKMARK [2][-]{subsection.4.2.2}{Low Level Subtraction}{section.4.2} +\BOOKMARK [2][-]{subsection.4.2.3}{High Level Addition}{section.4.2} +\BOOKMARK [2][-]{subsection.4.2.4}{High Level Subtraction}{section.4.2} +\BOOKMARK [1][-]{section.4.3}{Bit and Digit Shifting}{chapter.4} +\BOOKMARK [2][-]{subsection.4.3.1}{Multiplication by Two}{section.4.3} +\BOOKMARK [2][-]{subsection.4.3.2}{Division by Two}{section.4.3} +\BOOKMARK [1][-]{section.4.4}{Polynomial Basis Operations}{chapter.4} +\BOOKMARK [2][-]{subsection.4.4.1}{Multiplication by x}{section.4.4} +\BOOKMARK [2][-]{subsection.4.4.2}{Division by x}{section.4.4} +\BOOKMARK [1][-]{section.4.5}{Powers of Two}{chapter.4} +\BOOKMARK [2][-]{subsection.4.5.1}{Multiplication by Power of Two}{section.4.5} +\BOOKMARK [2][-]{subsection.4.5.2}{Division by Power of Two}{section.4.5} +\BOOKMARK [2][-]{subsection.4.5.3}{Remainder of Division by Power of Two}{section.4.5} +\BOOKMARK [0][-]{chapter.5}{Multiplication and Squaring}{} +\BOOKMARK [1][-]{section.5.1}{The Multipliers}{chapter.5} +\BOOKMARK [1][-]{section.5.2}{Multiplication}{chapter.5} +\BOOKMARK [2][-]{subsection.5.2.1}{The Baseline Multiplication}{section.5.2} +\BOOKMARK [2][-]{subsection.5.2.2}{Faster Multiplication by the ``Comba'' Method}{section.5.2} +\BOOKMARK [2][-]{subsection.5.2.3}{Polynomial Basis Multiplication}{section.5.2} +\BOOKMARK [2][-]{subsection.5.2.4}{Karatsuba Multiplication}{section.5.2} +\BOOKMARK [2][-]{subsection.5.2.5}{Toom-Cook 3-Way Multiplication}{section.5.2} +\BOOKMARK [2][-]{subsection.5.2.6}{Signed Multiplication}{section.5.2} +\BOOKMARK [1][-]{section.5.3}{Squaring}{chapter.5} +\BOOKMARK [2][-]{subsection.5.3.1}{The Baseline Squaring Algorithm}{section.5.3} +\BOOKMARK [2][-]{subsection.5.3.2}{Faster Squaring by the ``Comba'' Method}{section.5.3} +\BOOKMARK [2][-]{subsection.5.3.3}{Polynomial Basis Squaring}{section.5.3} +\BOOKMARK [2][-]{subsection.5.3.4}{Karatsuba Squaring}{section.5.3} +\BOOKMARK [2][-]{subsection.5.3.5}{Toom-Cook Squaring}{section.5.3} +\BOOKMARK [2][-]{subsection.5.3.6}{High Level Squaring}{section.5.3} +\BOOKMARK [0][-]{chapter.6}{Modular Reduction}{} +\BOOKMARK [1][-]{section.6.1}{Basics of Modular Reduction}{chapter.6} +\BOOKMARK [1][-]{section.6.2}{The Barrett Reduction}{chapter.6} +\BOOKMARK [2][-]{subsection.6.2.1}{Fixed Point Arithmetic}{section.6.2} +\BOOKMARK [2][-]{subsection.6.2.2}{Choosing a Radix Point}{section.6.2} +\BOOKMARK [2][-]{subsection.6.2.3}{Trimming the Quotient}{section.6.2} +\BOOKMARK [2][-]{subsection.6.2.4}{Trimming the Residue}{section.6.2} +\BOOKMARK [2][-]{subsection.6.2.5}{The Barrett Algorithm}{section.6.2} +\BOOKMARK [2][-]{subsection.6.2.6}{The Barrett Setup Algorithm}{section.6.2} +\BOOKMARK [1][-]{section.6.3}{The Montgomery Reduction}{chapter.6} +\BOOKMARK [2][-]{subsection.6.3.1}{Digit Based Montgomery Reduction}{section.6.3} +\BOOKMARK [2][-]{subsection.6.3.2}{Baseline Montgomery Reduction}{section.6.3} +\BOOKMARK [2][-]{subsection.6.3.3}{Faster ``Comba'' Montgomery Reduction}{section.6.3} +\BOOKMARK [2][-]{subsection.6.3.4}{Montgomery Setup}{section.6.3} +\BOOKMARK [1][-]{section.6.4}{The Diminished Radix Algorithm}{chapter.6} +\BOOKMARK [2][-]{subsection.6.4.1}{Choice of Moduli}{section.6.4} +\BOOKMARK [2][-]{subsection.6.4.2}{Choice of k}{section.6.4} +\BOOKMARK [2][-]{subsection.6.4.3}{Restricted Diminished Radix Reduction}{section.6.4} +\BOOKMARK [2][-]{subsection.6.4.4}{Unrestricted Diminished Radix Reduction}{section.6.4} +\BOOKMARK [1][-]{section.6.5}{Algorithm Comparison}{chapter.6} +\BOOKMARK [0][-]{chapter.7}{Exponentiation}{} +\BOOKMARK [1][-]{section.7.1}{Exponentiation Basics}{chapter.7} +\BOOKMARK [2][-]{subsection.7.1.1}{Single Digit Exponentiation}{section.7.1} +\BOOKMARK [1][-]{section.7.2}{k-ary Exponentiation}{chapter.7} +\BOOKMARK [2][-]{subsection.7.2.1}{Optimal Values of k}{section.7.2} +\BOOKMARK [2][-]{subsection.7.2.2}{Sliding-Window Exponentiation}{section.7.2} +\BOOKMARK [1][-]{section.7.3}{Modular Exponentiation}{chapter.7} +\BOOKMARK [2][-]{subsection.7.3.1}{Barrett Modular Exponentiation}{section.7.3} +\BOOKMARK [1][-]{section.7.4}{Quick Power of Two}{chapter.7} +\BOOKMARK [0][-]{chapter.8}{Higher Level Algorithms}{} +\BOOKMARK [1][-]{section.8.1}{Integer Division with Remainder}{chapter.8} +\BOOKMARK [2][-]{subsection.8.1.1}{Quotient Estimation}{section.8.1} +\BOOKMARK [2][-]{subsection.8.1.2}{Normalized Integers}{section.8.1} +\BOOKMARK [2][-]{subsection.8.1.3}{Radix- Division with Remainder}{section.8.1} +\BOOKMARK [1][-]{section.8.2}{Single Digit Helpers}{chapter.8} +\BOOKMARK [2][-]{subsection.8.2.1}{Single Digit Addition and Subtraction}{section.8.2} +\BOOKMARK [2][-]{subsection.8.2.2}{Single Digit Multiplication}{section.8.2} +\BOOKMARK [2][-]{subsection.8.2.3}{Single Digit Division}{section.8.2} +\BOOKMARK [2][-]{subsection.8.2.4}{Single Digit Root Extraction}{section.8.2} +\BOOKMARK [1][-]{section.8.3}{Random Number Generation}{chapter.8} +\BOOKMARK [1][-]{section.8.4}{Formatted Representations}{chapter.8} +\BOOKMARK [2][-]{subsection.8.4.1}{Reading Radix-n Input}{section.8.4} +\BOOKMARK [2][-]{subsection.8.4.2}{Generating Radix-n Output}{section.8.4} +\BOOKMARK [0][-]{chapter.9}{Number Theoretic Algorithms}{} +\BOOKMARK [1][-]{section.9.1}{Greatest Common Divisor}{chapter.9} +\BOOKMARK [2][-]{subsection.9.1.1}{Complete Greatest Common Divisor}{section.9.1} +\BOOKMARK [1][-]{section.9.2}{Least Common Multiple}{chapter.9} +\BOOKMARK [1][-]{section.9.3}{Jacobi Symbol Computation}{chapter.9} +\BOOKMARK [2][-]{subsection.9.3.1}{Jacobi Symbol}{section.9.3} +\BOOKMARK [1][-]{section.9.4}{Modular Inverse}{chapter.9} +\BOOKMARK [2][-]{subsection.9.4.1}{General Case}{section.9.4} +\BOOKMARK [1][-]{section.9.5}{Primality Tests}{chapter.9} +\BOOKMARK [2][-]{subsection.9.5.1}{Trial Division}{section.9.5} +\BOOKMARK [2][-]{subsection.9.5.2}{The Fermat Test}{section.9.5} +\BOOKMARK [2][-]{subsection.9.5.3}{The Miller-Rabin Test}{section.9.5} diff --git a/libtommath/tommath_class.h b/libtommath/tommath_class.h new file mode 100644 index 0000000..a4e275a --- /dev/null +++ b/libtommath/tommath_class.h @@ -0,0 +1,1005 @@ +#if !(defined(LTM1) && defined(LTM2) && defined(LTM3)) +#if defined(LTM2) +#define LTM3 +#endif +#if defined(LTM1) +#define LTM2 +#endif +#define LTM1 + +#if defined(LTM_ALL) +#define BN_ERROR_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_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_COPY_C +#define BN_MP_COUNT_BITS_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_EXCH_C +#define BN_MP_EXPT_D_C +#define BN_MP_EXPTMOD_C +#define BN_MP_EXPTMOD_FAST_C +#define BN_MP_EXTEUCLID_C +#define BN_MP_FREAD_C +#define BN_MP_FWRITE_C +#define BN_MP_GCD_C +#define BN_MP_GET_INT_C +#define BN_MP_GROW_C +#define BN_MP_INIT_C +#define BN_MP_INIT_COPY_C +#define BN_MP_INIT_MULTI_C +#define BN_MP_INIT_SET_C +#define BN_MP_INIT_SET_INT_C +#define BN_MP_INIT_SIZE_C +#define BN_MP_INVMOD_C +#define BN_MP_INVMOD_SLOW_C +#define BN_MP_IS_SQUARE_C +#define BN_MP_JACOBI_C +#define BN_MP_KARATSUBA_MUL_C +#define BN_MP_KARATSUBA_SQR_C +#define BN_MP_LCM_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_N_ROOT_C +#define BN_MP_NEG_C +#define BN_MP_OR_C +#define BN_MP_PRIME_FERMAT_C +#define BN_MP_PRIME_IS_DIVISIBLE_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_RANDOM_EX_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_READ_SIGNED_BIN_C +#define BN_MP_READ_UNSIGNED_BIN_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_RSHD_C +#define BN_MP_SET_C +#define BN_MP_SET_INT_C +#define BN_MP_SHRINK_C +#define BN_MP_SIGNED_BIN_SIZE_C +#define BN_MP_SQR_C +#define BN_MP_SQRMOD_C +#define BN_MP_SQRT_C +#define BN_MP_SUB_C +#define BN_MP_SUB_D_C +#define BN_MP_SUBMOD_C +#define BN_MP_TO_SIGNED_BIN_C +#define BN_MP_TO_SIGNED_BIN_N_C +#define BN_MP_TO_UNSIGNED_BIN_C +#define BN_MP_TO_UNSIGNED_BIN_N_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_UNSIGNED_BIN_SIZE_C +#define BN_MP_XOR_C +#define BN_MP_ZERO_C +#define BN_PRIME_TAB_C +#define BN_REVERSE_C +#define BN_S_MP_ADD_C +#define BN_S_MP_EXPTMOD_C +#define BN_S_MP_MUL_DIGS_C +#define BN_S_MP_MUL_HIGH_DIGS_C +#define BN_S_MP_SQR_C +#define BN_S_MP_SUB_C +#define BNCORE_C +#endif + +#if defined(BN_ERROR_C) + #define BN_MP_ERROR_TO_STRING_C +#endif + +#if defined(BN_FAST_MP_INVMOD_C) + #define BN_MP_ISEVEN_C + #define BN_MP_INIT_MULTI_C + #define BN_MP_COPY_C + #define BN_MP_MOD_C + #define BN_MP_SET_C + #define BN_MP_DIV_2_C + #define BN_MP_ISODD_C + #define BN_MP_SUB_C + #define BN_MP_CMP_C + #define BN_MP_ISZERO_C + #define BN_MP_CMP_D_C + #define BN_MP_ADD_C + #define BN_MP_EXCH_C + #define BN_MP_CLEAR_MULTI_C +#endif + +#if defined(BN_FAST_MP_MONTGOMERY_REDUCE_C) + #define BN_MP_GROW_C + #define BN_MP_RSHD_C + #define BN_MP_CLAMP_C + #define BN_MP_CMP_MAG_C + #define BN_S_MP_SUB_C +#endif + +#if defined(BN_FAST_S_MP_MUL_DIGS_C) + #define BN_MP_GROW_C + #define BN_MP_CLAMP_C +#endif + +#if defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C) + #define BN_MP_GROW_C + #define BN_MP_CLAMP_C +#endif + +#if defined(BN_FAST_S_MP_SQR_C) + #define BN_MP_GROW_C + #define BN_MP_CLAMP_C +#endif + +#if defined(BN_MP_2EXPT_C) + #define BN_MP_ZERO_C + #define BN_MP_GROW_C +#endif + +#if defined(BN_MP_ABS_C) + #define BN_MP_COPY_C +#endif + +#if defined(BN_MP_ADD_C) + #define BN_S_MP_ADD_C + #define BN_MP_CMP_MAG_C + #define BN_S_MP_SUB_C +#endif + +#if defined(BN_MP_ADD_D_C) + #define BN_MP_GROW_C + #define BN_MP_SUB_D_C + #define BN_MP_CLAMP_C +#endif + +#if defined(BN_MP_ADDMOD_C) + #define BN_MP_INIT_C + #define BN_MP_ADD_C + #define BN_MP_CLEAR_C + #define BN_MP_MOD_C +#endif + +#if defined(BN_MP_AND_C) + #define BN_MP_INIT_COPY_C + #define BN_MP_CLAMP_C + #define BN_MP_EXCH_C + #define BN_MP_CLEAR_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) + #define BN_MP_ISZERO_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_DIV_C) + #define BN_MP_ISZERO_C + #define BN_MP_CMP_MAG_C + #define BN_MP_COPY_C + #define BN_MP_ZERO_C + #define BN_MP_INIT_MULTI_C + #define BN_MP_SET_C + #define BN_MP_COUNT_BITS_C + #define BN_MP_ABS_C + #define BN_MP_MUL_2D_C + #define BN_MP_CMP_C + #define BN_MP_SUB_C + #define BN_MP_ADD_C + #define BN_MP_DIV_2D_C + #define BN_MP_EXCH_C + #define BN_MP_CLEAR_MULTI_C + #define BN_MP_INIT_SIZE_C + #define BN_MP_INIT_C + #define BN_MP_INIT_COPY_C + #define BN_MP_LSHD_C + #define BN_MP_RSHD_C + #define BN_MP_MUL_D_C + #define BN_MP_CLAMP_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_DIV_2_C) + #define BN_MP_GROW_C + #define BN_MP_CLAMP_C +#endif + +#if defined(BN_MP_DIV_2D_C) + #define BN_MP_COPY_C + #define BN_MP_ZERO_C + #define BN_MP_INIT_C + #define BN_MP_MOD_2D_C + #define BN_MP_CLEAR_C + #define BN_MP_RSHD_C + #define BN_MP_CLAMP_C + #define BN_MP_EXCH_C +#endif + +#if defined(BN_MP_DIV_3_C) + #define BN_MP_INIT_SIZE_C + #define BN_MP_CLAMP_C + #define BN_MP_EXCH_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_DIV_D_C) + #define BN_MP_ISZERO_C + #define BN_MP_COPY_C + #define BN_MP_DIV_2D_C + #define BN_MP_DIV_3_C + #define BN_MP_INIT_SIZE_C + #define BN_MP_CLAMP_C + #define BN_MP_EXCH_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_DR_IS_MODULUS_C) +#endif + +#if defined(BN_MP_DR_REDUCE_C) + #define BN_MP_GROW_C + #define BN_MP_CLAMP_C + #define BN_MP_CMP_MAG_C + #define BN_S_MP_SUB_C +#endif + +#if defined(BN_MP_DR_SETUP_C) +#endif + +#if defined(BN_MP_EXCH_C) +#endif + +#if defined(BN_MP_EXPT_D_C) + #define BN_MP_INIT_COPY_C + #define BN_MP_SET_C + #define BN_MP_SQR_C + #define BN_MP_CLEAR_C + #define BN_MP_MUL_C +#endif + +#if defined(BN_MP_EXPTMOD_C) + #define BN_MP_INIT_C + #define BN_MP_INVMOD_C + #define BN_MP_CLEAR_C + #define BN_MP_ABS_C + #define BN_MP_CLEAR_MULTI_C + #define BN_MP_REDUCE_IS_2K_L_C + #define BN_S_MP_EXPTMOD_C + #define BN_MP_DR_IS_MODULUS_C + #define BN_MP_REDUCE_IS_2K_C + #define BN_MP_ISODD_C + #define BN_MP_EXPTMOD_FAST_C +#endif + +#if defined(BN_MP_EXPTMOD_FAST_C) + #define BN_MP_COUNT_BITS_C + #define BN_MP_INIT_C + #define BN_MP_CLEAR_C + #define BN_MP_MONTGOMERY_SETUP_C + #define BN_FAST_MP_MONTGOMERY_REDUCE_C + #define BN_MP_MONTGOMERY_REDUCE_C + #define BN_MP_DR_SETUP_C + #define BN_MP_DR_REDUCE_C + #define BN_MP_REDUCE_2K_SETUP_C + #define BN_MP_REDUCE_2K_C + #define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C + #define BN_MP_MULMOD_C + #define BN_MP_SET_C + #define BN_MP_MOD_C + #define BN_MP_COPY_C + #define BN_MP_SQR_C + #define BN_MP_MUL_C + #define BN_MP_EXCH_C +#endif + +#if defined(BN_MP_EXTEUCLID_C) + #define BN_MP_INIT_MULTI_C + #define BN_MP_SET_C + #define BN_MP_COPY_C + #define BN_MP_ISZERO_C + #define BN_MP_DIV_C + #define BN_MP_MUL_C + #define BN_MP_SUB_C + #define BN_MP_NEG_C + #define BN_MP_EXCH_C + #define BN_MP_CLEAR_MULTI_C +#endif + +#if defined(BN_MP_FREAD_C) + #define BN_MP_ZERO_C + #define BN_MP_S_RMAP_C + #define BN_MP_MUL_D_C + #define BN_MP_ADD_D_C + #define BN_MP_CMP_D_C +#endif + +#if defined(BN_MP_FWRITE_C) + #define BN_MP_RADIX_SIZE_C + #define BN_MP_TORADIX_C +#endif + +#if defined(BN_MP_GCD_C) + #define BN_MP_ISZERO_C + #define BN_MP_ABS_C + #define BN_MP_ZERO_C + #define BN_MP_INIT_COPY_C + #define BN_MP_CNT_LSB_C + #define BN_MP_DIV_2D_C + #define BN_MP_CMP_MAG_C + #define BN_MP_EXCH_C + #define BN_S_MP_SUB_C + #define BN_MP_MUL_2D_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_GET_INT_C) +#endif + +#if defined(BN_MP_GROW_C) +#endif + +#if defined(BN_MP_INIT_C) +#endif + +#if defined(BN_MP_INIT_COPY_C) + #define BN_MP_COPY_C +#endif + +#if defined(BN_MP_INIT_MULTI_C) + #define BN_MP_ERR_C + #define BN_MP_INIT_C + #define BN_MP_CLEAR_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_SET_INT_C) + #define BN_MP_INIT_C + #define BN_MP_SET_INT_C +#endif + +#if defined(BN_MP_INIT_SIZE_C) + #define BN_MP_INIT_C +#endif + +#if defined(BN_MP_INVMOD_C) + #define BN_MP_ISZERO_C + #define BN_MP_ISODD_C + #define BN_FAST_MP_INVMOD_C + #define BN_MP_INVMOD_SLOW_C +#endif + +#if defined(BN_MP_INVMOD_SLOW_C) + #define BN_MP_ISZERO_C + #define BN_MP_INIT_MULTI_C + #define BN_MP_MOD_C + #define BN_MP_COPY_C + #define BN_MP_ISEVEN_C + #define BN_MP_SET_C + #define BN_MP_DIV_2_C + #define BN_MP_ISODD_C + #define BN_MP_ADD_C + #define BN_MP_SUB_C + #define BN_MP_CMP_C + #define BN_MP_CMP_D_C + #define BN_MP_CMP_MAG_C + #define BN_MP_EXCH_C + #define BN_MP_CLEAR_MULTI_C +#endif + +#if defined(BN_MP_IS_SQUARE_C) + #define BN_MP_MOD_D_C + #define BN_MP_INIT_SET_INT_C + #define BN_MP_MOD_C + #define BN_MP_GET_INT_C + #define BN_MP_SQRT_C + #define BN_MP_SQR_C + #define BN_MP_CMP_MAG_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_JACOBI_C) + #define BN_MP_CMP_D_C + #define BN_MP_ISZERO_C + #define BN_MP_INIT_COPY_C + #define BN_MP_CNT_LSB_C + #define BN_MP_DIV_2D_C + #define BN_MP_MOD_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_KARATSUBA_MUL_C) + #define BN_MP_MUL_C + #define BN_MP_INIT_SIZE_C + #define BN_MP_CLAMP_C + #define BN_MP_SUB_C + #define BN_MP_ADD_C + #define BN_MP_LSHD_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_KARATSUBA_SQR_C) + #define BN_MP_INIT_SIZE_C + #define BN_MP_CLAMP_C + #define BN_MP_SQR_C + #define BN_MP_SUB_C + #define BN_S_MP_ADD_C + #define BN_MP_LSHD_C + #define BN_MP_ADD_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_LCM_C) + #define BN_MP_INIT_MULTI_C + #define BN_MP_GCD_C + #define BN_MP_CMP_MAG_C + #define BN_MP_DIV_C + #define BN_MP_MUL_C + #define BN_MP_CLEAR_MULTI_C +#endif + +#if defined(BN_MP_LSHD_C) + #define BN_MP_GROW_C + #define BN_MP_RSHD_C +#endif + +#if defined(BN_MP_MOD_C) + #define BN_MP_INIT_C + #define BN_MP_DIV_C + #define BN_MP_CLEAR_C + #define BN_MP_ADD_C + #define BN_MP_EXCH_C +#endif + +#if defined(BN_MP_MOD_2D_C) + #define BN_MP_ZERO_C + #define BN_MP_COPY_C + #define BN_MP_CLAMP_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_COUNT_BITS_C + #define BN_MP_2EXPT_C + #define BN_MP_SET_C + #define BN_MP_MUL_2_C + #define BN_MP_CMP_MAG_C + #define BN_S_MP_SUB_C +#endif + +#if defined(BN_MP_MONTGOMERY_REDUCE_C) + #define BN_FAST_MP_MONTGOMERY_REDUCE_C + #define BN_MP_GROW_C + #define BN_MP_CLAMP_C + #define BN_MP_RSHD_C + #define BN_MP_CMP_MAG_C + #define BN_S_MP_SUB_C +#endif + +#if defined(BN_MP_MONTGOMERY_SETUP_C) +#endif + +#if defined(BN_MP_MUL_C) + #define BN_MP_TOOM_MUL_C + #define BN_MP_KARATSUBA_MUL_C + #define BN_FAST_S_MP_MUL_DIGS_C + #define BN_S_MP_MUL_C + #define BN_S_MP_MUL_DIGS_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_COPY_C + #define BN_MP_GROW_C + #define BN_MP_LSHD_C + #define BN_MP_CLAMP_C +#endif + +#if defined(BN_MP_MUL_D_C) + #define BN_MP_GROW_C + #define BN_MP_CLAMP_C +#endif + +#if defined(BN_MP_MULMOD_C) + #define BN_MP_INIT_C + #define BN_MP_MUL_C + #define BN_MP_CLEAR_C + #define BN_MP_MOD_C +#endif + +#if defined(BN_MP_N_ROOT_C) + #define BN_MP_INIT_C + #define BN_MP_SET_C + #define BN_MP_COPY_C + #define BN_MP_EXPT_D_C + #define BN_MP_MUL_C + #define BN_MP_SUB_C + #define BN_MP_MUL_D_C + #define BN_MP_DIV_C + #define BN_MP_CMP_C + #define BN_MP_SUB_D_C + #define BN_MP_EXCH_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_NEG_C) + #define BN_MP_COPY_C + #define BN_MP_ISZERO_C +#endif + +#if defined(BN_MP_OR_C) + #define BN_MP_INIT_COPY_C + #define BN_MP_CLAMP_C + #define BN_MP_EXCH_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_PRIME_FERMAT_C) + #define BN_MP_CMP_D_C + #define BN_MP_INIT_C + #define BN_MP_EXPTMOD_C + #define BN_MP_CMP_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_PRIME_IS_DIVISIBLE_C) + #define BN_MP_MOD_D_C +#endif + +#if defined(BN_MP_PRIME_IS_PRIME_C) + #define BN_MP_CMP_D_C + #define BN_MP_PRIME_IS_DIVISIBLE_C + #define BN_MP_INIT_C + #define BN_MP_SET_C + #define BN_MP_PRIME_MILLER_RABIN_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_PRIME_MILLER_RABIN_C) + #define BN_MP_CMP_D_C + #define BN_MP_INIT_COPY_C + #define BN_MP_SUB_D_C + #define BN_MP_CNT_LSB_C + #define BN_MP_DIV_2D_C + #define BN_MP_EXPTMOD_C + #define BN_MP_CMP_C + #define BN_MP_SQRMOD_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_PRIME_NEXT_PRIME_C) + #define BN_MP_CMP_D_C + #define BN_MP_SET_C + #define BN_MP_SUB_D_C + #define BN_MP_ISEVEN_C + #define BN_MP_MOD_D_C + #define BN_MP_INIT_C + #define BN_MP_ADD_D_C + #define BN_MP_PRIME_MILLER_RABIN_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_PRIME_RABIN_MILLER_TRIALS_C) +#endif + +#if defined(BN_MP_PRIME_RANDOM_EX_C) + #define BN_MP_READ_UNSIGNED_BIN_C + #define BN_MP_PRIME_IS_PRIME_C + #define BN_MP_SUB_D_C + #define BN_MP_DIV_2_C + #define BN_MP_MUL_2_C + #define BN_MP_ADD_D_C +#endif + +#if defined(BN_MP_RADIX_SIZE_C) + #define BN_MP_COUNT_BITS_C + #define BN_MP_INIT_COPY_C + #define BN_MP_ISZERO_C + #define BN_MP_DIV_D_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_RADIX_SMAP_C) + #define BN_MP_S_RMAP_C +#endif + +#if defined(BN_MP_RAND_C) + #define BN_MP_ZERO_C + #define BN_MP_ADD_D_C + #define BN_MP_LSHD_C +#endif + +#if defined(BN_MP_READ_RADIX_C) + #define BN_MP_ZERO_C + #define BN_MP_S_RMAP_C + #define BN_MP_RADIX_SMAP_C + #define BN_MP_MUL_D_C + #define BN_MP_ADD_D_C + #define BN_MP_ISZERO_C +#endif + +#if defined(BN_MP_READ_SIGNED_BIN_C) + #define BN_MP_READ_UNSIGNED_BIN_C +#endif + +#if defined(BN_MP_READ_UNSIGNED_BIN_C) + #define BN_MP_GROW_C + #define BN_MP_ZERO_C + #define BN_MP_MUL_2D_C + #define BN_MP_CLAMP_C +#endif + +#if defined(BN_MP_REDUCE_C) + #define BN_MP_REDUCE_SETUP_C + #define BN_MP_INIT_COPY_C + #define BN_MP_RSHD_C + #define BN_MP_MUL_C + #define BN_S_MP_MUL_HIGH_DIGS_C + #define BN_FAST_S_MP_MUL_HIGH_DIGS_C + #define BN_MP_MOD_2D_C + #define BN_S_MP_MUL_DIGS_C + #define BN_MP_SUB_C + #define BN_MP_CMP_D_C + #define BN_MP_SET_C + #define BN_MP_LSHD_C + #define BN_MP_ADD_C + #define BN_MP_CMP_C + #define BN_S_MP_SUB_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_REDUCE_2K_C) + #define BN_MP_INIT_C + #define BN_MP_COUNT_BITS_C + #define BN_MP_DIV_2D_C + #define BN_MP_MUL_D_C + #define BN_S_MP_ADD_C + #define BN_MP_CMP_MAG_C + #define BN_S_MP_SUB_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_REDUCE_2K_L_C) + #define BN_MP_INIT_C + #define BN_MP_COUNT_BITS_C + #define BN_MP_DIV_2D_C + #define BN_MP_MUL_C + #define BN_S_MP_ADD_C + #define BN_MP_CMP_MAG_C + #define BN_S_MP_SUB_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_REDUCE_2K_SETUP_C) + #define BN_MP_INIT_C + #define BN_MP_COUNT_BITS_C + #define BN_MP_2EXPT_C + #define BN_MP_CLEAR_C + #define BN_S_MP_SUB_C +#endif + +#if defined(BN_MP_REDUCE_2K_SETUP_L_C) + #define BN_MP_INIT_C + #define BN_MP_2EXPT_C + #define BN_MP_COUNT_BITS_C + #define BN_S_MP_SUB_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_REDUCE_IS_2K_C) + #define BN_MP_REDUCE_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_RSHD_C) + #define BN_MP_ZERO_C +#endif + +#if defined(BN_MP_SET_C) + #define BN_MP_ZERO_C +#endif + +#if defined(BN_MP_SET_INT_C) + #define BN_MP_ZERO_C + #define BN_MP_MUL_2D_C + #define BN_MP_CLAMP_C +#endif + +#if defined(BN_MP_SHRINK_C) +#endif + +#if defined(BN_MP_SIGNED_BIN_SIZE_C) + #define BN_MP_UNSIGNED_BIN_SIZE_C +#endif + +#if defined(BN_MP_SQR_C) + #define BN_MP_TOOM_SQR_C + #define BN_MP_KARATSUBA_SQR_C + #define BN_FAST_S_MP_SQR_C + #define BN_S_MP_SQR_C +#endif + +#if defined(BN_MP_SQRMOD_C) + #define BN_MP_INIT_C + #define BN_MP_SQR_C + #define BN_MP_CLEAR_C + #define BN_MP_MOD_C +#endif + +#if defined(BN_MP_SQRT_C) + #define BN_MP_N_ROOT_C + #define BN_MP_ISZERO_C + #define BN_MP_ZERO_C + #define BN_MP_INIT_COPY_C + #define BN_MP_RSHD_C + #define BN_MP_DIV_C + #define BN_MP_ADD_C + #define BN_MP_DIV_2_C + #define BN_MP_CMP_MAG_C + #define BN_MP_EXCH_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_SUB_C) + #define BN_S_MP_ADD_C + #define BN_MP_CMP_MAG_C + #define BN_S_MP_SUB_C +#endif + +#if defined(BN_MP_SUB_D_C) + #define BN_MP_GROW_C + #define BN_MP_ADD_D_C + #define BN_MP_CLAMP_C +#endif + +#if defined(BN_MP_SUBMOD_C) + #define BN_MP_INIT_C + #define BN_MP_SUB_C + #define BN_MP_CLEAR_C + #define BN_MP_MOD_C +#endif + +#if defined(BN_MP_TO_SIGNED_BIN_C) + #define BN_MP_TO_UNSIGNED_BIN_C +#endif + +#if defined(BN_MP_TO_SIGNED_BIN_N_C) + #define BN_MP_SIGNED_BIN_SIZE_C + #define BN_MP_TO_SIGNED_BIN_C +#endif + +#if defined(BN_MP_TO_UNSIGNED_BIN_C) + #define BN_MP_INIT_COPY_C + #define BN_MP_ISZERO_C + #define BN_MP_DIV_2D_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_TO_UNSIGNED_BIN_N_C) + #define BN_MP_UNSIGNED_BIN_SIZE_C + #define BN_MP_TO_UNSIGNED_BIN_C +#endif + +#if defined(BN_MP_TOOM_MUL_C) + #define BN_MP_INIT_MULTI_C + #define BN_MP_MOD_2D_C + #define BN_MP_COPY_C + #define BN_MP_RSHD_C + #define BN_MP_MUL_C + #define BN_MP_MUL_2_C + #define BN_MP_ADD_C + #define BN_MP_SUB_C + #define BN_MP_DIV_2_C + #define BN_MP_MUL_2D_C + #define BN_MP_MUL_D_C + #define BN_MP_DIV_3_C + #define BN_MP_LSHD_C + #define BN_MP_CLEAR_MULTI_C +#endif + +#if defined(BN_MP_TOOM_SQR_C) + #define BN_MP_INIT_MULTI_C + #define BN_MP_MOD_2D_C + #define BN_MP_COPY_C + #define BN_MP_RSHD_C + #define BN_MP_SQR_C + #define BN_MP_MUL_2_C + #define BN_MP_ADD_C + #define BN_MP_SUB_C + #define BN_MP_DIV_2_C + #define BN_MP_MUL_2D_C + #define BN_MP_MUL_D_C + #define BN_MP_DIV_3_C + #define BN_MP_LSHD_C + #define BN_MP_CLEAR_MULTI_C +#endif + +#if defined(BN_MP_TORADIX_C) + #define BN_MP_ISZERO_C + #define BN_MP_INIT_COPY_C + #define BN_MP_DIV_D_C + #define BN_MP_CLEAR_C + #define BN_MP_S_RMAP_C +#endif + +#if defined(BN_MP_TORADIX_N_C) + #define BN_MP_ISZERO_C + #define BN_MP_INIT_COPY_C + #define BN_MP_DIV_D_C + #define BN_MP_CLEAR_C + #define BN_MP_S_RMAP_C +#endif + +#if defined(BN_MP_UNSIGNED_BIN_SIZE_C) + #define BN_MP_COUNT_BITS_C +#endif + +#if defined(BN_MP_XOR_C) + #define BN_MP_INIT_COPY_C + #define BN_MP_CLAMP_C + #define BN_MP_EXCH_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_ZERO_C) +#endif + +#if defined(BN_PRIME_TAB_C) +#endif + +#if defined(BN_REVERSE_C) +#endif + +#if defined(BN_S_MP_ADD_C) + #define BN_MP_GROW_C + #define BN_MP_CLAMP_C +#endif + +#if defined(BN_S_MP_EXPTMOD_C) + #define BN_MP_COUNT_BITS_C + #define BN_MP_INIT_C + #define BN_MP_CLEAR_C + #define BN_MP_REDUCE_SETUP_C + #define BN_MP_REDUCE_C + #define BN_MP_REDUCE_2K_SETUP_L_C + #define BN_MP_REDUCE_2K_L_C + #define BN_MP_MOD_C + #define BN_MP_COPY_C + #define BN_MP_SQR_C + #define BN_MP_MUL_C + #define BN_MP_SET_C + #define BN_MP_EXCH_C +#endif + +#if defined(BN_S_MP_MUL_DIGS_C) + #define BN_FAST_S_MP_MUL_DIGS_C + #define BN_MP_INIT_SIZE_C + #define BN_MP_CLAMP_C + #define BN_MP_EXCH_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_S_MP_MUL_HIGH_DIGS_C) + #define BN_FAST_S_MP_MUL_HIGH_DIGS_C + #define BN_MP_INIT_SIZE_C + #define BN_MP_CLAMP_C + #define BN_MP_EXCH_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_S_MP_SQR_C) + #define BN_MP_INIT_SIZE_C + #define BN_MP_CLAMP_C + #define BN_MP_EXCH_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_S_MP_SUB_C) + #define BN_MP_GROW_C + #define BN_MP_CLAMP_C +#endif + +#if defined(BNCORE_C) +#endif + +#ifdef LTM3 +#define LTM_LAST +#endif +#include "tommath_superclass.h" +#include "tommath_class.h" +#else +#define LTM_LAST +#endif + +/* Dropbear doesn't need these. */ +#undef BN_MP_KARATSUBA_MUL_C +#undef BN_MP_KARATSUBA_SQR_C +#undef BN_MP_TOOM_MUL_C +#undef BN_MP_TOOM_SQR_C + +/* $Source: /cvs/libtom/libtommath/tommath_class.h,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2005/07/28 11:59:32 $ */ diff --git a/libtommath/tommath_superclass.h b/libtommath/tommath_superclass.h new file mode 100644 index 0000000..2fdebe6 --- /dev/null +++ b/libtommath/tommath_superclass.h @@ -0,0 +1,76 @@ +/* super class file for PK algos */ + +/* default ... include all MPI */ +#define LTM_ALL + +/* RSA only (does not support DH/DSA/ECC) */ +/* #define SC_RSA_1 */ + +/* For reference.... On an Athlon64 optimizing for speed... + + LTM's mpi.o with all functions [striped] is 142KiB in size. + +*/ + +/* Works for RSA only, mpi.o is 68KiB */ +#ifdef SC_RSA_1 + #define BN_MP_SHRINK_C + #define BN_MP_LCM_C + #define BN_MP_PRIME_RANDOM_EX_C + #define BN_MP_INVMOD_C + #define BN_MP_GCD_C + #define BN_MP_MOD_C + #define BN_MP_MULMOD_C + #define BN_MP_ADDMOD_C + #define BN_MP_EXPTMOD_C + #define BN_MP_SET_INT_C + #define BN_MP_INIT_MULTI_C + #define BN_MP_CLEAR_MULTI_C + #define BN_MP_UNSIGNED_BIN_SIZE_C + #define BN_MP_TO_UNSIGNED_BIN_C + #define BN_MP_MOD_D_C + #define BN_MP_PRIME_RABIN_MILLER_TRIALS_C + #define BN_REVERSE_C + #define BN_PRIME_TAB_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_TOOM_MUL_C + #undef BN_MP_TOOM_SQR_C + #undef BN_MP_KARATSUBA_MUL_C + #undef BN_MP_KARATSUBA_SQR_C + #undef BN_MP_REDUCE_C + #undef BN_MP_REDUCE_SETUP_C + #undef BN_MP_DR_IS_MODULUS_C + #undef BN_MP_DR_SETUP_C + #undef BN_MP_DR_REDUCE_C + #undef BN_MP_REDUCE_IS_2K_C + #undef BN_MP_REDUCE_2K_SETUP_C + #undef BN_MP_REDUCE_2K_C + #undef BN_S_MP_EXPTMOD_C + #undef BN_MP_DIV_3_C + #undef BN_S_MP_MUL_HIGH_DIGS_C + #undef BN_FAST_S_MP_MUL_HIGH_DIGS_C + #undef BN_FAST_MP_INVMOD_C + + /* 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_S_MP_MUL_DIGS_C + #undef BN_S_MP_SQR_C + #undef BN_MP_MONTGOMERY_REDUCE_C +#endif + +#endif + +/* $Source: /cvs/libtom/libtommath/tommath_superclass.h,v $ */ +/* $Revision: 1.3 $ */ +/* $Date: 2005/05/14 13:29:17 $ */ |