haskell中的SHA-1产生错误的哈希值

tol*_*ene 1 hash haskell sha1

我编写了一个在haskell中执行SHA-1的程序,虽然它确实产生了哈希,但它们与其他SHA-1程序产生的哈希不匹配

示例:cat hashes to:b5be86bc8bccfc24b01b093228ebb96fc92fa804但应该哈希到9d989e8d27dc9e0ec3389fc855f142c3d40f0c50

我的代码是:

(old code omitted)
Run Code Online (Sandbox Code Playgroud)

我不知道出了什么问题.有人能告诉我哪里弄错了吗?

编辑: 我修复了指出的东西,但它仍然无法正常工作.它正常工作直到内循环.我清理了代码,以便为内循环的功能都可以f1,f2f3 cat现在有趣的哈希来ebe6c9fa1afa0ef5a0ca80bab251fd41cc29127e.

码:

import Data.Word
import Data.Bits
import Data.Char (ord, intToDigit)
import Data.Binary (encode, decode)
import Numeric (showHex, showIntAtBase)
import System.IO (stdin)
import Data.Sequence ((<|), (|>))
import qualified Data.Sequence as S
import qualified Data.ByteString.Lazy as B
type Quintuple32 = (Word32, Word32, Word32, Word32, Word32)

addQuintuple (a, b, c, d, e) (f, g, h, i, j) =
    (a + f, b + g, c + h, d + i, e + j)

shower :: Quintuple32 -> String
shower (a, b, c, d, e) = concatMap (`showHex` "") [a, b, c, d, e]

hash :: Int -> S.Seq Word32 -> Quintuple32 -> Quintuple32
hash i w h@(a, b, c, d, e)
    | i < 20 = hash (i + 1) w (newhash (f1 h + k1))
    | i < 40 = hash (i + 1) w (newhash (f2 h + k2))
    | i < 60 = hash (i + 1) w (newhash (f3 h + k3))
    | i < 80 = hash (i + 1) w (newhash (f2 h + k4))
    | otherwise = h
  where (k1, k2, k3, k4) = (0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6)
        newhash a' = (rotate a 5 + a' + e + (w `S.index` i), a, rotate b 30, c, d)

f1 :: Quintuple32 -> Word32
f1 (_, b, c, _, _) = (b .&. c) .|. (complement b .&. c)

f2 :: Quintuple32 -> Word32
f2 (_, b, c, d, _) = b `xor` c `xor` d

f3 :: Quintuple32 -> Word32
f3 (_, b, c, d, _) = (b .&. c) .|. (b .&. d) .|. (c .&. d)

starting :: Quintuple32
starting = (0x67452301
           , 0xEFCDAB89
           , 0x98BADCFE
           , 0x10325476
           , 0xC3D2E1F0)

hasher :: Quintuple32 -> S.Seq Word32 -> Quintuple32
hasher acc x = addQuintuple acc (hash 0 (extend x) acc)

process :: B.ByteString -> Quintuple32
process = foldl hasher starting . chunks . pad

extend :: S.Seq Word32 -> S.Seq Word32
extend = extend' 16

extend' :: Int -> S.Seq Word32 -> S.Seq Word32
extend' 80 a = a
extend' i a = extend' (i + 1) (a |> xored)
  where xored = rotate ((a `S.index` (i - 3)) `xor`
                        (a `S.index` (i - 8)) `xor`
                        (a `S.index` (i - 14)) `xor`
                        (a `S.index` (i - 16))) 1

toBytes :: String -> B.ByteString
toBytes = B.pack . map (fromIntegral . ord)

splitEvery n xs
    | B.null xs = S.empty
    | otherwise = B.take n xs <| splitEvery n (B.drop n xs)

chunks :: B.ByteString -> [S.Seq Word32]
chunks xs
    | B.null xs = []
    | otherwise = x : chunks (B.drop 64 xs)
  where x = fmap decode (splitEvery 4 (B.take 64 xs))

pad :: B.ByteString -> B.ByteString
pad xs = B.append (add0 $ add1 xs) length64
  where length64 = encode (fromIntegral (8 * B.length xs) :: Word64)

add1 :: B.ByteString -> B.ByteString
add1 = flip B.append (B.singleton 128)

add0 :: B.ByteString -> B.ByteString
add0 xs
    | modulo /= 448 = add0 $ B.append xs (B.singleton 0)
    | otherwise = xs
  where modulo = (B.length xs * 8) `rem` 512
Run Code Online (Sandbox Code Playgroud)

另外,一个小问题:(a, b) = (8, 9)设置多个变量是否可以接受?

Tho*_*son 6

哦,另外一个!

两个错误立即跳出来:

pad :: B.ByteString -> B.ByteString
pad xs = B.append (add0 $ add1 xs) length64
  where length64 = encode (fromIntegral (B.length xs) :: Word64)
Run Code Online (Sandbox Code Playgroud)

请注意,您追加的长度应该是位长度,而不是字节长度.

add1 :: B.ByteString -> B.ByteString
add1 = flip B.append (B.singleton 255)
Run Code Online (Sandbox Code Playgroud)

请注意255 /= 0b10000000,垫应该是后者.

一般来说,你通过1)一遍又一遍地对规范进行调试.2)与另一个实现(如Adam Wick的SHA包)进行比较,并在尽可能细粒度级别上比较相等性.

编辑:还有两个错误,基本上是转录错误.如果你仍然卡住的话,环顾四周并大声喊叫.