packages feed

WringTwistree 0.0.1.1 → 0.1.0.0

raw patch · 11 files changed

+403/−121 lines, 11 filesdep +terminal-progress-barPVP ok

version bump matches the API change (PVP)

Dependencies added: terminal-progress-bar

API changes (from Hackage documentation)

+ Cryptography.Wring: encryptN :: Wring -> Int -> Vector Word8 -> (Vector Word8, [Int])
+ Cryptography.Wring: findMaxOrder :: Integer -> Integer

Files

CHANGELOG.md view
@@ -7,7 +7,19 @@ [Haskell Package Versioning Policy](https://pvp.haskell.org/) for Haskell and [Semantic Versioning](https://semver.org/) for Rust. -## Unreleased+## 0.1.0.0 - 1.0.0 - 2024-05-30++### Added++- -O2 option+- Progress bar for cryptanalysis+- In Rust, initialize sbox of new Wring and Twistree+- 15-byte test vectors++### Changed++- Increased number of rounds in Wring, because cryptanalysis showed it was not sufficient for security of large messages+- Make Rust modules and functions private  ## 0.0.1.1 - 0.1.0 - 2024-01-11 
README.md view
@@ -12,8 +12,9 @@ 2. The three key-dependent 8×8 S-boxes provide confusion and  resist linear cryptanalysis. 3. Rotating by the population count thwarts integral and differential cryptanalysis by moving the difference around to a different part of the message.-4. Wring's round constant, which is dependent on the byte position as well as the round number, is added to every byte to prevent slide attacks and ensure that an all-zero message doesn't stay that way.-4. Twistree runs a CRC backwards to make the four bytes about to be dropped affect all the other bytes.+4.  +    * Wring's round constant, which is dependent on the byte position as well as the round number, is added to every byte to prevent slide attacks and ensure that an all-zero message doesn't stay that way.+    * Twistree runs a CRC backwards to make the four bytes about to be dropped affect all the other bytes.  # Rust To run the program, type `cargo run`. The first time you run it, Cargo may download a quarter-gigabyte of data, which is the index to all crates. You can also test the program with `cargo test`.@@ -21,6 +22,8 @@ # Haskell You can run WringTwistree in the REPL with `stack ghci`, compile and run it with `stack run`, or use other Stack commands. You can also test the program with `stack test`. +If you develop this using Cabal, please edit `package.yaml` to match any changes you make to `WringTwistree.cabal`.+ # Command-line options `stack run -- -k key -e plaintext -o ciphertext` enciphers a file. Omit `-o ciphertext` to encipher in place. @@ -28,7 +31,7 @@  `stack run -- -k key -H plaintext -o hash` hashes a file. Omit `-o hash` to output the hash to stdout. -`stack run -- -c foo` runs cryptanalysis of type `foo`, which is currently `relkey` for related-key cryptanalysis. This option is not available in the Rust implementation.+`stack run -- -c foo` runs cryptanalysis of type `foo`, which is currently `relkey` for related-key cryptanalysis, `integral` for integral cryptanalysis, `hashcoll` for hash collisions, or `integral-fixed` or `hashcoll-linear` for variants of the preceding. This option is not available in the Rust implementation.  `cargo` instead of `stack` runs the Rust implementation; the options are the same, except that hash is `-h`. 
WringTwistree.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack  name:           WringTwistree-version:        0.0.1.1+version:        0.1.0.0 synopsis:       Whole-message cipher and tree hash description:    Please see the README on GitHub at <https://github.com/phma/wring-twistree#readme> category:       Cryptography@@ -39,7 +39,7 @@       Cryptography.WringTwistree.Sboxes   hs-source-dirs:       src-  ghc-options: -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints+  ghc-options: -O2 -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints   build-depends:       arithmoi     , array@@ -61,7 +61,7 @@       Paths_WringTwistree   hs-source-dirs:       app-  ghc-options: -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N+  ghc-options: -O2 -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N   build-depends:       WringTwistree     , arithmoi@@ -74,6 +74,7 @@     , parallel     , sort     , split+    , terminal-progress-bar     , utf8-string     , vector   default-language: Haskell2010@@ -85,7 +86,7 @@       Paths_WringTwistree   hs-source-dirs:       test-  ghc-options: -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N+  ghc-options: -O2 -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N   build-depends:       WringTwistree     , array
app/Cryptanalysis.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE BangPatterns #-} module Cryptanalysis   ( key96_0   , key96_1@@ -27,12 +28,15 @@   , wring6_3   , same30_3   , same96_0+  , nopio   , match   , rot1Bit   , bias   , convolve   , unbiasedConvolve   , convolveDiff+  , big3Power+  , thueMorse   , priminal   , byteArray   , b125@@ -63,11 +67,16 @@   , collisions1   , hashColl   , hashCollLinear+  , cumRot+  , rotations1+  , rotations256+  , pairs+  , jiggleMatch   ) where  import Data.Word import Data.Bits-import Data.Sort+import Data.List (sort,sortOn,group,inits,tails,transpose) import Math.NumberTheory.Primes import Data.Array.Unboxed import qualified Data.Sequence as Seq@@ -76,6 +85,8 @@ import Control.DeepSeq import Control.Parallel import Control.Parallel.Strategies+import System.ProgressBar+import System.IO.Unsafe import GHC.Conc (numCapabilities) import qualified Data.ByteString as B import Data.ByteString.UTF8 (fromString)@@ -136,6 +147,12 @@ wring6_2 = keyedWring $ fromString key6_2 wring6_3 = keyedWring $ fromString key6_3 +nopio :: IO () -- for calling functions which have a progress bar update+nopio = return () -- argument from GHCI++dotio :: IO ()+dotio = putStrLn "."+ -- Because of rotBitcount, fixed-position bit differences are inadequate to -- telling whether two outputs of Wring are similar. Convolve them instead. @@ -172,6 +189,30 @@   (sum $ map (^2) $ unbiasedConvolve as bs) / scale where   scale = ((1+(bias as))*(1+(bias bs))*(1-(bias as))*(1-(bias bs))) +-- Big numbers used for generating plaintext sequences++-- Big power of 3++big3Power :: Integral a => Int -> a+big3Power n = 3 ^ (n * 53 `div` 84)++-- Thue-Morse word++log2 :: Integral a => a -> Int+log2 0 = (-1)+log2 (-1) = (-1771476585)+log2 n = 1 + (log2 (n `div` 2))++thueMorse_ :: Int -> Integer+thueMorse_ 0 = 1+thueMorse_ n = (((1 .<<. nbits) - 1 - (thueMorse_ (n-1))) .<<. nbits)+               + (thueMorse_ (n-1)) where+  nbits = (1 .<<. (n-1))++thueMorse :: Integral a => Int -> a+-- Returns a Thue-Morse word of at least n bits ending in 1.+thueMorse n = fromIntegral (thueMorse_ ((log2 n)+1))+ -- Multiples of the priminal word for spreading plaintexts around the -- space of plaintext @@ -273,58 +314,68 @@ name2 :: Wring -> String -> Wring -> String name2 w0 s w1 = (wringName w0) ++ s ++ (wringName w1) -diff1Related :: Wring -> Wring -> Word64 -> Word64-diff1Related w0 w1 pt = ct0 .^. ct1 where+{-# NOINLINE diff1Related #-}+diff1Related :: Wring -> Wring -> IO () -> Word64 -> Word64+diff1Related w0 w1 upd pt = seq+  (if mod pt 256 == 0 then unsafePerformIO upd else ()) $ ct0 .^. ct1 where   ct0 = makeArrayInt $ encrypt w0 $ eightByteArray pt   ct1 = makeArrayInt $ encrypt w1 $ eightByteArray pt -conDiff1Related :: Wring -> Wring -> Word64 -> Double-conDiff1Related w0 w1 pt = par ct0 $ convolveDiff ct0 ct1 where+{-# NOINLINE conDiff1Related #-}+conDiff1Related :: Wring -> Wring -> IO () -> Word64 -> Double+conDiff1Related w0 w1 upd pt = seq+  (if mod pt 256 == 0 then unsafePerformIO upd else ()) $+  par ct0 $ convolveDiff ct0 ct1 where   ct0 = V.toList $ encrypt w0 $ eightByteArray pt   ct1 = V.toList $ encrypt w1 $ eightByteArray pt -diffRelated :: Wring -> Wring -> [Word64]-diffRelated w0 w1 = traceEvent (name2 w0 "-diff-" w1) $ map ((diff1Related w0 w1) . ((priminal 64) *)) [0..]+diffRelated :: Wring -> Wring -> IO () -> [Word64]+diffRelated w0 w1 upd = traceEvent (name2 w0 "-diff-" w1) $+  map ((diff1Related w0 w1 upd) . ((priminal 64) *)) [0..] -conDiffRelated :: Wring -> Wring -> [Double]-conDiffRelated w0 w1 = traceEvent (name2 w0 "-con-" w1) $ map ((conDiff1Related w0 w1) . ((priminal 64) *)) [0..]+conDiffRelated :: Wring -> Wring -> IO () -> [Double]+conDiffRelated w0 w1 upd = traceEvent (name2 w0 "-con-" w1) $+  map ((conDiff1Related w0 w1 upd) . ((priminal 64) *)) [0..]  plaintextHisto :: Histo plaintextHisto = foldl' hCountBits (emptyHisto 64)   (take (div samples 2) (map ((priminal 64) *) [0..])) -relatedKeyHisto :: Wring -> Wring -> Histo-relatedKeyHisto w0 w1 = foldl' hCountBits (emptyHisto 64)-  (take (div samples 2) (diffRelated w0 w1) `using` parListDeal numCapabilities rdeepseq)+relatedKeyHisto :: Wring -> Wring -> IO () -> Histo+relatedKeyHisto w0 w1 upd = foldl' hCountBits (emptyHisto 64)+  (take (div samples 2) (diffRelated w0 w1 upd)+  `using` parListDeal numCapabilities rdeepseq) -relatedKeyStatBit :: Wring -> Wring -> Double-relatedKeyStatBit w0 w1 = binomial (relatedKeyHisto w0 w1) (div samples 2)+relatedKeyStatBit :: Wring -> Wring -> IO () -> Double+relatedKeyStatBit w0 w1 upd = binomial (relatedKeyHisto w0 w1 upd) (div samples 2) -relatedKeyStatConv :: Wring -> Wring -> (Double,Double)-relatedKeyStatConv w0 w1 = normμσ 1 (sqrt (1/32))-  (take (div samples 2) (conDiffRelated w0 w1) `using` parListDeal numCapabilities rdeepseq)+relatedKeyStatConv :: Wring -> Wring -> IO () -> (Double,Double)+relatedKeyStatConv w0 w1 upd = normμσ 1 (sqrt (1/32))+  (take (div samples 2) (conDiffRelated w0 w1 upd)+  `using` parListDeal numCapabilities rdeepseq) -sixStatsBit :: Wring -> Wring -> Wring -> Wring -> [Double]-sixStatsBit w0 w1 w2 w3 = par s01 $ par s23 $ par s02 $ par s13 $ par s03 $ par s12 $+sixStatsBit :: Wring -> Wring -> Wring -> Wring -> IO () -> [Double]+sixStatsBit w0 w1 w2 w3 upd =+  par s01 $ par s23 $ par s02 $ par s13 $ par s03 $ par s12 $   [s01,s23,s02,s13,s03,s12] where-    s01 = relatedKeyStatBit w0 w1-    s23 = relatedKeyStatBit w2 w3-    s02 = relatedKeyStatBit w0 w2-    s13 = relatedKeyStatBit w1 w3-    s03 = relatedKeyStatBit w0 w3-    s12 = relatedKeyStatBit w1 w2+    s01 = relatedKeyStatBit w0 w1 upd+    s23 = relatedKeyStatBit w2 w3 upd+    s02 = relatedKeyStatBit w0 w2 upd+    s13 = relatedKeyStatBit w1 w3 upd+    s03 = relatedKeyStatBit w0 w3 upd+    s12 = relatedKeyStatBit w1 w2 upd -sixStatsConv :: Wring -> Wring -> Wring -> Wring -> [(Double,Double)]-sixStatsConv w0 w1 w2 w3 =+sixStatsConv :: Wring -> Wring -> Wring -> Wring -> IO () -> [(Double,Double)]+sixStatsConv w0 w1 w2 w3 upd =   par (force s01) $ par (force s23) $ par (force s02) $   par (force s13) $ par (force s03) $ par (force s12) $   [s01,s23,s02,s13,s03,s12] where-    s01 = relatedKeyStatConv w0 w1-    s23 = relatedKeyStatConv w2 w3-    s02 = relatedKeyStatConv w0 w2-    s13 = relatedKeyStatConv w1 w3-    s03 = relatedKeyStatConv w0 w3-    s12 = relatedKeyStatConv w1 w2+    s01 = relatedKeyStatConv w0 w1 upd+    s23 = relatedKeyStatConv w2 w3 upd+    s02 = relatedKeyStatConv w0 w2 upd+    s13 = relatedKeyStatConv w1 w3 upd+    s03 = relatedKeyStatConv w0 w3 upd+    s12 = relatedKeyStatConv w1 w2 upd  tellStat64 :: Double -> String -- 0.635 and 1.456 are 1% tails at 64 degrees of freedom, divided by 64.@@ -350,7 +401,8 @@  relatedKey4Bit :: Wring -> Wring -> Wring -> Wring -> IO () relatedKey4Bit w0 w1 w2 w3 = do-  let sixS = sixStatsBit w0 w1 w2 w3+  pb <- newProgressBar defStyle 3 (Progress 0 (div (samples*3) 256) ())+  let sixS = sixStatsBit w0 w1 w2 w3 (incProgress pb 1)   putStrLn (show sixS)   putStrLn ("0,1: " ++ tellStat64 (sixS !! 0))   putStrLn ("2,3: " ++ tellStat64 (sixS !! 1))@@ -361,7 +413,8 @@  relatedKey4Conv :: Wring -> Wring -> Wring -> Wring -> IO () relatedKey4Conv w0 w1 w2 w3 = do-  let sixS = sixStatsConv w0 w1 w2 w3+  pb <- newProgressBar defStyle 3 (Progress 0 (div (samples*3) 256) ())+  let sixS = sixStatsConv w0 w1 w2 w3 (incProgress pb 1)   putStrLn (show sixS)   putStrLn ("0,1: " ++ tellStatμσ (sixS !! 0))   putStrLn ("2,3: " ++ tellStatμσ (sixS !! 1))@@ -397,38 +450,40 @@ -- and xor all the ciphertexts produced by changing the byte of the plaintext -- to all 256 possibilities. -sum1Wring :: Crypt -> Wring -> Word64 -> Int -> Word64+{-# NOINLINE sum1Wring #-}+sum1Wring :: Crypt -> Wring -> IO () -> Word64 -> Int -> Word64 -- Take pt with all values in the bth byte, encrypt them all, -- and xor the ciphertexts.-sum1Wring enc w pt b = foldl' xor 0 cts where+sum1Wring enc w upd pt b = seq (unsafePerformIO upd) $ foldl' xor 0 cts where   pts = map eightByteArray $ zipWith xor (repeat pt) (map (.<<. (b .<<. 3)) [0..255])   cts = map makeArrayInt $ map (enc w) pts -integralHisto :: Crypt -> Wring -> Int -> Histo-integralHisto enc w b = foldl' hCountBits (emptyHisto 64)+integralHisto :: Crypt -> Wring -> IO () -> Int -> Histo+integralHisto enc w upd b = foldl' hCountBits (emptyHisto 64)   (take (div samples 256)-  (map ((\pt -> sum1Wring enc w pt b) . ((priminal 64) *)) [0..])+  (map ((\pt -> sum1Wring enc w upd pt b) . ((priminal 64) *)) [0..])   `using` parListDeal numCapabilities rdeepseq) -integralStat :: Crypt -> Wring -> Int -> Double-integralStat enc w b = binomial (integralHisto enc w b) (div samples 256)+integralStat :: Crypt -> Wring -> IO () -> Int -> Double+integralStat enc w upd b = binomial (integralHisto enc w upd b) (div samples 256) -eightStats :: Crypt -> Wring -> [Double]-eightStats enc w =+eightStats :: Crypt -> Wring -> IO () -> [Double]+eightStats enc w upd =   par s0 $ par s1 $ par s2 $ par s3 $ par s4 $ par s5 $ par s6 $ par s7 $   [s0,s1,s2,s3,s4,s5,s6,s7] where-    s0 = integralStat enc w 0-    s1 = integralStat enc w 1-    s2 = integralStat enc w 2-    s3 = integralStat enc w 3-    s4 = integralStat enc w 4-    s5 = integralStat enc w 5-    s6 = integralStat enc w 6-    s7 = integralStat enc w 7+    s0 = integralStat enc w upd 0+    s1 = integralStat enc w upd 1+    s2 = integralStat enc w upd 2+    s3 = integralStat enc w upd 3+    s4 = integralStat enc w upd 4+    s5 = integralStat enc w upd 5+    s6 = integralStat enc w upd 6+    s7 = integralStat enc w upd 7  integral1 :: Crypt -> Wring -> IO () integral1 enc w = do-  let eightS = eightStats enc w+  pb <- newProgressBar defStyle 10 (Progress 0 (div samples 32) ())+  let eightS = eightStats enc w (incProgress pb 1)   putStrLn (show eightS)   putStrLn ("Byte 0: " ++ tellStat64 (eightS !! 0))   putStrLn ("Byte 1: " ++ tellStat64 (eightS !! 1))@@ -450,9 +505,9 @@   putStrLn "Linear key, 8-byte data:"   integral1 encrypt linearWring   putStrLn "96-byte key, byte 7:" -- This byte came out as "too much variation".-  putStrLn $ show $ integralHisto encrypt wring96_0 7+  putStrLn $ show $ integralHisto encrypt wring96_0 nopio 7   putStrLn "Linear key, byte 3:" -- This byte came out as "low-discrepancy".-  putStrLn $ show $ integralHisto encrypt linearWring 3+  putStrLn $ show $ integralHisto encrypt linearWring nopio 3  integralCrFixed :: IO () integralCrFixed = do@@ -500,27 +555,131 @@   | h0==h1    = (a,b):(dups ((b,h1):xs))   | otherwise = dups ((b,h1):xs) -collisions1 :: SBox -> Integer -> [(V.Vector Word8,V.Vector Word8)]+{-# NOINLINE collisions1 #-}+collisions1 :: SBox -> IO () -> Integer -> [(V.Vector Word8,V.Vector Word8)] -- Given an S-box and a 64-nybble integer, tries compressing all 961 blocks -- made from the integer changed by 0 or 1 nybble, and returns any collisions.-collisions1 sbox n = dups $ sortOn snd $ compressChanges sbox n+collisions1 sbox upd n = seq (unsafePerformIO upd) $ dups+  $ sortOn snd $ compressChanges sbox n -collisions :: SBox -> [(V.Vector Word8,V.Vector Word8)]-collisions sbox = foldl' (++) []+collisions :: SBox -> IO () -> [(V.Vector Word8,V.Vector Word8)]+collisions sbox upd = foldl' (++) []   (take (div samples 961)-  (map ((collisions1 sbox) . ((priminal 256) *)) [0..])+  (map ((collisions1 sbox upd) . ((priminal 256) *)) [0..])   `using` parListDeal numCapabilities rdeepseq)  hashColl :: IO () hashColl = do   putStrLn "Hash collisions, 30-byte key:"-  let colls = collisions sbox30_3+  pb <- newProgressBar defStyle 10 (Progress 0 (div samples 961) ())+  let colls = collisions sbox30_3 (incProgress pb 1)   putStrLn (show colls)   putStrLn ((show (length colls)) ++ " collisions")  hashCollLinear :: IO () hashCollLinear = do   putStrLn "Hash collisions, linear S-box:"-  let colls = collisions linearSbox+  pb <- newProgressBar defStyle 10 (Progress 0 (div samples 961) ())+  let colls = collisions linearSbox (incProgress pb 1)   putStrLn (show colls)   putStrLn ((show (length colls)) ++ " collisions")++-- Clutch cryptanalysis: find out how often two messages are rotated together++clutchSamples = 1+clutchMsgLen = 10000+clutchRounds = 8+clutchParNum = 2 + numCapabilities `div` 256 -- this 256 is from rotations256++countPairs :: Ord a => [a] -> Int+-- Given a list of numbers representing the amount by which a message has been+-- rotated by some number of rounds, returns the number of pairs of+-- equal numbers.+countPairs ns = sum $ map (\n -> n*(n-1)) $ map length $ group $ sort ns++cumRot :: [Int] -> [Int]+cumRot rotations = map (`mod` (8*clutchMsgLen)) $ map sum $ tail $ inits rotations++messageArray :: Integer -> V.Vector Word8+messageArray pt = byteArray clutchMsgLen pt++rotations1 :: Wring -> Integer -> [Int]+rotations1 wring pt = cumRot $ snd $ encryptN wring clutchRounds $ messageArray pt++rotations256 :: Wring -> Integer -> Int -> [[Int]]+rotations256 wring pt n = (map (rotations1 wring) $ map (xor pt) $+  map (.<<. (8*n)) [0..255])+  `using` parListDeal numCapabilities rdeepseq++type Jiggle =+  ( Integer -- plaintext+  , Int     -- byte which is changed+  , Int     -- two byte values which give the same sum of first and second+  , Int     -- rotations, but different first and second rotations+  )++pairs1 :: [a] -> [(a,a)]+pairs1 [] = []+pairs1 (x:xs) = zip (repeat x) xs++pairs :: [a] -> [(a,a)]+pairs xs = concatMap pairs1 (tails xs)++isJiggly :: (Eq b,Eq c) => ((a,b,c),(a,b,c)) -> Bool+isJiggly ((inx0,each0,sum0),(inx1,each1,sum1)) = (sum0 == sum1) && (each0 /= each1)++jigglize :: Integer -> Int -> ((Int,b,c),(Int,b,c)) -> Jiggle+jigglize pt n ((inx0,each0,sum0),(inx1,each1,sum1)) = (pt,n,inx0,inx1)++{-# NOINLINE clutch1 #-}+clutch1 :: Fractional a => Wring -> IO () -> (Integer,Int) -> ([a],[a],[Jiggle])+clutch1 wring upd (pt,n) = (totalRotStats,togetherRotStats,jiggle) where+  rotations = seq (unsafePerformIO upd) $ rotations256 wring pt n+  rotTogether = map (tail . inits) rotations+  totalRotStats = map (/(256*255)) $ map (fromIntegral . countPairs) $ transpose rotations+  togetherRotStats = map (/(256*255)) $ map (fromIntegral . countPairs) $ transpose rotTogether+  jiggle = map (jigglize pt n) $ filter isJiggly $ pairs $+    zip3 [0..255] (map (!! 1) rotTogether) (map (!! 1) rotations)++addClutch :: Num a => ([a],[a],[b]) -> ([a],[a],[b]) -> ([a],[a],[b])+addClutch (a,b,c) (m,n,o) = (zipWith (+) a m,zipWith (+) b n,c ++ o)++divClutch :: Fractional a => ([a],[a],[b]) -> ([a],[a],[b])+divClutch (a,b,c) = (map (/(fromIntegral clutchSamples)) a,+                     map (/(fromIntegral clutchSamples)) b,+                     c)++clutchStats :: Fractional a => Wring -> ProgressBar s -> ([a],[a],[Jiggle])+clutchStats wring pb = divClutch $ foldl' addClutch (repeat 0,repeat 0,[]) $+  map (clutch1 wring (incProgress pb 1)) $+  map (\x -> ((big3Power (8*clutchMsgLen))*(fromIntegral x),+              (x*(fromIntegral (findMaxOrder (fromIntegral clutchMsgLen))) `mod` clutchMsgLen)))+  ([1..clutchSamples] `using` parListDeal clutchParNum rdeepseq)++{-# NOINLINE jiggleMatch #-}+jiggleMatch :: Wring -> IO () -> Jiggle -> (Int,Int)+jiggleMatch wring upd (pt,byte,b0,b1) = (sideways,matches) where+  (ct0,r0) = encryptN wring 2 $ messageArray (pt .^. ((fromIntegral b0) .<<. (8*byte)))+  (ct1,r1) = encryptN wring 2 $ messageArray (pt .^. ((fromIntegral b1) .<<. (8*byte)))+  sideways' = ((head r1) - (head r0)) `mod` (8*clutchMsgLen)+  sideways = if (sideways' > 4*clutchMsgLen)+                then (sideways' - 8*clutchMsgLen)+                else sideways'+  matches = seq (unsafePerformIO upd) $ match (V.toList ct0) (V.toList ct1)++clutch :: IO ()+clutch = do+  pb <- newProgressBar defStyle 10 (Progress 0 clutchSamples ())+  let (statsTotal,statsTogether,jiggles) = clutchStats wring96_0 pb+  seq (length statsTotal) nopio+  putStrLn "Same total rotation after n rounds:"+  putStrLn $ show statsTotal+  putStrLn "Rotated together for n rounds:"+  putStrLn $ show statsTogether+  putStr "Number of 2-round jiggles: "+  putStrLn $ show $ length jiggles+  pbj <- newProgressBar defStyle 10 (Progress 0 (length jiggles) ())+  let jh = jiggleHisto $ map (jiggleMatch wring96_0 (incProgress pbj 1)) jiggles+  let jStats = jiggleStats jh+  seq (sum (map (\(a,(b,c,d,e,f)) -> c) jStats)) nopio+  putStrLn $ show jStats
app/Stats.hs view
@@ -11,12 +11,18 @@   , bitFold   , sacStats   , normμσ+  , jhCount+  , emptyJiggleHisto+  , jiggleHisto+  , listStats+  , jiggleStats   ) where  import Data.Bits import Data.Word import qualified Data.Sequence as Seq import Data.Sequence ((><), (<|), (|>), Seq((:<|)), Seq((:|>)))+import qualified Data.IntMap.Strict as Map import Data.Foldable (toList,foldl') import Control.Parallel import Control.Parallel.Strategies@@ -122,3 +128,28 @@   (n,total,total2) = pairwiseSumCount ndevsqs   mean = total / (fromIntegral n)   var = total2 / (fromIntegral n)++type JiggleHisto = Map.IntMap [Int]+-- The key is sideways; the value is the list of matches from jiggleMatch.++jhCount :: JiggleHisto -> (Int,Int) -> JiggleHisto+jhCount jh (sideways,matches) = Map.insertWith (++) sideways [matches] jh++emptyJiggleHisto :: JiggleHisto+emptyJiggleHisto = Map.empty++jiggleHisto :: [(Int,Int)] -> JiggleHisto+jiggleHisto sidematches = foldl' jhCount emptyJiggleHisto sidematches++listStats :: (Real a,Bounded a) => [a] -> (Int,Double,Double,a,a)+listStats xs = (n,mean,sqrt var,minxs,maxxs) where+  minxs = if null xs then maxBound else minimum xs+  maxxs = if null xs then minBound else maximum xs+  devs = map realToFrac xs+  devsqs = map (\x -> (1,x,x^2)) devs+  (n,total,total2) = pairwiseSumCount devsqs+  mean = total / (fromIntegral n)+  var = (total2 - total * mean) / (fromIntegral n-1)++jiggleStats :: JiggleHisto -> [(Int,(Int,Double,Double,Int,Int))]+jiggleStats jh = Map.toList $ Map.map listStats jh
src/Cryptography/Twistree.hs view
@@ -60,7 +60,14 @@  deal n = transpose . chunksOf n -- to be used as a parallel strategy -parListDeal :: Int -> Strategy a -> Strategy [a]+-- | Deals a list among threads; each thread evaluates the items of its part+-- of the list in sequence, and all the threads run in parallel. If n is 12,+-- the 0th, 12th, 24th, ... items are evaluated by one thread, the 1st, 13rd,+-- 25th, ... items are evaluated by another thread, and so on.+parListDeal+  :: Int -- ^ n, the number of threads+  -> Strategy a+  -> Strategy [a] parListDeal n strat xs   | n <= 1    = evalList strat xs   | otherwise = concat `fmap` parList (evalList strat) (deal n xs)
src/Cryptography/Wring.hs view
@@ -1,6 +1,7 @@ module Cryptography.Wring   ( Wring   , mix3Parts -- reexported for use in Cryptanalysis.hs+  , findMaxOrder -- reexported for use in Cryptanalysis.hs   , permut8 -- reexported for testing   , mul65537 -- "   , wringName -- For events in traces when profiling@@ -10,6 +11,7 @@   , encrypt   , decrypt   , encryptFixed -- Only for cryptanalysis and testing+  , encryptN -- Only for cryptanalysis and testing   ) where  {- This cipher is intended to be used with short random keys (32 bytes or less,@@ -50,8 +52,8 @@  nRounds :: Integral a => a -> a nRounds len-  | len < 3 = 3-  | otherwise = (nRounds (len `div` 3)) +1+  | len < 2 = 3+  | otherwise = (nRounds (len `div` 2)) +1  -- | Exclusive-ors all bytes in a nonnegative number. The only reason this -- function is public is that it's used to generate a long `ByteString`@@ -102,6 +104,24 @@   i4 = V.fromListN len $ zipWith (+) (V.toList i3)     (map (xor xornrond) (V.toList xornary)) +roundEncryptFunN ::+  Int ->+  SBox ->+  V.Vector Word8 ->+  (V.Vector Word8, [Int]) ->+  Int ->+  (V.Vector Word8, [Int])+roundEncryptFunN rprime sbox xornary (buf,ns) rond = (i4,ns') where+  len = V.length buf+  xornrond = xorn rond+  i1 = mix3Parts buf rprime+  i2 = V.fromListN len $ map (sbox V.!) $+    zipWith sboxInx (drop rond cycle3) (V.toList i1)+  (i3,n) = rotBitcountN i2 1+  i4 = V.fromListN len $ zipWith (+) (V.toList i3)+    (map (xor xornrond) (V.toList xornary))+  ns' = ns ++ [n]+ roundDecryptFun ::   Int ->   SBox ->@@ -128,6 +148,15 @@     rprime = fromIntegral $ findMaxOrder (fromIntegral $ len `div` 3)     rounds = [0 .. (nRounds len) -1] +encryptFunN :: Wring -> Int -> V.Vector Word8 -> (V.Vector Word8, [Int])+encryptFunN wring n buf = foldl' (roundEncryptFunN rprime (sbox wring) xornary)+  (buf,[]) rounds+  where+    len = V.length buf+    xornary = xornArray len+    rprime = fromIntegral $ findMaxOrder (fromIntegral $ len `div` 3)+    rounds = [0 .. n-1]+ decryptFun :: Wring -> V.Vector Word8 -> V.Vector Word8 decryptFun wring buf = foldl' (roundDecryptFun rprime (invSbox wring) xornary)   buf rounds@@ -260,6 +289,9 @@  -- | Used only for cryptanalysis encryptFixed = encryptFixedST++-- | Used only for cryptanalysis+encryptN = encryptFunN  -- | Decrypts a message. decrypt
src/Cryptography/WringTwistree/Mix3.hs view
@@ -74,9 +74,11 @@ searchFrom :: (Integer,Int) -> [Integer] searchFrom (start,dir) = map (\x -> x*(fromIntegral dir)+start) searchSeq -findMaxOrder :: Integer -> Integer--- n must be positive.--- Returns the number of maximum multiplicative order mod n closest to n/φ.+findMaxOrder+  :: Integer -- ^ n must be positive.+  -> Integer -- ^ A number relatively prime to n+-- ^ Returns the number of maximum multiplicative order mod n closest to n/φ.+-- This is a primitive root, if there are any. -- n=1 is a special case, as (isMaxOrder 1 1 [] i) returns False for all i>=0. findMaxOrder 1 = 1 findMaxOrder n = head $ filter (isMaxOrder n car fac) $ searchFrom $ searchDir n
src/Cryptography/WringTwistree/RotBitcount.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE BangPatterns #-} module Cryptography.WringTwistree.RotBitcount   ( rotBitcount+  , rotBitcountN -- Only for cryptanalysis and testing   , rotBitcount'   , rotFixed   , rotFixed'@@ -37,17 +38,31 @@     multmod = if len>0 then mult `mod` (len * 8) else mult     bitcount = sum $ map popCount $ V.toList src     rotcount = if len>0 then (bitcount * multmod) `mod` (len * 8)-			else bitcount * multmod+                        else bitcount * multmod     !byte = rotcount .>>. 3     !bit = rotcount .&. 7 +rotBitcountN :: V.Vector Word8 -> Int -> (V.Vector Word8, Int)+-- for cryptanalysis+rotBitcountN src mult = (V.fromListN len+  [ (src V.! ((i+len-byte)   `mod` len) .<<. bit) .|.+    (src V.! ((i+len-byte-1) `mod` len) .>>. (8-bit)) | i <- [0..(len-1)]], bitcount)+  where+    len = V.length src+    multmod = if len>0 then mult `mod` (len * 8) else mult+    bitcount = sum $ map popCount $ V.toList src+    rotcount = if len>0 then (bitcount * multmod) `mod` (len * 8)+                        else bitcount * multmod+    !byte = rotcount .>>. 3+    !bit = rotcount .&. 7+ rotBitcount' :: MV.MVector s Word8 -> Int -> MV.MVector s Word8 -> ST s () rotBitcount' src mult dst = do     bitcount <- MV.foldl' (\acc x -> acc + popCount x) 0 src     let len = MV.length src         !multmod = if len>0 then mult `mod` (len * 8) else mult         rotcount = if len>0 then (bitcount * multmod) `rem` (len * 8)-			    else bitcount * multmod+                            else bitcount * multmod         !byte = rotcount .>>. 3         !bit = rotcount .&. 7     forM_ [0..MV.length src - 1] $ \i -> do
src/Cryptography/WringTwistree/Sboxes.hs view
@@ -29,7 +29,7 @@ import Cryptography.WringTwistree.KeySchedule import qualified Data.Vector.Unboxed as V --- | Three 8×8 S-boxes used alternatively to substitute bytes+-- | Three 8×8 S-boxes used alternately to substitute bytes type SBox = V.Vector Word8  {-# SPECIALIZE sboxInx :: Word8 -> Word8 -> Int #-}
test/Spec.hs view
@@ -72,94 +72,114 @@ testVectorsWring = testGroup "Test vectors for Wring"   [ testCase "lin8nulls" $       (encrypt linearWring (fromListN 8 [0,0,0,0,0,0,0,0]))-      @?= fromListN 8 [0x04,0xd7,0x16,0x6a,0xca,0x70,0x57,0xbc]+      @?= fromListN 8 [0x5e,0x09,0xc0,0x54,0x3c,0x82,0xdc,0xe8]   , testCase "lin8ff" $       (encrypt linearWring (fromListN 8 [255,255,255,255,255,255,255,255]))-      @?= fromListN 8 [0x84,0x91,0x95,0xa0,0x9f,0x48,0x4b,0x59]+      @?= fromListN 8 [0x69,0x9d,0x9d,0xff,0xbc,0x22,0x8a,0x5d]   , testCase "lin8Twistree" $       (encrypt linearWring (fromListN 8 $ stringToBytes "Twistree"))-      @?= fromListN 8 [0xed,0x4b,0x2e,0xc6,0xc4,0x39,0x65,0x2b]+      @?= fromListN 8 [0xbb,0xc3,0x28,0x40,0x8c,0x94,0xae,0xf8]   , testCase "lin9nulls" $       (encrypt linearWring (fromListN 9 [0,0,0,0,0,0,0,0,0]))-      @?= fromListN 9 [0xad,0x93,0x5e,0x85,0xe1,0x49,0x45,0xca,0xe2]+      @?= fromListN 9 [0x4a,0xb1,0x99,0x07,0x1b,0x8c,0xd4,0x54,0xaf]   , testCase "lin9ff" $       (encrypt linearWring (fromListN 9 [255,255,255,255,255,255,255,255,255]))-      @?= fromListN 9 [0x36,0xdf,0x60,0xae,0xf5,0xbd,0x1a,0xaf,0x6e]+      @?= fromListN 9 [0x8b,0x6c,0x0a,0x7d,0x32,0x23,0xee,0xc5,0x7f]   , testCase "lin9AllOrNone" $       (encrypt linearWring (fromListN 9 $ stringToBytes "AllOrNone"))-      @?= fromListN 9 [0x53,0x28,0xe7,0xc7,0xe0,0x71,0xa5,0x2e,0x8c]+      @?= fromListN 9 [0xc1,0xd8,0x4e,0x09,0xea,0x44,0xf3,0x0d,0x19]+  , testCase "lin15Encipher" $+      (encrypt linearWring (fromListN 15 $ stringToBytes "EncipherMessage"))+      @?= fromListN 15 [ 0xc5, 0x0e, 0xc1, 0x88, 0xfd, 0x97, 0x89, 0x2d+                       , 0xa3, 0xdf, 0x58, 0x15, 0xd3, 0xf4, 0x8c]   , testCase "null8nulls" $       (encrypt wring0 (fromListN 8 [0,0,0,0,0,0,0,0]))-      @?= fromListN 8 [0x77,0x3e,0x34,0x8f,0x48,0xa1,0x24,0x1a]+      @?= fromListN 8 [0x61,0x4b,0xf3,0x34,0x9e,0x21,0xd1,0x21]   , testCase "null8ff" $       (encrypt wring0 (fromListN 8 [255,255,255,255,255,255,255,255]))-      @?= fromListN 8 [0xc7,0xa7,0x58,0xed,0x5c,0x2b,0xb6,0xec]+      @?= fromListN 8 [0x22,0xc3,0x6c,0x9f,0xe4,0x27,0xbc,0xce]   , testCase "null8Twistree" $       (encrypt wring0 (fromListN 8 $ stringToBytes "Twistree"))-      @?= fromListN 8 [0xa3,0xcf,0xd4,0xa1,0x0d,0x7e,0xb7,0xb3]+      @?= fromListN 8 [0x9a,0xcd,0xf5,0xe0,0xb0,0x3c,0x0c,0x32]   , testCase "null9nulls" $       (encrypt wring0 (fromListN 9 [0,0,0,0,0,0,0,0,0]))-      @?= fromListN 9 [0x10,0x10,0x95,0x96,0x90,0xb5,0x97,0xeb,0x38]+      @?= fromListN 9 [0x72,0x4d,0x2a,0x49,0xc9,0xb3,0x00,0xdb,0x32]   , testCase "null9ff" $       (encrypt wring0 (fromListN 9 [255,255,255,255,255,255,255,255,255]))-      @?= fromListN 9 [0x09,0x0f,0xf3,0x66,0x36,0xa4,0xac,0x8d,0x5c]+      @?= fromListN 9 [0xbc,0x05,0xcf,0x4b,0x0f,0x31,0x81,0xba,0x5c]   , testCase "null9AllOrNone" $       (encrypt wring0 (fromListN 9 $ stringToBytes "AllOrNone"))-      @?= fromListN 9 [0xee,0x15,0x02,0x05,0xdd,0xa9,0x77,0xe4,0x23]+      @?= fromListN 9 [0x06,0x15,0xaf,0x81,0x8b,0x63,0x9c,0xa2,0x9e]+  , testCase "null15Encipher" $+      (encrypt wring0 (fromListN 15 $ stringToBytes "EncipherMessage"))+      @?= fromListN 15 [ 0x29, 0xb5, 0x8f, 0xd1, 0x67, 0xa7, 0xb3, 0xf6+                       , 0x99, 0x33, 0xa8, 0x47, 0x3c, 0xb4, 0xcf]   , testCase "aerate8nulls" $       (encrypt wring6 (fromListN 8 [0,0,0,0,0,0,0,0]))-      @?= fromListN 8 [0x23,0x44,0x2e,0x6e,0xf3,0xd7,0xa0,0x7e]+      @?= fromListN 8 [0x7d,0x9b,0x65,0x67,0xe8,0xa3,0xd2,0x7d]   , testCase "aerate8ff" $       (encrypt wring6 (fromListN 8 [255,255,255,255,255,255,255,255]))-      @?= fromListN 8 [0x7e,0x05,0xae,0x5c,0x64,0xdd,0xf4,0xeb]+      @?= fromListN 8 [0x2d,0xdc,0xb9,0xb7,0xaa,0x88,0xa2,0xcf]   , testCase "aerate8Twistree" $       (encrypt wring6 (fromListN 8 $ stringToBytes "Twistree"))-      @?= fromListN 8 [0x36,0x39,0x14,0x22,0x40,0x7f,0xc3,0x79]+      @?= fromListN 8 [0xc8,0xbc,0x27,0x92,0x7a,0x8d,0x96,0x97]   , testCase "aerate9nulls" $       (encrypt wring6 (fromListN 9 [0,0,0,0,0,0,0,0,0]))-      @?= fromListN 9 [0x41,0xc1,0x44,0x0f,0x07,0x2d,0x92,0xbf,0x43]+      @?= fromListN 9 [0xbe,0x74,0x4a,0x6c,0x6b,0x5b,0x2a,0x6c,0x4e]   , testCase "aerate9ff" $       (encrypt wring6 (fromListN 9 [255,255,255,255,255,255,255,255,255]))-      @?= fromListN 9 [0x46,0xb0,0x57,0x43,0xfb,0xdb,0x9d,0x32,0x88]+      @?= fromListN 9 [0xb3,0xb5,0xf1,0x9d,0x44,0xa3,0x19,0xd0,0x10]   , testCase "aerate9AllOrNone" $       (encrypt wring6 (fromListN 9 $ stringToBytes "AllOrNone"))-      @?= fromListN 9 [0x5e,0x3b,0x49,0xd4,0xb8,0x70,0xdd,0x07,0xac]+      @?= fromListN 9 [0xe8,0x23,0xcd,0x4d,0x80,0x5f,0xdb,0xb4,0x0a]+  , testCase "aerate15Encipher" $+      (encrypt wring6 (fromListN 15 $ stringToBytes "EncipherMessage"))+      @?= fromListN 15 [ 0x17, 0x95, 0x06, 0x84, 0x85, 0x6c, 0x0e, 0xed+                       , 0x68, 0x70, 0xe4, 0xdd, 0xeb, 0xd1, 0x92]   , testCase "χαίρετε8nulls" $       (encrypt wring30 (fromListN 8 [0,0,0,0,0,0,0,0]))-      @?= fromListN 8 [0x90,0x4d,0x00,0x3e,0x39,0x75,0x9e,0xe4]+      @?= fromListN 8 [0xa3,0x5d,0x2e,0x41,0xf3,0x20,0x9e,0x5c]   , testCase "χαίρετε8ff" $       (encrypt wring30 (fromListN 8 [255,255,255,255,255,255,255,255]))-      @?= fromListN 8 [0x85,0x56,0x3d,0x4e,0x84,0x5a,0x14,0xe3]+      @?= fromListN 8 [0xbf,0xab,0x12,0xd1,0xa4,0xa7,0x59,0x24]   , testCase "χαίρετε8Twistree" $       (encrypt wring30 (fromListN 8 $ stringToBytes "Twistree"))-      @?= fromListN 8 [0x96,0x89,0x48,0x50,0x98,0x26,0xeb,0x03]+      @?= fromListN 8 [0xf1,0x45,0xbe,0x34,0x3e,0x0e,0x50,0x44]   , testCase "χαίρετε9nulls" $       (encrypt wring30 (fromListN 9 [0,0,0,0,0,0,0,0,0]))-      @?= fromListN 9 [0x04,0xb0,0x1e,0xdf,0xd3,0xf0,0x39,0xa3,0x3c]+      @?= fromListN 9 [0x29,0x37,0x34,0x65,0xb4,0xe3,0xd6,0x8b,0x08]   , testCase "χαίρετε9ff" $       (encrypt wring30 (fromListN 9 [255,255,255,255,255,255,255,255,255]))-      @?= fromListN 9 [0x7c,0x67,0xeb,0xc8,0x40,0x97,0xc2,0x5f,0x82]+      @?= fromListN 9 [0xb9,0x31,0xfb,0xd0,0x08,0x42,0x24,0xe0,0x54]   , testCase "χαίρετε9AllOrNone" $       (encrypt wring30 (fromListN 9 $ stringToBytes "AllOrNone"))-      @?= fromListN 9 [0x4b,0xb2,0x68,0xe9,0xf1,0x64,0x0a,0x44,0xc4]+      @?= fromListN 9 [0xa3,0xab,0x75,0x4b,0xea,0x16,0x54,0xd6,0xa7]+  , testCase "χαίρετε15Encipher" $+      (encrypt wring30 (fromListN 15 $ stringToBytes "EncipherMessage"))+      @?= fromListN 15 [ 0x9b, 0x21, 0x52, 0x31, 0x35, 0x7c, 0xb4, 0x51+                       , 0x85, 0x6d, 0xbd, 0x1b, 0xf0, 0xf6, 0x4d]   , testCase "двор8nulls" $       (encrypt wring96 (fromListN 8 [0,0,0,0,0,0,0,0]))-      @?= fromListN 8 [0x9c,0xc1,0x3c,0xe7,0x8a,0xc5,0x6f,0x18]+      @?= fromListN 8 [0xb3,0x8c,0xb4,0x4e,0x32,0xef,0xd7,0xc8]   , testCase "двор8ff" $       (encrypt wring96 (fromListN 8 [255,255,255,255,255,255,255,255]))-      @?= fromListN 8 [0x37,0x42,0x00,0x47,0xd5,0x2f,0x9d,0x7f]+      @?= fromListN 8 [0x8d,0x0d,0x3c,0x89,0x73,0x22,0xe6,0x6b]   , testCase "двор8Twistree" $       (encrypt wring96 (fromListN 8 $ stringToBytes "Twistree"))-      @?= fromListN 8 [0x15,0x06,0xc6,0xa6,0x3d,0xef,0x19,0xf1]+      @?= fromListN 8 [0xb7,0x00,0x83,0x84,0x41,0x4d,0x14,0x4b]   , testCase "двор9nulls" $       (encrypt wring96 (fromListN 9 [0,0,0,0,0,0,0,0,0]))-      @?= fromListN 9 [0xd6,0x7b,0x2c,0xcc,0x71,0x24,0x5d,0x06,0x07]+      @?= fromListN 9 [0x84,0xfb,0x3e,0x5b,0x4f,0xce,0x43,0x54,0x84]   , testCase "двор9ff" $       (encrypt wring96 (fromListN 9 [255,255,255,255,255,255,255,255,255]))-      @?= fromListN 9 [0xd3,0xa8,0x3f,0xb6,0x9a,0x5e,0x0f,0x07,0x11]+      @?= fromListN 9 [0xed,0xa7,0x7a,0x91,0x3e,0x47,0xa4,0x1e,0x50]   , testCase "двор9AllOrNone" $       (encrypt wring96 (fromListN 9 $ stringToBytes "AllOrNone"))-      @?= fromListN 9 [0x53,0x6c,0x7e,0x2d,0xcd,0xda,0xdc,0xf2,0x70]+      @?= fromListN 9 [0x21,0x15,0x76,0xbc,0x8b,0x29,0x18,0x92,0x21]+  , testCase "двор15Encipher" $+      (encrypt wring96 (fromListN 15 $ stringToBytes "EncipherMessage"))+      @?= fromListN 15 [ 0x5d, 0x6d, 0x0c, 0xa5, 0xfb, 0x0d, 0x38, 0x74+                       , 0x6b, 0xd0, 0x41, 0x10, 0x80, 0xf3, 0x78]   , testCase "searchDir" $       (encrypt wring96 (fromList $ stringToBytes key96))       -- This comes from a typo when translating to Julia. All the 8- and 9-byte@@ -167,18 +187,18 @@       -- wrong, because it was searching in the wrong direction.       -- This typo would also cause all hashes of strings >31 bytes to be wrong.       @?= fromList-        [ 0xed, 0xbb, 0x75, 0xc4, 0xb2, 0xc9, 0xd2, 0x82-        , 0xa5, 0xbe, 0x37, 0x62, 0x4f, 0x5e, 0x7c, 0x1e -        , 0x22, 0x59, 0xca, 0x7a, 0x66, 0xb3, 0xa7, 0x91-        , 0x34, 0xec, 0x50, 0x2e, 0x45, 0x3e, 0xc5, 0xc3-        , 0xcc, 0xf3, 0xa3, 0x49, 0x72, 0x38, 0x3e, 0x5c-        , 0xf6, 0x91, 0x44, 0x1c, 0x04, 0xf7, 0x80, 0x45 -        , 0xdb, 0x9c, 0xcb, 0xe6, 0x08, 0xa2, 0x8d, 0x6a-        , 0x5d, 0x28, 0x68, 0x93, 0x43, 0xa8, 0xb2, 0x65-        , 0x2b, 0xc3, 0x1e, 0xa3, 0x70, 0xcc, 0x1e, 0x40-        , 0xee, 0x7d, 0xa8, 0x19, 0x00, 0x72, 0x1e, 0x19 -        , 0x46, 0xb1, 0x18, 0x6d, 0x9c, 0x7d, 0x88, 0x59-        , 0x1b, 0x25, 0x01, 0x5d, 0x9d, 0xd7, 0x7c, 0x6d+        [ 0x45, 0x34, 0xac, 0xc5, 0xda, 0x60, 0xe1, 0x0f+        , 0xbf, 0x17, 0x5d, 0xc7, 0x4c, 0xfc, 0x96, 0xe2+        , 0xe9, 0x7a, 0x49, 0x58, 0x38, 0x74, 0x0f, 0x30+        , 0x42, 0x30, 0xcc, 0x39, 0x96, 0x2b, 0x1e, 0xd8+        , 0x1c, 0x82, 0x76, 0x82, 0x65, 0x09, 0xb3, 0xd8+        , 0x31, 0xa6, 0xd2, 0xec, 0x36, 0xdd, 0x80, 0x8a+        , 0x7b, 0x24, 0x56, 0x3e, 0x37, 0xe7, 0x20, 0x68+        , 0x45, 0x1f, 0x15, 0xa8, 0xf2, 0x17, 0xb3, 0xd5+        , 0x78, 0x48, 0xef, 0xc5, 0x73, 0xa6, 0x5c, 0x3c+        , 0x07, 0x11, 0xe2, 0x76, 0xc0, 0xeb, 0xc3, 0xf1+        , 0x96, 0x24, 0xb4, 0x8e, 0xdf, 0x94, 0xba, 0x4d+        , 0x67, 0x2f, 0xc5, 0x6f, 0x4a, 0x5d, 0x85, 0x7e         ]   ]