diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,10 @@
 The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
 and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
 
+## 0.1.5
+### Added
+- Flag for ECDH bindings.
+
 ## 0.1.4
 ### Changed
 - Constrain imports to avoid clashes with a QuickCheck function.
diff --git a/secp256k1-haskell.cabal b/secp256k1-haskell.cabal
--- a/secp256k1-haskell.cabal
+++ b/secp256k1-haskell.cabal
@@ -1,11 +1,13 @@
--- This file has been generated from package.yaml by hpack version 0.28.2.
+cabal-version: 1.12
+
+-- This file has been generated from package.yaml by hpack version 0.31.1.
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 58645b833648dc708bc3a12e73c150371aa406be204c2cf66bedc596427e8593
+-- hash: 91fa76fe92d389dbf944a0c2dfd36b0278ab7c18beb9cfea60a863b2c9c2c186
 
 name:           secp256k1-haskell
-version:        0.1.4
+version:        0.1.5
 synopsis:       Bindings for secp256k1 library from Bitcoin Core
 description:    Sign and verify signatures using the very fast C secp256k1 library from Pieter Wuille. Has Haskell types and abstractions for keys and signatures.
 category:       Crypto
@@ -17,7 +19,6 @@
 license:        PublicDomain
 license-file:   UNLICENSE
 build-type:     Simple
-cabal-version:  >= 1.10
 extra-source-files:
     CHANGELOG.md
     README.md
@@ -26,6 +27,11 @@
   type: git
   location: https://github.com/haskoin/secp256k1-haskell.git
 
+flag ecdh
+  description: Enable (experimental) ECDH APIs
+  manual: True
+  default: False
+
 library
   exposed-modules:
       Crypto.Secp256k1
@@ -45,6 +51,8 @@
     , entropy
     , hashable
     , string-conversions
+  if flag(ecdh)
+    cpp-options: -DECDH
   default-language: Haskell2010
 
 test-suite spec
diff --git a/src/Crypto/Secp256k1.hs b/src/Crypto/Secp256k1.hs
--- a/src/Crypto/Secp256k1.hs
+++ b/src/Crypto/Secp256k1.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP                   #-}
 {-# LANGUAGE FlexibleContexts      #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-|
@@ -56,6 +57,11 @@
     , tweakAddPubKey
     , tweakMulPubKey
     , combinePubKeys
+
+#ifdef ECDH
+    -- * Diffie Hellman
+    , ecdh
+#endif
     ) where
 
 import           Control.Monad             (replicateM, unless, (<=<))
@@ -455,6 +461,20 @@
         fp <- mallocForeignPtr
         ret <- withForeignPtr fp $ \pp -> ecdsaRecover ctx pp prg pm
         if isSuccess ret then return $ Just $ PubKey fp else return Nothing
+
+#ifdef ECDH
+-- | Compute Diffie-Hellman secret.
+ecdh :: PubKey -> SecKey -> ByteString
+ecdh (PubKey pk) (SecKey sk) = withContext $ \ctx ->
+    withForeignPtr pk $ \pkPtr -> withForeignPtr sk $ \skPtr ->
+        allocaBytes size $ \o -> do
+            ret <- ecEcdh ctx o pkPtr skPtr nullPtr nullPtr
+            unless (isSuccess ret) $ error "ecdh failed"
+            packByteString (o, size)
+  where
+    size :: Integral a => a
+    size = 32
+#endif
 
 instance Arbitrary Msg where
     arbitrary = gen_msg
