Search code examples
haskellscryptio-monad

Haskell & Scrypt: How to get the encrypted hash


*Sorry for the basic question, just started learning Haskell.

I am trying to write a function that will get a string and return an encrypted hash.

What I have come up with for the moment is:

encrypt :: ByteString -> ByteString
encrypt = do
    x <- Crypto.Scrypt.encryptPassIO' (Pass "secret")
    fmap Crypto.Scrypt.getEncryptedPass x

However I get the error:

• Couldn't match expected type ‘ByteString’
              with actual type ‘IO ByteString’
• In a stmt of a 'do' block: x <- encryptPassIO' (Pass plain)
  In the expression:
    do { x <- encryptPassIO' (Pass plain);
         fmap Crypto.Scrypt.getEncryptedPass x }
  In an equation for ‘encrypt’:
      encrypt plain
        = do { x <- encryptPassIO' (Pass plain);
               fmap Crypto.Scrypt.getEncryptedPass x }

Any idea how I can get rid of the IO?

Thanks!


Solution

  • Rather than getting rid of the IO, you need to adjust encrypt to return an IO ByteString. encryptPassIO' needs random data to use for the salt, which it gets from the IO monad, so you are stuck there.

    import Crypto.Scrypt (encryptPassIO', getEncryptedPass)
    encrypt :: ByteString -> IO ByteString
    encrypt = fmap getEncryptedPass . encryptPassIO' . Pass
    

    Instead of do notation, I've used encryptPassIO' . Pass to get the IO EncryptedPass value from the argument. We then use fmap to lift getEncryptedPass :: EncryptedPass -> ByteString into the IO monad.

    You could use do notation, but IMO fmap makes this cleaner:

    encrypt pass = do
        x <- encryptPassIO' pass
        return (getEncryptedPass x)