How do I implement BN_num_bytes() (and BN_num_bits() ) in C#?

早过忘川 提交于 2019-12-08 15:55:30

问题


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:

  • 0
  • Any negative number
  • 0x00123456

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...


回答1:


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.




回答2:


Combine what WhozCraig in the comments said with this link explaining BN_num_bits:

http://www.openssl.org/docs/crypto/BN_num_bytes.html

And you end up with something like this, which should tell you the significant number of bytes:

public static int NumberOfBytes(BigInteger bigInt)
{
    if (bigInt == 0)
    {
        return 0; //you need to check what BN_num_bits actually does here as not clear from docs, probably returns 0
    }

    return (int)Math.Ceiling(BigInteger.Log(bigInt + 1, 2) + 7) / 8;
}


来源:https://stackoverflow.com/questions/15213853/how-do-i-implement-bn-num-bytes-and-bn-num-bits-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!