|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| {-# LANGUAGE OverloadedStrings #-}
|
|
|
| module SovKangarooShake
|
| ( sovKangarooShake
|
| , sovKangarooShake64
|
| , sovKangarooShake128
|
| , hashAgentState
|
| , hashWORMEntry
|
| , hashTransition
|
| , verifyHashLength
|
| , SovHash(..)
|
| ) where
|
|
|
| import Data.ByteString (ByteString)
|
| import qualified Data.ByteString as BS
|
| import qualified Data.ByteString.Char8 as BSC
|
| import Data.Bits (xor, shiftR, shiftL, (.&.), (.|.))
|
| import Data.List (foldl')
|
| import Data.Word (Word8, Word64)
|
| import Numeric (showHex)
|
| import Data.Char (intToDigit)
|
|
|
|
|
|
|
| data SovHash = SovHash
|
| { shBytes :: ByteString
|
| , shHex :: String
|
| , shLength :: Int
|
| } deriving (Show, Eq)
|
|
|
|
|
| mkSovHash :: ByteString -> SovHash
|
| mkSovHash bs = SovHash
|
| { shBytes = bs
|
| , shHex = hexEncode bs
|
| , shLength = BS.length bs
|
| }
|
|
|
|
|
|
|
| hexEncode :: ByteString -> String
|
| hexEncode = concatMap byteToHex . BS.unpack
|
| where
|
| byteToHex b = [intToDigit (fromIntegral (b `shiftR` 4) .&. 0xF),
|
| intToDigit (fromIntegral b .&. 0xF)]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| keccakRC :: [Word64]
|
| keccakRC =
|
| [ 0x0000000000000001, 0x0000000000008082
|
| , 0x800000000000808A, 0x8000000080008000
|
| , 0x000000000000808B, 0x0000000080000001
|
| , 0x8000000080008081, 0x8000000000008009
|
| , 0x000000000000008A, 0x0000000000000088
|
| , 0x0000000080008009, 0x000000008000000A
|
| ]
|
|
|
|
|
| rhoOffsets :: [Int]
|
| rhoOffsets = [1,62,28,27,36,44,6,55,20,3,10,43,25,39,41,45,15,21,8,18,2,61,56,14]
|
|
|
|
|
| type KeccakState = [Word64]
|
|
|
| rotL64 :: Word64 -> Int -> Word64
|
| rotL64 w n = (w `shiftL` n') .|. (w `shiftR` (64 - n'))
|
| where n' = n `mod` 64
|
|
|
|
|
| theta :: KeccakState -> KeccakState
|
| theta s =
|
| let c = [foldl' xor 0 [s !! (x + 5*y) | y <- [0..4]] | x <- [0..4]]
|
| d = [c !! ((x-1) `mod` 5) `xor` rotL64 (c !! ((x+1) `mod` 5)) 1 | x <- [0..4]]
|
| in [s !! (x + 5*y) `xor` (d !! x) | y <- [0..4], x <- [0..4]]
|
|
|
|
|
| rhoPi :: KeccakState -> KeccakState
|
| rhoPi s = map (\i ->
|
| let x = i `mod` 5; y = i `div` 5
|
| (x', y') = (y, (2*x + 3*y) `mod` 5)
|
| idx = x' + 5*y'
|
| in if idx < length rhoOffsets
|
| then rotL64 (s !! idx) (rhoOffsets !! idx)
|
| else s !! idx) [0..24]
|
|
|
|
|
| chi :: KeccakState -> KeccakState
|
| chi s = [s !! (x + 5*y) `xor`
|
| ((complement (s !! ((x+1)`mod`5 + 5*y))) .&. (s !! ((x+2)`mod`5 + 5*y)))
|
| | y <- [0..4], x <- [0..4]]
|
|
|
|
|
| iota :: Word64 -> KeccakState -> KeccakState
|
| iota rc (h:t) = (h `xor` rc) : t
|
| iota _ [] = []
|
|
|
|
|
| keccakRound :: Word64 -> KeccakState -> KeccakState
|
| keccakRound rc = iota rc . chi . rhoPi . theta
|
|
|
|
|
| k12Permute :: KeccakState -> KeccakState
|
| k12Permute s = foldl' (flip keccakRound) s keccakRC
|
|
|
|
|
| absorbBlock :: KeccakState -> ByteString -> KeccakState
|
| absorbBlock state block =
|
| let words64 = toWord64s (BS.unpack block)
|
| xored = zipWith xor state (words64 ++ repeat 0)
|
| in k12Permute xored
|
|
|
| toWord64s :: [Word8] -> [Word64]
|
| toWord64s [] = []
|
| toWord64s bs =
|
| let (chunk, rest) = splitAt 8 bs
|
| w = foldl' (\acc (i, b) -> acc .|. (fromIntegral b `shiftL` (8*i)))
|
| 0 (zip [0..] chunk)
|
| in w : toWord64s rest
|
|
|
| fromWord64s :: [Word64] -> [Word8]
|
| fromWord64s = concatMap w64ToBytes
|
| where w64ToBytes w = [fromIntegral (w `shiftR` (8*i)) .&. 0xFF | i <- [0..7]]
|
|
|
|
|
| k12Absorb :: ByteString -> KeccakState
|
| k12Absorb input =
|
| let rate = 168
|
| padded = padKeccak rate input
|
| blocks = chunksOf rate padded
|
| initial = replicate 25 0
|
| in foldl' absorbBlock initial blocks
|
|
|
| padKeccak :: Int -> ByteString -> ByteString
|
| padKeccak rate bs =
|
| let len = BS.length bs
|
| padLen = rate - (len `mod` rate)
|
| padding = if padLen == 1
|
| then BS.singleton 0x81
|
| else BS.cons 0x01 (BS.replicate (padLen - 2) 0x00) `BS.append` BS.singleton 0x80
|
| in bs `BS.append` padding
|
|
|
| chunksOf :: Int -> ByteString -> [ByteString]
|
| chunksOf n bs
|
| | BS.null bs = []
|
| | otherwise = let (h, t) = BS.splitAt n bs in h : chunksOf n t
|
|
|
|
|
|
|
|
|
|
|
| shake256Rate :: Int
|
| shake256Rate = 136
|
|
|
|
|
| squeeze :: Int -> KeccakState -> ByteString
|
| squeeze n state = BS.take n (BS.pack (fromWord64s (go n state)))
|
| where
|
| go remaining st
|
| | remaining <= 0 = []
|
| | otherwise =
|
| let block = take (shake256Rate * 8 `div` 8) (fromWord64s st)
|
| next = k12Permute st
|
| in block ++ go (remaining - shake256Rate) next
|
|
|
|
|
| domainSep :: ByteString
|
| domainSep = "SOVKERNELv1\x1f"
|
|
|
|
|
|
|
|
|
|
|
|
|
| sovKangarooShake :: Int -> ByteString -> SovHash
|
| sovKangarooShake outputBytes input =
|
| let
|
| k12State = k12Absorb input
|
| k12Bytes = BS.pack (take 32 (fromWord64s k12State))
|
|
|
|
|
| shakeInput = k12Bytes `BS.append` domainSep
|
|
|
|
|
| shakeState = k12Absorb shakeInput
|
|
|
|
|
| output = squeeze outputBytes shakeState
|
| in mkSovHash output
|
|
|
|
|
|
|
|
|
| sovKangarooShake64 :: ByteString -> SovHash
|
| sovKangarooShake64 = sovKangarooShake 32
|
|
|
|
|
| sovKangarooShake128 :: ByteString -> SovHash
|
| sovKangarooShake128 = sovKangarooShake 64
|
|
|
|
|
|
|
|
|
|
|
| hashAgentState :: String -> Int -> (Double, Double) -> String -> SovHash
|
| hashAgentState agentId step pos frame =
|
| let input = BSC.pack $ concat
|
| [ "AGENT:", agentId
|
| , "|STEP:", show step
|
| , "|POS:", show pos
|
| , "|FRAME:", frame
|
| , "|DOMAIN:SPACETIME"
|
| ]
|
| in sovKangarooShake64 input
|
|
|
|
|
|
|
| hashWORMEntry :: String -> String -> String -> SovHash
|
| hashWORMEntry prevHash eventType payload =
|
| let input = BSC.pack $ concat
|
| [ "WORM:", prevHash
|
| , "|EVENT:", eventType
|
| , "|PAYLOAD:", payload
|
| , "|VERSION:1"
|
| ]
|
| in sovKangarooShake64 input
|
|
|
|
|
|
|
| hashTransition :: String -> String -> String -> Double -> SovHash
|
| hashTransition source target morphism omegaWeight =
|
| let input = BSC.pack $ concat
|
| [ "TRANS:", source
|
| , "->", target
|
| , "|MORPH:", morphism
|
| , "|OMEGA:", show omegaWeight
|
| , "|DOMAIN:SDC"
|
| ]
|
| in sovKangarooShake64 input
|
|
|
|
|
|
|
|
|
|
|
| verifyHashLength :: SovHash -> Bool
|
| verifyHashLength h = length (shHex h) == 64
|
|
|
|
|
| verifyChainLink :: SovHash -> String -> Bool
|
| verifyChainLink currentHash prevHex = shHex currentHash == prevHex
|
|
|
|
|
|
|
| demoHashes :: IO ()
|
| demoHashes = do
|
| putStrLn "SovKangarooShake β Sovereign Kernel Hash Demo"
|
| putStrLn ""
|
|
|
| let h1 = sovKangarooShake64 "hello sovereign"
|
| putStrLn $ "sovKangarooShake64 'hello sovereign':"
|
| putStrLn $ " hex=" ++ shHex h1
|
| putStrLn $ " len=" ++ show (length (shHex h1)) ++ " (must be 64)"
|
| putStrLn $ " valid=" ++ show (verifyHashLength h1)
|
| putStrLn ""
|
|
|
| let h2 = hashAgentState "ahmad-1" 42 (35.0, 15.0) "Gravity"
|
| putStrLn $ "hashAgentState 'ahmad-1' step=42:"
|
| putStrLn $ " hex=" ++ shHex h2
|
| putStrLn $ " valid=" ++ show (verifyHashLength h2)
|
| putStrLn ""
|
|
|
| let h3 = hashTransition "BotState{step=0}" "BotState{step=1}" "AToKio.step" 0.618
|
| putStrLn $ "hashTransition step 0β1 omega=0.618:"
|
| putStrLn $ " hex=" ++ shHex h3
|
| putStrLn $ " valid=" ++ show (verifyHashLength h3)
|
| putStrLn ""
|
|
|
|
|
| let h4 = hashWORMEntry (shHex h1) "AGENT_STEP" "step=1"
|
| putStrLn $ "WORM chain link (h1 β h4):"
|
| putStrLn $ " prev=" ++ take 16 (shHex h1) ++ "..."
|
| putStrLn $ " curr=" ++ take 16 (shHex h4) ++ "..."
|
| putStrLn $ " valid=" ++ show (verifyHashLength h4)
|
|
|