haskell - How to create two ByteStrings calling this external library API? -
i'm writing bindings cryptographic library exposes function generating keypairs:
const size_t publickeybytes = 32; const size_t secretkeybytes = 32; int random_keypair(unsigned char pk[publickeybytes], unsigned char sk[secretkeybytes]);
this function randomly generates secret key, computes corresponding public key , puts results in pk
, sk
.
when returning 1 bytestring
i've found easiest way use create :: int -> (ptr word8 -> io ()) -> io bytestring
data.bytestring.internal
. however, function can't create 2 bytestrings
@ same time.
my first approach write like:
newtype publickey = publickey bytestring newtype secretkey = secretkey bytestring randomkeypair :: io (publickey, secretkey) randomkeypair = let pk = b.replicate 0 publickeybytes sk = b.replicate 0 secretkeybytes b.unsafeuseascstring pk $ \ppk -> b.unsafeuseascstring sk $ \psk -> c_random_keypair ppk psk return (publickey pk, secretkey sk)
however, doesn't seem work ghc 7.10.2. when running test suite i'm finding seem have sharing of bytestring
s in between function calls, leading encryption/decryption failing , giving incorrect results.
i've managed work around problem defining own function:
createwithresult :: int -> (ptr word8 -> io a) -> io (bytestring, a) createwithresult f = fp <- b.mallocbytestring r <- withforeignptr fp f return (b.fromforeignptr fp 0 i, r)
and using like:
randomkeypair = fmap (publickey *** secretkey) $ createwithresult publickeybytes $ \ppk -> b.create secretkeybytes $ \psk -> void $ c_random_keypair ppk psk
this seems work, tests pass.
my question is, semantics when comes sharing , referential transparency when comes io
monad?
my intuition told me (incorrectly) solve problem in first way, apparently couldn't. believe happening optimizer saw let
-statements floated top level definitions, , reason got these issues.
the problem first approach you're trying modify immutable value (pk
, sk
in function). docs unsafeuseascstring say:
modifying cstring, either in c, or using poke, cause contents of bytestring change, breaking referential transparency
the io
monad doesn't have different semantics when comes sharing , referential transparency. in fact, let
in do
block not in way related io
monad; code equivalent to:
randomkeypair :: io (publickey, secretkey) randomkeypair = let pk = b.replicate 0 publickeybytes sk = b.replicate 0 secretkeybytes in b.unsafeuseascstring pk (\ppk -> b.unsafeuseascstring sk $ \psk -> c_random_keypair ppk psk) >> return (publickey pk, secretkey sk)
now it's visible pk
, sk
can floated top level.
Comments
Post a Comment