Posso construir um BigInt com qualquer matriz de bytes (Scala)?
-
10-07-2019 - |
Pergunta
Eu estou tentando representar o resultado de um hash MD5 no menor corda possível. Parece um desperdício apenas para transformá-lo em uma string hex e deixe G a Z ir para o lixo.
Uma idéia que eu tive é obter o hash MD5 da minha entrada como um array de bytes e construindo uma BigInt
com ele. Posso, então, chamar toString(36)
, e obter o número como uma base-36 em um string (-?[0-9a-z]*
, o número pode ser positivo ou negativo). Ele funciona para mim.
O problema é que eu não tenho certeza de que um BigInt
pode ser construído com qualquer matriz de bytes, e eu não posso provar isso com testes (pelo menos não de uma forma oportuna!). Presumo que sim, porque eu entendo que um BigInt pode ser de tamanho arbitrário. Eu não pode usar esse método até que eu sei com certeza que ele vai trabalhar para todas as saídas possíveis. Então, alguém pode me dizer se ele vai funcionar para todas as entradas (ou como converter facilmente uma matriz de bytes para que ele possa ser representado na base 36).
Clarificação : Eu tenho a implementação, eu estou perguntando sobre o comportamento ao longo do todo o domínio (ou seja 00000000000000000000000000000000 para FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
Solução
Com base no seu feedback acima, a seguinte implementação será confiável codificar / decodificar uma matriz de bytes arbitrário:
package blevins.example
object BigIntEncoder {
val radix = 36
implicit def byteArrayToString(ba: Array[Byte]): String = {
new java.math.BigInteger(addByte(ba)).toString(radix)
}
implicit def stringToByteArray(s: String): Array[Byte] = {
stripByte(new java.math.BigInteger(s, radix).toByteArray)
}
def addByte(ba: Array[Byte]): Array[Byte] = {
val h = new Array[Byte](1)
h(0) = 0x01
h ++ ba
}
def stripByte(ba: Array[Byte]): Array[Byte] = {
ba.slice(1,ba.size)
}
}
Note que estamos adicionando um 0x01 byte extra para a cabeça da matriz para evitar quaisquer efeitos secundários de tomar a dois complemento da matriz de bytes.
EDIT: O teste envolveu a provar isso está documentado aqui: http: // cleverlytitled.blogspot.com/2009/10/scalacheck.html
Outras dicas
Será que não codificação Base64 ser inferior a Base36? Você pode encontrar muitas das implementações ao redor.
Mas, para realmente responder à pergunta:
// Make a big randomly-filled byte array
val random = scala.util.Random
val arraySize = 8543
val bytes: Array[Byte] = new Array[Byte](arraySize) // make some big array
random.nextBytes(bytes) // fill it randomly
// Make a BigInt out of it and the corresponding base36 string representation
val bi: BigInt = new BigInt(new java.math.BigInteger(bytes))
val strRep: String = bi.toString(36)
// Make a new BigInt out of the string rep. Does it match?
val bi2: BigInt = new BigInt(new java.math.BigInteger(strRep, 36))
if (bi == bi2) {
println("yippee!!")
}
// Make a new byte array out of the BigInt. Does it match the original array?
val bytes2: Array[Byte] = bi2.toByteArray
if (bytes deepEquals bytes2) {
println("yippee again!!")
}