BIP340.hs (2972B)
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 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) $ 37 case parse_point (decodeLenient c_pk) of 38 Nothing -> assertBool mempty (not c_res) 39 Just pk -> do 40 if c_sk == mempty 41 then do -- no signature; test verification 42 let ver = verify_schnorr c_msg pk c_sig 43 ver' = verify_schnorr' tex c_msg pk c_sig 44 if c_res 45 then do 46 assertBool mempty ver 47 assertBool mempty ver' 48 else do 49 assertBool mempty (not ver) 50 assertBool mempty (not ver') 51 -- XX test pubkey derivation from sk 52 else do -- signature present; test sig too 53 let sk = unsafe_roll32 c_sk 54 Just sig = sign_schnorr sk c_msg c_aux 55 Just sig' = sign_schnorr' tex sk c_msg c_aux 56 ver = verify_schnorr c_msg pk sig 57 ver' = verify_schnorr' tex c_msg pk sig 58 assertEqual mempty c_sig sig 59 assertEqual mempty c_sig sig' 60 if c_res 61 then do 62 assertBool mempty ver 63 assertBool mempty ver' 64 else do 65 assertBool mempty (not ver) 66 assertBool mempty (not ver') 67 68 header :: AT.Parser () 69 header = do 70 _ <- AT.string "index,secret key,public key,aux_rand,message,signature,verification result,comment" 71 AT.endOfLine 72 73 test_case :: AT.Parser Case 74 test_case = do 75 c_index <- AT.decimal AT.<?> "index" 76 _ <- AT.char ',' 77 c_sk <- fmap decodeLenient (AT.takeWhile (/= ',') AT.<?> "sk") 78 _ <- AT.char ',' 79 c_pk <- AT.takeWhile1 (/= ',') AT.<?> "pk" 80 _ <- AT.char ',' 81 c_aux <- fmap decodeLenient (AT.takeWhile (/= ',') AT.<?> "aux") 82 _ <- AT.char ',' 83 c_msg <- fmap decodeLenient (AT.takeWhile (/= ',') AT.<?> "msg") 84 _ <- AT.char ',' 85 c_sig <- fmap decodeLenient (AT.takeWhile1 (/= ',') AT.<?> "sig") 86 _ <- AT.char ',' 87 c_res <- (AT.string "TRUE" *> pure True) <|> (AT.string "FALSE" *> pure False) 88 AT.<?> "res" 89 _ <- AT.char ',' 90 c_comment <- AT.takeWhile (/= '\n') AT.<?> "comment" 91 AT.endOfLine 92 pure Case {..} 93 94 cases :: AT.Parser [Case] 95 cases = header *> AT.many1 test_case 96