I'm porting this line from C++ to C#, and I'm not an experienced C++ programmer:
unsigned int nSize = BN_num_bytes(this);
In .NET I'm using System.Numerics.BigInteger
BigInteger num = originalBigNumber;
byte[] numAsBytes = num.ToByteArray();
uint compactBitsRepresentation = 0;
uint size2 = (uint)numAsBytes.Length;
I think there is a fundamental difference in how they operate internally, since the sources' unit tests' results don't match if the BigInt equals:
I know literally nothing about BN_num_bytes
(edit: the comments just told me that it's a macro for BN_num_bits).
Question
Would you verify these guesses about the code:
I need to port BN_num_bytes
which is a macro for ((BN_num_bits(bn)+7)/8)
(Thank you @WhozCraig)
I need to port BN_num_bits
which is floor(log2(w))+1
Then, if the possibility exists that leading and trailing bytes aren't counted, then what happens on Big/Little endian machines? Does it matter?
Based on these answers on Security.StackExchange, and that my application isn't performance critical, I may use the default implementation in .NET and not use an alternate library that may already implement a comparable workaround.
Edit: so far my implementation looks something like this, but I'm not sure what the "LookupTable" is as mentioned in the comments.
private static int BN_num_bytes(byte[] numAsBytes)
{
int bits = BN_num_bits(numAsBytes);
return (bits + 7) / 8;
}
private static int BN_num_bits(byte[] numAsBytes)
{
var log2 = Math.Log(numAsBytes.Length, 2);
var floor = Math.Floor(log2);
return (uint)floor + 1;
}
Edit 2:
After some more searching, I found that:
BN_num_bits does not return the number of significant bits of a given bignum, but rather the position of the most significant 1 bit, which is not necessarily the same thing
Though I still don't know what the source of it looks like...
The man page (OpenSSL project) of BN_num_bits says that "Basically, except for a zero, it returns floor(log2(w))+1
.".
So these are the correct implementations of the BN_num_bytes
and BN_num_bits
functions for .Net's BigInteger
.
public static int BN_num_bytes(BigInteger number) {
if (number == 0) {
return 0;
}
return 1 + (int)Math.Floor(BigInteger.Log(BigInteger.Abs(number), 2)) / 8;
}
public static int BN_num_bits(BigInteger number) {
if (number == 0) {
return 0;
}
return 1 + (int)Math.Floor(BigInteger.Log(BigInteger.Abs(number), 2));
}
You should probably change these into extension methods for convenience.
You should understand that these functions measure the minimum number of bits/bytes that are needed to express a given integer number. Variables declared as int
(System.Int32
) take 4 bytes of memory, but you only need 1 byte (or 3 bits) to express the integer number 7. This is what BN_num_bytes and BN_num_bits calculate - the minimum required storage size for a concrete number.
You can find the source code of the original implementations of the functions in the official OpenSSL repository.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With