BIP340.hs (2511B)
1 {-# LANGUAGE OverloadedStrings #-} 2 {-# LANGUAGE RecordWildCards #-} 3 {-# LANGUAGE ViewPatterns #-} 4 5 module BIP340 ( 6 cases 7 , execute 8 ) where 9 10 import Control.Applicative 11 import Control.Exception 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 Test.Tasty 17 import Test.Tasty.HUnit 18 19 data Case = Case { 20 c_index :: !Int 21 , c_sk :: !BS.ByteString 22 , c_pk :: !BS.ByteString 23 , c_aux :: !BS.ByteString 24 , c_msg :: !BS.ByteString 25 , c_sig :: !BS.ByteString 26 , c_res :: !Bool 27 , c_comment :: !BS.ByteString 28 } deriving Show 29 30 execute :: Context -> Case -> TestTree 31 execute tex Case {..} = testCase ("bip0340 " <> show c_index) $ do 32 par <- try (parse_xonly tex (B16.decodeLenient c_pk)) 33 :: IO (Either Secp256k1Exception XOnlyPub) 34 case par of 35 Left _ -> assertBool mempty (not c_res) 36 Right (XOnlyPub pub) -> do 37 let pk = Pub pub 38 if c_sk == mempty 39 then do -- no signature; test verification 40 ver <- verify_schnorr tex pk c_msg c_sig 41 if c_res 42 then assertBool mempty ver 43 else assertBool mempty (not ver) 44 -- XX test pubkey derivation from sk 45 else do -- signature present; test sig too 46 sig <- sign_schnorr tex c_msg c_sk c_aux 47 ver <- verify_schnorr tex pk c_msg sig 48 assertEqual mempty c_sig sig 49 if c_res 50 then assertBool mempty ver 51 else assertBool mempty (not ver) 52 53 header :: AT.Parser () 54 header = do 55 _ <- AT.string "index,secret key,public key,aux_rand,message,signature,verification result,comment" 56 AT.endOfLine 57 58 test_case :: AT.Parser Case 59 test_case = do 60 c_index <- AT.decimal AT.<?> "index" 61 _ <- AT.char ',' 62 c_sk <- fmap B16.decodeLenient (AT.takeWhile (/= ',') AT.<?> "sk") 63 _ <- AT.char ',' 64 c_pk <- AT.takeWhile1 (/= ',') AT.<?> "pk" 65 _ <- AT.char ',' 66 c_aux <- fmap B16.decodeLenient (AT.takeWhile (/= ',') AT.<?> "aux") 67 _ <- AT.char ',' 68 c_msg <- fmap B16.decodeLenient (AT.takeWhile (/= ',') AT.<?> "msg") 69 _ <- AT.char ',' 70 c_sig <- fmap B16.decodeLenient (AT.takeWhile1 (/= ',') AT.<?> "sig") 71 _ <- AT.char ',' 72 c_res <- (AT.string "TRUE" *> pure True) <|> (AT.string "FALSE" *> pure False) 73 AT.<?> "res" 74 _ <- AT.char ',' 75 c_comment <- AT.takeWhile (/= '\n') AT.<?> "comment" 76 AT.endOfLine 77 pure Case {..} 78 79 cases :: AT.Parser [Case] 80 cases = header *> AT.many1 test_case 81