diff --git a/src/Crypto/Secp256k1/Internal.hs b/src/Crypto/Secp256k1/Internal.hs
--- a/src/Crypto/Secp256k1/Internal.hs
+++ b/src/Crypto/Secp256k1/Internal.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP             #-}
 {-# LANGUAGE RecordWildCards #-}
 {-|
 Module      : Crypto.Secp256k1.Internal
@@ -471,3 +472,16 @@
     -> Ptr RecSig65
     -> Ptr Msg32
     -> IO Ret
+
+#ifdef ECDH
+foreign import ccall
+    "secp256k1_ecdh.h secp256k1_ecdh"
+    ecEcdh
+    :: Ptr Ctx
+    -> Ptr CUChar
+    -> Ptr PubKey64
+    -> Ptr SecKey32
+    -> Ptr a
+    -> Ptr b
+    -> IO Ret
+#endif
diff --git a/test/Crypto/Secp256k1Spec.hs b/test/Crypto/Secp256k1Spec.hs
--- a/test/Crypto/Secp256k1Spec.hs
+++ b/test/Crypto/Secp256k1Spec.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 module Crypto.Secp256k1Spec (spec) where
 
 import           Crypto.Secp256k1
@@ -51,6 +52,10 @@
         it "add public key" $ property $ tweakAddPubKeyTest
         it "multiply public key" $ property $ tweakMulPubKeyTest
         it "combine public keys" $ property $ combinePubKeyTest
+#ifdef ECDH
+    describe "ecdh" $ do
+        it "computes dh secret" $ property $ computeDhSecret
+#endif
 
 isStringPubKey :: (PubKey, Bool) -> Bool
 isStringPubKey (k, c) = k == fromString (cs hex) where
@@ -199,14 +204,12 @@
   where
     tweaked = do
         pub <- importPubKey $ fst $ B16.decode $ B8.pack
-            "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd44705\
-            \12213d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"
+            "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd4470512213d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"
         twk <- tweak $ fst $ B16.decode $ B8.pack
             "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"
         tweakAddPubKey pub twk
     expected = importPubKey $ fst $ B16.decode $ B8.pack
-        "04441c3982b97576646e0df0c96736063df6b42f2ee566d13b9f6424302d1379e518fd\
-        \c87a14c5435bff7a5db4552042cb4120c6b86a4bbd3d0643f3c14ad01368"
+        "04441c3982b97576646e0df0c96736063df6b42f2ee566d13b9f6424302d1379e518fdc87a14c5435bff7a5db4552042cb4120c6b86a4bbd3d0643f3c14ad01368"
 
 tweakMulPubKeyTest :: Assertion
 tweakMulPubKeyTest =
@@ -214,14 +217,12 @@
   where
     tweaked = do
         pub <- importPubKey $ fst $ B16.decode $ B8.pack
-            "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd44705\
-            \12213d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"
+            "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd4470512213d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"
         twk <- tweak $ fst $ B16.decode $ B8.pack
             "f5cbe7d88182a4b8e400f96b06128921864a18187d114c8ae8541b566c8ace00"
         tweakMulPubKey pub twk
     expected = importPubKey $ fst $ B16.decode $ B8.pack
-        "04f379dc99cdf5c83e433defa267fbb3377d61d6b779c06a0e4ce29ae3ff5353b12ae4\
-        \9c9d07e7368f2ba5a446c203255ce912322991a2d6a9d5d5761c61ed1845"
+        "04f379dc99cdf5c83e433defa267fbb3377d61d6b779c06a0e4ce29ae3ff5353b12ae49c9d07e7368f2ba5a446c203255ce912322991a2d6a9d5d5761c61ed1845"
 
 combinePubKeyTest :: Assertion
 combinePubKeyTest =
@@ -229,15 +230,26 @@
   where
     combined = do
         pub1 <- importPubKey $ fst $ B16.decode $ B8.pack
-            "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd44705\
-            \12213d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"
+            "04dded4203dac96a7e85f2c374a37ce3e9c9a155a72b64b4551b0bfe779dd4470512213d5ed790522c042dee8e85c4c0ec5f96800b72bc5940c8bc1c5e11e4fcbf"
         pub2 <- importPubKey $ fst $ B16.decode $ B8.pack
-            "0487d82042d93447008dfe2af762068a1e53ff394a5bf8f68a045fa642b99ea5d1\
-            \53f577dd2dba6c7ae4cfd7b6622409d7edd2d76dd13a8092cd3af97b77bd2c77"
+            "0487d82042d93447008dfe2af762068a1e53ff394a5bf8f68a045fa642b99ea5d153f577dd2dba6c7ae4cfd7b6622409d7edd2d76dd13a8092cd3af97b77bd2c77"
         pub3 <- importPubKey $ fst $ B16.decode $ B8.pack
-            "049b101edcbe1ee37ff6b2318526a425b629e823d7d8d9154417880595a28000ee\
-            \3febd908754b8ce4e491aa6fe488b41fb5d4bb3788e33c9ff95a7a9229166d59"
+            "049b101edcbe1ee37ff6b2318526a425b629e823d7d8d9154417880595a28000ee3febd908754b8ce4e491aa6fe488b41fb5d4bb3788e33c9ff95a7a9229166d59"
         combinePubKeys [pub1, pub2, pub3]
     expected = importPubKey $ fst $ B16.decode $ B8.pack
-        "043d9a7ec70011efc23c33a7e62d2ea73cca87797e3b659d93bea6aa871aebde56c3bc\
-        \6134ca82e324b0ab9c0e601a6d2933afe7fb5d9f3aae900f5c5dc6e362c8"
+        "043d9a7ec70011efc23c33a7e62d2ea73cca87797e3b659d93bea6aa871aebde56c3bc6134ca82e324b0ab9c0e601a6d2933afe7fb5d9f3aae900f5c5dc6e362c8"
+
+#ifdef ECDH
+computeDhSecret :: Assertion
+computeDhSecret =
+    assertEqual "ecdh computes known secret" expected computed
+  where
+    computed = do
+        pub <- importPubKey $ fst $ B16.decode $ B8.pack
+            "028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7"
+        sec <- secKey $ fst $ B16.decode $ B8.pack
+            "1212121212121212121212121212121212121212121212121212121212121212"
+        pure $ ecdh pub sec
+    expected = Just $ fst $ B16.decode $ B8.pack
+        "1e2fb3c8fe8fb9f262f649f64d26ecf0f2c0a805a767cf02dc2d77a6ef1fdcc3"
+#endif
