Dust-crypto-0.1: Dust/Crypto/Curve25519.hs
{-# CFILES lib/curve25519-donna.c #-}
{-# LANGUAGE ForeignFunctionInterface #-}
module Dust.Crypto.Curve25519 (curve25519) where
import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import Data.ByteString.Unsafe (unsafeUseAsCString)
import Foreign.C.String (CString)
import Foreign.Marshal.Unsafe (unsafeLocalState)
curve25519 :: ByteString -> ByteString -> ByteString
curve25519 bs1 bs2 = curve
where
Just curve = unsafeLocalState $ unsafe_curve25519 bs1 bs2
unsafe_curve25519 :: ByteString -> ByteString -> IO (Maybe ByteString)
unsafe_curve25519 secret basepoint
| B.length secret >= 32 && B.length basepoint >= 32 =
-- This ByteString will be overwritten by the C call, but so long as
-- the C side does not keep a reference to it afterward, it does what we
-- expect and saves us a copy
unsafeUseAsCString outBS $ \output ->
B.useAsCString secret $ \csecret ->
B.useAsCString basepoint $ \cbasepoint -> do
result <- c_curve25519_donna output csecret cbasepoint
case result of
0 -> return $ Just outBS
_ -> return Nothing
| otherwise = return Nothing
where
outBS = B.replicate 32 0xAB
-- Should be Ptr Word8 (not CString), but this should be safe if we just
-- use them as bytes
foreign import ccall unsafe "curve25519_donna" c_curve25519_donna ::
CString -> CString -> CString -> IO Int