2

Let's say I have an arbitrary string that's ~1000 bytes long. (I'm studying crypto.) How can I unpack that into a BigNum? I understand how to pack it into 8-bit numbers, say, or 32-bit numbers.

s='I am a grumpy potato'
s.unpack('C*')
[73, 32, 97, 109, 32, 97, 32, 103, 114, 117, 109, 112, 121, 32, 112, 111, 116, 97, 116, 111]
s.upack('L*')
=> [1835081801, 1730175264, 1886221682, 1869619321, 1869898100]

Or, is there a straightforward way to combine, say, the 8-bit numbers into a BigNum? I could probably unpack into an array of 8-bit numbers and multiply each element of the array by subsequent powers of 8. But that seems too complicated to be the right way.

EDIT: What's the preferred way to turn the BigNum back into a string? I don't mean to_s, I mean taking the same pattern of bytes and interpreting it as a string?

4

2 回答 2

4

我认为你对如何处理它的预感是正确的。Unpack 不处理 Bignums;它们在经典上相当棘手,特别是因为它们不适合标准的 64 位 int。

您可以通过以下方式手动“解包”它:

str.unpack("C*").reverse.each_with_index.inject(0) do |sum, (byte, index)|
  sum + byte * (256 ** index)
end

也就是说,反转字节列表(如果在大端系统上),迭代每个字节,并将其值乘以256^position. 一旦值变得足够大,Ruby 的 BigNum 就会发挥作用,您可以毫不费力地将字节字符串转换为非常大的数字。

您也可以在 32 位(或 64 位,如果平台支持)整数块中执行相同操作:

INT32_MAX = 256 ** [1].pack("L*").size
INT64_MAX = 256 ** [1].pack("Q*").size

str.unpack("L*").reverse.each_with_index.inject(0) do |sum, (byte, index)|
  sum + byte * (INT32_MAX ** index)
end

str.unpack("Q*").reverse.each_with_index.inject(0) do |sum, (byte, index)|
  sum + byte * (INT64_MAX ** index)
end
于 2013-06-09T21:40:08.730 回答
0

非常感谢https://stackoverflow.com/a/17014450/204070。对我来说很棒。答案可以简化为:

str.unpack("C*").inject(0) do |sum, (byte, index)|
  sum * 256 + byte
end
于 2015-06-11T00:55:53.250 回答