📄 integer.cpp
字号:
// integer.cpp - written and placed in the public domain by Wei Dai// contains public domain code contributed by Alister Lee and Leonard Janke#include "pch.h"#ifndef CRYPTOPP_IMPORTS#include "integer.h"#include "modarith.h"#include "nbtheory.h"#include "asn.h"#include "oids.h"#include "words.h"#include "algparam.h"#include "pubkey.h" // for P1363_KDF2#include "sha.h"#include "cpu.h"#include <iostream>#if _MSC_VER >= 1400 #include <intrin.h>#endif#ifdef __DECCXX #include <c_asm.h>#endif#ifdef CRYPTOPP_MSVC6_NO_PP #pragma message("You do not seem to have the Visual C++ Processor Pack installed, so use of SSE2 instructions will be disabled.")#endif#define CRYPTOPP_INTEGER_SSE2 (CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE && CRYPTOPP_BOOL_X86)NAMESPACE_BEGIN(CryptoPP)bool AssignIntToInteger(const std::type_info &valueType, void *pInteger, const void *pInt){ if (valueType != typeid(Integer)) return false; *reinterpret_cast<Integer *>(pInteger) = *reinterpret_cast<const int *>(pInt); return true;}inline static int Compare(const word *A, const word *B, size_t N){ while (N--) if (A[N] > B[N]) return 1; else if (A[N] < B[N]) return -1; return 0;}inline static int Increment(word *A, size_t N, word B=1){ assert(N); word t = A[0]; A[0] = t+B; if (A[0] >= t) return 0; for (unsigned i=1; i<N; i++) if (++A[i]) return 0; return 1;}inline static int Decrement(word *A, size_t N, word B=1){ assert(N); word t = A[0]; A[0] = t-B; if (A[0] <= t) return 0; for (unsigned i=1; i<N; i++) if (A[i]--) return 0; return 1;}static void TwosComplement(word *A, size_t N){ Decrement(A, N); for (unsigned i=0; i<N; i++) A[i] = ~A[i];}static word AtomicInverseModPower2(word A){ assert(A%2==1); word R=A%8; for (unsigned i=3; i<WORD_BITS; i*=2) R = R*(2-R*A); assert(R*A==1); return R;}// ********************************************************#if !defined(CRYPTOPP_NATIVE_DWORD_AVAILABLE) || (defined(__x86_64__) && defined(CRYPTOPP_WORD128_AVAILABLE)) #define Declare2Words(x) word x##0, x##1; #define AssignWord(a, b) a##0 = b; a##1 = 0; #define Add2WordsBy1(a, b, c) a##0 = b##0 + c; a##1 = b##1 + (a##0 < c); #define LowWord(a) a##0 #define HighWord(a) a##1 #ifdef _MSC_VER #define MultiplyWordsLoHi(p0, p1, a, b) p0 = _umul128(a, b, &p1); #ifndef __INTEL_COMPILER #define Double3Words(c, d) d##1 = __shiftleft128(d##0, d##1, 1); d##0 = __shiftleft128(c, d##0, 1); c *= 2; #endif #elif defined(__DECCXX) #define MultiplyWordsLoHi(p0, p1, a, b) p0 = a*b; p1 = asm("umulh %a0, %a1, %v0", a, b); #elif defined(__x86_64__) #ifdef __SUNPRO_CC // Sun Studio's gcc-style inline assembly is heavily bugged as of version 5.9 Patch 124864-09 2008/12/16, but this one works #define MultiplyWordsLoHi(p0, p1, a, b) asm ("mulq %3" : "=a"(p0), "=d"(p1) : "a"(a), "r"(b) : "cc"); #else #define MultiplyWordsLoHi(p0, p1, a, b) asm ("mulq %3" : "=a"(p0), "=d"(p1) : "a"(a), "g"(b) : "cc"); #define MulAcc(c, d, a, b) asm ("mulq %6; addq %3, %0; adcq %4, %1; adcq $0, %2;" : "+r"(c), "+r"(d##0), "+r"(d##1), "=a"(p0), "=d"(p1) : "a"(a), "g"(b) : "cc"); #define Double3Words(c, d) asm ("addq %0, %0; adcq %1, %1; adcq %2, %2;" : "+r"(c), "+r"(d##0), "+r"(d##1) : : "cc"); #define Acc2WordsBy1(a, b) asm ("addq %2, %0; adcq $0, %1;" : "+r"(a##0), "+r"(a##1) : "r"(b) : "cc"); #define Acc2WordsBy2(a, b) asm ("addq %2, %0; adcq %3, %1;" : "+r"(a##0), "+r"(a##1) : "r"(b##0), "r"(b##1) : "cc"); #define Acc3WordsBy2(c, d, e) asm ("addq %5, %0; adcq %6, %1; adcq $0, %2;" : "+r"(c), "=r"(e##0), "=r"(e##1) : "1"(d##0), "2"(d##1), "r"(e##0), "r"(e##1) : "cc"); #endif #endif #define MultiplyWords(p, a, b) MultiplyWordsLoHi(p##0, p##1, a, b) #ifndef Double3Words #define Double3Words(c, d) d##1 = 2*d##1 + (d##0>>(WORD_BITS-1)); d##0 = 2*d##0 + (c>>(WORD_BITS-1)); c *= 2; #endif #ifndef Acc2WordsBy2 #define Acc2WordsBy2(a, b) a##0 += b##0; a##1 += a##0 < b##0; a##1 += b##1; #endif #define AddWithCarry(u, a, b) {word t = a+b; u##0 = t + u##1; u##1 = (t<a) + (u##0<t);} #define SubtractWithBorrow(u, a, b) {word t = a-b; u##0 = t - u##1; u##1 = (t>a) + (u##0>t);} #define GetCarry(u) u##1 #define GetBorrow(u) u##1#else #define Declare2Words(x) dword x; #if _MSC_VER >= 1400 && !defined(__INTEL_COMPILER) #define MultiplyWords(p, a, b) p = __emulu(a, b); #else #define MultiplyWords(p, a, b) p = (dword)a*b; #endif #define AssignWord(a, b) a = b; #define Add2WordsBy1(a, b, c) a = b + c; #define Acc2WordsBy2(a, b) a += b; #define LowWord(a) word(a) #define HighWord(a) word(a>>WORD_BITS) #define Double3Words(c, d) d = 2*d + (c>>(WORD_BITS-1)); c *= 2; #define AddWithCarry(u, a, b) u = dword(a) + b + GetCarry(u); #define SubtractWithBorrow(u, a, b) u = dword(a) - b - GetBorrow(u); #define GetCarry(u) HighWord(u) #define GetBorrow(u) word(u>>(WORD_BITS*2-1))#endif#ifndef MulAcc #define MulAcc(c, d, a, b) MultiplyWords(p, a, b); Acc2WordsBy1(p, c); c = LowWord(p); Acc2WordsBy1(d, HighWord(p));#endif#ifndef Acc2WordsBy1 #define Acc2WordsBy1(a, b) Add2WordsBy1(a, a, b)#endif#ifndef Acc3WordsBy2 #define Acc3WordsBy2(c, d, e) Acc2WordsBy1(e, c); c = LowWord(e); Add2WordsBy1(e, d, HighWord(e));#endifclass DWord{public: DWord() {}#ifdef CRYPTOPP_NATIVE_DWORD_AVAILABLE explicit DWord(word low) { m_whole = low; }#else explicit DWord(word low) { m_halfs.low = low; m_halfs.high = 0; }#endif DWord(word low, word high) { m_halfs.low = low; m_halfs.high = high; } static DWord Multiply(word a, word b) { DWord r; #ifdef CRYPTOPP_NATIVE_DWORD_AVAILABLE r.m_whole = (dword)a * b; #elif defined(MultiplyWordsLoHi) MultiplyWordsLoHi(r.m_halfs.low, r.m_halfs.high, a, b); #endif return r; } static DWord MultiplyAndAdd(word a, word b, word c) { DWord r = Multiply(a, b); return r += c; } DWord & operator+=(word a) { #ifdef CRYPTOPP_NATIVE_DWORD_AVAILABLE m_whole = m_whole + a; #else m_halfs.low += a; m_halfs.high += (m_halfs.low < a); #endif return *this; } DWord operator+(word a) { DWord r; #ifdef CRYPTOPP_NATIVE_DWORD_AVAILABLE r.m_whole = m_whole + a; #else r.m_halfs.low = m_halfs.low + a; r.m_halfs.high = m_halfs.high + (r.m_halfs.low < a); #endif return r; } DWord operator-(DWord a) { DWord r; #ifdef CRYPTOPP_NATIVE_DWORD_AVAILABLE r.m_whole = m_whole - a.m_whole; #else r.m_halfs.low = m_halfs.low - a.m_halfs.low; r.m_halfs.high = m_halfs.high - a.m_halfs.high - (r.m_halfs.low > m_halfs.low); #endif return r; } DWord operator-(word a) { DWord r; #ifdef CRYPTOPP_NATIVE_DWORD_AVAILABLE r.m_whole = m_whole - a; #else r.m_halfs.low = m_halfs.low - a; r.m_halfs.high = m_halfs.high - (r.m_halfs.low > m_halfs.low); #endif return r; } // returns quotient, which must fit in a word word operator/(word divisor); word operator%(word a); bool operator!() const { #ifdef CRYPTOPP_NATIVE_DWORD_AVAILABLE return !m_whole; #else return !m_halfs.high && !m_halfs.low; #endif } word GetLowHalf() const {return m_halfs.low;} word GetHighHalf() const {return m_halfs.high;} word GetHighHalfAsBorrow() const {return 0-m_halfs.high;}private: union { #ifdef CRYPTOPP_NATIVE_DWORD_AVAILABLE dword m_whole; #endif struct { #ifdef IS_LITTLE_ENDIAN word low; word high; #else word high; word low; #endif } m_halfs; };};class Word{public: Word() {} Word(word value) { m_whole = value; } Word(hword low, hword high) { m_whole = low | (word(high) << (WORD_BITS/2)); } static Word Multiply(hword a, hword b) { Word r; r.m_whole = (word)a * b; return r; } Word operator-(Word a) { Word r; r.m_whole = m_whole - a.m_whole; return r; } Word operator-(hword a) { Word r; r.m_whole = m_whole - a; return r; } // returns quotient, which must fit in a word hword operator/(hword divisor) { return hword(m_whole / divisor); } bool operator!() const { return !m_whole; } word GetWhole() const {return m_whole;} hword GetLowHalf() const {return hword(m_whole);} hword GetHighHalf() const {return hword(m_whole>>(WORD_BITS/2));} hword GetHighHalfAsBorrow() const {return 0-hword(m_whole>>(WORD_BITS/2));} private: word m_whole;};// do a 3 word by 2 word divide, returns quotient and leaves remainder in Atemplate <class S, class D>S DivideThreeWordsByTwo(S *A, S B0, S B1, D *dummy=NULL){ // assert {A[2],A[1]} < {B1,B0}, so quotient can fit in a S assert(A[2] < B1 || (A[2]==B1 && A[1] < B0)); // estimate the quotient: do a 2 S by 1 S divide S Q; if (S(B1+1) == 0) Q = A[2]; else Q = D(A[1], A[2]) / S(B1+1); // now subtract Q*B from A D p = D::Multiply(B0, Q); D u = (D) A[0] - p.GetLowHalf(); A[0] = u.GetLowHalf(); u = (D) A[1] - p.GetHighHalf() - u.GetHighHalfAsBorrow() - D::Multiply(B1, Q); A[1] = u.GetLowHalf(); A[2] += u.GetHighHalf(); // Q <= actual quotient, so fix it while (A[2] || A[1] > B1 || (A[1]==B1 && A[0]>=B0)) { u = (D) A[0] - B0; A[0] = u.GetLowHalf(); u = (D) A[1] - B1 - u.GetHighHalfAsBorrow(); A[1] = u.GetLowHalf(); A[2] += u.GetHighHalf(); Q++; assert(Q); // shouldn't overflow } return Q;}// do a 4 word by 2 word divide, returns 2 word quotient in Q0 and Q1template <class S, class D>inline D DivideFourWordsByTwo(S *T, const D &Al, const D &Ah, const D &B){ if (!B) // if divisor is 0, we assume divisor==2**(2*WORD_BITS) return D(Ah.GetLowHalf(), Ah.GetHighHalf()); else { S Q[2]; T[0] = Al.GetLowHalf(); T[1] = Al.GetHighHalf(); T[2] = Ah.GetLowHalf(); T[3] = Ah.GetHighHalf(); Q[1] = DivideThreeWordsByTwo<S, D>(T+1, B.GetLowHalf(), B.GetHighHalf()); Q[0] = DivideThreeWordsByTwo<S, D>(T, B.GetLowHalf(), B.GetHighHalf()); return D(Q[0], Q[1]); }}// returns quotient, which must fit in a wordinline word DWord::operator/(word a){ #ifdef CRYPTOPP_NATIVE_DWORD_AVAILABLE return word(m_whole / a); #else hword r[4]; return DivideFourWordsByTwo<hword, Word>(r, m_halfs.low, m_halfs.high, a).GetWhole(); #endif}inline word DWord::operator%(word a){ #ifdef CRYPTOPP_NATIVE_DWORD_AVAILABLE return word(m_whole % a); #else if (a < (word(1) << (WORD_BITS/2))) { hword h = hword(a); word r = m_halfs.high % h; r = ((m_halfs.low >> (WORD_BITS/2)) + (r << (WORD_BITS/2))) % h; return hword((hword(m_halfs.low) + (r << (WORD_BITS/2))) % h); } else { hword r[4]; DivideFourWordsByTwo<hword, Word>(r, m_halfs.low, m_halfs.high, a); return Word(r[0], r[1]).GetWhole(); } #endif}// ********************************************************// use some tricks to share assembly code between MSVC and GCC#if defined(__GNUC__) #define AddPrologue \ int result; \ __asm__ __volatile__ \ ( \ ".intel_syntax noprefix;" #define AddEpilogue \ ".att_syntax prefix;" \ : "=a" (result)\ : "d" (C), "a" (A), "D" (B), "c" (N) \ : "%esi", "memory", "cc" \ );\ return result; #define MulPrologue \ __asm__ __volatile__ \ ( \ ".intel_syntax noprefix;" \ AS1( push ebx) \ AS2( mov ebx, edx) #define MulEpilogue \ AS1( pop ebx) \ ".att_syntax prefix;" \ : \ : "d" (s_maskLow16), "c" (C), "a" (A), "D" (B) \ : "%esi", "memory", "cc" \ ); #define SquPrologue MulPrologue #define SquEpilogue \ AS1( pop ebx) \ ".att_syntax prefix;" \ : \ : "d" (s_maskLow16), "c" (C), "a" (A) \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -