diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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
 
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -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`.
 
diff --git a/WringTwistree.cabal b/WringTwistree.cabal
--- a/WringTwistree.cabal
+++ b/WringTwistree.cabal
@@ -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
diff --git a/app/Cryptanalysis.hs b/app/Cryptanalysis.hs
--- a/app/Cryptanalysis.hs
+++ b/app/Cryptanalysis.hs
@@ -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
diff --git a/app/Stats.hs b/app/Stats.hs
--- a/app/Stats.hs
+++ b/app/Stats.hs
@@ -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
diff --git a/src/Cryptography/Twistree.hs b/src/Cryptography/Twistree.hs
--- a/src/Cryptography/Twistree.hs
+++ b/src/Cryptography/Twistree.hs
@@ -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)
diff --git a/src/Cryptography/Wring.hs b/src/Cryptography/Wring.hs
--- a/src/Cryptography/Wring.hs
+++ b/src/Cryptography/Wring.hs
@@ -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
diff --git a/src/Cryptography/WringTwistree/Mix3.hs b/src/Cryptography/WringTwistree/Mix3.hs
--- a/src/Cryptography/WringTwistree/Mix3.hs
+++ b/src/Cryptography/WringTwistree/Mix3.hs
@@ -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
diff --git a/src/Cryptography/WringTwistree/RotBitcount.hs b/src/Cryptography/WringTwistree/RotBitcount.hs
--- a/src/Cryptography/WringTwistree/RotBitcount.hs
+++ b/src/Cryptography/WringTwistree/RotBitcount.hs
@@ -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
diff --git a/src/Cryptography/WringTwistree/Sboxes.hs b/src/Cryptography/WringTwistree/Sboxes.hs
--- a/src/Cryptography/WringTwistree/Sboxes.hs
+++ b/src/Cryptography/WringTwistree/Sboxes.hs
@@ -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 #-}
diff --git a/test/Spec.hs b/test/Spec.hs
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -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
         ]
   ]
 
