Как мне реализовать BN_num_bytes () (и BN_num_bits ()) в C #?

я портирование этой строки из 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 равен:

  • 0
  • Любое отрицательное число
  • 0x00123456

Я буквально ничего не знаю о BN_num_bytes (редактировать: комментарии только что сказали мне, что это макрос для BN_num_bits).

Вопрос

Не могли бы вы проверить эти предположения о коде:

  • Мне нужно портировать BN_num_bytes который является макросом для ((BN_num_bits(bn)+7)/8) (Спасибо, @WhozCraig)

  • Мне нужно портировать BN_num_bits который floor(log2(w))+1

Тогда, если существует вероятность того, что ведущие и конечные байты не учитываются, то что происходит на машинах Big / Little endian? Это имеет значение?

На основе эти ответы на 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 бита, что необязательно является тем же самым

Хотя я до сих пор не знаю, как это выглядит …

15

Решение

справочная страница (Проект OpenSSL) BN_num_bits говорит, что «в основном, кроме нуля, он возвращает floor(log2(w))+1. «.
Так что это правильные реализации BN_num_bytes а также BN_num_bits функции для .Net 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));
}

Возможно, вам следует изменить их на методы расширения для удобства.

Вы должны понимать, что эти функции измеряют минимальное количество бит / байтов, необходимое для выражения заданного целого числа. Переменные, объявленные как int (System.Int32) занимает 4 байта памяти, но вам нужно только 1 байт (или 3 бита) для выражения целого числа 7. Это то, что вычисляют BN_num_bytes и BN_num_bits — минимальный требуемый размер хранилища для конкретного числа.

Вы можете найти исходный код оригинальной реализации функций в официальный репозиторий OpenSSL.

8

Другие решения

Объедините то, что сказал 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;
}
-2