candid 0.3.1 → 0.3.2
raw patch · 4 files changed
+23/−14 lines, 4 files
Files
- CHANGELOG.md +4/−0
- candid.cabal +1/−1
- src/Codec/Candid/Hash.hs +12/−5
- test/test.hs +6/−8
CHANGELOG.md view
@@ -1,5 +1,9 @@ # Revision history for haskell-candid +## 0.3.2 -- 2022-10-07++* Candid hash reversal: Also try upper case+ ## 0.3.1 -- 2022-01-10 * GHC-9.0 compatibility
candid.cabal view
@@ -1,6 +1,6 @@ cabal-version: >=1.10 name: candid-version: 0.3.1+version: 0.3.2 license: Apache license-file: LICENSE maintainer: mail@joachim-breitner.de
src/Codec/Candid/Hash.hs view
@@ -30,18 +30,23 @@ invertHash w32 = listToMaybe guesses where x = fromIntegral w32 :: Word64+ chars = ['a'..'z'] ++ ['_'] ords = 0 : map (fromIntegral . ord) chars+ init_chars = chars ++ [ 'A'..'Z' ]+ init_ords = 0 : map (fromIntegral . ord) init_chars+ non_mod x = x - (x `mod` 2^(32::Int)) guesses = [ T.pack $ reverse guess- | c8 <- ords, c7 <- ords, c6 <- ords, c5 <- ords+ | c8 <- init_ords, c7 <- ords, c6 <- ords, c5 <- ords -- It seems that 8 characters are enough to invert anything -- (based on quickchecking) -- Set up so that short guesses come first , let high_chars = c5 * 223^(4::Int) + c6 * 223^(5::Int) + c7 * 223^(6::Int) + c8 * 223^(7::Int) , let guess = simple $ x + non_mod high_chars- , all (`elem` chars) guess+ , all (`elem` init_chars) (take 1 guess)+ , all (`elem` chars) (drop 1 guess) ] -- inverts the Hash if the hash was created without modulos@@ -52,8 +57,10 @@ where (a, b) = x `divMod` 223 -- Word list obtained from https://github.com/dwyl/english-words-ws :: T.Text-ws = $(embedStringFile "words.txt")+wordFile :: T.Text+wordFile = $(embedStringFile "words.txt") m :: M.IntMap T.Text-m = M.fromList [ (fromIntegral (candidHash w), w) | w <- T.lines ws]+m = M.fromList [ (fromIntegral (candidHash w), w) | w <- word_list ]+ where+ word_list = T.lines wordFile ++ map T.toTitle (T.lines wordFile)
test/test.hs view
@@ -322,8 +322,8 @@ in [ t True "(true)" , t (SimpleRecord False 42) "(record {bar = (42 : nat8); foo = false})"- , t (JustRight (Just (3 :: Natural))) "(variant {gp_jocd = opt 3})"- , t (JustRight (3 :: Word8)) "(variant {gp_jocd = (3 : nat8)})"+ , t (JustRight (Just (3 :: Natural))) "(variant {Right = opt 3})"+ , t (JustRight (3 :: Word8)) "(variant {Right = (3 : nat8)})" , t () "()" , t (Unary ()) "(null)" , t (Unary (True, False)) "(record {true; false})"@@ -409,13 +409,11 @@ let f' = unescapeFieldName (escapeFieldName f) in f' == f , testGroup "candid hash inversion"- [ QC.testProperty "small names invert" $- QC.forAll (QC.choose (0,4)) $ \len ->- QC.forAll (T.pack <$> QC.vectorOf len (QC.elements ('_':['a'..'z']))) $ \s ->- candidHash s >= 32 QC.==>- invertHash (candidHash s) QC.=== Just s- , QC.testProperty "long dictionary name" $+ [ QC.testProperty "long dictionary name" $ let s = "precriticized" in+ invertHash (candidHash s) QC.=== Just s+ , QC.testProperty "long capitalized dictionary name" $+ let s = "Precriticized" in invertHash (candidHash s) QC.=== Just s , QC.testProperty "all hashes find something" $ QC.forAll QC.arbitraryBoundedIntegral $ \w ->