hsblst-0.0.1: test/Test/BLST.hs
-- SPDX-FileCopyrightText: 2022 Serokell <https://serokell.io>
-- SPDX-License-Identifier: MPL-2.0
module Test.BLST
( test_highlevel
) where
import Data.ByteArray (Bytes, convert)
import Data.ByteArray.Sized qualified as AS
import Data.ByteString (ByteString)
import Data.List.NonEmpty (NonEmpty(..))
import Data.Proxy (Proxy(..))
import Test.Tasty (TestTree, testGroup)
import Test.Tasty.HUnit (assertBool, testCase, (@?=))
import Crypto.BLST
import Test.BLST.Fixtures
import Test.BLST.Util
test_highlevel :: TestTree
test_highlevel = testGroup "High-level interface"
[ withAllOptions "sign and verify" $ \(_ :: Proxy '(c, m)) ->
verify @c @m sig pk msg noDST @?= BlstSuccess
, withAllOptions "sign and verify with DST" $ \(_ :: Proxy '(c, m)) ->
verify @c @m sigDST pk msg myDST @?= BlstSuccess
, testGroup "PK"
[ testGroup "Serialize"
[ testCase "G1" $ serializePk @'G1 pk @?= expectedSer1
, testCase "G2" $ serializePk @'G2 pk @?= expectedSer2
]
, testGroup "Deserialize"
[ testCase "G1" $ deserializePk @'G1 expectedSer1 @?= Right pk
, testCase "G2" $ deserializePk @'G2 expectedSer2 @?= Right pk
]
, testGroup "Compress"
[ testCase "G1" $ compressPk @'G1 pk @?= fromHex expectedComp1
, testCase "G2" $ compressPk @'G2 pk @?= fromHex expectedComp2
]
, testGroup "Decompress"
[ testCase "G1" $ decompressPk @'G1 (fromHex expectedComp1) @?= Right pk
, testCase "G2" $ decompressPk @'G2 (fromHex expectedComp2) @?= Right pk
]
]
, testGroup "SK"
[ testCase "Serialize" $
serializeSk key @?= AS.convert (fromHex expectedSerKey)
, testCase "Deserialize" $
deserializeSk (fromHex expectedSerKey) @?= key
]
, withAllOptions "Serialize-deserialize signature roundtrip" $ \(_ :: Proxy '(c, m)) ->
sigRoundtrip @c @m sig @?= Right sig
, withAllOptions "Compress-decompress signature roundtrip" $ \(_ :: Proxy '(c, m)) ->
sigCompRoundtrip @c @m sig @?= Right sig
, withAllOptions "DST affects signature" $ \(_ :: Proxy '(c, m)) ->
assertBool "signatures match when DSTs differ" $
sig @m @c /= sigDST
, withAllOptions "Aggregate" $ testAgg noDST
, withAllOptions "Aggregate with DST" $ testAgg myDST
]
testAgg :: forall c m. (ToCurve m c) => Maybe Bytes -> Proxy '(c, m) -> IO ()
testAgg dst _ = do
let sk1 = keygen $
AS.unsafeSizedByteArray @32 @ByteString "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"
sk2 = keygen $
AS.unsafeSizedByteArray @32 @ByteString "wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"
(pk1, pk2) = (skToPk @c sk1, skToPk @c sk2)
msg1 = "hello" :: ByteString
msg2 = "world" :: ByteString
sig1 = sign @c @m sk1 msg1 dst
sig2 = sign @c @m sk2 msg2 dst
sig3 = sign @c @m sk2 msg2 (Just ("xxx" :: ByteString))
agg = aggregateSignatures (sig1 :| [sig2])
agg' = aggregateSignatures (sig1 :| [sig2, sig3])
aggregateVerify ((pk1, msg1) :| [(pk2, msg2)]) agg dst @?= Right True
aggregateVerify ((pk1, msg1 <> "asd") :| [(pk2, msg2)]) agg dst @?= Right False
aggregateVerify ((pk2, msg1) :| [(pk1, msg2)]) agg dst @?= Right False
aggregateVerify ((pk1, msg1) :| [(pk2, msg2), (pk2, msg2)]) agg' dst @?= Right False
withAllOptions
:: String
-> (forall (c :: Curve) (m :: EncodeMethod). (ToCurve m c)
=> Proxy '(c, m) -> IO ())
-> TestTree
withAllOptions name f = testGroup name
[ testCase "G1 Hash" $ f @'G1 @'Hash Proxy
, testCase "G2 Hash" $ f @'G2 @'Hash Proxy
, testCase "G1 Encode" $ f @'G1 @'Encode Proxy
, testCase "G2 Encode" $ f @'G2 @'Encode Proxy
]
sigRoundtrip
:: IsCurve c
=> Signature c m
-> Either BlstError (Signature c m)
sigRoundtrip = deserializeSignature . serializeSignature
sigCompRoundtrip
:: IsCurve c
=> Signature c m
-> Either BlstError (Signature c m)
sigCompRoundtrip = decompressSignature . compressSignature
key :: SecretKey
key = keygen $ AS.unsafeSizedByteArray @32 seed
pk :: IsCurve c => PublicKey c
pk = skToPk key
myDST :: Maybe Bytes
myDST = Just $ convert ("MY-DST" :: ByteString)
sig :: (ToCurve m c) => Signature c m
sig = sign key msg noDST
sigDST :: (ToCurve m c) => Signature c m
sigDST = sign key msg myDST