From 16ffe513a42110193254dac663ebfc732959ac85 Mon Sep 17 00:00:00 2001 From: Jeffrey Walton Date: Wed, 23 Nov 2016 21:55:30 -0500 Subject: [PATCH] Add Integer bitwise AND, OR and XOR (Issue 336) --- cryptlib.h | 2 +- integer.cpp | 136 +++++++++++++++++++++++++++++ integer.h | 244 ++++++++++++++++++++++++++++++++++++++-------------- words.h | 12 +++ 4 files changed, 329 insertions(+), 65 deletions(-) diff --git a/cryptlib.h b/cryptlib.h index ce287217..e60efb36 100644 --- a/cryptlib.h +++ b/cryptlib.h @@ -592,7 +592,7 @@ public: {SetKeyWithIV(key, length, iv, IVSize());} //! \brief Secure IVs requirements as enumerated values. - //! \details Provides secure IV requirements as a monotomically increasing enumerated values. Requirements can be + //! \details Provides secure IV requirements as a monotonically increasing enumerated values. Requirements can be //! compared using less than (<) and greater than (>). For example, UNIQUE_IV < RANDOM_IV //! and UNPREDICTABLE_RANDOM_IV > RANDOM_IV. //! \sa IsResynchronizable(), CanUseRandomIVs(), CanUsePredictableIVs(), CanUseStructuredIVs() diff --git a/integer.cpp b/integer.cpp index dfd767e3..766f35d8 100644 --- a/integer.cpp +++ b/integer.cpp @@ -3738,6 +3738,84 @@ Integer& Integer::operator--() return *this; } +// This is a bit operation. We set sign to POSITIVE, so there's no need to +// worry about negative zero. Also see http://stackoverflow.com/q/11644362. +Integer Integer::And(const Integer& t) const +{ + if (this == &t) + { + return AbsoluteValue(); + } + else if (WordCount() >= t.WordCount()) + { + Integer result(t); + AndWords(result.reg, reg, t.WordCount()); + + result.sign = POSITIVE; + return result; + } + else // WordCount() < t.WordCount() + { + Integer result(*this); + AndWords(result.reg, t.reg, WordCount()); + + result.sign = POSITIVE; + return result; + } +} + +// This is a bit operation. We set sign to POSITIVE, so there's no need to +// worry about negative zero. Also see http://stackoverflow.com/q/11644362. +Integer Integer::Or(const Integer& t) const +{ + if (this == &t) + { + return AbsoluteValue(); + } + else if (WordCount() >= t.WordCount()) + { + Integer result(*this); + OrWords(result.reg, t.reg, t.WordCount()); + + result.sign = POSITIVE; + return result; + } + else // WordCount() < t.WordCount() + { + Integer result(t); + OrWords(result.reg, reg, WordCount()); + + result.sign = POSITIVE; + return result; + } +} + +// This is a bit operation. We set sign to POSITIVE, so there's no need to +// worry about negative zero. Also see http://stackoverflow.com/q/11644362. +Integer Integer::Xor(const Integer& t) const +{ + if (this == &t) + { + return Integer::Zero(); + } + else if (WordCount() >= t.WordCount()) + { + Integer result(*this); + XorWords(result.reg, t.reg, t.WordCount()); + + result.sign = POSITIVE; + return result; + } + else // WordCount() < t.WordCount() + { + Integer result(t); + XorWords(result.reg, reg, WordCount()); + + result.sign = POSITIVE; + return result; + } +} + void PositiveAdd(Integer &sum, const Integer &a, const Integer& b) { // Profiling tells us the original second Else If was dominant, so it was promoted to the first If statement. @@ -3932,6 +4010,64 @@ Integer& Integer::operator>>=(size_t n) return *this; } +Integer& Integer::operator&=(const Integer& t) +{ + if (this != &t) + { + const size_t size = STDMIN(WordCount(), t.WordCount()); + reg.resize(size); + AndWords(reg, t.reg, size); + } + sign = POSITIVE; + return *this; +} + +Integer& Integer::operator|=(const Integer& t) +{ + if (this != &t) + { + if (WordCount() >= t.WordCount()) + { + OrWords(reg, t.reg, t.WordCount()); + } + else // WordCount() < t.WordCount() + { + const size_t head = WordCount(); + const size_t tail = t.WordCount() - WordCount(); + reg.resize(head+tail); + OrWords(reg, t.reg, head); + CopyWords(reg+head,t.reg+head,tail); + } + } + sign = POSITIVE; + return *this; +} + +Integer& Integer::operator^=(const Integer& t) +{ + if (this == &t) + { + *this = Zero(); + } + else + { + if (WordCount() >= t.WordCount()) + { + XorWords(reg, t.reg, t.WordCount()); + } + else // WordCount() < t.WordCount() + { + const size_t head = WordCount(); + const size_t tail = t.WordCount() - WordCount(); + reg.resize(head+tail); + XorWords(reg, t.reg, head); + CopyWords(reg+head,t.reg+head,tail); + } + } + sign = POSITIVE; + return *this; +} + void PositiveMultiply(Integer &product, const Integer &a, const Integer &b) { size_t aSize = RoundupSize(a.WordCount()); diff --git a/integer.h b/integer.h index e59b0a56..5dd80101 100644 --- a/integer.h +++ b/integer.h @@ -6,8 +6,9 @@ //! with absolute value less than (256**sizeof(word))(256**sizeof(int)). //! \details Internally, the library uses a sign magnitude representation, and the class //! has two data members. The first is a IntegerSecBlock (a SecBlock) and it is -//! used to hold the representation. The second is a Sign, and its is used to track -//! the sign of the Integer. +//! used to hold the representation. The second is a Sign (an enumeration), and it is +//! used to track the sign of the Integer. +//! \since Crypto++ 1.0 #ifndef CRYPTOPP_INTEGER_H #define CRYPTOPP_INTEGER_H @@ -21,26 +22,23 @@ NAMESPACE_BEGIN(CryptoPP) //! \struct InitializeInteger -//! Performs static intialization of the Integer class +//! \brief Performs static intialization of the Integer class struct InitializeInteger { InitializeInteger(); }; -// http://github.com/weidai11/cryptopp/issues/256 -#if defined(CRYPTOPP_WORD128_AVAILABLE) +// Always align, http://github.com/weidai11/cryptopp/issues/256 typedef SecBlock > IntegerSecBlock; -#else -typedef SecBlock > IntegerSecBlock; -#endif //! \brief Multiple precision integer with arithmetic operations //! \details The Integer class can represent positive and negative integers //! with absolute value less than (256**sizeof(word))(256**sizeof(int)). //! \details Internally, the library uses a sign magnitude representation, and the class //! has two data members. The first is a IntegerSecBlock (a SecBlock) and it is -//! used to hold the representation. The second is a Sign, and its is used to track -//! the sign of the Integer. +//! used to hold the representation. The second is a Sign (an enumeration), and it is +//! used to track the sign of the Integer. +//! \since Crypto++ 1.0 //! \nosubgrouping class CRYPTOPP_DLL Integer : private InitializeInteger, public ASN1Object { @@ -65,7 +63,7 @@ public: //! \enum Sign //! \brief Used internally to represent the integer //! \details Sign is used internally to represent the integer. It is also used in a few API functions. - //! \sa Signedness + //! \sa SetPositive(), SetNegative(), Signedness enum Sign { //! \brief the value is positive or 0 POSITIVE=0, @@ -198,7 +196,7 @@ public: //! \name ENCODE/DECODE //@{ - //! \brief The minimum number of bytes to encode this integer + //! \brief Minimum number of bytes to encode this integer //! \param sign enumeration indicating Signedness //! \note The MinEncodedSize() of 0 is 1. size_t MinEncodedSize(Signedness sign=UNSIGNED) const; @@ -227,7 +225,7 @@ public: //! The result is placed into a BufferedTransformation object void DEREncode(BufferedTransformation &bt) const; - //! encode absolute value as big-endian octet string + //! \brief Encode absolute value as big-endian octet string //! \param bt BufferedTransformation object //! \param length the number of mytes to decode void DEREncodeAsOctetString(BufferedTransformation &bt, size_t length) const; @@ -349,31 +347,68 @@ public: //! \name MANIPULATORS //@{ - //! + //! \brief Assignment Integer& operator=(const Integer& t); - //! + //! \brief Addition Assignment Integer& operator+=(const Integer& t); - //! + //! \brief Subtraction Assignment Integer& operator-=(const Integer& t); - //! + //! \brief Multiplication Assignment //! \sa a_times_b_mod_c() and a_exp_b_mod_c() Integer& operator*=(const Integer& t) {return *this = Times(t);} - //! + //! \brief Division Assignment Integer& operator/=(const Integer& t) {return *this = DividedBy(t);} - //! + //! \brief Remainder Assignment //! \sa a_times_b_mod_c() and a_exp_b_mod_c() Integer& operator%=(const Integer& t) {return *this = Modulo(t);} - //! + //! \brief Division Assignment Integer& operator/=(word t) {return *this = DividedBy(t);} - //! + //! \brief Remainder Assignment //! \sa a_times_b_mod_c() and a_exp_b_mod_c() Integer& operator%=(word t) {return *this = Integer(POSITIVE, 0, Modulo(t));} - //! - Integer& operator<<=(size_t); - //! - Integer& operator>>=(size_t); + //! \brief Left-shift Assignment + Integer& operator<<=(size_t n); + //! \brief Right-shift Assignment + Integer& operator>>=(size_t n); + + //! \brief Bitwise AND Assignment + //! \param t the other Integer + //! \returns the result of *this & t + //! \details operator&=() performs a bitwise AND on *this. Missing bits are truncated + //! at the most significant bit positions, so the result is as small as the + //! smaller of the operands. + //! \details Internally, Crypto++ uses a sign-magnitude representation. The library + //! does not attempt to interpret bits, and the result is always POSITIVE. If needed, + //! the integer should be converted to a 2's compliment representation before performing + //! the operation. + //! \since Crypto++ 5.7 + Integer& operator&=(const Integer& t); + //! \brief Bitwise OR Assignment + //! \param t the second Integer + //! \returns the result of *this | t + //! \details operator|=() performs a bitwise OR on *this. Missing bits are shifted in + //! at the most significant bit positions, so the result is as large as the + //! larger of the operands. + //! \details Internally, Crypto++ uses a sign-magnitude representation. The library + //! does not attempt to interpret bits, and the result is always POSITIVE. If needed, + //! the integer should be converted to a 2's compliment representation before performing + //! the operation. + //! \since Crypto++ 5.7 + Integer& operator|=(const Integer& t); + //! \brief Bitwise XOR Assignment + //! \param t the other Integer + //! \returns the result of *this ^ t + //! \details operator^=() performs a bitwise XOR on *this. Missing bits are shifted + //! in at the most significant bit positions, so the result is as large as the + //! larger of the operands. + //! \details Internally, Crypto++ uses a sign-magnitude representation. The library + //! does not attempt to interpret bits, and the result is always POSITIVE. If needed, + //! the integer should be converted to a 2's compliment representation before performing + //! the operation. + //! \since Crypto++ 5.7 + Integer& operator^=(const Integer& t); //! \brief Set this Integer to random integer //! \param rng RandomNumberGenerator used to generate material @@ -436,19 +471,19 @@ public: //! \name UNARY OPERATORS //@{ - //! + //! \brief Negation bool operator!() const; - //! + //! \brief Addition Integer operator+() const {return *this;} - //! + //! \brief Subtraction Integer operator-() const; - //! + //! \brief Pre-increment Integer& operator++(); - //! + //! \brief Pre-decrement Integer& operator--(); - //! + //! \brief Post-increment Integer operator++(int) {Integer temp = *this; ++*this; return temp;} - //! + //! \brief Post-decrement Integer operator--(int) {Integer temp = *this; --*this; return temp;} //@} @@ -461,42 +496,82 @@ public: //! \retval 1 if *this > a int Compare(const Integer& a) const; - //! + //! \brief Addition Integer Plus(const Integer &b) const; - //! + //! \brief Subtraction Integer Minus(const Integer &b) const; - //! + //! \brief Multiplication //! \sa a_times_b_mod_c() and a_exp_b_mod_c() Integer Times(const Integer &b) const; - //! + //! \brief Division Integer DividedBy(const Integer &b) const; - //! + //! \brief Remainder //! \sa a_times_b_mod_c() and a_exp_b_mod_c() Integer Modulo(const Integer &b) const; - //! + //! \brief Division Integer DividedBy(word b) const; - //! + //! \brief Remainder //! \sa a_times_b_mod_c() and a_exp_b_mod_c() word Modulo(word b) const; - //! + //! \brief Bitwise AND + //! \param t the other Integer + //! \returns the result of *this & t + //! \details And() performs a bitwise AND on the operands. Missing bits are truncated + //! at the most significant bit positions, so the result is as small as the + //! smaller of the operands. + //! \details Internally, Crypto++ uses a sign-magnitude representation. The library + //! does not attempt to interpret bits, and the result is always POSITIVE. If needed, + //! the integer should be converted to a 2's compliment representation before performing + //! the operation. + //! \since Crypto++ 5.7 + Integer And(const Integer&) const; + + //! \brief Bitwise OR + //! \param t the other Integer + //! \returns the result of *this | t + //! \details Or() performs a bitwise OR on the operands. Missing bits are shifted in + //! at the most significant bit positions, so the result is as large as the + //! larger of the operands. + //! \details Internally, Crypto++ uses a sign-magnitude representation. The library + //! does not attempt to interpret bits, and the result is always POSITIVE. If needed, + //! the integer should be converted to a 2's compliment representation before performing + //! the operation. + //! \since Crypto++ 5.7 + Integer Or(const Integer&) const; + + //! \brief Bitwise XOR + //! \param t the other Integer + //! \returns the result of *this ^ t + //! \details Xor() performs a bitwise XOR on the operands. Missing bits are shifted in + //! at the most significant bit positions, so the result is as large as the + //! larger of the operands. + //! \details Internally, Crypto++ uses a sign-magnitude representation. The library + //! does not attempt to interpret bits, and the result is always POSITIVE. If needed, + //! the integer should be converted to a 2's compliment representation before performing + //! the operation. + //! \since Crypto++ 5.7 + Integer Xor(const Integer&) const; + + //! \brief Right-shift Integer operator>>(size_t n) const {return Integer(*this)>>=n;} - //! + //! \brief Left-shift Integer operator<<(size_t n) const {return Integer(*this)<<=n;} //@} //! \name OTHER ARITHMETIC FUNCTIONS //@{ - //! + //! \brief Retrieve the absolute value of this integer Integer AbsoluteValue() const; - //! + //! \brief Add this integer to itself Integer Doubled() const {return Plus(*this);} - //! + //! \brief Multiply this integer by itself //! \sa a_times_b_mod_c() and a_exp_b_mod_c() Integer Squared() const {return Times(*this);} - //! extract square root, if negative return 0, else return floor of square root + //! \brief Extract square root + //! \details if negative return 0, else return floor of square root Integer SquareRoot() const; - //! return whether this integer is a perfect square + //! \brief Determine whether this integer is a perfect square bool IsSquare() const; //! is 1 or -1 @@ -504,18 +579,17 @@ public: //! return inverse if 1 or -1, otherwise return 0 Integer MultiplicativeInverse() const; - //! calculate r and q such that (a == d*q + r) && (0 <= r < abs(d)) + //! \brief calculate r and q such that (a == d*q + r) && (0 <= r < abs(d)) static void CRYPTOPP_API Divide(Integer &r, Integer &q, const Integer &a, const Integer &d); - //! use a faster division algorithm when divisor is short + //! \brief use a faster division algorithm when divisor is short static void CRYPTOPP_API Divide(word &r, Integer &q, const Integer &a, word d); - //! returns same result as Divide(r, q, a, Power2(n)), but faster + //! \brief returns same result as Divide(r, q, a, Power2(n)), but faster static void CRYPTOPP_API DivideByPowerOf2(Integer &r, Integer &q, const Integer &a, unsigned int n); //! greatest common divisor static Integer CRYPTOPP_API Gcd(const Integer &a, const Integer &n); - //! calculate multiplicative inverse of *this mod n - //! \sa a_times_b_mod_c() and a_exp_b_mod_c() + //! \brief calculate multiplicative inverse of *this mod n Integer InverseMod(const Integer &n) const; //! //! \sa a_times_b_mod_c() and a_exp_b_mod_c() @@ -570,36 +644,78 @@ private: #endif }; -//! +//! \brief Comparison inline bool operator==(const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)==0;} -//! +//! \brief Comparison inline bool operator!=(const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)!=0;} -//! +//! \brief Comparison inline bool operator> (const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)> 0;} -//! +//! \brief Comparison inline bool operator>=(const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)>=0;} -//! +//! \brief Comparison inline bool operator< (const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)< 0;} -//! +//! \brief Comparison inline bool operator<=(const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)<=0;} -//! +//! \brief Addition inline CryptoPP::Integer operator+(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Plus(b);} -//! +//! \brief Subtraction inline CryptoPP::Integer operator-(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Minus(b);} -//! +//! \brief Multiplication //! \sa a_times_b_mod_c() and a_exp_b_mod_c() inline CryptoPP::Integer operator*(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Times(b);} -//! +//! \brief Division inline CryptoPP::Integer operator/(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.DividedBy(b);} -//! +//! \brief Remainder //! \sa a_times_b_mod_c() and a_exp_b_mod_c() inline CryptoPP::Integer operator%(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Modulo(b);} -//! +//! \brief Division inline CryptoPP::Integer operator/(const CryptoPP::Integer &a, CryptoPP::word b) {return a.DividedBy(b);} -//! +//! \brief Remainder //! \sa a_times_b_mod_c() and a_exp_b_mod_c() inline CryptoPP::word operator%(const CryptoPP::Integer &a, CryptoPP::word b) {return a.Modulo(b);} +//! \brief Bitwise AND +//! \param a the first Integer +//! \param b the second Integer +//! \returns the result of a & b +//! \details operator&() performs a bitwise AND on the operands. Missing bits are truncated +//! at the most significant bit positions, so the result is as small as the +//! smaller of the operands. +//! \details Internally, Crypto++ uses a sign-magnitude representation. The library +//! does not attempt to interpret bits, and the result is always POSITIVE. If needed, +//! the integer should be converted to a 2's compliment representation before performing +//! the operation. +//! \since Crypto++ 5.7 +inline CryptoPP::Integer operator&(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.And(b);} + +//! \brief Bitwise OR +//! \param a the first Integer +//! \param b the second Integer +//! \returns the result of a | b +//! \details operator|() performs a bitwise OR on the operands. Missing bits are shifted in +//! at the most significant bit positions, so the result is as large as the +//! larger of the operands. +//! \details Internally, Crypto++ uses a sign-magnitude representation. The library +//! does not attempt to interpret bits, and the result is always POSITIVE. If needed, +//! the integer should be converted to a 2's compliment representation before performing +//! the operation. +//! \since Crypto++ 5.7 +inline CryptoPP::Integer operator|(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Or(b);} + +//! \brief Bitwise XOR +//! \param a the first Integer +//! \param b the second Integer +//! \returns the result of a ^ b +//! \details operator^() performs a bitwise XOR on the operands. Missing bits are shifted +//! in at the most significant bit positions, so the result is as large as the +//! larger of the operands. +//! \details Internally, Crypto++ uses a sign-magnitude representation. The library +//! does not attempt to interpret bits, and the result is always POSITIVE. If needed, +//! the integer should be converted to a 2's compliment representation before performing +//! the operation. +//! \since Crypto++ 5.7 +inline CryptoPP::Integer operator^(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Xor(b);} + NAMESPACE_END #ifndef __BORLANDC__ diff --git a/words.h b/words.h index c2be9793..79f61f49 100644 --- a/words.h +++ b/words.h @@ -53,6 +53,18 @@ inline void AndWords(word *r, const word *a, size_t n) r[i] &= a[i]; } +inline void OrWords(word *r, const word *a, const word *b, size_t n) +{ + for (size_t i=0; i