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