Hello
I need to decode/encode cpp_int values from/into byte arrays.
The encoding must be shortest little endian two's complement representation of the value.
For example:
00 = 0
01 = 1
ff = -1
ff:7f = 32767
01:80 = -32767
00:80:00 = 32768
00:80 = -32768
01:80:00 = 32769
ff:7f:ff = -32769
ff:ff:ef:9c:d2:40:43:da:4f:40:6b:06:6a:cd:92:c2:93:bf:a4:5c:c3:f1:29:63:1d = 184467440737095516151844674407370955161518446744073709551615
01:00:10:63:2d:bf:bc:25:b0:bf:94:f9:95:32:6d:3d:6c:40:5b:a3:3c:0e:d6:9c:e2 = -184467440737095516151844674407370955161518446744073709551615
I found a way to archive my goal (see below), but it seems way to complex and too inefficient.
For encoding I basically converting the cpp_int to a uint8_t to get 8 bit and then shift the cpp_int by 8, creating a new cpp_int... Twice (once to compute it's length, again to encode it).
For decoding I already shift the byte read to the "right" position and "|=" it into the existing cpp_int.
Isn't there an easier way access the binary representation of an cpp_int?
Regards,
Steffen
---
#include <iostream>
#include
using namespace std;
using namespace boost::multiprecision;
size_t binLength( cpp_int value )
{
if ( value.is_zero() )
return 1;
if ( value.sign() < 0 )
value = ~ value;
size_t length = 0;
uint8_t lastByte;
do {
lastByte = value.convert_to();
value >>= 8;
length ++;
} while ( ! value.is_zero() );
if ( lastByte >= 0x80 )
length ++;
return length;
}
void binEncode( cpp_int value, uint8_t* output, size_t length )
{
if ( value.is_zero() )
*output = 0;
else if ( value.sign() > 0 )
while ( length -- > 0 ) {
*( output ++ ) = value.convert_to();
value >>= 8;
}
else {
value = ~ value;
while ( length -- > 0 ) {
*( output ++ ) = ~ value.convert_to();
value >>= 8;
}
}
}
cpp_int binDecode( uint8_t* input, size_t length )
{
boost::multiprecision::cpp_int result( 0 );
int bits = - 8;
while ( length -- > 1 )
result |= (boost::multiprecision::cpp_int) *( input ++ ) << ( bits += 8 );
uint8_t a = *( input ++ );
result |= (boost::multiprecision::cpp_int) a << ( bits += 8 );
if ( a >= 0x80 )
result |= (boost::multiprecision::cpp_int) - 1 << ( bits + 8 );
return result;
}
void test( string s )
{
cpp_int x( s );
uint8_t buffer[ 100 ];
size_t length = binLength( x ), index = 0;
binEncode( x, buffer, length );
cpp_int y = binDecode( buffer, length );
cout << hex << setw( 2 ) << setfill( '0' ) << (int) buffer[ 0 ];
while ( -- length > 0 )
cout << ':' << setw( 2 ) << setfill( '0' ) << (int) buffer[ ++ index ];
cout << " = " << dec << setw( 1 ) << x << endl;
if ( x != y )
cerr << "failed" << endl;
}
int main( int argc, const char* argv[] )
{
test( "0" );
test( "1" );
test( "-1" );
test( "32767" );
test( "-32767" );
test( "32768" );
test( "-32768" );
test( "32769" );
test( "-32769" );
test( "184467440737095516151844674407370955161518446744073709551615" );
test( "-184467440737095516151844674407370955161518446744073709551615" );
}