WMSigner (empty) → 0.1.0.0
raw patch · 8 files changed
+607/−0 lines, 8 filesdep +basedep +base64-bytestringdep +binarysetup-changed
Dependencies added: base, base64-bytestring, binary, bytestring, cryptohash, directory, hspec, lens, mtl, random, split, vector
Files
- LICENSE +21/−0
- Setup.hs +2/−0
- WMSigner.cabal +63/−0
- src/Data/Digest/WebMoney.hs +20/−0
- src/Data/Digest/WebMoney/Algebra.hs +172/−0
- src/Data/Digest/WebMoney/Montgomery.hs +114/−0
- src/Data/Digest/WebMoney/Signer.hs +102/−0
- test/Spec.hs +113/−0
+ LICENSE view
@@ -0,0 +1,21 @@+The MIT License (MIT)++Copyright (c) 2014 Ilya++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ WMSigner.cabal view
@@ -0,0 +1,63 @@+name: WMSigner+version: 0.1.0.0+synopsis: WebMoney authentication module+description:+ Pure haskell implementation WMSigner authentication module.+ .+ Simple examples:+ .+ > import Data.Digest.Webmoney+ >+ > signer = newSigner (exponent :: [Word8) (modulus :: [Word8])+ >+ > main = do+ > putStrLn $ signUnsafe signer "message" -- static version+ > sign signer "message" >>= putStrLn -- randomized version+license: MIT+license-file: LICENSE+copyright: Ilya Smelkov <triplepointfive@gmail.com>+author: Ilya Smelkov <triplepointfive@gmail.com>+maintainer: Ilya Smelkov <triplepointfive@gmail.com>+category: Data, Cryptography+build-type: Simple+cabal-version: >=1.8++library+ exposed-modules: Data.Digest.WebMoney+ other-modules: Data.Digest.WebMoney.Signer+ Data.Digest.WebMoney.Montgomery+ Data.Digest.WebMoney.Algebra+ build-depends: base >=4.6 && <4.8+ , bytestring >= 0.10+ , directory >= 1.0.0.0+ , cryptohash+ , random+ , vector >= 0.10+ , base64-bytestring >= 1+ , binary >= 0.5+ , random >= 1.0.1+ , mtl >= 2.1+ , split >= 0.2+ , lens >= 4.4+ hs-source-dirs: src+ ghc-options: -Wall -fno-warn-unused-do-bind -fno-warn-missing-signatures++Test-Suite test-WMSigner+ type: exitcode-stdio-1.0+ main-is: Spec.hs+ build-depends: base+ , hspec+ , lens >= 4.4+ , bytestring >= 0.10+ , split >= 0.2+ , cryptohash+ , random+ , vector >= 0.10+ buildable: True+ cpp-options: -DTEST_MODE=true+ hs-source-dirs: src test+ ghc-options: -Wall -fno-warn-unused-do-bind -fno-warn-missing-signatures++source-repository head+ type: git+ location: git://github.com/triplepointfive/wmsigner
+ src/Data/Digest/WebMoney.hs view
@@ -0,0 +1,20 @@+module Data.Digest.WebMoney+ (+ newSigner+ , sign+ , signUnsafe+ , S.Signer+ )+ where++import qualified Data.Digest.WebMoney.Signer as S (Signer, newSigner, sign,+ signUnsafe)++-- |Initializes new 'Signer' object, takes exponent and modulus as arguments+newSigner = S.newSigner++-- |Calculates static signature for string+signUnsafe = S.signUnsafe++-- |Calculates randomized signature for string+sign = S.sign
+ src/Data/Digest/WebMoney/Algebra.hs view
@@ -0,0 +1,172 @@+module Data.Digest.WebMoney.Algebra where++import Data.Bits (Bits, bitSize, shiftL, shiftR, testBit, (.&.),+ (.|.))+import Data.Int (Int32, Int64)+import Data.Word (Word32, Word64)++import Control.Lens (ix, (&), (.~))+import Data.Vector (Vector, singleton, (!))+import qualified Data.Vector as V (init, last, length, null, replicate, take,+ (++))++longMask :: Int64+longMask = 0xFFFFFFFF++intSize :: Int+intSize = 32++logicalShiftR :: Integral a => a -> Int -> a+logicalShiftR x i = fromIntegral ((fromIntegral x :: Word64) `shiftR` i)++logicalShiftRight :: Int32 -> Int -> Int32+logicalShiftRight x i = fromIntegral ((fromIntegral x :: Word32) `shiftR` i)++getBitsNumber :: Bits a => a -> Int+getBitsNumber x = intSize - numberOfLeadingZeros x++numberOfLeadingZeros :: Bits a => a -> Int+numberOfLeadingZeros x = length $ takeWhile (not . testBit x) [size - 1, size - 2 .. 0]+ where size = bitSize x++getBitsCount :: (Bits a, Num a) => Vector a -> Int+getBitsCount xs = ( vLenght - 1 ) * intSize + getBitsNumber ( xs ! (vLenght - 1) )+ where vLenght = significance xs++compareLists :: Vector Int32 -> Vector Int32 -> Ordering+compareLists lhs rhs+ | lhsLenght > rhsLenght = GT+ | lhsLenght < rhsLenght = LT+ | otherwise = comp (V.take lhsLenght lhs) (V.take lhsLenght rhs)+ where+ lhsLenght = significance lhs+ rhsLenght = significance rhs++ comp :: Vector Int32 -> Vector Int32 -> Ordering+ comp ls rs+ | V.null ls || V.null rs = EQ+ | lb > rb = GT+ | lb < rb = LT+ | otherwise = comp (V.init ls) (V.init rs)+ where+ lb = fromIntegral (V.last ls) .&. longMask+ rb = fromIntegral (V.last rs) .&. longMask++significance :: (Eq a, Bits a, Num a) => Vector a -> Int+significance xs+ | V.null xs = 0+ | V.last xs == 0 = significance ( V.init xs )+ | otherwise = V.length xs++shift :: Vector Int32 -> Int -> Vector Int32+shift lhs rhs+ | outWordsCount <= 0 = singleton 0+ | shiftBits == 0 && rhs > 0 = V.take shiftWords r0 V.++ V.take (outWordsCount - shiftWords) lhs+ | rhs > 0 =+ let (res, carry) = foldl shRight (r0, 0) [0 .. inWordsCount - 1]+ in if inWordsCount - 1 + shiftWords < outWordsCount+ then res & ix ( inWordsCount + shiftWords ) .~ (res ! (inWordsCount + shiftWords) .|. carry)+ else res+ | shiftBits == 0 = error "3"+ | otherwise =+ let carry = if outWordsCount + shiftWords < inWordsCount+ then (lhs ! (outWordsCount + shiftWords)) `shiftL` ( intSize - shiftBits)+ else 0+ in fst $ foldl shLeft (r0, carry) [inWordsCount - 1, inWordsCount - 2 .. 0]+ where+ shiftBits, shiftWords, inBitsCount, inWordsCount, outBitsCount, outWordsCount :: Int+ shiftBits = abs rhs `mod` intSize+ shiftWords = abs rhs `div` intSize+ inBitsCount = getBitsCount lhs+ inWordsCount = inBitsCount `div` intSize + (if inBitsCount `mod` intSize > 0 then 1 else 0)+ outBitsCount = inBitsCount + rhs+ outWordsCount = outBitsCount `div` intSize + (if outBitsCount `mod` intSize > 0 then 1 else 0)++ r0 = V.replicate (max inWordsCount outWordsCount) 0++ shRight, shLeft :: (Vector Int32, Int32) -> Int -> (Vector Int32, Int32)+ shRight (res, carry) pos = ( res & ix ( pos + shiftWords ) .~ val, nextCarry )+ where+ temp = lhs ! pos+ val = ( temp `shiftL` shiftBits ) .|. carry+ nextCarry = temp `logicalShiftRight` ( intSize - shiftBits )+ shLeft (res, carry) pos = ( res & ix ( pos + shiftWords ) .~ val, nextCarry )+ where+ temp = lhs ! (pos + shiftWords)+ val = (temp `logicalShiftRight` shiftBits) .|. carry+ nextCarry = temp `shiftL` ( intSize - shiftBits )++shiftRight :: Vector Int32 -> Vector Int32+shiftRight value = fst $ foldl right (value, 0) [len-1, len-2..0]+ where+ len = significance value+ right :: (Vector Int32, Int64) -> Int -> (Vector Int32, Int64)+ right (v, carry) pos = ( v & ix pos .~ fromIntegral val, nextCarry )+ where+ temp, nextCarry, val :: Int64+ temp = fromIntegral ( v ! pos) .&. longMask+ nextCarry = (temp .&. 1) `shiftL` ( intSize - 1) .&. longMask+ val = ((temp `logicalShiftR` 1) .|. carry ) .&. longMask++sub :: Vector Int32 -> Vector Int32 -> Vector Int32+sub lhs rhs+ | lhsLength < rhsLength = error "Difference should not be negative."+ | otherwise = modulo $ rest subscribed+ where+ lhsLength = significance lhs+ rhsLength = significance rhs++ modulo :: (Vector Int32, Int32) -> Vector Int32+ modulo (_, 1) = error "Difference should not be negative."+ modulo (l, _) = l++ subscribed :: (Vector Int32, Int32)+ subscribed = foldl substr (lhs, 0) [0..rhsLength - 1]+ where+ substr :: (Vector Int32, Int32) -> Int -> (Vector Int32, Int32)+ substr (l, borrow) pos = ( l & ix pos .~ fromIntegral temp, nBorrow )+ where+ temp = (fromIntegral ( l ! pos ) .&. longMask )+ - (fromIntegral ( rhs ! pos ) .&. longMask )+ - fromIntegral borrow+ nBorrow = if temp .&. ( 1 `shiftL` intSize ) /= 0 then 1 else 0++ rest :: (Vector Int32, Int32) -> (Vector Int32, Int32)+ rest (ls, b) = foldl substr (ls, b) [rhsLength..lhsLength - 1]+ where+ substr :: (Vector Int32, Int32) -> Int -> (Vector Int32, Int32)+ substr (l, borrow) pos = ( l & ix pos .~ fromIntegral temp, nBorrow )+ where+ temp = (fromIntegral ( l ! pos ) .&. longMask ) - fromIntegral borrow+ nBorrow = if temp .&. ( 1 `shiftL` intSize ) /= 0 then 1 else 0++remainder :: Vector Int32 -> Vector Int32 -> Vector Int32+remainder lhs rhs = divide lhs rhs+ where+ rhsBitsCount = getBitsCount rhs -- check attemption to divide by zero++ divide :: Vector Int32 -> Vector Int32 -> Vector Int32+ divide l r+ | LT == compareLists l r = l+ | lhsBitsCount == 0 = l+ | otherwise =+ let temp' = if compareLists l temp == LT then shiftRight temp else temp+ in divide ( subs l temp' ) r+ where+ lhsBitsCount = getBitsCount l+ temp = shift r (lhsBitsCount - rhsBitsCount)+ subs :: Vector Int32 -> Vector Int32 -> Vector Int32+ subs l t =+ if compareLists l t /= LT+ then subs (sub l t) t+ else l++resize :: Vector Int32 -> Int -> Vector Int32+resize v l+ | l < 0 = error "Invalid value for length"+ | vLength < l = v V.++ V.replicate (l - vLength) 0+ | otherwise = V.take l v+ where vLength = V.length v++normalize :: Vector Int32 -> Vector Int32+normalize x = resize x ( significance x )
+ src/Data/Digest/WebMoney/Montgomery.hs view
@@ -0,0 +1,114 @@+module Data.Digest.WebMoney.Montgomery where++import Control.Lens (ix, (&), (.~))+import Data.Bits (Bits, shiftL, shiftR, (.&.))+import Data.Int (Int32, Int64)++import Data.Digest.WebMoney.Algebra (logicalShiftR, normalize,+ remainder, resize, significance)++import Data.Vector (Vector, cons, snoc, (!))+import qualified Data.Vector as V (head, length, replicate)++intSize, longMask :: Int+intSize = 32+longMask = 0xFFFFFFFF++bitMask :: Int64+bitMask = 0x80000000++-- Algorithm Montgomery exponentiation+-- INPUT:+-- m = (m[l-1] ... m[0]){b},+-- R = b^l,+-- mQ = m^-1 mod b,+-- e = (e[t] ... e[0]){2}+-- with e[t] = 1,+-- and an integer x, 1 <= x < m.+-- OUTPUT: x^e mod m.+exponentation :: Vector Int32 -> Vector Int32 -> Vector Int32 -> Vector Int32+exponentation x e m = normalize a3+ where+ -- mQ = -m^1 mod b+ mQ = inverse $ V.head m+ eLength = significance e+ mLength = significance m+ -- 1. temp = Mont(x, R^2 mod m), A = R mod m.+ temp = multiplication x' r2 m mQ+ where+ r = V.replicate ( 2 * V.length m ) 0 `snoc` 1+ r2 = remainder r m+ x' = if mLength > V.length x then resize x mLength else x+ a0 = remainder a' m+ where+ a' = V.replicate (V.length m) 0 `snoc` 1++ pos0 = eLength - 1++ mask0 :: Int64+ mask0 = head $ dropWhile (\mask -> fromIntegral (e ! pos0) .&. mask == 0) $ iterate (`logicalShiftR` 1) bitMask++ -- 2. For i from t down to 0 do the following:+ a2 = mont a0 pos0 mask0+ mont :: Vector Int32 -> Int -> Int64 -> Vector Int32+ mont a pos mask+ | pos < 0 = a+ | mask' == 0 = mont a'' (pos - 1) bitMask+ | otherwise = mont a'' pos mask'+ where+ -- 2.1 A = Mont(A, A).+ a' = multiplication a a m mQ+ -- 2.2 If e[i] = 1 then A = Mont(A, temp).+ a'' = if 0 /= fromIntegral (e ! pos) .&. mask then multiplication a' temp m mQ else a'+ mask' = mask `shiftR` 1++ -- 3. A Mont(A, 1).+ one = 1 `cons` V.replicate (V.length m - 1) 0+ a3 = multiplication a2 one m mQ++-- Algorithm Montgomery multiplication+-- INPUT: integers+-- m = (m[n-1] ... m[1] m[0]){b},+-- x = (x[n-1] ... x[1] x[0]){b},+-- y = (y[n-1] ... y[1] y[0]){b}+-- with 0 <= x, y < m,+-- R = b^n with gcd(m, b) = 1,+-- and mQ = -m^1 mod b.+-- OUTPUT: x * y * R^-1 mod m.+multiplication :: Vector Int32 -> Vector Int32 -> Vector Int32 -> Int32 -> Vector Int32+multiplication x y m mQ = foldl iter a0 [0..n-1]+ where+ n = significance m+ -- 1. A = 0. (Notation: A = (a[n] a[n-1] ... a[1] a[0]){b})+ a0 = V.replicate (n + 1) 0+ -- 2. For i from 0 to (n - 1) do the following:+ iter :: Vector Int32 -> Int -> Vector Int32+ iter a i = ( fin_a & ix ( n - 1 ) .~ fromIntegral fin_carry ) & ix n .~ fromIntegral ( fin_carry `logicalShiftR` intSize )+ where+ -- 2.1 u_i = (a[0] + x[i] * y[0]) * mQ mod b.+ u :: Int+ u = (( fromIntegral (V.head a)+ + (((fromIntegral (x ! i) .&. longMask) * (fromIntegral (V.head y) .&. longMask)) .&. longMask))+ * fromIntegral mQ ) .&. longMask+ -- 2.2 A = (A + x[i] * y + u_i * m) / b.+ proc :: (Int, Vector Int32) -> Int -> (Int, Vector Int32)+ proc (last_carry, a') pos = (carry, a' & ix ( pos - 1 ) .~ fromIntegral temp)+ where+ xy, um, temp, carry :: Int+ xy = (fromIntegral (x ! i) .&. longMask) * (fromIntegral (y ! pos) .&. longMask)+ um = u * (fromIntegral (m ! pos) .&. longMask)+ temp = (fromIntegral (a' ! pos) .&. longMask)+ + (xy .&. fromIntegral longMask)+ + (um .&. fromIntegral longMask)+ + (last_carry .&. fromIntegral longMask)+ carry = (last_carry `logicalShiftR` 32)+ + (xy `logicalShiftR` intSize)+ + (um `logicalShiftR` intSize)+ + (temp `logicalShiftR` intSize)+ (carry', fin_a) = foldl proc (0, a) [0..n-1]+ fin_carry = carry' + (fromIntegral ( fin_a ! n ) .&. longMask)++inverse :: ( Num a, Bits a ) => a -> a+inverse value = -1 * ( iterate (\t -> t * ( 2 - value * t) ) temp !! 4 )+ where+ temp = ( ( ( value + 2 ) .&. 4 ) `shiftL` 1 ) + value
+ src/Data/Digest/WebMoney/Signer.hs view
@@ -0,0 +1,102 @@+{-# LANGUAGE GADTs #-}++module Data.Digest.WebMoney.Signer where++import Control.Monad (replicateM)+import Data.Bits (shiftL, (.|.))+import Data.Char (ord)+import Data.Int (Int16, Int32)+import Data.List (foldl')+import Data.Word (Word8)+import System.Random (randomIO)+import Text.Printf (printf)++import Crypto.Hash.MD4 (hash)+import qualified Data.ByteString as B (ByteString, elem, pack,+ unpack)+import qualified Data.ByteString.Internal as B (c2w)+import Data.List.Split (chunksOf)++import Data.Digest.WebMoney.Algebra (logicalShiftRight,+ significance)+import Data.Digest.WebMoney.Montgomery (exponentation)++import Data.Vector (Vector, fromList, (!))++intSize, shortSize, byteSize, hashSize :: Int+intSize = 32+shortSize = 16+byteSize = 8+hashSize = 128++header, trail :: [Word8]+header = [0x38, 0]+trail = [1, 0]++data Signer where+ Signer :: { expon :: !(Vector Int32)+ , modulus :: !(Vector Int32)+ , keyLength :: !Int+ } -> Signer++newSigner :: [Word8] -> [Word8] -> Signer+newSigner expon' modul = Signer { expon = fromList (cast expon')+ , modulus = modulus'+ , keyLength = significance (fromList modul) * byteSize+ }+ where modulus' = fromList (cast modul)++-- |Calculates static signature for string+signUnsafe :: Signer -> String -> String+signUnsafe signer = signWithBuffer signer (zeroBuffer signer)++-- |Calculates randomized signature for string+sign :: Signer -> String -> IO String+sign signer message = do+ rndBuf <- randomBuffer signer+ return $ signWithBuffer signer rndBuf message++signWithBuffer :: Signer -> [Word8] -> String -> String+signWithBuffer signer buffer =+ buildSignature signer . signBytes signer buffer . validate . B.pack . map ( fromIntegral . ord )++validate :: B.ByteString -> B.ByteString+validate message = if B.c2w '\r' `B.elem` message+ then error "Message cannot contain of the following character: '\r'."+ else message++zeroBuffer :: Signer -> [Word8]+zeroBuffer signer = replicate (bufferLength signer) 0++randomBuffer :: Signer -> IO [Word8]+randomBuffer signer = replicateM (bufferLength signer) randomIO++bufferLength :: Signer -> Int+bufferLength signer = keyLength signer `div` byteSize+ - length header+ - hashSize `div` byteSize+ - length trail++buildSignature :: Signer -> Vector Int32 -> String+buildSignature signer signature = concat+ [ if significance signature > pos `div` ( intSize `div` shortSize )+ then+ let+ shift = if 0 == pos `mod` ( intSize `div` shortSize ) then 0 else shortSize :: Int+ letter = signature ! fromIntegral (pos `div` ( intSize `div` shortSize ))+ in printf "%04x" (fromIntegral (letter `logicalShiftRight` shift) :: Int16)+ else+ printf "%04x" ( 0 :: Int )+ | pos <- [0, 1 .. keyLength signer `div` shortSize - 1]+ ]++signBytes :: Signer -> [Word8] -> B.ByteString -> Vector Int32+signBytes signer rndBuffer message = exponentation (fromList $ cast blob) (expon signer) (modulus signer)+ where blob = header ++ B.unpack ( hash message ) ++ rndBuffer ++ trail++cast :: Integral a => [a] -> [Int32]+cast xs = map ( fromOctets . reverse ) $ chunksOf 4 xs++fromOctets :: Integral a => [a] -> Int32+fromOctets = foldl' accum 0+ where accum a o = (a `shiftL` 8) .|. fromIntegral o
+ test/Spec.hs view
@@ -0,0 +1,113 @@+module Main where++import Data.Int (Int32)++import Data.Digest.WebMoney.Algebra+import Data.Digest.WebMoney.Montgomery+import Data.Digest.WebMoney.Signer++import qualified Data.ByteString as B (pack)+import Data.Vector (Vector, fromList)+import Test.Hspec++signer :: Signer+signer = newSigner+ [125, -78, 54, 8, -67, -98, -116, 15, -88, -19, -82, 2, 108, 41, 89, 27, 34, -80, -49, 55, -62, -2, -89, 19, -79, 41, -65, 11, -120, 87, -64, 89, 27, -67, -92, -23, -77, 29, 46, -52, 95, -96, -113, -32, -99, -26, -95, -27, 12, 108, -18, -101, -46, 103, -29, -112, 16, -50, -67, 88, -2, -86, 40, -69, -65, 0]+ [85, 31, -1, -98, -62, -2, -13, 76, -48, 2, 103, -66, -71, -41, -49, 106, 114, 99, 102, -28, -55, 93, -75, 98, 119, 68, 60, 66, 123, 101, -99, -16, 30, 118, -66, 123, 77, -103, -59, -116, -92, -90, 9, 98, 108, -92, -111, -108, -18, -62, -20, -35, 83, -11, 115, 70, -20, -42, -31, -80, -44, -53, -42, -16, 110, 5]++main :: IO ()+main = hspec $ do+ describe "Signer" $ do+ it "signBytes" $ do+ ( signBytes+ signer+ (replicate 46 0)+ (B.pack [109, 101, 115, 115, 97, 103, 101]))+ `shouldBe`+ (fromList [1420192846, -514184231, -858634323, -658448382, 52207915, -437346630, -666018004, -2043170752, 1241009014, 879655623, -1601019036, -1233902541, 17763596, -1169198420, 1209444264, 223198074, 1327])+ it "buildSignature" $ do+ ( buildSignature+ signer+ (fromList [1420192846, -514184231, -858634323, -658448382, 52207915, -437346630, -666018004, -2043170752, 1241009014, 879655623, -1601019036, -1233902541, 17763596, -1169198420, 1209444264, 223198074, 1327]))+ `shouldBe`+ "6c4e54a62bd9e15a47adccd2e002d8c0a12b031c9ebae5ee5f2cd84db04086374b7649f87ac7346e6364a0922433b6740d0c010f72acba4fa7a84816bb7a0d4d052f"+ it "blank" $ do+ ( signUnsafe+ signer+ " ")+ `shouldBe`+ "d5295349168cdb6fdbdb9c1984836cc1db939dda1dd6e18112db007154db8065b25583c71bd952f88f24f2515fbc4bb3037e5cedd5ef33cd336960b6a655537304bf"+ it "symbols" $ do+ ( signUnsafe+ signer+ "!@#$%^&*()-=_{}[]\"'1234567890.,%:?<>/\\")+ `shouldBe`+ "61b8260b9d5d7cce8e1c0262f0722b8114a7b3e233d76f4b93d08933a89d23d73acfb2d960966b0c175a8604e7c71c391b7f2a64743b3c3b11c5d07ed224445300b3"+ it "specSymbols" $ do+ ( signUnsafe+ signer+ "\n\n\n\n\t\t\t\t\n\n\n\n")+ `shouldBe`+ "c37c96e02f8678a13a43a3bade0ba77275da0d9869d18856daaf4b413106a9bfea74054462d851a0c5a2596dbf9c371284c61b3741b35343c91d2978db328c2f00c9"+ describe "Montgomery" $ do+ it "multiplication" $ do+ ( multiplication+ (fromList [-1476460488, -1118323957, 1120423587, -1596341302, 43673, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1])+ (fromList [887153153, 1663090240, 2023161700, -1792225711, -2037349738, 431338827, 936480955, 1341971236, 1200687489, 795067959, -325209191, 1292772351, 905855361, -230695685, -1798442900, 313894787, 1080, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])+ (fromList [-1627447467, 1291058882, -1100545328, 1792006073, -463051918, 1656053193, 1111245943, -258120325, 2076079646, -1933207219, 1644799652, -1802394516, -571686162, 1182004563, -1327376660, -254358572, 1390])+ 3397655043)+ `shouldBe`+ (fromList [629254954, -1321769800, 1900654924, 2056436422, 1791614990, 475542676, 547583796, 1358516486, 1650142553, -1578392030, -1395505261, 1389520284, -494774702, 536840267, 790850704, -1567780526, 64, 0])+ it "exponentaion" $ do+ ( exponentation+ (fromList [-1476460488, -1118323957, 1120423587, -1596341302, 43673, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1])+ (fromList [137802365, 260873917, 45018536, 458828140, 936357922, 329776834, 197077425, 1505777544, -375079653, -869392973, -527458209, -442374499, -1678873588, -1864144942, 1488834064, -1154962690, 191])+ (fromList [-1627447467, 1291058882, -1100545328, 1792006073, -463051918, 1656053193, 1111245943, -258120325, 2076079646, -1933207219, 1644799652, -1802394516, -571686162, 1182004563, -1327376660, -254358572, 1390]) )+ `shouldBe`+ (fromList [1420192846, -514184231, -858634323, -658448382, 52207915, -437346630, -666018004, -2043170752, 1241009014, 879655623, -1601019036, -1233902541, 17763596, -1169198420, 1209444264, 223198074, 1327])+ describe "Algebra" $ do+ it "reminder" $ do+ ( remainder+ (fromList [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1])+ (fromList [-1627447467, 1291058882, -1100545328, 1792006073, -463051918, 1656053193, 1111245943, -258120325, 2076079646, -1933207219, 1644799652, -1802394516, -571686162, 1182004563, -1327376660, -254358572, 1390]) )+ `shouldBe`+ (fromList [1602626370, 296859807, -1933305503, 1018504923, 2106164031, -469194707, 1605789230, 1881367321, 127989226, -1751912682, 2087886977, 1741983051, -1090589209, 1428161158, 647631356, -121976833, 889, 0])+ it "getBitsCount" $ do+ ( getBitsCount+ (fromList [-1627447467, 1291058882, -1100545328, 1792006073, -463051918, 1656053193, 1111245943, -258120325, 2076079646, -1933207219, 1644799652, -1802394516, -571686162, 1182004563, -1327376660, -254358572, 1390] :: Vector Int32))+ `shouldBe`+ 523+ it "getBitsCount" $ do+ ( getBitsCount+ (fromList [358612992, 665591836, -1510579840, 147338015, -1850563067, 1187214131, 1897113940, 1352120439, 1008856147, -699365327, 728655692, 1920188107, -1574081077, 1434731111, 578236801, -2056657979, 1377953062, 0] :: Vector Int32))+ `shouldBe`+ 543+ it "comparison with equal length" $ do+ ( compareLists+ (fromList [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1])+ (fromList [-1627447467, 1291058882, -1100545328, 1792006073, -463051918, 1656053193, 1111245943, -258120325, 2076079646, -1933207219, 1644799652, -1802394516, -571686162, 1182004563, -1327376660, -254358572, 1390]) )+ `shouldBe`+ GT+ it "comparison with different length" $ do+ ( compareLists+ (fromList [358612992, 665591836, -1510579840, 147338015, -1850563067, 1187214131, 1897113940, 1352120439, 1008856147, -699365327, 728655692, 1920188107, -1574081077, 1434731111, 578236801, -2056657979, 1377953062, 0])+ (fromList [-1627447467, 1291058882, -1100545328, 1792006073, -463051918, 1656053193, 1111245943, -258120325, 2076079646, -1933207219, 1644799652, -1802394516, -571686162, 1182004563, -1327376660, -254358572, 1390]) )+ `shouldBe`+ GT+ it "sub" $ do+ ( sub+ (fromList [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1])+ (fromList [-358612992, -665591837, 1510579839, -147338016, 1850563066, -1187214132, -1897113941, -1352120440, -1008856148, 699365326, -728655693, -1920188108, 1574081076, -1434731112, -578236802, 2056657978, -1377953063, 0]) )+ `shouldBe`+ (fromList [358612992, 665591836, -1510579840, 147338015, -1850563067, 1187214131, 1897113940, 1352120439, 1008856147, -699365327, 728655692, 1920188107, -1574081077, 1434731111, 578236801, -2056657979, 1377953062, 0])+ it "shiftRight" $ do+ ( shiftRight+ (fromList [-717225984, -1331183673, -1273807617, -294676032, -593841163, 1920539032, 500739415, 1590726417, -2017712295, 1398730653, -1457311386, 454591081, -1146805143, 1425505072, -1156473603, -181651339, 1539061170, 1]))+ `shouldBe`+ (fromList [-358612992, -665591837, 1510579839, -147338016, 1850563066, -1187214132, -1897113941, -1352120440, -1008856148, 699365326, -728655693, -1920188108, 1574081076, -1434731112, -578236802, 2056657978, -1377953063, 0])+ it "shift" $ do+ ( shift+ (fromList [-1627447467, 1291058882, -1100545328, 1792006073, -463051918, 1656053193, 1111245943, -258120325, 2076079646, -1933207219, 1644799652, -1802394516, -571686162, 1182004563, -1327376660, -254358572, 1390])+ 22)+ `shouldBe`+ (fromList [-717225984, -1331183673, -1273807617, -294676032, -593841163, 1920539032, 500739415, 1590726417, -2017712295, 1398730653, -1457311386, 454591081, -1146805143, 1425505072, -1156473603, -181651339, 1539061170, 1])