Left rotate through carry in Ruby
I'm trying to implement SHA1 in Ruby and in order to do so I need to preform a left rotate through carry. The code I've written seems to work for 1 rotation, but any more than that it fails my tests, anybody know why?
class Integer
def rotate_left(count, size)
temp = self
count.times do
first_bit = (self & 2 开发者_运维问答** size)[size]
temp = temp << 1
temp = temp ^ first_bit
temp = temp ^ (2 ** (size + 1))
end
return temp
end
end
I checked Wikipedia first to make sure I understood the operation. It looks as if you were losing your carry's. Also, I added the test class to make sure I was getting the right answers. I wasn't sure if you wanted to preserve the carried bits or not so I commented out the code to truncate the result. Hope this helps!
class Integer
def rotate_left(count, size)
temp = self
carry = 0
count.times do
temp = temp << 1
temp = temp | carry
carry = (temp >> size) & 1
end
return temp # & (( 1 << size ) - 1)
end
end
if __FILE__ == $0 then
require 'test/unit'
class TestRotateLeft < Test::Unit::TestCase
def test_no_rotation
result = 5.rotate_left(0,4)
answer = result & 15
carry = ( result & 16 ) >> 4
assert_equal 5, result
assert_equal 0, carry
end
def test_one_rotation
result = 5.rotate_left(1,4)
answer = result & 15
carry = ( result & 16 ) >> 4
assert_equal 10, answer
assert_equal 0, carry
end
def test_first_carry
result = 5.rotate_left(2,4)
answer = result & 15
carry = ( result & 16 ) >> 4
assert_equal 4, answer
assert_equal 1, carry
end
def test_shift_from_carry
result = 5.rotate_left(3,4)
answer = result & 15
carry = ( result & 16 ) >> 4
assert_equal 9, answer
assert_equal 0, carry
end
def test_second_carry
result = 5.rotate_left(4,4)
answer = result & 15
carry = ( result & 16 ) >> 4
assert_equal 2, answer
assert_equal 1, carry
end
def test_full_rotation
result = 5.rotate_left(5,4)
answer = result & 15
carry = ( result & 16 ) >> 4
assert_equal 5, answer
assert_equal 0, carry
end
end
end
what are you using for size
? If you are trying to do a 4 bit rotation for example, and you set size to 4, then the first_bit calculation is getting the 5th bit:
2**4 => 16
16.to_s(2) => "10000"
So the indexing is Ok. But in the inner loop, you are getting first_bit from self
instead of temp. So this will only work the 1st time through.
I once implemented SHA-256 in Ruby (which is using right rotate) and finally used this code:
class Integer
def rotate(n=1)
self >> n | self << (32 - n)
end
end
You can modify it for left rotate:
class Integer
def lotate(n=1)
self << n | self >> (32 - n)
end
end
Although it's very hard to understand... it works :)
精彩评论