I've been trying to use the hsblst library and I having problems with Data.ByteArray.Sized. For example, to use keygen
from Crypto.BLST
with signature
keygen :: (ByteArrayAccess ba, 32 <= n, KnownNat n) => SizedByteArray n ba -> SecretKey
How do I make a SizedByteArray n ba
object? In this link there is an example where
sk1 = keygen $ AS.unsafeSizedByteArray @32 @ByteString "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"
where AS
is an alias for Data.ByteArray.Sized
. This example is not working for me. When I try to do the same those at_marks do not work.
Then I tried this code
import Data.ByteArray.Sized qualified as AS
import Data.Text.Encoding
import qualified Data.ByteString as B
import qualified Data.Text as T
import Data.Proxy (Proxy(..))
import Crypto.BLST
sk ="79cc407e6917b5673a1f6966c23c9e15\
\d257e5ab46cfe7b9b2f64200f2b2843e"
skp = T.pack sk
skpb = encodeUtf8 skp
the name skpb
is of type ByteString
. So, according to the definition of sizedByteArray
(shown below) I should get a Maybe SizedByteArray
right?
-- | create a 'SizedByteArray' from the given 'ByteArrayAccess' if the
-- size is the same as the target size.
--
sizedByteArray :: forall n ba . (KnownNat n, ByteArrayAccess ba)
=> ba
-> Maybe (SizedByteArray n ba)
sizedByteArray ba
| length ba == n = Just $ SizedByteArray ba
| otherwise = Nothing
where
n = fromInteger $ natVal (Proxy @n)
After trying this I get these errors:
ghci> AS.sizedByteArray skpb
<interactive>:7:1: error: [GHC-39999]
• No instance for ‘GHC.TypeNats.KnownNat n0’
arising from a use of ‘it’
• In the first argument of ‘print’, namely ‘it’
In a stmt of an interactive GHCi command: print it
and
ghci> keygen $ AS.sizedByteArray skpb
<interactive>:8:1: error: [GHC-64725]
• Cannot satisfy: 32 <= n0
• In the first argument of ‘($)’, namely ‘keygen’
In the expression: keygen $ AS.sizedByteArray skpb
In an equation for ‘it’: it = keygen $ AS.sizedByteArray skpb
What am I doing wrong?
The definition:
sk1 :: SecretKey
sk1 = keygen $ AS.unsafeSizedByteArray @32 @B.ByteString
"qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"
will work fine, but you need to enable DataKinds
to use 32
as a type, OverloadedStrings
to use a string literal as a ByteString
, and TypeApplications
to allow those @
-marks, which are applications to type-level arguments. So, the following should compile:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}
import Crypto.BLST
import qualified Data.ByteArray.Sized as AS
import qualified Data.ByteString as B
sk1 :: SecretKey
sk1 = keygen $ AS.unsafeSizedByteArray @32 @B.ByteString
"qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"
More generally, with those extensions enabled, you should be able to construct SizedByteArray
values using any of the following methods:
-- type applications
sba2 = AS.unsafeSizedByteArray @64 @B.ByteString
"0123456789012345678901234567890123456789012345678901234567890123"
-- top-level type signature
sba1 :: AS.SizedByteArray 64 B.ByteString
sba1 = AS.unsafeSizedByteArray
"0123456789012345678901234567890123456789012345678901234567890123"
-- in-line type signature
sba3 = AS.unsafeSizedByteArray
"0123456789012345678901234567890123456789012345678901234567890123"
:: AS.SizedByteArray 64 B.ByteString
Note that these sizes aren't checked at compile time, so the following will compile:
sbabadlen = AS.unsafeSizedByteArray @100 @B.ByteString "too short"
but throw a runtime exception when it's evaluated. The "safe" version will also compile:
sbabadlen = AS.sizedByteArray @100 @B.ByteString "too short"
and will evaluate to Nothing
instead of Just
a SizedByteArray
.
Oh, and I should add: there is no simple way of constructing a SizedByteArray
without specifying its length explicitly in the source code, so that's why your attempt to have the compiler determine the length based on the actual contents failed with a missing KnownNat
instance.