cref - ¿Cómo implemento BN_num_bytes()(y BN_num_bits()) en C#?
remarks c# (2)
Estoy portando esta línea de C ++ a C #, y no soy un programador experto en C ++:
unsigned int nSize = BN_num_bytes(this);
En .NET estoy usando System.Numerics.BigInteger
BigInteger num = originalBigNumber;
byte[] numAsBytes = num.ToByteArray();
uint compactBitsRepresentation = 0;
uint size2 = (uint)numAsBytes.Length;
Creo que hay una diferencia fundamental en la forma en que operan internamente, ya que los resultados de las pruebas unitarias de las fuentes no coinciden si BigInt es igual a:
- 0
- Cualquier número negativo
- 0x00123456
Sé literalmente nada sobre BN_num_bytes
( edit: los comentarios me dijeron que es una macro para BN_num_bits) .
Pregunta
¿Verificarías estas conjeturas sobre el código?
Necesito portar
BN_num_bytes
que es una macro para((BN_num_bits(bn)+7)/8)
(Gracias @WhozCraig)Necesito portar
BN_num_bits
que esfloor(log2(w))+1
Entonces, si existe la posibilidad de que los bytes iniciales y finales no se contabilicen, ¿qué ocurre en las máquinas Big / Little Endian? ¿Importa?
En función de estas respuestas en Security.StackExchange, y de que mi aplicación no es crítica para el rendimiento, puedo usar la implementación predeterminada en .NET y no usar una biblioteca alternativa que ya puede implementar una solución comparable.
Editar: hasta ahora mi implementación se parece a esto, pero no estoy seguro de qué es la "LookupTable" como se menciona en los comentarios.
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;
}
Editar 2:
Después de buscar un poco más, descubrí que:
BN_num_bits no devuelve el número de bits significativos de un bignum dado, sino la posición del bit 1 más significativo, que no es necesariamente lo mismo
Aunque todavía no sé cómo se ve su origen ...
Combine lo que dijo WhozCraig en los comentarios con este enlace explicando BN_num_bits:
http://www.openssl.org/docs/crypto/BN_num_bytes.html
Y terminas con algo como esto, que debería decirte la cantidad significativa de 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;
}
La página man (proyecto OpenSSL) de BN_num_bits dice que "Básicamente, excepto por un cero, devuelve floor(log2(w))+1
". Estas son las implementaciones correctas de las funciones BN_num_bytes
y BN_num_bits
para BigInteger
de .Net.
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));
}
Probablemente debería cambiarlos a métodos de extensión para mayor comodidad.
Debe comprender que estas funciones miden el número mínimo de bits / bytes que se necesitan para expresar un número entero dado. Las variables declaradas como int
( System.Int32
) toman 4 bytes de memoria, pero solo necesita 1 byte (o 3 bits) para expresar el número entero 7. Esto es lo que BN_num_bytes y BN_num_bits calculan: el tamaño de almacenamiento mínimo requerido para un número concreto .
Puede encontrar el código fuente de las implementaciones originales de las funciones en el repositorio oficial de OpenSSL .