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