packages feed

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