1

作为个人挑战,我正在尝试在 Ruby 中实现 SIMON 分组密码。我在寻找处理数据的最佳方式时遇到了一些问题。与此问题相关的完整代码位于:https ://github.com/Rami114/Personal/blob/master/Simon/Simon.rb

SIMON 需要 XOR、移位和循环移位操作,最后一个是迫使我使用 BigNums,这样我就可以用数学来执行左循环移位,而不是在字节数组上执行更复杂/更慢的双循环。

有没有更好的方法将字符串转换为 BigNum 并再次返回。

String -> BigNum(其中 N 是 64,pt 是明文字符串)

 pt = pt.chars.each_slice(N/8).map {|x| x.join.unpack('b*')[0].to_i(2)}.to_a

因此,我将字符串分解为单个字符,切成 N 大小的数组(SIMON 中的单词大小)并将每个集合解压缩成一个 BigNum。这似乎工作正常,我可以将其转换回来。

现在我的 SIMON 代码目前已损坏,但这更多是我认为/希望的数学而不是代码。转换回来的是(其中 ct 是表示密文的 bignums 数组):

ct.map { |x| [x.to_s(2).rjust(128,'0')].pack('b*') }.join

我似乎必须右对齐填充字符串,因为 bignums 的宽度未定义,所以我没有前导 0。不幸的是,该包要求定义的 with 具有合理的输出。

这是一种有效的转换方法吗?有没有更好的办法?我不确定这两个计数,希望这里有人可以提供帮助。

E:对于@torimus,我正在使用的循环移位实现(来自上面的链接)

def self.lcs (bytes, block_size, shift)
  ((bytes << shift) | (bytes >> (block_size - shift))) & ((1<< block_size)-1)
end
4

1 回答 1

0

如果您对 msb 第一个二进制数同样满意unpack('B*')(如果您的所有处理都是循环的,那么您很可能会这样做),那么您也可以使用.unpack('Q>')而不是.unpack('B*')[0].to_i(2)生成pt

pt = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890!@"

# Your version (with 'B' == msb first) for comparison:
pt_nums = pt.chars.each_slice(N/8).map {|x| x.join.unpack('B*')[0].to_i(2)}.to_a
=> [8176115190769218921, 8030025283835160424, 7668342063789995618, 7957105551900562521,
  6145530372635706438, 5136437062280042563, 6215616529169527604, 3834312847369707840]

# unpack to 64-bit unsigned integers directly
pt_nums =  pt.unpack('Q>8')
=> [8176115190769218921, 8030025283835160424, 7668342063789995618, 7957105551900562521, 
  6145530372635706438, 5136437062280042563, 6215616529169527604, 3834312847369707840]

没有本机 128 位打包/解包返回另一个方向,但您也可以使用它Fixnum来解决这个问题:

split128 = 1 << 64
ct = pt # Just to show round-trip
ct.map { |x| [ x / split128, x % split128 ].pack('Q>2') }.join

=> "\x00\x00\x00\x00\x00\x00\x00\x00qwertyui . . . " # truncated

这避免了代码中的许多临时阶段,但是以使用不同的字节编码为代价——我对 SIMON 了解不足,无法评论这是否适合您的需求。

于 2013-07-22T14:33:41.407 回答