diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/binary_integer_over_array.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/binary_integer_over_array.hpp index 375a435b28..ebdc5424b5 100644 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/binary_integer_over_array.hpp +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/binary_integer_over_array.hpp @@ -15,6 +15,38 @@ namespace nil { namespace multiprecision { +// Turns out, no need for this forward declaration + +// Forward declaration of the class. +//template< typename LimbType, unsigned int LimbsCount, typename DblLimbType > +//class binary_integer_over_array; + + +// Forward declarations of some global functions. + +// Turns out, no need for this forward declarations. + +/// Regular multiplication of big integers with different limbs count. +/// Caller is able to control number of the least significant limbs +/// of result of multiplication. +//template< unsigned int R, +// typename LimbType, unsigned int U1, unsigned int U2, typename DblLimbType > +//binary_integer_over_array< LimbType, R, DblLimbType > +// multiply_by_limbs( +// const binary_integer_over_array< LimbType, U1, DblLimbType >& a, +// const binary_integer_over_array< LimbType, U2, DblLimbType >& b ); + +/// Regular multiplication of big integer on a primitive value. +/// Caller is able to control number of the least significant limbs +/// of result of multiplication. +//template< unsigned int R, +// typename LimbType, unsigned int U1, typename DblLimbType > +//binary_integer_over_array< LimbType, R, DblLimbType > +// multiply_by_limbs( +// const binary_integer_over_array< LimbType, U1, DblLimbType >& a, +// const LimbType b ); + + /// This class represents a big integer, which stores data as binary /// digits in an 'std::array<>' class. This way, the data is sotred in /// the stack memory. @@ -23,17 +55,17 @@ class binary_integer_over_array { public: typedef LimbType limb_type; - static constexpr unsigned int limbs_count = LimbsCount; + static constexpr unsigned int _limbs_count = LimbsCount; typedef DblLimbType dbl_limb_type; typedef binary_integer_over_array< LimbType, LimbsCount, DblLimbType > this_type; // Synonym for this class -protected: - typedef std::array< limb_type, limbs_count > limbs_type; - /// How many bits there are in a single limb. - static constexpr unsigned int limb_bits = sizeof(limb_type) * CHAR_BIT; + static constexpr unsigned int _limb_bits = sizeof(limb_type) * CHAR_BIT; + +protected: + typedef std::array< limb_type, _limbs_count > limbs_type; /// The array, which stores all limbs of the integer. /// '_limbs[0]' corresponds to the least significant limb. @@ -41,11 +73,11 @@ class binary_integer_over_array protected: /// Increments by one the most-significant limbs, starting from 'limb_index'. - /// This is the same as adding "2^(limb_index * limb_bits)" to the + /// This is the same as adding "2^(limb_index * _limb_bits)" to the /// entire number. - this_type& increment_from_limb( unsigned int limb_index ) { + constexpr this_type& increment_from_limb( unsigned int limb_index ) { limb_type* ptr = _limbs.data() + limb_index; - limb_type* const ptr_end = _limbs.data() + limbs_count; + limb_type* const ptr_end = _limbs.data() + _limbs_count; for ( ; ptr < ptr_end; ++ptr ) { ++(*ptr); if ( *ptr != 0 ) @@ -55,11 +87,11 @@ class binary_integer_over_array } /// Decrements by one the most-significant limbs, starting from 'limb_index'. - /// This is the same as subtracting "2^(limb_index * limb_bits)" from the + /// This is the same as subtracting "2^(limb_index * _limb_bits)" from the /// entire number. - this_type& decrement_from_limb( unsigned int limb_index ) { + constexpr this_type& decrement_from_limb( unsigned int limb_index ) { limb_type* ptr = _limbs.data() + limb_index; - limb_type* const ptr_end = _limbs.data() + limbs_count; + limb_type* const ptr_end = _limbs.data() + _limbs_count; for ( ; ptr < ptr_end; ++ptr ) { if ( *ptr > 0 ) { --(*ptr); @@ -73,32 +105,32 @@ class binary_integer_over_array /// Constructs value of this object from given 'value', which can /// have any size (in bytes) template< typename RawT > - this_type& construct_from_raw( RawT value ) { + constexpr this_type& construct_from_raw( RawT value ) { constexpr unsigned int value_bits = sizeof(value) * CHAR_BIT; // Count of bits in 'value'. - std::fill_n( _limbs.data(), limbs_count, (limb_type)0 ); + std::fill_n( _limbs.data(), _limbs_count, (limb_type)0 ); // At first, reset the number to 0. // Check different cases - if constexpr ( value_bits <= limb_bits ) + if constexpr ( value_bits <= _limb_bits ) _limbs[ 0 ] = value; - else if constexpr ( value_bits <= limb_bits * 2 ) { + else if constexpr ( value_bits <= _limb_bits * 2 ) { // We must fill 2 limbs _limbs[ 0 ] = (limb_type)value; - _limbs[ 1 ] = (limb_type)(value >> limb_bits); + _limbs[ 1 ] = (limb_type)(value >> _limb_bits); } - else if constexpr ( value_bits <= limb_bits * 4 ) { + else if constexpr ( value_bits <= _limb_bits * 4 ) { // We must fill 4 limbs _limbs[ 0 ] = (limb_type)value; - _limbs[ 1 ] = (limb_type)(value >>= limb_bits); - _limbs[ 2 ] = (limb_type)(value >>= limb_bits); - _limbs[ 3 ] = (limb_type)(value >>= limb_bits); + _limbs[ 1 ] = (limb_type)(value >>= _limb_bits); + _limbs[ 2 ] = (limb_type)(value >>= _limb_bits); + _limbs[ 3 ] = (limb_type)(value >>= _limb_bits); } else { // The general case, we iterate over limbs limb_type* limb_ptr = _limbs.data(); *(limb_ptr++) = (limb_type)value; - while ( value != 0 && limb_ptr < _limbs.data() + limbs_count ) - *(limb_ptr++) = (limb_type)(value >>= limb_bits); + while ( value != 0 && limb_ptr < _limbs.data() + _limbs_count ) + *(limb_ptr++) = (limb_type)(value >>= _limb_bits); } return *this; } @@ -106,26 +138,27 @@ class binary_integer_over_array /// Converts value of this number into raw type 'RawT', which can /// have arbitrary number of bits. template< typename RawT > - RawT convert_to_raw() const { - constexpr unsigned int value_bits = sizeof(value) * CHAR_BIT; + constexpr RawT convert_to_raw() const { + constexpr unsigned int raw_bits = sizeof(RawT) * CHAR_BIT; // Count of bits in 'value'. // Check different cases - if constexpr ( value_bits <= limb_bits ) + if constexpr ( raw_bits <= _limb_bits ) return _limbs[ 0 ]; - else if constexpr ( value_bits <= limb_bits * 2 ) - return (RawT(_limbs[ 1 ]) << limb_bits) + else if constexpr ( raw_bits <= _limb_bits * 2 ) + return (RawT(_limbs[ 1 ]) << _limb_bits) | RawT(_limbs[ 0 ]); - else if constexpr ( value_bits <= limb_bits * 4 ) - return (RawT(_limbs[ 3 ]) << (limb_bits*3)) - | (RawT(_limbs[ 2 ]) << (limb_bits*2)) - | (RawT(_limbs[ 1 ]) << limb_bits) + else if constexpr ( raw_bits <= _limb_bits * 4 ) + return (RawT(_limbs[ 3 ]) << (_limb_bits*3) ) + | (RawT(_limbs[ 2 ]) << (_limb_bits*2) ) + | (RawT(_limbs[ 1 ]) << _limb_bits) | RawT(_limbs[ 0 ]); else { RawT result( 0 ); - for ( const limb_type* ptr = _limbs.data() + limbs_count - 1; + for ( const limb_type* ptr = _limbs.data() + _limbs_count - 1; ptr >= _limbs.data(); --ptr ) { - result *= (dbl_limb_type)(1 << limb_bits); + //result *= (dbl_limb_type)(1 << _limb_bits); + result <<= _limb_bits; // This line should work faster result += *ptr; } return result; @@ -135,32 +168,32 @@ class binary_integer_over_array public: /// Default constructor /// Initializes to 0. - this_type() { - std::fill_n( _limbs.data(), limbs_count, (limb_type)0 ); + constexpr binary_integer_over_array() { + std::fill_n( _limbs.data(), _limbs_count, (limb_type)0 ); } /// Conversion constructors - this_type( unsigned char value ) + constexpr binary_integer_over_array( unsigned char value ) { construct_from_raw( value ); } - this_type( char value ) + constexpr binary_integer_over_array( char value ) { construct_from_raw( value ); } - this_type( unsigned short value ) + constexpr binary_integer_over_array( unsigned short value ) { construct_from_raw( value ); } - this_type( short value ) + constexpr binary_integer_over_array( short value ) { construct_from_raw( value ); } - this_type( unsigned int value ) + constexpr binary_integer_over_array( unsigned int value ) { construct_from_raw( value ); } - this_type( int value ) + constexpr binary_integer_over_array( int value ) { construct_from_raw( value ); } - this_type( unsigned long long value ) + constexpr binary_integer_over_array( unsigned long long value ) { construct_from_raw( value ); } - this_type( long long value ) + constexpr binary_integer_over_array( long long value ) { construct_from_raw( value ); } /// Constructor /// Creates the big integer equal to 'value'. -// this_type( limb_type value ) { -// std::fill_n( _limbs.data(), limbs_count, 0 ); +// binary_integer_over_array( limb_type value ) { +// std::fill_n( _limbs.data(), _limbs_count, 0 ); // _limbs[ 0 ] = value; // Place to the last limb // } @@ -168,34 +201,35 @@ class binary_integer_over_array /// Creates the big integer equal to 'value'. // Note: We declare this constructor as explicit, because otherwise // it causes a lot of ambiguity with constructor from "limb_type". -// explicit this_type( dbl_limb_type value ) { -// std::fill_n( _limbs.data(), limbs_count, 0 ); -// _limbs[ 1 ] = (limb_type)(value >> limb_bits); +// explicit binary_integer_over_array( dbl_limb_type value ) { +// std::fill_n( _limbs.data(), _limbs_count, 0 ); +// _limbs[ 1 ] = (limb_type)(value >> _limb_bits); // _limbs[ 0 ] = (limb_type)value; // } /// Constructor /// Allows to specify value of every limb separately. /// The unspecified most significant limbs are filled with 0. - this_type( std::initializer_list< limb_type > digits ) { + constexpr binary_integer_over_array( std::initializer_list< limb_type > digits ) { // Place the specified limbs, in reverse order std::reverse_copy( digits.begin(), digits.end(), _limbs.data() ); // Fill upper limbs with '0' - std::fill( _limbs.data() + digits.size(), _limbs.data() + limbs_count, 0 ); + std::fill( _limbs.data() + digits.size(), _limbs.data() + _limbs_count, 0 ); } /// Convertion constructor /// Narrows or widens provided other big integer object. template< unsigned int OtherLimbsCount > - this_type( const binary_integer_over_array< LimbType, OtherLimbsCount, DblLimbType >& other ) { - if constexpr ( limbs_count < other.limbs_count ) { + constexpr binary_integer_over_array( + const binary_integer_over_array< LimbType, OtherLimbsCount, DblLimbType >& other ) { + if constexpr ( _limbs_count < other._limbs_count ) { // Narrowing - std::copy_n( other._limbs.data(), limbs_count, _limbs.data() ); + std::copy_n( other.data(), _limbs_count, _limbs.data() ); } else { // Widening - std::copy_n( other._limbs.data(), other.limbs_count, _limbs.data() ); - std::fill( _limbs.data() + other.limbs_count, _limbs.data() + limbs_count, 0 ); + std::copy_n( other.data(), other._limbs_count, _limbs.data() ); + std::fill( _limbs.data() + other._limbs_count, _limbs.data() + _limbs_count, 0 ); } } @@ -219,38 +253,48 @@ class binary_integer_over_array /// Assignment operators // this_type& operator=( limb_type value ) { -// std::fill_n( _limbs.data(), limbs_count, 0 ); +// std::fill_n( _limbs.data(), _limbs_count, 0 ); // _limbs[ 0 ] = value; // Place into the last limb // return *this; // } // this_type& operator=( dbl_limb_type value ) { -// std::fill_n( _limbs.data(), limbs_count, 0 ); -// _limbs[ 1 ] = (limb_type)(value >> limb_bits); +// std::fill_n( _limbs.data(), _limbs_count, 0 ); +// _limbs[ 1 ] = (limb_type)(value >> _limb_bits); // _limbs[ 0 ] = (limb_type)value; // return *this; // } /// Access to underlying array. - limb_type* data() { + constexpr limb_type* data() { return _limbs.data(); } - const limb_type* data() const { + constexpr const limb_type* data() const { return _limbs.data(); } /// Access to separate limbs, by index. - limb_type& operator[]( unsigned int index ) { + constexpr limb_type& operator[]( unsigned int index ) { return _limbs[ index ]; } - limb_type operator[]( unsigned int index ) const { + constexpr limb_type operator[]( unsigned int index ) const { return _limbs[ index ]; } + /// Access to count of limbs. + size_t size() const { + return _limbs.size(); + } + + /// Fills all limbs with 'arg' value. + void fill( limb_type arg ) { + _limbs.fill( arg ); + } + // Addition - this_type& operator+=( const this_type& rhs ) { + constexpr this_type& operator+=( const this_type& rhs ) { limb_type carry( 0 ); limb_type* this_ptr = _limbs.data(); - limb_type* const this_ptr_end = _limbs.data() + limbs_count; + limb_type* const this_ptr_end = _limbs.data() + _limbs_count; const limb_type* rhs_ptr = rhs._limbs.data(); for ( ; this_ptr < this_ptr_end; ++this_ptr, ++rhs_ptr ) { @@ -276,10 +320,10 @@ class binary_integer_over_array } // Subtraction - this_type& operator-=( const this_type& rhs ) { + constexpr this_type& operator-=( const this_type& rhs ) { limb_type carry( 0 ); limb_type* this_ptr = _limbs.data(); - limb_type* const this_ptr_end = _limbs.data() + limbs_count; + limb_type* const this_ptr_end = _limbs.data() + _limbs_count; const limb_type* rhs_ptr = rhs._limbs.data(); for ( ; this_ptr < this_ptr_end; ++this_ptr, ++rhs_ptr ) { @@ -306,7 +350,7 @@ class binary_integer_over_array } /// Addition by regular number - this_type& operator+=( limb_type rhs ) { + constexpr this_type& operator+=( limb_type rhs ) { limb_type* ptr = _limbs.data(); (*ptr) += rhs; if ( *ptr < rhs ) // There was a carry @@ -315,31 +359,31 @@ class binary_integer_over_array } /// Prefix increment - this_type& operator++() { + constexpr this_type& operator++() { return increment_from_limb( 0 ); } /// Postfix increment - this_type operator++( int ) { + constexpr this_type operator++( int ) { this_type result( *this ); ++(*this); return result; } /// Prefix decrement - this_type& operator--() { + constexpr this_type& operator--() { return decrement_from_limb( 0 ); } /// Postfix decrement - this_type operator--( int ) { + constexpr this_type operator--( int ) { this_type result( *this ); --(*this); return result; } /// Subtraction by regular number - this_type& operator-=( limb_type rhs ) { + constexpr this_type& operator-=( limb_type rhs ) { limb_type* ptr = _limbs.data(); if ( *ptr < rhs ) { // There will be a carry (*ptr) -= rhs; @@ -350,99 +394,29 @@ class binary_integer_over_array return *this; } - /// Regular multiplication of big integers with different limbs count. - /// Caller is able to control number of the least significant limbs - /// of result of multiplication. - template< unsigned int R, unsigned int U1, unsigned int U2 > - static binary_integer_over_array< limb_type, R, dbl_limb_type > + // Declaration as 'friend' function, so function with some value of 'R' + // will be able to access the class with another value of 'R'. + template< unsigned int R_, + typename LimbType_, unsigned int U1_, unsigned int U2_, typename DblLimbType_ > + friend binary_integer_over_array< LimbType_, R_, DblLimbType_ > multiply_by_limbs( - const binary_integer_over_array< limb_type, U1, dbl_limb_type >& a, - const binary_integer_over_array< limb_type, U2, dbl_limb_type >& b ) { - binary_integer_over_array< limb_type, R, dbl_limb_type > r; - limb_type *r_low_ptr = r._limbs.data(), - *r_high_ptr = r._limbs.data() + 1; - for ( int r_index = 0; - r_index < R; - ++r_index, ++r_low_ptr, ++r_high_ptr ) { - // Now we are calculating "r[ r_index ]" - int a_index = r_index; - int b_index = 0; - if ( a_index >= U1 ) { // 'a' hasn't that many limbs - b_index = a_index - (U1 - 1); - a_index = U1 - 1; - } - if ( b_index >= U2 ) // 'b' hasn't that many limbs too - break; // All necessary limbs of result are calculated - const int a_last_index = 0; - const int b_last_index = U2 - 1; - // Iterate in parallel over a in [a_index -> a_last_index], - // and over 'b' in [b_index -> b_last_index]. - for ( ; a_index >= a_last_index && b_index <= b_last_index; - --a_index, ++b_index ) { - // Now we need to multiply 'a[ a_index ]' over 'b[ b_index ]', - // and add the result to (*r_high_ptr, *r_low_ptr). - dbl_limb_type tmp( a[ a_index ] ); - tmp *= b[ b_index ]; - // Add to '*r_low_ptr' - assert( r_low_ptr < r._limbs.data() + R ); - *r_low_ptr += (limb_type)tmp; - if ( *r_low_ptr < (limb_type)tmp ) // There was an overflow - r.increment_from_limb( r_index + 1 ); - // Add to '*r_high_ptr' - if ( r_high_ptr < r._limbs.data() + R ) { // Check that the result - // can fit also the high bits of multiplication - tmp >>= limb_bits; - *r_high_ptr += (limb_type)tmp; - if ( *r_high_ptr < (limb_type)tmp ) // There was an overflow - r.increment_from_limb( r_index + 2 ); - } - } - } - return r; - } - - /// Regular multiplication of big integer on a primitive value. - /// Caller is able to control number of the least significant limbs - /// of result of multiplication. - template< unsigned int R, unsigned int U1 > - static binary_integer_over_array< limb_type, R, dbl_limb_type > + const binary_integer_over_array< LimbType_, U1_, DblLimbType_ >& a, + const binary_integer_over_array< LimbType_, U2_, DblLimbType_ >& b ); + + // Declaration as 'friend' function, so function with some value of 'R' + // will be able to access the class with another value of 'R'. + template< unsigned int R_, + typename LimbType_, unsigned int U1_, typename DblLimbType_ > + friend binary_integer_over_array< LimbType_, R_, DblLimbType_ > multiply_by_limbs( - const binary_integer_over_array< limb_type, U1, dbl_limb_type >& a, - const limb_type b ) { - binary_integer_over_array< limb_type, R, dbl_limb_type > r; - limb_type *r_low_ptr = r._limbs.data(), - *r_high_ptr = r._limbs.data() + 1; - for ( unsigned int r_index = 0; - r_index < R; - ++r_index, ++r_low_ptr, ++r_high_ptr ) { - if ( r_index >= U1 ) // 'a' hasn't that many limbs - break; // All necessary limbs of result are calculated - // Now we need to multiply 'a[ r_index ]' over 'b', - // and add the result to (*r_high_ptr, *r_low_ptr). - dbl_limb_type tmp( a[ r_index ] ); - tmp *= b; - // Add to '*r_low_ptr' - assert( r_low_ptr < r._limbs.data() + R ); - *r_low_ptr += (limb_type)tmp; - if ( *r_low_ptr < (limb_type)tmp ) // There was an overflow - r.increment_from_limb( r_index + 1 ); - // Add to '*r_high_ptr' - if ( r_high_ptr < r._limbs.data() + R ) { // Check that the result - // can fit also the high bits of multiplication - tmp >>= limb_bits; - *r_high_ptr += (limb_type)tmp; - if ( *r_high_ptr < (limb_type)tmp ) // There was an overflow - r.increment_from_limb( r_index + 2 ); - } - } - return r; - } + const binary_integer_over_array< LimbType_, U1_, DblLimbType_ >& a, + const LimbType_ b ); /// Multiplication this_type& operator*=( const this_type& rhs ) { // We can't multiply inplace, so write in a temporary this_type result - = multiply_by_limbs< limbs_count >( *this, rhs ); + = multiply_by_limbs< _limbs_count >( *this, rhs ); (*this) = result; return *this; } @@ -451,7 +425,7 @@ class binary_integer_over_array this_type& operator*=( limb_type rhs ) { // We can't multiply inplace, so write in a temporary this_type result - = multiply_by_limbs< limbs_count >( *this, rhs ); + = multiply_by_limbs< _limbs_count >( *this, rhs ); (*this) = result; return *this; } @@ -506,13 +480,13 @@ class binary_integer_over_array } /// Bit shift to right - this_type& operator>>=( unsigned int bits ) { - assert( bits < limb_bits ); + constexpr this_type& operator>>=( unsigned int bits ) { + assert( bits < _limb_bits ); // We are not going to shift too long. - const unsigned int bits_complement = limb_bits - bits; + const unsigned int bits_complement = _limb_bits - bits; limb_type *ptr = _limbs.data(), *next_ptr = _limbs.data() + 1; - limb_type* const ptr_end = _limbs.data() + limbs_count; + limb_type* const ptr_end = _limbs.data() + _limbs_count; for ( ; next_ptr < ptr_end; ++ptr, ++next_ptr ) { (*ptr) >>= bits; @@ -523,12 +497,12 @@ class binary_integer_over_array } /// Bit shift to left - this_type& operator<<=( unsigned int bits ) { - assert( bits < limb_bits ); + constexpr this_type& operator<<=( unsigned int bits ) { + assert( bits < _limb_bits ); // We are not going to shift too long. - const unsigned int bits_complement = limb_bits - bits; - limb_type *ptr = _limbs.data() + limbs_count - 1, - *next_ptr = _limbs.data() + limbs_count - 2; + const unsigned int bits_complement = _limb_bits - bits; + limb_type *ptr = _limbs.data() + _limbs_count - 1, + *next_ptr = _limbs.data() + _limbs_count - 2; limb_type* const ptr_end = _limbs.data(); for ( ; next_ptr >= ptr_end; --ptr, --next_ptr ) { @@ -540,36 +514,36 @@ class binary_integer_over_array } /// Sets bit at 'index' to 1. - this_type& set_bit( unsigned int index ) { + constexpr this_type& set_bit( unsigned int index ) { // Obtain parts of 'index' - unsigned int limb_index = index / limb_bits; - assert( limb_index < limbs_count ); - unsigned int index_in_limb = index - (limb_index * limb_bits); - assert( index_in_limb < limb_bits ); + unsigned int limb_index = index / _limb_bits; + assert( limb_index < _limbs_count ); + unsigned int index_in_limb = index - (limb_index * _limb_bits); + assert( index_in_limb < _limb_bits ); // Set _limbs[ limb_index ] |= limb_type( 1 ) << index_in_limb; return *this; } /// Unsets bit at 'index' to 0. - this_type& unset_bit( unsigned int index ) { + constexpr this_type& unset_bit( unsigned int index ) { // Obtain parts of 'index' - unsigned int limb_index = index / limb_bits; - assert( limb_index < limbs_count ); - unsigned int index_in_limb = index - (limb_index * limb_bits); - assert( index_in_limb < limb_bits ); + unsigned int limb_index = index / _limb_bits; + assert( limb_index < _limbs_count ); + unsigned int index_in_limb = index - (limb_index * _limb_bits); + assert( index_in_limb < _limb_bits ); // Unset _limbs[ limb_index ] &= ~( limb_type( 1 ) << index_in_limb ); return *this; } /// Checks if bit at 'index' is 1. - bool test_bit( unsigned int index ) const { + constexpr bool test_bit( unsigned int index ) const { // Obtain parts of 'index' - unsigned int limb_index = index / limb_bits; - assert( limb_index < limbs_count ); - unsigned int index_in_limb = index - (limb_index * limb_bits); - assert( index_in_limb < limb_bits ); + unsigned int limb_index = index / _limb_bits; + assert( limb_index < _limbs_count ); + unsigned int index_in_limb = index - (limb_index * _limb_bits); + assert( index_in_limb < _limb_bits ); // Check return _limbs[ limb_index ] & (limb_type( 1 ) << index_in_limb); } @@ -602,7 +576,7 @@ class binary_integer_over_array // it causes a lot of ambiguity with the conversion operator to "limb_type". // explicit operator dbl_limb_type() const { // dbl_limb_type result( _limbs[ 1 ] ); // Take one before last limb -// result <<= limb_bits; +// result <<= _limb_bits; // result |= _limbs[ 0 ]; // and the last one. // return result; // } @@ -616,11 +590,117 @@ class binary_integer_over_array }; +// Definition of some global functions + + +/// Regular multiplication of big integers with different limbs count. +/// Caller is able to control number of the least significant limbs +/// of result of multiplication. +template< unsigned int R, + typename LimbType, unsigned int U1, unsigned int U2, typename DblLimbType > +inline binary_integer_over_array< LimbType, R, DblLimbType > + multiply_by_limbs( + const binary_integer_over_array< LimbType, U1, DblLimbType >& a, + const binary_integer_over_array< LimbType, U2, DblLimbType >& b ) { + // Some typdefs and constants + typedef LimbType limb_type; + constexpr auto _limb_bits + = binary_integer_over_array< LimbType, R, DblLimbType >::_limb_bits; + typedef DblLimbType dbl_limb_type; + // Prepare the result variable + binary_integer_over_array< limb_type, R, dbl_limb_type > r; + limb_type *r_low_ptr = r.data(), + *r_high_ptr = r.data() + 1; + for ( int r_index = 0; + r_index < R; + ++r_index, ++r_low_ptr, ++r_high_ptr ) { + // Now we are calculating "r[ r_index ]" + int a_index = r_index; + int b_index = 0; + if ( a_index >= U1 ) { // 'a' hasn't that many limbs + b_index = a_index - (U1 - 1); + a_index = U1 - 1; + } + if ( b_index >= U2 ) // 'b' hasn't that many limbs too + break; // All necessary limbs of result are calculated + const int a_last_index = 0; + const int b_last_index = U2 - 1; + // Iterate in parallel over a in [a_index -> a_last_index], + // and over 'b' in [b_index -> b_last_index]. + for ( ; a_index >= a_last_index && b_index <= b_last_index; + --a_index, ++b_index ) { + // Now we need to multiply 'a[ a_index ]' over 'b[ b_index ]', + // and add the result to (*r_high_ptr, *r_low_ptr). + dbl_limb_type tmp( a[ a_index ] ); + tmp *= b[ b_index ]; + // Add to '*r_low_ptr' + assert( r_low_ptr < r.data() + R ); + *r_low_ptr += (limb_type)tmp; + if ( *r_low_ptr < (limb_type)tmp ) // There was an overflow + r.increment_from_limb( r_index + 1 ); + // Add to '*r_high_ptr' + if ( r_high_ptr < r.data() + R ) { // Check that the result + // can fit also the high bits of multiplication + tmp >>= _limb_bits; + *r_high_ptr += (limb_type)tmp; + if ( *r_high_ptr < (limb_type)tmp ) // There was an overflow + r.increment_from_limb( r_index + 2 ); + } + } + } + return r; +} + +/// Regular multiplication of big integer on a primitive value. +/// Caller is able to control number of the least significant limbs +/// of result of multiplication. +template< unsigned int R, + typename LimbType, unsigned int U1, typename DblLimbType > +inline binary_integer_over_array< LimbType, R, DblLimbType > + multiply_by_limbs( + const binary_integer_over_array< LimbType, U1, DblLimbType >& a, + const LimbType b ) { + // Some typdefs and constants + typedef LimbType limb_type; + constexpr auto _limb_bits + = binary_integer_over_array< LimbType, R, DblLimbType >::_limb_bits; + typedef DblLimbType dbl_limb_type; + // Prepare the result variable + binary_integer_over_array< limb_type, R, dbl_limb_type > r; + limb_type *r_low_ptr = r._limbs.data(), + *r_high_ptr = r._limbs.data() + 1; + for ( unsigned int r_index = 0; + r_index < R; + ++r_index, ++r_low_ptr, ++r_high_ptr ) { + if ( r_index >= U1 ) // 'a' hasn't that many limbs + break; // All necessary limbs of result are calculated + // Now we need to multiply 'a[ r_index ]' over 'b', + // and add the result to (*r_high_ptr, *r_low_ptr). + dbl_limb_type tmp( a[ r_index ] ); + tmp *= b; + // Add to '*r_low_ptr' + assert( r_low_ptr < r._limbs.data() + R ); + *r_low_ptr += (limb_type)tmp; + if ( *r_low_ptr < (limb_type)tmp ) // There was an overflow + r.increment_from_limb( r_index + 1 ); + // Add to '*r_high_ptr' + if ( r_high_ptr < r._limbs.data() + R ) { // Check that the result + // can fit also the high bits of multiplication + tmp >>= _limb_bits; + *r_high_ptr += (limb_type)tmp; + if ( *r_high_ptr < (limb_type)tmp ) // There was an overflow + r.increment_from_limb( r_index + 2 ); + } + } + return r; +} + + // Global operators template< typename LimbType, unsigned int LimbsCount, typename DblLimbType > -inline binary_integer_over_array< LimbType, LimbsCount, DblLimbType > +inline constexpr binary_integer_over_array< LimbType, LimbsCount, DblLimbType > operator+( const binary_integer_over_array< LimbType, LimbsCount, DblLimbType >& lhs, const binary_integer_over_array< LimbType, LimbsCount, DblLimbType >& rhs ) @@ -631,7 +711,7 @@ operator+( } template< typename LimbType, unsigned int LimbsCount, typename DblLimbType > -inline binary_integer_over_array< LimbType, LimbsCount, DblLimbType > +inline constexpr binary_integer_over_array< LimbType, LimbsCount, DblLimbType > operator+( const binary_integer_over_array< LimbType, LimbsCount, DblLimbType >& lhs, LimbType rhs ) @@ -642,7 +722,7 @@ operator+( } template< typename LimbType, unsigned int LimbsCount, typename DblLimbType > -inline binary_integer_over_array< LimbType, LimbsCount, DblLimbType > +inline constexpr binary_integer_over_array< LimbType, LimbsCount, DblLimbType > operator+( LimbType lhs, const binary_integer_over_array< LimbType, LimbsCount, DblLimbType >& rhs ) @@ -653,7 +733,7 @@ operator+( } template< typename LimbType, unsigned int LimbsCount, typename DblLimbType > -inline binary_integer_over_array< LimbType, LimbsCount, DblLimbType > +inline constexpr binary_integer_over_array< LimbType, LimbsCount, DblLimbType > operator-( const binary_integer_over_array< LimbType, LimbsCount, DblLimbType >& lhs, const binary_integer_over_array< LimbType, LimbsCount, DblLimbType >& rhs ) @@ -664,7 +744,7 @@ operator-( } template< typename LimbType, unsigned int LimbsCount, typename DblLimbType > -inline binary_integer_over_array< LimbType, LimbsCount, DblLimbType > +inline constexpr binary_integer_over_array< LimbType, LimbsCount, DblLimbType > operator-( const binary_integer_over_array< LimbType, LimbsCount, DblLimbType >& lhs, LimbType rhs ) @@ -680,8 +760,7 @@ operator*( const binary_integer_over_array< LimbType, LimbsCount, DblLimbType >& lhs, const binary_integer_over_array< LimbType, LimbsCount, DblLimbType >& rhs ) { - return binary_integer_over_array< LimbType, LimbsCount, DblLimbType > - ::multiply_by_limbs< LimbsCount >( lhs, rhs ); + return multiply_by_limbs< LimbsCount >( lhs, rhs ); } template< typename LimbType, unsigned int LimbsCount, typename DblLimbType > @@ -690,8 +769,7 @@ operator*( const binary_integer_over_array< LimbType, LimbsCount, DblLimbType >& lhs, LimbType rhs ) { - return binary_integer_over_array< LimbType, LimbsCount, DblLimbType > - ::multiply_by_limbs< LimbsCount >( lhs, rhs ); + return multiply_by_limbs< LimbsCount >( lhs, rhs ); } template< typename LimbType, unsigned int LimbsCount, typename DblLimbType > @@ -700,8 +778,7 @@ operator*( LimbType lhs, const binary_integer_over_array< LimbType, LimbsCount, DblLimbType >& rhs ) { - return binary_integer_over_array< LimbType, LimbsCount, DblLimbType > - ::multiply_by_limbs< LimbsCount >( rhs, lhs ); + return multiply_by_limbs< LimbsCount >( rhs, lhs ); } template< typename LimbType, unsigned int LimbsCount, typename DblLimbType > @@ -735,7 +812,7 @@ inline bool operator==( const binary_integer_over_array< LimbType, LimbsCount, DblLimbType >& rhs ) { return std::equal( - lhs.data(), lhs.data() + lhs.limbs_count, + lhs.data(), lhs.data() + lhs._limbs_count, rhs.data() ); } @@ -752,8 +829,8 @@ inline bool operator<( const binary_integer_over_array< LimbType, LimbsCount, DblLimbType >& lhs, const binary_integer_over_array< LimbType, LimbsCount, DblLimbType >& rhs ) { - const LimbType* lhs_ptr = lhs.data() + lhs.limbs_count - 1; - const LimbType* rhs_ptr = rhs.data() + rhs.limbs_count - 1; + const LimbType* lhs_ptr = lhs.data() + lhs._limbs_count - 1; + const LimbType* rhs_ptr = rhs.data() + rhs._limbs_count - 1; const LimbType* lhs_ptr_end = lhs.data(); for ( ; lhs_ptr >= lhs_ptr_end; --lhs_ptr, --rhs_ptr ) { @@ -920,6 +997,15 @@ inline std::istream& operator>>( } +/** + * ToDo: + * + * Add faster comparison functions, when one of operands is 'limb_type' + * ... don't force its conversion to 'BigInteger', followed by + * comparison of 2 BigIntegers. + * + */ + } } diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/binary_modular_integer_over_array.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/binary_modular_integer_over_array.hpp index 41dda8ce19..a6e7c4faae 100644 --- a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/binary_modular_integer_over_array.hpp +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/binary_modular_integer_over_array.hpp @@ -4,14 +4,18 @@ #include #include +#include +#include #include #include "binary_integer_over_array.hpp" +#include "detail/util.hpp" + namespace nil { namespace multiprecision { - +/* /// Names of the integers, which are used as modules, in modular arithmetic. enum class modules_names : unsigned int { @@ -29,41 +33,55 @@ class modules_values static constexpr BigIntegerType values[] = { } -}; +};*/ -/// This class is ordinary implementation of modular big number. +/// This class is ordinary implementation of modular big integer. /// It derives a regular 'BigIntegerType', and adds modular behavior. -template< typename BigIntegerType, unsigned int ModuleIndex > +/// The module is specified with help of 'ModuleCarrierType' class, which is +/// expected to have: +/// --- +/// typedef ... type; +/// static constexpr type _value = ...; +/// --- +template< typename BigIntegerType, typename ModuleCarrierType > class binary_modular_integer_over_array : public BigIntegerType { public: - typedef BigIntegerType big_integer_type; typedef BigIntegerType base_type; - static constexpr unsigned int _module_index = ModuleIndex; + typedef ModuleCarrierType module_carrier_type; typedef binary_modular_integer_over_array< - BigIntegerType, ModuleIndex > this_type; + BigIntegerType, + ModuleCarrierType > this_type; - typedef typename base_type::limb_type limb_type; - static constexpr unsigned int _limbs_count = base_type::limbs_count; - typedef typename base_type::dbl_limb_type dbl_limb_type; + using typename base_type::limb_type; + using base_type::_limbs_count; + using typename base_type::dbl_limb_type; - /// The module of this big integer - static constexpr big_integer_type _module - = modules_values< big_integer_type >.values[ _module_index ]; + using base_type::_limb_bits; + + /// Type of underlying regular number, which has doubled precision. + /// Such integer will be used during intermediate calculations. +// typedef binary_integer_over_array< +// limb_type, +// 2 * _limbs_count, +// dbl_limb_type > extended_base_type; + + /// The module of this big integer. + static constexpr base_type _module = module_carrier_type::_value; // Check that keeping double module will not overflow the regular // big integer. static_assert( - _module * 2 > _module, - "Implementation of this class requires that a value twice larger than the module" - " can still fit in the underlying big integer." ); + detail::util::obtain_bits_count( _module ) < _limbs_count * _limb_bits, + "Implementation of this class requires that a value twice larger" + " than the module can still fit in the underlying big integer." ); protected: /// Normalizes this modular number (brings it into range [0, module) ), /// assuming that currently it might be at most twice larger than the module. - void normalize_once_down() { - if ( _module <= *this ) + constexpr void normalize_once_down() { + if ( *this >= _module ) base_type::operator-=( _module ); // Check that this normalization was enough assert( *this < _module ); @@ -71,50 +89,22 @@ class binary_modular_integer_over_array : public BigIntegerType /// Normalizes this modular number (brings it into range [0, module) ), /// assuming that currently it might be "negative", in range (-module, 0). - void normalize_once_up() { - if ( _module <= *this ) + constexpr void normalize_once_up() { + if ( *this >= _module ) base_type::operator+=( _module ); // Check that this normalization was enough assert( *this < _module ); } - /// Normalizes this modular number (brings it into range [0, module) ), - /// assuming that currently it might be many times larger than the module. -/* void normalize_multiple() { - static std::vector< base_type > modules_multiples( - 1, _module ); - // Multiples of the module, where every next value - // is twice larger from previous one. - // Find the smallest multiple, larger than current value - int i = 0; - while ( i < (int)modules_multiples.size() - && modules_multiples[ i ] <= *this ) - ++i; - // ... append new multiples, if necessary - if ( i == (int)modules_multiples.size() ) { - do { - modules_multiples.push_back( - modules_multiples.back() + modules_multiples.back() ); - } while ( modules_multiples.back() <= *this ); - i = (int)modules_multiples.size() - 1; - } - // ... check that in any case we are on a greater multiple - assert( modules_multiples[ i ] > *this ); - // Start reducing - for ( --i; i >= 0; --i ) - if ( modules_multiples[ i ] <= *this ) - (*this) -= modules_multiples[ i ]; - }*/ - /// Normalizes 'value' (brings it into range [0, module) ), - /// assuming that currently it might be many times larger than the module. - /// For example, if a raw multiplication was performed on 2 modular numbers. - static void reduce( binary_integer_over_array< - limb_type, - _limbs_count * 2, - dbl_limb_type >& value ) { - static std::vector< base_type > modules_multiples( - 1, _module ); + /// assuming that currently it might be much larger than the module. + /// For example, after a raw multiplication was performed on two + /// modular numbers. + template< typename ValueType > + constexpr static void reduce( ValueType& value ) { + static std::vector< ValueType > modules_multiples( + 1, + static_cast< ValueType >( _module ) ); // Multiples of the module, where every next value // is twice larger from previous one. // Find the smallest multiple, larger than current value @@ -141,7 +131,7 @@ class binary_modular_integer_over_array : public BigIntegerType /// Constructs value of this object from given 'value', which can /// have any size (in bytes) template< typename RawT > - this_type& construct_from_raw( RawT value ) { + constexpr this_type& construct_from_raw( RawT value ) { base_type::construct_from_raw( value ); normalize_once_down(); return *this; @@ -150,45 +140,46 @@ class binary_modular_integer_over_array : public BigIntegerType public: /// Default constructor /// Initializes to 0. - this_type() { - std::fill_n( _limbs.data(), _limbs_count, (limb_type)0 ); - } + constexpr binary_modular_integer_over_array() + : base_type() + {} /// Conversion constructors - this_type( unsigned char value ) + constexpr binary_modular_integer_over_array( unsigned char value ) { construct_from_raw( value ); } - this_type( char value ) + constexpr binary_modular_integer_over_array( char value ) { construct_from_raw( value ); } - this_type( unsigned short value ) + constexpr binary_modular_integer_over_array( unsigned short value ) { construct_from_raw( value ); } - this_type( short value ) + constexpr binary_modular_integer_over_array( short value ) { construct_from_raw( value ); } - this_type( unsigned int value ) + constexpr binary_modular_integer_over_array( unsigned int value ) { construct_from_raw( value ); } - this_type( int value ) + constexpr binary_modular_integer_over_array( int value ) { construct_from_raw( value ); } - this_type( unsigned long long value ) + constexpr binary_modular_integer_over_array( unsigned long long value ) { construct_from_raw( value ); } - this_type( long long value ) + constexpr binary_modular_integer_over_array( long long value ) { construct_from_raw( value ); } + /// Constructor from base type + constexpr explicit binary_modular_integer_over_array( + const base_type& rhs ) + : base_type( rhs ) { + // Normalize + reduce( static_cast< base_type& >( *this ) ); + } + /// Constructor /// Allows to specify value of every limb separately. /// The unspecified most significant limbs are filled with 0. - this_type( std::initializer_list< limb_type > digits ) + constexpr binary_modular_integer_over_array( + std::initializer_list< limb_type > digits ) : base_type( digits ) { // Normalize reduce( static_cast< base_type& >( *this ) ); } - // We assume that no need will arise for calling conversion constructor - // with same limb types but different limbs count. - template< unsigned int OtherLimbsCount > - this_type( const binary_modular_integer_over_array< - LimbType, - OtherLimbsCount, - DblLimbType >& ); - /// Assignment operators this_type& operator=( unsigned char value ) { return construct_from_raw( value ); } @@ -253,7 +244,7 @@ class binary_modular_integer_over_array : public BigIntegerType /// Decrement this_type& operator--() { if ( *this == 0 ) // Prepare for possible reset - *this = _module; + base_type::operator=( _module ); base_type::operator--(); return *this; } @@ -265,6 +256,13 @@ class binary_modular_integer_over_array : public BigIntegerType return result; } + /// Negation + this_type operator-() { + this_type result; + result -= (*this); + return result; + } + /// Multiplication this_type& operator*=( const this_type& rhs ) { auto result = (*this) * rhs; @@ -277,79 +275,241 @@ class binary_modular_integer_over_array : public BigIntegerType return (*this) = result; } +private: + /// Here we disable all methods which are related to division, + /// to force user to calculate the inverse number instead. + /// So, when it is needed to calculate "a/b", at first "b^(-1)" + /// will be calculated, and "a*[b^(-1)]" will be written instead. + /// This will prevent user from calculating inverse of "b" implicitly. + using base_type::div_mod; + using base_type::operator%=; + using base_type::operator/=; + +public: + /// Calculates and returns inverse of this modular number. + this_type inversed() const { + static constexpr size_t module_bits + = detail::util::obtain_bits_count( _module ); + static constexpr std::bitset< module_bits > exponent_bits + = detail::util::obtain_bits< module_bits >( _module - base_type(2) ); + return detail::util::power( *this, exponent_bits ); + } + + /// Same calculation of invertion, but called by an operator. + this_type operator~() const { + return inversed(); + } + + /// Inverses current value of this number in-place, and returns + /// this object. + this_type& inverse() { + (*this) = inversed(); + return *this; + } + + + + }; // Global operators -template< typename LimbType, unsigned int LimbsCount, typename DblLimbType > -inline binary_modular_integer_over_array< LimbType, LimbsCount, DblLimbType > +template< typename BigIntegerType, typename ModuleCarrierType > +inline binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType > +operator+( + const binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType >& lhs, + const binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType >& rhs ) +{ + auto result( lhs ); + result += rhs; + return result; +} + +template< typename BigIntegerType, typename ModuleCarrierType > +inline binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType > +operator+( + const binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType >& lhs, + typename BigIntegerType::limb_type rhs ) +{ + auto result( lhs ); + result += rhs; + return result; +} + +template< typename BigIntegerType, typename ModuleCarrierType > +inline binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType > +operator+( + typename BigIntegerType::limb_type lhs, + const binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType >& rhs ) +{ + auto result( rhs ); + result += lhs; + return result; +} + +template< typename BigIntegerType, typename ModuleCarrierType > +inline binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType > +operator-( + const binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType >& lhs, + const binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType >& rhs ) +{ + auto result( lhs ); + result -= rhs; + return result; +} + +template< typename BigIntegerType, typename ModuleCarrierType > +inline binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType > +operator-( + const binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType >& lhs, + typename BigIntegerType::limb_type rhs ) +{ + auto result( lhs ); + result -= rhs; + return result; +} + +template< typename BigIntegerType, typename ModuleCarrierType > +inline binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType > +operator-( + typename BigIntegerType::limb_type lhs, + const binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType >& rhs ) +{ + binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType > result( lhs ); + result -= rhs; + return result; +} + +template< typename BigIntegerType, typename ModuleCarrierType > +inline binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType > operator*( - const binary_modular_integer_over_array< LimbType, LimbsCount, DblLimbType >& lhs, - const binary_modular_integer_over_array< LimbType, LimbsCount, DblLimbType >& rhs ) + const binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType >& lhs, + const binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType >& rhs ) { // Just some shortcuts to types of the arguments - typedef binary_modular_integer_over_array< LimbType, LimbsCount, DblLimbType > + typedef binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType > this_type; typedef typename this_type::base_type base_type; + typedef typename this_type::limb_type limb_type; + static constexpr size_t limbs_count = this_type::_limbs_count; + typedef typename this_type::dbl_limb_type dbl_limb_type; // Perform regular multiplication - binary_integer_over_array< LimbType, LimbsCount * 2, DblLimbType > result_raw - = base_type::multiply_by_limbs< LimbsCount * 2 >( lhs, rhs ); - // Reduce it - this_type::reduce( result_raw ); - assert( result_raw < this_type::_module ); + binary_integer_over_array< limb_type, limbs_count * 2, dbl_limb_type > result_raw + = multiply_by_limbs< limbs_count * 2 >( lhs, rhs ); return this_type( result_raw ); + // We expect that the conversion constructor of this class + // will reduce the result. } -template< typename LimbType, unsigned int LimbsCount, typename DblLimbType > -inline binary_modular_integer_over_array< LimbType, LimbsCount, DblLimbType > +template< typename BigIntegerType, typename ModuleCarrierType > +inline binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType > operator*( - const binary_modular_integer_over_array< LimbType, LimbsCount, DblLimbType >& lhs, - LimbType rhs ) + const binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType >& lhs, + typename BigIntegerType::limb_type rhs ) { // Just some shortcuts to types of the arguments - typedef binary_modular_integer_over_array< LimbType, LimbsCount, DblLimbType > + typedef binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType > this_type; typedef typename this_type::base_type base_type; + typedef typename this_type::limb_type limb_type; + static constexpr size_t limbs_count = this_type::_limbs_count; + typedef typename this_type::dbl_limb_type dbl_limb_type; // Perform regular multiplication - binary_integer_over_array< LimbType, LimbsCount * 2, DblLimbType > result_raw - = base_type::multiply_by_limbs< LimbsCount * 2 >( lhs, rhs ); - // Reduce it - this_type::reduce( result_raw ); - assert( result_raw < this_type::_module ); + binary_integer_over_array< limb_type, limbs_count + 1, dbl_limb_type > result_raw + = multiply_by_limbs< limbs_count + 1 >( lhs, rhs ); return this_type( result_raw ); + // We expect that the conversion constructor of this class + // will reduce the result. } -template< typename LimbType, unsigned int LimbsCount, typename DblLimbType > -inline binary_modular_integer_over_array< LimbType, LimbsCount, DblLimbType > +template< typename BigIntegerType, typename ModuleCarrierType > +inline binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType > operator*( - LimbType lhs, - const binary_modular_integer_over_array< LimbType, LimbsCount, DblLimbType >& rhs ) + typename BigIntegerType::limb_type lhs, + const binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType >& rhs ) { return rhs * lhs; } +template< typename BigIntegerType, typename ModuleCarrierType > +inline binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType > +operator%( + const binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType >& a, + const binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType >& b ) +{ + // Just some shortcuts to types of the arguments + typedef binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType > + this_type; + typedef typename this_type::base_type base_type; + static_assert( false, + "Modulo calculation should not be called on modular integers." + " In case if division is required, at first calculate inverse of " + "the second argument, and use multiplication instead." ); + return this_type(); +} + +template< typename BigIntegerType, typename ModuleCarrierType > +inline binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType > +operator/( + const binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType >& a, + const binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType >& b ) +{ + // Just some shortcuts to types of the arguments + typedef binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType > + this_type; + typedef typename this_type::base_type base_type; + static_assert( false, + "Division should not be called on modular integers." + " In case if division is required, at first calculate inverse of " + "the second argument, and use multiplication instead." ); + return this_type(); +} + + +// Stream operators + + +template< typename BigIntegerType, typename ModuleCarrierType > +inline std::istream& operator>>( + std::istream& istr, + binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType >& rhs ) +{ + // Just some shortcuts to types of the arguments + typedef binary_modular_integer_over_array< BigIntegerType, ModuleCarrierType > + this_type; + typedef typename this_type::base_type base_type; + // Input raw number + istr >> static_cast< base_type& >( rhs ); + // Normalize + this_type::reduce( static_cast< base_type& >( rhs ) ); +} + /** * ToDo: * - * Add global addition / subtraction operators + * + Add global addition / subtraction operators * * In base class, add casting to twice more limbs count and twice less limbs count * - * Decide about changing template arguments of this class to: - * LimbType, - * LimbsCount, - * DblLimbType, - * instead of relying on BigIntegerType. + * - Decide about changing template arguments of this class to: + * LimbType, LimbsCount, DblLimbType, + * instead of relying on BigIntegerType. * - * Check that conversion from 'base_type' to 'this_type' can work. + * + Check that conversion from 'base_type' to 'this_type' can work. * ... perhaps make it explicit. * - * Check that comparison between 'modular' and 'regular' works as expected. + * [later] Check that comparison between 'modular' and 'regular' works as expected. + * + * + Implement negation + * + * + Adjust 'reduce()' method to work both on regular 'base_type', and 'extended_base_type'. * + * + Decide if to disable division operator for this class. * + * + Decide if to change the method how module value is provided. * */ diff --git a/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/util.hpp b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/util.hpp new file mode 100644 index 0000000000..31fa23bd3d --- /dev/null +++ b/crypto3/libs/multiprecision/include/nil/crypto3/multiprecision/detail/util.hpp @@ -0,0 +1,97 @@ + +#ifndef NIL__MULTIPRECISION__DETAIL__UTIL_HPP +#define NIL__MULTIPRECISION__DETAIL__UTIL_HPP + +#include +#include +#include + +namespace nil { +namespace multiprecision { +namespace detail { + + +/// This class contains utility functions, for working with multiprecision +/// objects. +class util +{ +public: + /// Given the 'value', represented as sequence of binary limbs, calculates + /// and returns the required minimal amount of bits, to represent such + /// 'value'. Generally, this is overall number of bits in 'value', subtracted + /// by the number of leading 0 bits. + template< typename BigIntegerType > + static constexpr size_t obtain_bits_count( const BigIntegerType& value ) { + // Some typedefs & constants + typedef typename BigIntegerType::limb_type limb_type; + constexpr auto _limbs_count = BigIntegerType::_limbs_count; + constexpr auto _limb_bits = BigIntegerType::_limb_bits; + // Process + size_t result = _limbs_count * _limb_bits; + for ( int limb_index = _limbs_count - 1; limb_index >= 0; --limb_index ) { + const limb_type& limb = value[ limb_index ]; + for ( int limb_bit = _limb_bits - 1; limb_bit >= 0; --limb_bit ) { + if ( ! (limb & (((limb_type)1) << limb_bit)) ) + --result; + else + return result; + } + } + assert( ! "The previous return statement should be invoked, if at least" + " one bit of 'value' is set." ); + assert( result == 0 ); + return result; + } + + /// Calculates and returns pure binary representation of 'value'. + /// Generally, 'value' is already stored in binary format, but in different limbs. + /// This function converts the sequence of limbs into sequence of bits, + /// and returns as 'std::bitset<>'. + /// 0-th bit of the result corresponds to least significant bit of 'value', + /// while the last bit of the result corresponds to most significant bit of 'value'. + template< size_t Bits, typename BigIntegerType > + static constexpr std::bitset< Bits > obtain_bits( const BigIntegerType& value ) { + // Some typedefs & constants + typedef typename BigIntegerType::limb_type limb_type; + constexpr auto _limbs_count = BigIntegerType::_limbs_count; + constexpr auto _limb_bits = BigIntegerType::_limb_bits; + // Process + std::bitset< Bits > result; + int result_bit_index = 0; // Index over bits of 'result' + for ( int limb_index = 0; limb_index < _limbs_count; ++limb_index ) { + const limb_type& limb = value[ limb_index ]; + for ( int bit_index = 0; bit_index < _limb_bits; ++bit_index ) { + if ( limb & (((limb_type)1) << bit_index) ) + result.set( result_bit_index ); + ++result_bit_index; + } + } + assert( result_bit_index == _limbs_count * _limb_bits ); + return result; + } + + /// Calculates and returns 'a' powered to such exponent, which bits are + /// represented in 'bits' argument. + /// "bits[0]" corresponds to least significant binary digit of the exponent, + /// while "bits[bits.size() - 1]" corresponds to its most significant bit. + template< typename BigIntegerType, size_t Bits > + static constexpr BigIntegerType power( + const BigIntegerType& a, + const std::bitset< Bits >& bits ) { + BigIntegerType result( 1 ); + for ( int i = (int)bits.size() - 1; i >= 0; --i ) { + result *= result; + if ( bits[ i ] ) + result *= a; + } + return result; + } + +}; + + +} +} +} + +#endif // NIL__MULTIPRECISION__DETAIL__UTIL_HPP diff --git a/crypto3/libs/multiprecision/test/binary_integer_over_array_test.hpp b/crypto3/libs/multiprecision/test/binary_integer_over_array_test.hpp index d32bcc7443..924fc264f1 100644 --- a/crypto3/libs/multiprecision/test/binary_integer_over_array_test.hpp +++ b/crypto3/libs/multiprecision/test/binary_integer_over_array_test.hpp @@ -537,7 +537,7 @@ inline void test_big_integer_bit_operations() NIL_CHECK( ! a.test_bit( 1 ) ); NIL_CHECK( a.test_bit( 0 ) ); - a *= (dbl_limb_type)2; + a *= (limb_type)2; NIL_CHECK( a.test_bit( 3 ) ); NIL_CHECK( ! a.test_bit( 2 ) ); diff --git a/crypto3/libs/multiprecision/test/binary_modular_integer_over_array_test.hpp b/crypto3/libs/multiprecision/test/binary_modular_integer_over_array_test.hpp new file mode 100644 index 0000000000..0d5a371db7 --- /dev/null +++ b/crypto3/libs/multiprecision/test/binary_modular_integer_over_array_test.hpp @@ -0,0 +1,199 @@ + +#ifndef NIL__TEST__MULTIPRECISION__BINARY_MODULAR_INTEGER_OVER_ARRAY_TEST_HPP +#define NIL__TEST__MULTIPRECISION__BINARY_MODULAR_INTEGER_OVER_ARRAY_TEST_HPP + +#include + +#include "../../unit_test/include.hpp" + +#include "../../multiprecision/binary_modular_integer_over_array.hpp" + +namespace nil { +namespace test { +namespace multiprecision { + + +/// Runs addition and subtraction unit tests on provided modular +/// integer type 'IntT', as (mod 17). +template< typename IntT > +inline void test_modular_integer_add_sub_mod_17() +{ + { + IntT a, b, c; + + a = 10, b = 9, c = 2; + NIL_CHECK_EQUAL( a + b, c ); + NIL_CHECK_EQUAL( b + a, c ); + NIL_CHECK_EQUAL( c - a, b ); + NIL_CHECK_EQUAL( c - b, a ); + + a = 16, b = 1, c = 0; + NIL_CHECK_EQUAL( a + b, c ); + NIL_CHECK_EQUAL( b + a, c ); + NIL_CHECK_EQUAL( c - a, b ); + NIL_CHECK_EQUAL( c - b, a ); + + a = 16, b = 16, c = 15; + NIL_CHECK_EQUAL( a + b, c ); + NIL_CHECK_EQUAL( b + a, c ); + NIL_CHECK_EQUAL( c - a, b ); + NIL_CHECK_EQUAL( c - b, a ); + + a = 9, b = 5, c = 14; + NIL_CHECK_EQUAL( a + b, c ); + NIL_CHECK_EQUAL( b + a, c ); + NIL_CHECK_EQUAL( c - a, b ); + NIL_CHECK_EQUAL( c - b, a ); + + a = 8, b = 0, c = 8; + NIL_CHECK_EQUAL( a + b, c ); + NIL_CHECK_EQUAL( b + a, c ); + NIL_CHECK_EQUAL( c - a, b ); + NIL_CHECK_EQUAL( c - b, a ); + } +} + + +/// Runs multiplication unit tests on provided modular integer type +/// 'IntT', as (mod 17). +template< typename IntT > +inline void test_modular_integer_mul_mod_17() +{ + { + IntT a, b, c; + + a = 10, b = 7, c = 2; + NIL_CHECK_EQUAL( a * b, c ); + NIL_CHECK_EQUAL( b * a, c ); + + a = 5, b = 5, c = 8; + NIL_CHECK_EQUAL( a * b, c ); + NIL_CHECK_EQUAL( b * a, c ); + + a = 10, b = 4, c = 6; + NIL_CHECK_EQUAL( a * b, c ); + NIL_CHECK_EQUAL( b * a, c ); + + a = 4, b = 4, c = 16; + NIL_CHECK_EQUAL( a * b, c ); + NIL_CHECK_EQUAL( b * a, c ); + + a = 7, b = 2, c = 14; + NIL_CHECK_EQUAL( a * b, c ); + NIL_CHECK_EQUAL( b * a, c ); + + a = 12, b = 0, c = 0; + NIL_CHECK_EQUAL( a * b, c ); + NIL_CHECK_EQUAL( b * a, c ); + + a = 1, b = 14, c = 14; + NIL_CHECK_EQUAL( a * b, c ); + NIL_CHECK_EQUAL( b * a, c ); + + a = 16, b = 16, c = 1; + NIL_CHECK_EQUAL( a * b, c ); + NIL_CHECK_EQUAL( b * a, c ); + + a = 15, b = 15, c = 4; + NIL_CHECK_EQUAL( a * b, c ); + NIL_CHECK_EQUAL( b * a, c ); + } +} + + +/// Runs inversion unit tests on provided modular integer type +/// 'IntT', as (mod 17). +template< typename IntT > +inline void test_modular_integer_inv_mod_17() +{ + { + IntT a, b; + + a = 10, b = 12; + NIL_CHECK_EQUAL( a.inversed(), b ); + NIL_CHECK_EQUAL( b.inversed(), a ); + + a = 2, b = 9; + NIL_CHECK_EQUAL( a.inversed(), b ); + NIL_CHECK_EQUAL( b.inversed(), a ); + + a = 3, b = 6; + NIL_CHECK_EQUAL( a.inversed(), b ); + NIL_CHECK_EQUAL( b.inversed(), a ); + + a = 4, b = 13; + NIL_CHECK_EQUAL( a.inversed(), b ); + NIL_CHECK_EQUAL( b.inversed(), a ); + + a = 5, b = 7; + NIL_CHECK_EQUAL( a.inversed(), b ); + NIL_CHECK_EQUAL( b.inversed(), a ); + + a = 1, b = 1; + NIL_CHECK_EQUAL( a.inversed(), b ); + NIL_CHECK_EQUAL( b.inversed(), a ); + + a = 15, b = 8; + NIL_CHECK_EQUAL( a.inversed(), b ); + NIL_CHECK_EQUAL( b.inversed(), a ); + + a = 16, b = 16; + NIL_CHECK_EQUAL( a.inversed(), b ); + NIL_CHECK_EQUAL( b.inversed(), a ); + + } +} + + +/// This class represents a module with value of '17'. +template< typename RawIntT > +struct modulo_17_t +{ + typedef RawIntT type; + static constexpr type _value = type( 17 ); +}; + + +/// Runs tests on "binary_modular_integer_over_array<>" template. +inline void test_binary_modular_integer_over_array() +{ + using nil::multiprecision::binary_modular_integer_over_array; + using nil::multiprecision::binary_integer_over_array; + + { + typedef binary_integer_over_array< unsigned char, 4, unsigned short > + raw_int_t; + typedef binary_modular_integer_over_array< raw_int_t, modulo_17_t< raw_int_t > > + int_t; + + test_modular_integer_add_sub_mod_17< int_t >(); + test_modular_integer_mul_mod_17< int_t >(); + test_modular_integer_inv_mod_17< int_t >(); + + + + + } + + { + typedef binary_integer_over_array< unsigned short, 4, unsigned int > + raw_int_t; + typedef binary_modular_integer_over_array< raw_int_t, modulo_17_t< raw_int_t > > + int_t; + + test_modular_integer_add_sub_mod_17< int_t >(); + test_modular_integer_mul_mod_17< int_t >(); + test_modular_integer_inv_mod_17< int_t >(); + + + + } +} + + + +} +} +} + +#endif // NIL__TEST__MULTIPRECISION__BINARY_MODULAR_INTEGER_OVER_ARRAY_TEST_HPP