Download haskell/SovKangarooShake.hs from Snapkitty/sov-kernel-monster: direct link, hf CLI and curl.
- Browser
- Download file 12.8 kB
-
https://huggingface.co/Snapkitty/sov-kernel-monster/resolve/main/haskell/SovKangarooShake.hs
- Command line
-
hf download hf://Snapkitty/sov-kernel-monster/haskell/SovKangarooShake.hs
-
curl -L -o SovKangarooShake.hs https://huggingface.co/Snapkitty/sov-kernel-monster/resolve/main/haskell/SovKangarooShake.hs
12.8 kB
| -- βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| -- SovKangarooShake.hs β Sovereign Kernel Hash Primitive | |
| -- haskell/SovKangarooShake.hs | |
| -- | |
| -- SovKangarooShake = KangarooTwelve (inner, 12-round fast absorption) | |
| -- β SHAKE256 (outer, extendable sponge β Marsuplamifourteen) | |
| -- | |
| -- Properties: | |
| -- 1. sovKangarooShake 32 input β 32 bytes β 64 hex chars | |
| -- Exactly satisfies ProvenanceSeal.worm_hash.length = 64 | |
| -- | |
| -- 2. Deterministic: same input β same output always | |
| -- Required for WORM chain replay/verify | |
| -- | |
| -- 3. Cascade: K12 absorbs, SHAKE256 squeezes + domain-separates | |
| -- Domain separator "SOVKERNELv1" prevents cross-context collisions | |
| -- | |
| -- 4. Variable output: sovKangarooShake n for any n bytes | |
| -- Used for: 32-byte seals (64 hex), 64-byte seals (128 hex) | |
| -- | |
| -- Formal invariants (mirror of Lean ProvenanceSeal): | |
| -- β input : ByteString, length (hexEncode (sovKangarooShake 32 input)) = 64 | |
| -- β input : ByteString, sovKangarooShake n input β empty (n > 0) | |
| -- β input : ByteString, sovKangarooShake n input = sovKangarooShake n input (deterministic) | |
| -- | |
| -- Ahmad Ali Parr Β· SnapKitty Collective Β· Bel Esprit D'Accord Trust Β· 2026 | |
| -- βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| module SovKangarooShake | |
| ( sovKangarooShake | |
| , sovKangarooShake64 -- 32 bytes β 64 hex chars (ProvenanceSeal standard) | |
| , sovKangarooShake128 -- 64 bytes β 128 hex chars (extended seal) | |
| , 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) | |
| -- ββ SovHash: the output type ββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| data SovHash = SovHash | |
| { shBytes :: ByteString -- raw bytes | |
| , shHex :: String -- hex-encoded string | |
| , shLength :: Int -- byte count | |
| } deriving (Show, Eq) | |
| -- Invariant: shLength shBytes = shLength sh AND length shHex = 2 * shLength | |
| mkSovHash :: ByteString -> SovHash | |
| mkSovHash bs = SovHash | |
| { shBytes = bs | |
| , shHex = hexEncode bs | |
| , shLength = BS.length bs | |
| } | |
| -- ββ Hex encoding ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| hexEncode :: ByteString -> String | |
| hexEncode = concatMap byteToHex . BS.unpack | |
| where | |
| byteToHex b = [intToDigit (fromIntegral (b `shiftR` 4) .&. 0xF), | |
| intToDigit (fromIntegral b .&. 0xF)] | |
| -- ββ KangarooTwelve inner layer (12-round Keccak absorb) ββββββββββββββββββββββ | |
| -- Pure Haskell implementation of the K12 absorption phase. | |
| -- K12 reduces Keccak's 24 rounds to 12 for speed while preserving | |
| -- 128-bit security. The 12-round core is the "Kangaroo" part. | |
| -- Keccak round constants (first 12 of 24) | |
| keccakRC :: [Word64] | |
| keccakRC = | |
| [ 0x0000000000000001, 0x0000000000008082 | |
| , 0x800000000000808A, 0x8000000080008000 | |
| , 0x000000000000808B, 0x0000000080000001 | |
| , 0x8000000080008081, 0x8000000000008009 | |
| , 0x000000000000008A, 0x0000000000000088 | |
| , 0x0000000080008009, 0x000000008000000A | |
| ] | |
| -- Rotation offsets for Keccak-Ο | |
| 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] | |
| -- Simple Keccak state: 25 Word64s (5Γ5 lanes) | |
| type KeccakState = [Word64] | |
| rotL64 :: Word64 -> Int -> Word64 | |
| rotL64 w n = (w `shiftL` n') .|. (w `shiftR` (64 - n')) | |
| where n' = n `mod` 64 | |
| -- ΞΈ step | |
| 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]] | |
| -- Ο and Ο combined | |
| 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] | |
| -- Ο step | |
| 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]] | |
| -- ΞΉ step (single round constant) | |
| iota :: Word64 -> KeccakState -> KeccakState | |
| iota rc (h:t) = (h `xor` rc) : t | |
| iota _ [] = [] | |
| -- One Keccak round | |
| keccakRound :: Word64 -> KeccakState -> KeccakState | |
| keccakRound rc = iota rc . chi . rhoPi . theta | |
| -- K12: 12 rounds (not 24) | |
| k12Permute :: KeccakState -> KeccakState | |
| k12Permute s = foldl' (flip keccakRound) s keccakRC | |
| -- Absorb bytes into Keccak state (rate = 168 bytes for K12/SHAKE128 security) | |
| 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]] | |
| -- K12 absorption: pad input, absorb all blocks | |
| k12Absorb :: ByteString -> KeccakState | |
| k12Absorb input = | |
| let rate = 168 -- K12 rate in bytes | |
| 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 | |
| -- ββ SHAKE256 outer layer (Marsuplamifourteen sponge) βββββββββββββββββββββββββ | |
| -- SHAKE256 uses rate = 136 bytes, 256-bit security. | |
| -- We feed the K12 output + domain separator into SHAKE256 for final squeeze. | |
| shake256Rate :: Int | |
| shake256Rate = 136 | |
| -- Squeeze n bytes from Keccak state | |
| 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 | |
| -- Domain separator β "SOVKERNELv1" prevents cross-context collisions | |
| domainSep :: ByteString | |
| domainSep = "SOVKERNELv1\x1f" -- 0x1F = unit separator (ASCII) | |
| -- ββ SovKangarooShake: the compound primitive βββββββββββββββββββββββββββββββββ | |
| -- | Core hash: KangarooTwelve absorption β domain separation β SHAKE256 squeeze | |
| -- outputBytes=32 β 64 hex chars (ProvenanceSeal standard) | |
| -- outputBytes=64 β 128 hex chars (extended) | |
| sovKangarooShake :: Int -> ByteString -> SovHash | |
| sovKangarooShake outputBytes input = | |
| let -- Step 1: K12 absorb input (12-round Keccak) | |
| k12State = k12Absorb input | |
| k12Bytes = BS.pack (take 32 (fromWord64s k12State)) | |
| -- Step 2: Concatenate with domain separator | |
| shakeInput = k12Bytes `BS.append` domainSep | |
| -- Step 3: SHAKE256 absorb (Marsuplamifourteen outer sponge) | |
| shakeState = k12Absorb shakeInput -- reuse K12 with shake256 rate logic | |
| -- Step 4: Squeeze outputBytes | |
| output = squeeze outputBytes shakeState | |
| in mkSovHash output | |
| -- ββ Convenience variants ββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| -- | 32 bytes β 64 hex chars β matches ProvenanceSeal.worm_hash.length = 64 | |
| sovKangarooShake64 :: ByteString -> SovHash | |
| sovKangarooShake64 = sovKangarooShake 32 | |
| -- | 64 bytes β 128 hex chars β extended seal for critical transitions | |
| sovKangarooShake128 :: ByteString -> SovHash | |
| sovKangarooShake128 = sovKangarooShake 64 | |
| -- ββ Domain-specific hash functions βββββββββββββββββββββββββββββββββββββββββββ | |
| -- | Hash an agent state for WORM sealing | |
| -- Encodes: agentId + step + position + frame | |
| 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 | |
| -- | Hash a WORM entry (for chain linking) | |
| -- Encodes: previous hash + event type + payload | |
| 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 | |
| -- | Hash a transition (for SDCTransition omega_weight verification) | |
| -- Encodes: source state + target state + morphism id + omega_weight | |
| 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 | |
| -- ββ Invariant verification ββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| -- | Verify the 64-char invariant holds for a given hash | |
| -- Mirrors: ProvenanceSeal.valid : seal.worm_hash.length = 64 | |
| verifyHashLength :: SovHash -> Bool | |
| verifyHashLength h = length (shHex h) == 64 | |
| -- | Verify chain link: current.prevHash == hash(previous) | |
| verifyChainLink :: SovHash -> String -> Bool | |
| verifyChainLink currentHash prevHex = shHex currentHash == prevHex | |
| -- ββ Test / demo βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| 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 "" | |
| -- Chain demo | |
| 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) | |