diff --git a/binding.go b/binding.go
index 986174dd5ccab0adea6934e1ce2e47250d5dc143..df19c0ee6e654e002904bee7dd3666afc9329ad6 100644
--- a/binding.go
+++ b/binding.go
@@ -1,14 +1,31 @@
 package ctidh
 
-// #include "binding.h"
-// #include <csidh.h>
+/*
+#include "binding.h"
+#include <csidh.h>
+
+void custom_gen_private(private_key *priv) {
+  csidh_private_withrng(priv, fillrandom_custom);
+}
+
+void fillrandom_custom(
+  void *const outptr,
+  const size_t outsz,
+  const uintptr_t context)
+{
+  (void) context;
+  go_fillrandom(outptr, outsz);
+}
+*/
 import "C"
 import (
 	"bytes"
 	"crypto/hmac"
 	"encoding/pem"
 	"fmt"
+	"io"
 	"io/ioutil"
+	"sync"
 	"unsafe"
 )
 
@@ -33,6 +50,9 @@ var (
 
 	// ErrCTIDH indicates a group action failure.
 	ErrCTIDH error = fmt.Errorf("%s: group action failure", Name())
+
+	privateKeyRNGLock sync.Mutex
+	privateKeyRNG     io.Reader = nil
 )
 
 // ErrPEMKeyTypeMismatch returns an error indicating that we tried
@@ -300,6 +320,39 @@ func GenerateKeyPair() (*PrivateKey, *PublicKey) {
 	return privKey, DerivePublicKey(privKey)
 }
 
+//export go_fillrandom
+func go_fillrandom(outptr unsafe.Pointer, outsz C.size_t) {
+	buf := make([]byte, outsz)
+	privateKeyRNGLock.Lock()
+	rng := privateKeyRNG
+	privateKeyRNGLock.Unlock()
+	count, err := rng.Read(buf)
+	if err != nil {
+		panic(err)
+	}
+	if count != int(outsz) {
+		panic("rng fail")
+	}
+	p := uintptr(outptr)
+	for i := 0; i < int(outsz); i++ {
+		(*(*uint8)(unsafe.Pointer(p))) = uint8(buf[i])
+		p += 1
+	}
+}
+
+// GenerateKeyPairWithRNG uses the given RNG to derive a new keypair.
+// HOWEVER, if GenerateKeyPairWithRNG is called by multiple threads
+// then the rng is overwritten with each call which can unintentionally
+// cause multiple RNGs to be used to generate the keypair.
+func GenerateKeyPairWithRNG(rng io.Reader) (*PrivateKey, *PublicKey) {
+	privKey := new(PrivateKey)
+	privateKeyRNGLock.Lock()
+	privateKeyRNG = rng
+	privateKeyRNGLock.Unlock()
+	C.custom_gen_private(&privKey.privateKey)
+	return privKey, DerivePublicKey(privKey)
+}
+
 func groupAction(privateKey *PrivateKey, publicKey *PublicKey) *PublicKey {
 	sharedKey := new(PublicKey)
 	ok := C.csidh(&sharedKey.publicKey, &publicKey.publicKey, &privateKey.privateKey)
diff --git a/binding_test.go b/binding_test.go
index e18bba6262e72c46749226e3aff8c2e205d08561..2efbface5b1501525a35e0deaedd49ac1eb15d7e 100644
--- a/binding_test.go
+++ b/binding_test.go
@@ -1,6 +1,7 @@
 package ctidh
 
 import (
+	"crypto/rand"
 	"os"
 	"path/filepath"
 	"testing"
@@ -8,6 +9,16 @@ import (
 	"github.com/stretchr/testify/require"
 )
 
+func TestGenerateKeyPairWithRNG(t *testing.T) {
+	privateKey, publicKey := GenerateKeyPairWithRNG(rand.Reader)
+
+	zeros := make([]byte, PublicKeySize)
+	require.NotEqual(t, privateKey.Bytes(), zeros)
+	require.NotEqual(t, publicKey.Bytes(), zeros)
+
+	t.Logf("privateKey.Bytes() %x", privateKey.Bytes())
+}
+
 func TestPrivateKeyPEMSerialization(t *testing.T) {
 	privateKey, _ := GenerateKeyPair()