BIP340.hs (3171B)
1 {-# OPTIONS_GHC -fno-warn-incomplete-uni-patterns #-} 2 {-# LANGUAGE OverloadedStrings #-} 3 {-# LANGUAGE RecordWildCards #-} 4 {-# LANGUAGE ViewPatterns #-} 5 6 module BIP340 ( 7 cases 8 , execute 9 ) where 10 11 import Control.Applicative 12 import Crypto.Curve.Secp256k1 13 import qualified Data.Attoparsec.ByteString.Char8 as AT 14 import qualified Data.ByteString as BS 15 import qualified Data.ByteString.Base16 as B16 16 import qualified GHC.Num.Integer as I 17 import Test.Tasty 18 import Test.Tasty.HUnit 19 20 -- XX make a test prelude instead of copying/pasting these things everywhere 21 22 fi :: (Integral a, Num b) => a -> b 23 fi = fromIntegral 24 {-# INLINE fi #-} 25 26 roll :: BS.ByteString -> Integer 27 roll = BS.foldl' unstep 0 where 28 unstep a (fi -> b) = (a `I.integerShiftL` 8) `I.integerOr` b 29 30 data Case = Case { 31 c_index :: !Int 32 , c_sk :: !BS.ByteString 33 , c_pk :: !BS.ByteString 34 , c_aux :: !BS.ByteString 35 , c_msg :: !BS.ByteString 36 , c_sig :: !BS.ByteString 37 , c_res :: !Bool 38 , c_comment :: !BS.ByteString 39 } deriving Show 40 41 execute :: Context -> Case -> TestTree 42 execute tex Case {..} = testCase ("bip0340 " <> show c_index) $ 43 case parse_point (B16.decodeLenient c_pk) of 44 Nothing -> assertBool mempty (not c_res) 45 Just pk -> do 46 if c_sk == mempty 47 then do -- no signature; test verification 48 let ver = verify_schnorr c_msg pk c_sig 49 ver' = verify_schnorr' tex c_msg pk c_sig 50 if c_res 51 then do 52 assertBool mempty ver 53 assertBool mempty ver' 54 else do 55 assertBool mempty (not ver) 56 assertBool mempty (not ver') 57 -- XX test pubkey derivation from sk 58 else do -- signature present; test sig too 59 let sk = roll c_sk 60 Just sig = sign_schnorr sk c_msg c_aux 61 Just sig' = sign_schnorr' tex sk c_msg c_aux 62 ver = verify_schnorr c_msg pk sig 63 ver' = verify_schnorr' tex c_msg pk sig 64 assertEqual mempty c_sig sig 65 assertEqual mempty c_sig sig' 66 if c_res 67 then do 68 assertBool mempty ver 69 assertBool mempty ver' 70 else do 71 assertBool mempty (not ver) 72 assertBool mempty (not ver') 73 74 header :: AT.Parser () 75 header = do 76 _ <- AT.string "index,secret key,public key,aux_rand,message,signature,verification result,comment" 77 AT.endOfLine 78 79 test_case :: AT.Parser Case 80 test_case = do 81 c_index <- AT.decimal AT.<?> "index" 82 _ <- AT.char ',' 83 c_sk <- fmap B16.decodeLenient (AT.takeWhile (/= ',') AT.<?> "sk") 84 _ <- AT.char ',' 85 c_pk <- AT.takeWhile1 (/= ',') AT.<?> "pk" 86 _ <- AT.char ',' 87 c_aux <- fmap B16.decodeLenient (AT.takeWhile (/= ',') AT.<?> "aux") 88 _ <- AT.char ',' 89 c_msg <- fmap B16.decodeLenient (AT.takeWhile (/= ',') AT.<?> "msg") 90 _ <- AT.char ',' 91 c_sig <- fmap B16.decodeLenient (AT.takeWhile1 (/= ',') AT.<?> "sig") 92 _ <- AT.char ',' 93 c_res <- (AT.string "TRUE" *> pure True) <|> (AT.string "FALSE" *> pure False) 94 AT.<?> "res" 95 _ <- AT.char ',' 96 c_comment <- AT.takeWhile (/= '\n') AT.<?> "comment" 97 AT.endOfLine 98 pure Case {..} 99 100 cases :: AT.Parser [Case] 101 cases = header *> AT.many1 test_case 102