如何在C#中实现BN_num_bytes()(和BN_num_bits())?
我将这一行从C ++移植到C#,我不是一个经验丰富的C ++程序员:
unsigned int nSize = BN_num_bytes(this);
在.NET中我使用的是System.Numerics.BigInteger
BigInteger num = originalBigNumber; byte[] numAsBytes = num.ToByteArray(); uint compactBitsRepresentation = 0; uint size2 = (uint)numAsBytes.Length;
我认为内部运作方式存在根本区别,因为如果BigInt等于: 来源的unit testing结果不匹配:
- 0
- 任何负数
- 0x00123456
我对BN_num_bytes
( 编辑:评论只是告诉我它是BN_num_bits的一个宏) 。
题
你会validation这些关于代码的猜测:
-
我需要移植
BN_num_bytes
这是一个宏((BN_num_bits(bn)+7)/8)
(谢谢@WhozCraig) -
我需要移植
BN_num_bits
,它是floor(log2(w))+1
然后,如果存在不计算前导和尾随字节的可能性,那么Big / Little端机器上会发生什么? 有关系吗?
基于Security.StackExchange上的这些答案,以及我的应用程序不是性能关键,我可以使用.NET中的默认实现,而不是使用可能已经实现类似解决方法的备用库。
编辑:到目前为止,我的实现看起来像这样,但我不确定评论中提到的“LookupTable”是什么。
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; }
编辑2:
经过一番搜索后, 我发现:
BN_num_bits不返回给定bignum的有效位数,而是返回最重要的1位的位置,这不一定是同一个东西
虽然我仍然不知道它的来源是什么样的……
BN_num_bits的手册页 (OpenSSL项目)说“基本上,除零之外,它返回floor(log2(w))+1
”。 所以这些是.Net的BigInteger
的BN_num_bytes
和BN_num_bits
函数的正确实现。
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)); }
为方便起见,您可能应将这些更改为扩展方法。
您应该了解这些函数测量表示给定整数所需的最小位/字节数。 声明为int
( System.Int32
)的变量占用4个字节的内存,但您只需要1个字节(或3个比特)来表示整数7.这是BN_num_bytes和BN_num_bits计算的内容 – 具体数字所需的最小存储大小。
您可以在官方OpenSSL存储库中找到这些函数的原始实现的源代码。
将评论中的WhozCraig与解释BN_num_bits的链接结合起来:
http://www.openssl.org/docs/crypto/BN_num_bytes.html
你最终得到这样的东西,它应该告诉你大量的字节:
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; }