Commit 2ba8a342 authored by Gerard Ryan's avatar Gerard Ryan
Browse files

benchmarks build on all platforms. Integer runs for all integers

parent 806fa56b
......@@ -22,159 +22,47 @@
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/*
Description:
This code benchmarks functions of the math directory of the PALISADE lattice encryption library.
*/
#include "benchmark/benchmark_api.h"
#include <iostream>
// this file contains the magic needed to compile and benchmark all backends in the same executable
#ifndef BENCHMARK_SRC_ALLBACKENDS_H_
#define BENCHMARK_SRC_ALLBACKENDS_H_
#define _USE_MATH_DEFINES
#include "math/backend.h"
#include "utils/inttypes.h"
#include "math/nbtheory.h"
#include "math/distrgen.h"
#include "lattice/elemparams.h"
#include "lattice/ilparams.h"
#include "lattice/ildcrtparams.h"
#include "lattice/ilelement.h"
#include "math/distrgen.h"
#include "lattice/poly.h"
#include "../../src/core/lib/lattice/dcrtpoly.h"
#include "lattice/dcrtpoly.h"
#include "utils/utilities.h"
using namespace std;
using namespace lbcrypto;
//four simple benchmarks to test constructing BBIs
// typically the code to benchmark is in a 'function' that is then
// called within the actual benchmark.
// test BBI constants
static void make_NativeInt_constants(void) { // function
NativeInteger one(1);
}
void BM_NativeInt_constants(benchmark::State& state) { // benchmark
while (state.KeepRunning()) {
make_NativeInt_constants(); // note even with -O3 it appears
// this is not optimized out
// though check with your compiler
}
}
BENCHMARK(BM_NativeInt_constants); // register benchmark
// make variables
static NativeInteger smalla("10403"), smallb("103");
static NativeInteger largea("4294967295"), largeb("4294967");
static void make_NativeInt_small_variables (void) { // function
NativeInteger a("10403"), b("103");
}
void BM_NativeInt_small_variables(benchmark::State& state) { // benchmark
while (state.KeepRunning()) {
make_NativeInt_small_variables(); // note even with -O3 it appears
// this is not optimized out
// though check with your compiler
}
}
BENCHMARK(BM_NativeInt_small_variables); // register benchmark
static void make_NativeInt_large_variables (void) { // function
NativeInteger a("9446744073709551616"), b("9446744073709551617");
}
void BM_NativeInt_large_variables(benchmark::State& state) { // benchmark
while (state.KeepRunning()) {
make_NativeInt_large_variables();
}
}
BENCHMARK(BM_NativeInt_large_variables);
// add
static void add_NativeInt(benchmark::State& state) { // function
state.PauseTiming();
NativeInteger& a = state.range(0) == 0 ? smalla : largea;
NativeInteger& b = state.range(0) == 0 ? smallb : largeb;
state.ResumeTiming();
NativeInteger c = a+b;
}
static void BM_NativeInt_Addition(benchmark::State& state) { // benchmark
while (state.KeepRunning()) {
add_NativeInt(state);
}
}
BENCHMARK(BM_NativeInt_Addition)->ArgName("Small")->Arg(0);
BENCHMARK(BM_NativeInt_Addition)->ArgName("Large")->Arg(1);
// +=
static void addeq_NativeInt(benchmark::State& state) { // function
state.PauseTiming();
NativeInteger a = state.range(0) == 0 ? smalla : largea;
NativeInteger b = state.range(0) == 0 ? smallb : largeb;
state.ResumeTiming();
a += b;
}
static void BM_NativeInt_Addeq(benchmark::State& state) { // benchmark
while (state.KeepRunning()) {
addeq_NativeInt(state);
}
}
BENCHMARK(BM_NativeInt_Addeq)->ArgName("Small")->Arg(0);
BENCHMARK(BM_NativeInt_Addeq)->ArgName("Large")->Arg(1);
// mult
static void mult_NativeInt(benchmark::State& state) { // function
state.PauseTiming();
NativeInteger& a = state.range(0) == 0 ? smalla : largea;
NativeInteger& b = state.range(0) == 0 ? smallb : largeb;
state.ResumeTiming();
NativeInteger c = a*b;
}
static void BM_NativeInt_Mult(benchmark::State& state) { // benchmark
while (state.KeepRunning()) {
mult_NativeInt(state);
}
}
BENCHMARK(BM_NativeInt_Mult)->ArgName("Small")->Arg(0);
BENCHMARK(BM_NativeInt_Mult)->ArgName("Large")->Arg(1);
// *=
static void multeq_NativeInt(benchmark::State& state) { // function
state.PauseTiming();
NativeInteger a = state.range(0) == 0 ? smalla : largea;
NativeInteger b = state.range(0) == 0 ? smallb : largeb;
state.ResumeTiming();
a *= b;
}
static void BM_NativeInt_Multeq(benchmark::State& state) { // benchmark
while (state.KeepRunning()) {
multeq_NativeInt(state);
}
}
BENCHMARK(BM_NativeInt_Multeq)->ArgName("Small")->Arg(0);
BENCHMARK(BM_NativeInt_Multeq)->ArgName("Large")->Arg(1);
//execute the benchmarks
BENCHMARK_MAIN()
using BE2Integer = cpu_int::BigInteger<integral_dtype,BigIntegerBitLength>;
using BE2ILParams = ILParamsImpl<BE2Integer>;
using BE2ILDCRTParams = ILDCRTParams<BE2Integer>;
using BE2Vector = cpu_int::BigVectorImpl<BE2Integer>;
using BE2Poly = PolyImpl<BE2Integer, BE2Integer, BE2Vector, BE2ILParams>;
using BE2DCRTPoly = DCRTPolyImpl<BE2Integer, BE2Integer, BE2Vector, BE2ILDCRTParams>;
using BE4Integer = exp_int::xubint;
using BE4ILParams = ILParamsImpl<BE4Integer>;
using BE4ILDCRTParams = ILDCRTParams<BE4Integer>;
using BE4Vector = exp_int::xmubintvec;
using BE4Poly = PolyImpl<BE4Integer, BE4Integer, BE4Vector, BE4ILParams>;
using BE4DCRTPoly = DCRTPolyImpl<BE4Integer, BE4Integer, BE4Vector, BE4ILDCRTParams>;
using BE6Integer = NTL::myZZ;
using BE6ILParams = ILParamsImpl<BE6Integer>;
using BE6ILDCRTParams = ILDCRTParams<BE6Integer>;
using BE6Vector = NTL::myVecP<NTL::myZZ>;
using BE6Poly = PolyImpl<BE6Integer, BE6Integer, BE6Vector, BE6ILParams>;
using BE6DCRTPoly = DCRTPolyImpl<BE6Integer, BE6Integer, BE6Vector, BE6ILDCRTParams>;
#endif /* BENCHMARK_SRC_ALLBACKENDS_H_ */
......@@ -28,157 +28,173 @@
*/
#include "benchmark/benchmark_api.h"
#include "AllBackends.h"
#include <iostream>
#define _USE_MATH_DEFINES
#include "math/backend.h"
#include "utils/inttypes.h"
#include "math/nbtheory.h"
#include "lattice/elemparams.h"
#include "lattice/ilparams.h"
#include "lattice/ildcrtparams.h"
#include "lattice/ilelement.h"
#include "math/distrgen.h"
#include "lattice/poly.h"
#include "../../src/core/lib/lattice/dcrtpoly.h"
#include "utils/utilities.h"
#include <vector>
using namespace std;
using namespace lbcrypto;
#define DO_BENCHMARK_TEMPLATE(X,Y) \
BENCHMARK_TEMPLATE(X,Y)->Unit(benchmark::kMicrosecond);
//four simple benchmarks to test constructing BigInts
// typically the code to benchmark is in a 'function' that is then
// called within the actual benchmark.
// test BigInt constants
template<typename I>
static void make_BigInt_constants(void) { // function
BigInteger one(1);
I one(1);
}
template<typename I>
void BM_BigInt_constants(benchmark::State& state) { // benchmark
while (state.KeepRunning()) {
make_BigInt_constants(); // note even with -O3 it appears
// this is not optimized out
// though check with your compiler
make_BigInt_constants<I>();
}
}
BENCHMARK(BM_BigInt_constants); // register benchmark
// make variables
DO_BENCHMARK_TEMPLATE(BM_BigInt_constants,BE2Integer)
DO_BENCHMARK_TEMPLATE(BM_BigInt_constants,BE4Integer)
DO_BENCHMARK_TEMPLATE(BM_BigInt_constants,BE6Integer)
DO_BENCHMARK_TEMPLATE(BM_BigInt_constants,NativeInteger)
template<typename I>
static void make_BigInt_small_variables (void) { // function
BigInteger a("10403"), b("103");
I a("10403"), b("103");
}
template<typename I>
void BM_BigInt_small_variables(benchmark::State& state) { // benchmark
while (state.KeepRunning()) {
make_BigInt_small_variables(); // note even with -O3 it appears
// this is not optimized out
// though check with your compiler
make_BigInt_small_variables<I>();
}
}
BENCHMARK(BM_BigInt_small_variables); // register benchmark
DO_BENCHMARK_TEMPLATE(BM_BigInt_small_variables,BE2Integer)
DO_BENCHMARK_TEMPLATE(BM_BigInt_small_variables,BE4Integer)
DO_BENCHMARK_TEMPLATE(BM_BigInt_small_variables,BE6Integer)
DO_BENCHMARK_TEMPLATE(BM_BigInt_small_variables,NativeInteger)
template<typename I>
static void make_BigInt_large_variables (void) { // function
BigInteger a("18446744073709551616"), b("18446744073709551617");
I a("18446744073709551616"), b("18446744073709551617");
}
template<typename I>
void BM_BigInt_large_variables(benchmark::State& state) { // benchmark
while (state.KeepRunning()) {
make_BigInt_large_variables();
make_BigInt_large_variables<I>();
}
}
BENCHMARK(BM_BigInt_large_variables);
DO_BENCHMARK_TEMPLATE(BM_BigInt_large_variables,BE2Integer)
DO_BENCHMARK_TEMPLATE(BM_BigInt_large_variables,BE4Integer)
DO_BENCHMARK_TEMPLATE(BM_BigInt_large_variables,BE6Integer)
static BigInteger smalla("10403"), smallb("103");
static BigInteger largea("18446744073709551616"), largeb("18446744073709551617");
static string smalla("10403"), smallb("103");
static string largea("18446744073709551616"), largeb("18446744073709551617");
// add
static void add_BigInt(benchmark::State& state) { // function
state.PauseTiming();
BigInteger& a = state.range(0) == 0 ? smalla : largea;
BigInteger& b = state.range(0) == 0 ? smallb : largeb;
state.ResumeTiming();
BigInteger c = a+b;
template<typename I>
static void add_BigInt(const I& a, const I& b) { // function
I c = a+b;
}
static void BM_BigInt_Addition(benchmark::State& state) { // benchmark
template<typename I>
static void BM_BigInt_Add(benchmark::State& state) { // benchmark
I a( state.range(0) == 0 ? smalla : largea );
I b( state.range(0) == 0 ? smallb : largeb );
while (state.KeepRunning()) {
add_BigInt(state);
add_BigInt(a, b);
}
}
BENCHMARK(BM_BigInt_Addition)->ArgName("Small")->Arg(0);
BENCHMARK(BM_BigInt_Addition)->ArgName("Large")->Arg(1);
BENCHMARK_TEMPLATE(BM_BigInt_Add,BE2Integer)->Unit(benchmark::kMicrosecond)->ArgName("Small")->Arg(0);
BENCHMARK_TEMPLATE(BM_BigInt_Add,BE2Integer)->Unit(benchmark::kMicrosecond)->ArgName("Large")->Arg(1);
BENCHMARK_TEMPLATE(BM_BigInt_Add,BE4Integer)->Unit(benchmark::kMicrosecond)->ArgName("Small")->Arg(0);
BENCHMARK_TEMPLATE(BM_BigInt_Add,BE4Integer)->Unit(benchmark::kMicrosecond)->ArgName("Large")->Arg(1);
BENCHMARK_TEMPLATE(BM_BigInt_Add,BE6Integer)->Unit(benchmark::kMicrosecond)->ArgName("Small")->Arg(0);
BENCHMARK_TEMPLATE(BM_BigInt_Add,BE6Integer)->Unit(benchmark::kMicrosecond)->ArgName("Large")->Arg(1);
BENCHMARK_TEMPLATE(BM_BigInt_Add,NativeInteger)->Unit(benchmark::kMicrosecond)->ArgName("Small")->Arg(0);
// +=
static void addeq_BigInt(benchmark::State& state) { // function
state.PauseTiming();
BigInteger a = state.range(0) == 0 ? smalla : largea;
BigInteger b = state.range(0) == 0 ? smallb : largeb;
state.ResumeTiming();
template<typename I>
static void addeq_BigInt(I& a, const I& b) { // function
a += b;
}
template<typename I>
static void BM_BigInt_Addeq(benchmark::State& state) { // benchmark
I b( state.range(0) == 0 ? smallb : largeb );
while (state.KeepRunning()) {
addeq_BigInt(state);
I a( state.range(0) == 0 ? smalla : largea );
addeq_BigInt(a, b);
}
}
BENCHMARK(BM_BigInt_Addeq)->ArgName("Small")->Arg(0);
BENCHMARK(BM_BigInt_Addeq)->ArgName("Large")->Arg(1);
BENCHMARK_TEMPLATE(BM_BigInt_Addeq,BE2Integer)->Unit(benchmark::kMicrosecond)->ArgName("Small")->Arg(0);
BENCHMARK_TEMPLATE(BM_BigInt_Addeq,BE2Integer)->Unit(benchmark::kMicrosecond)->ArgName("Large")->Arg(1);
BENCHMARK_TEMPLATE(BM_BigInt_Addeq,BE4Integer)->Unit(benchmark::kMicrosecond)->ArgName("Small")->Arg(0);
BENCHMARK_TEMPLATE(BM_BigInt_Addeq,BE4Integer)->Unit(benchmark::kMicrosecond)->ArgName("Large")->Arg(1);
BENCHMARK_TEMPLATE(BM_BigInt_Addeq,BE6Integer)->Unit(benchmark::kMicrosecond)->ArgName("Small")->Arg(0);
BENCHMARK_TEMPLATE(BM_BigInt_Addeq,BE6Integer)->Unit(benchmark::kMicrosecond)->ArgName("Large")->Arg(1);
BENCHMARK_TEMPLATE(BM_BigInt_Addeq,NativeInteger)->Unit(benchmark::kMicrosecond)->ArgName("Small")->Arg(0);
// mult
static void mult_BigInt(benchmark::State& state) { // function
state.PauseTiming();
BigInteger& a = state.range(0) == 0 ? smalla : largea;
BigInteger& b = state.range(0) == 0 ? smallb : largeb;
state.ResumeTiming();
BigInteger c1 = a*b;
template<typename I>
static void mult_BigInt(const I& a, const I& b) { // function
I c1 = a*b;
}
static void BM_BigInt_Multiplication(benchmark::State& state) { // benchmark
template<typename I>
static void BM_BigInt_Mult(benchmark::State& state) { // benchmark
I a( state.range(0) == 0 ? smalla : largea );
I b( state.range(0) == 0 ? smallb : largeb );
while (state.KeepRunning()) {
mult_BigInt(state);
mult_BigInt(a,b);
}
}
BENCHMARK(BM_BigInt_Multiplication)->ArgName("Small")->Arg(0);
BENCHMARK(BM_BigInt_Multiplication)->ArgName("Large")->Arg(1);
BENCHMARK_TEMPLATE(BM_BigInt_Mult,BE2Integer)->Unit(benchmark::kMicrosecond)->ArgName("Small")->Arg(0);
BENCHMARK_TEMPLATE(BM_BigInt_Mult,BE2Integer)->Unit(benchmark::kMicrosecond)->ArgName("Large")->Arg(1);
BENCHMARK_TEMPLATE(BM_BigInt_Mult,BE4Integer)->Unit(benchmark::kMicrosecond)->ArgName("Small")->Arg(0);
BENCHMARK_TEMPLATE(BM_BigInt_Mult,BE4Integer)->Unit(benchmark::kMicrosecond)->ArgName("Large")->Arg(1);
BENCHMARK_TEMPLATE(BM_BigInt_Mult,BE6Integer)->Unit(benchmark::kMicrosecond)->ArgName("Small")->Arg(0);
BENCHMARK_TEMPLATE(BM_BigInt_Mult,BE6Integer)->Unit(benchmark::kMicrosecond)->ArgName("Large")->Arg(1);
BENCHMARK_TEMPLATE(BM_BigInt_Mult,NativeInteger)->Unit(benchmark::kMicrosecond)->ArgName("Small")->Arg(0);
// *=
static void multeq_BigInt(benchmark::State& state) { // function
state.PauseTiming();
BigInteger a = state.range(0) == 0 ? smalla : largea;
BigInteger b = state.range(0) == 0 ? smallb : largeb;
state.ResumeTiming();
template<typename I>
static void multeq_BigInt(I& a, const I& b) { // function
a *= b;
}
template<typename I>
static void BM_BigInt_Multeq(benchmark::State& state) { // benchmark
I b( state.range(0) == 0 ? smallb : largeb );
while (state.KeepRunning()) {
multeq_BigInt(state);
I a( state.range(0) == 0 ? smalla : largea );
multeq_BigInt(a, b);
}
}
BENCHMARK(BM_BigInt_Multeq)->ArgName("Small")->Arg(0);
BENCHMARK(BM_BigInt_Multeq)->ArgName("Large")->Arg(1);
BENCHMARK_TEMPLATE(BM_BigInt_Multeq,BE2Integer)->Unit(benchmark::kMicrosecond)->ArgName("Small")->Arg(0);
BENCHMARK_TEMPLATE(BM_BigInt_Multeq,BE2Integer)->Unit(benchmark::kMicrosecond)->ArgName("Large")->Arg(1);
BENCHMARK_TEMPLATE(BM_BigInt_Multeq,BE4Integer)->Unit(benchmark::kMicrosecond)->ArgName("Small")->Arg(0);
BENCHMARK_TEMPLATE(BM_BigInt_Multeq,BE4Integer)->Unit(benchmark::kMicrosecond)->ArgName("Large")->Arg(1);
BENCHMARK_TEMPLATE(BM_BigInt_Multeq,BE6Integer)->Unit(benchmark::kMicrosecond)->ArgName("Small")->Arg(0);
BENCHMARK_TEMPLATE(BM_BigInt_Multeq,BE6Integer)->Unit(benchmark::kMicrosecond)->ArgName("Large")->Arg(1);
BENCHMARK_TEMPLATE(BM_BigInt_Multeq,NativeInteger)->Unit(benchmark::kMicrosecond)->ArgName("Small")->Arg(0);
//execute the benchmarks
BENCHMARK_MAIN()
......@@ -30,21 +30,9 @@
#include "benchmark/benchmark_api.h"
#include <iostream>
#define _USE_MATH_DEFINES
#include "math/backend.h"
#include "utils/inttypes.h"
#include "math/nbtheory.h"
#include "lattice/elemparams.h"
#include "lattice/ilparams.h"
#include "lattice/ildcrtparams.h"
#include "lattice/ildcrtparams.h"
#include "lattice/ilelement.h"
#include "math/distrgen.h"
#include "lattice/poly.h"
#include "../../src/core/lib/lattice/dcrtpoly.h"
#include "utils/utilities.h"
#include "AllBackends.h"
#include <iostream>
#include <vector>
#include "vechelper.h"
......@@ -85,22 +73,31 @@ static E makeElement(shared_ptr<lbcrypto::ILDCRTParams<typename E::Integer>> p)
}
static vector<usint> o( { 16, 1024, 2048, 4096, 8192, 16384, 32768 } );
static const usint DCRTBITS = 28;
template<typename P>
static void GenerateParms(map<usint,shared_ptr<P>>& parmArray) {
for(usint v : o ) {
shared_ptr<P> value;
try {
parmArray[v] = ElemParamFactory::GenElemParams<P>(v);
value = ElemParamFactory::GenElemParams<P>(v);
} catch( ... ) {
break;
}
parmArray[v] = value;
}
}
template<typename P>
static void GenerateDCRTParms(map<usint,shared_ptr<P>>& parmArray) {
for(usint v : o ) {
parmArray[v] = ElemParamFactory::GenElemParams<P>(v, 28, 5);
size_t idx = ElemParamFactory::GetNearestIndex(v);
BE2Integer primeq( ElemParamFactory::DefaultSet[idx].q);
usint bits = primeq.GetMSB();
usint ntowers = bits/DCRTBITS + 1;
parmArray[v] = ElemParamFactory::GenElemParams<P>(v, 28, ntowers);
}
}
......@@ -112,27 +109,6 @@ static void GeneratePolys(map<usint,shared_ptr<P>>& parmArray, map<usint,vector<
}
}
using BE2Integer = cpu_int::BigInteger<integral_dtype,BigIntegerBitLength>;
using BE2ILParams = ILParamsImpl<BE2Integer>;
using BE2ILDCRTParams = ILDCRTParams<BE2Integer>;
using BE2Vector = cpu_int::BigVectorImpl<BE2Integer>;
using BE2Poly = PolyImpl<BE2Integer, BE2Integer, BE2Vector, BE2ILParams>;
using BE2DCRTPoly = DCRTPolyImpl<BE2Integer, BE2Integer, BE2Vector, BE2ILDCRTParams>;
using BE4Integer = exp_int::xubint;
using BE4ILParams = ILParamsImpl<BE4Integer>;
using BE4ILDCRTParams = ILDCRTParams<BE4Integer>;
using BE4Vector = exp_int::xmubintvec;
using BE4Poly = PolyImpl<BE4Integer, BE4Integer, BE4Vector, BE4ILParams>;
using BE4DCRTPoly = DCRTPolyImpl<BE4Integer, BE4Integer, BE4Vector, BE4ILDCRTParams>;
using BE6Integer = NTL::myZZ;
using BE6ILParams = ILParamsImpl<BE6Integer>;
using BE6ILDCRTParams = ILDCRTParams<BE6Integer>;
using BE6Vector = NTL::myVecP<NTL::myZZ>;
using BE6Poly = PolyImpl<BE6Integer, BE6Integer, BE6Vector, BE6ILParams>;
using BE6DCRTPoly = DCRTPolyImpl<BE6Integer, BE6Integer, BE6Vector, BE6ILDCRTParams>;
// the ifdefs below are a hack to make sure this compiles in all backends
// when backend is == 2, BigInteger is the same as BE2Integer... and so these methods
// will have duplicate instantiations... which is bad
......
......@@ -62,6 +62,20 @@ public:
string ru; // root of unity
} DefaultSet[];
static size_t GetNearestIndex(usint m) {
size_t sIdx = 0;
if( DefaultSet[0].m < m ) {
for( sIdx = 1; DefaultSet[sIdx].m != 0; sIdx++ ) {
if( m <= DefaultSet[sIdx].m )
break;
}
}
if( DefaultSet[sIdx].m == 0 )
sIdx--;
return sIdx;
}
/**
* GenElemParams for a particular predefined cyclotomic order
*
......@@ -81,15 +95,7 @@ public:
*/
template<typename P>
static shared_ptr<P> GenElemParams(usint m) {
size_t sIdx = 0;
if( DefaultSet[0].m < m ) {
for( sIdx = 1; DefaultSet[sIdx].m != 0; sIdx++ ) {
if( m <= DefaultSet[sIdx].m )
break;
}
}
if( DefaultSet[sIdx].m == 0 )
sIdx--;
size_t sIdx = GetNearestIndex(m);
return shared_ptr<P>( new P(DefaultSet[sIdx].m, typename P::Integer(DefaultSet[sIdx].q), typename P::Integer(DefaultSet[sIdx].ru)) );
}
......
......@@ -1560,6 +1560,17 @@ BigInteger<uint_type,BITLENGTH> BigInteger<uint_type,BITLENGTH>::ModInverse(cons
template<typename uint_type,usint BITLENGTH>
BigInteger<uint_type,BITLENGTH> BigInteger<uint_type,BITLENGTH>::ModAdd(const BigInteger& b, const BigInteger& modulus) const{
BigInteger a(*this);
BigInteger bb(b);
if( a >= modulus ) a.ModEq(modulus);
if( bb >= modulus ) bb.ModEq(modulus);
a.PlusEq(bb);
return a.ModEq(modulus);
}
template<typename uint_type,usint BITLENGTH>
BigInteger<uint_type,BITLENGTH> BigInteger<uint_type,BITLENGTH>::ModAddFast(const BigInteger& b, const BigInteger& modulus) const{
return this->Plus(b).Mod(modulus);
}
......@@ -1606,6 +1617,21 @@ BigInteger<uint_type,BITLENGTH> BigInteger<uint_type,BITLENGTH>::ModSub(const Bi
return a;
}
template<typename uint_type,usint BITLENGTH>
BigInteger<uint_type,BITLENGTH> BigInteger<uint_type,BITLENGTH>::ModSubFast(const BigInteger& b, const BigInteger& modulus) const{
BigInteger a(*this);
if(a >= b){