I am experiencing a few problems with Crypto++'s Integer
class. I am using the latest release, 5.6.2.
I'm attempting to convert Integer to string with the following code:
CryptoPP::Integer i("12345678900987654321");
std::ostrstream oss;
oss << i;
std::string s(oss.str());
LOGDEBUG(oss.str()); // Pumps log to console and log file
The output appears to have extra garbage data:
12345678900987654321.ÍÍÍÍÍÍÍÍÍÍÍýýýý««««««««îþîþ
I get the same thing when I output directly to the console:
std::cout << "Dec: " << i << std::endl; // Same result
Additionally, I cannot get precision or scientific notation working. The following will output the same results:
std::cout.precision(5); // Does nothing with CryptoPP::Integer
std::cout << "Dec: " << std::setprecision(1) << std::dec << i << std::endl;
std::cout << "Sci: " << std::setprecision(5) << std::scientific << i << std::endl;
On top of all of this, sufficiently large numbers breaks the entire thing.
CryptoPP::Integer i("12345");
// Calculate i^16
for (int x = 0; x < 16; x++)
{
i *= i;
}
std::cout << i << std::endl; // Will never finish
Ultimately I'm trying to get something where I can work with large Integer
numbers, and can output a string in scientific notation. I have no problems with extracting the Integer
library or modifying it as necessary, but I would prefer working with stable code.
Am I doing something wrong, or is there a way that I can get this working correctly?
I'm attempting to convert Integer to string with the following code:
CryptoPP::Integer i("12345678900987654321"); std::ostrstream oss; oss << i; std::string s(oss.str()); LOGDEBUG(oss.str()); // Pumps log to console and log file
The output appears to have extra garbage data:
12345678900987654321.ÍÍÍÍÍÍÍÍÍÍÍýýýý««««««««îþîþ
I can't reproduce this with Crypto++ 5.6.2 on Visual Studio 2010. The corrupted output is likely the result of some other issue, not a bug in Crypto++. If you haven't done so already, I'd suggest trying to reproduce this in a minimal program just using CryptoPP::Integer
and std::cout
, and none of your other application code, to eliminate all other possible problems. If it's not working in a trivial stand-alone test (which would be surprising), there could be problems with the way the library was built (e.g. maybe it was built with a different C++ runtime or compiler version from what your application is using). If your stand-alone test passes, you can add in other string operations, logging code etc. until you find the culprit.
I do notice though that you're using std::ostrstream
which is deprecated. You may want to use std::ostringstream
instead. This Stack Overflow answer to the question "Why was std::strstream deprecated?" may be of interest, and it may even the case that the issues mentioned in that answer are causing your problems here.
Additionally, I cannot get precision or scientific notation working. The following will output the same results:
std::cout.precision(5); // Does nothing with CryptoPP::Integer std::cout << "Dec: " << std::setprecision(1) << std::dec << i << std::endl; std::cout << "Sci: " << std::setprecision(5) << std::scientific << i << std::endl;
std::setprecision
and std::scientific
modify floating-point input/output. So, with regular integer types in C++ like int
or long long
this wouldn't work either (but I can see that especially with arbitrary-length integers like CryptoPP:Integer
being able to output in scientific notation with a specified precision would make sense).
Even if C++ didn't define it like this, Crypto++'s implementation would still need to heed those flags. From looking at the Crypto++ implementation of std::ostream& operator<<(std::ostream& out, const Integer &a)
, I can see that the only iostream flags it recognizes are std::ios::oct
and std::ios::hex
(for octal and hex format numbers respectively).
If you want scientific notation, you'll have to format the output yourself (or use a different library).
On top of all of this, sufficiently large numbers breaks the entire thing.
CryptoPP::Integer i("12345"); // Calculate i^16 for (int x = 0; x < 16; x++) { i *= i; } std::cout << i << std::endl; // Will never finish
That will actually calculate i^(2^16) = i^65536
, not i^16
, because on each loop you're multiplying i
with its new intermediate value, not with its original value. The actual result with this code would be 268,140 digits long, so I expect it's just taking Crypto++ a long time to produce that output.
Here is the code adjusted to produce the correct result:
CryptoPP::Integer i("12345");
CryptoPP::Integer i_to_16(1);
// Calculate i^16
for (int x = 0; x < 16; x++)
{
i_to_16 *= i;
}
std::cout << i_to_16 << std::endl;