module Network.Haskoin.Crypto.ECDSA.Tests (tests) where import Test.Framework (Test, testGroup) import Test.Framework.Providers.QuickCheck2 (testProperty) import Data.Bits (testBit) import qualified Data.ByteString as BS (index, length) import Network.Haskoin.Test import Network.Haskoin.Crypto import Network.Haskoin.Util tests :: [Test] tests = [ testGroup "ECDSA signatures" [ testProperty "Verify signature" testVerifySig , testProperty "S component <= order/2" $ \(ArbitrarySignature _ _ sig) -> halfOrderSig sig ] , testGroup "ECDSA Binary" [ testProperty "Encoded signature is canonical" $ \(ArbitrarySignature _ _ sig) -> testIsCanonical sig ] ] {- ECDSA Signatures -} halfOrderSig :: Signature -> Bool halfOrderSig = isCanonicalHalfOrder testVerifySig :: ArbitrarySignature -> Bool testVerifySig (ArbitrarySignature msg key sig) = verifySig msg sig pubkey where pubkey = derivePubKey key {- ECDSA Binary -} -- github.com/bitcoin/bitcoin/blob/master/src/script.cpp -- from function IsCanonicalSignature testIsCanonical :: Signature -> Bool testIsCanonical sig = not $ -- Non-canonical signature: too short (len < 8) || -- Non-canonical signature: too long (len > 72) || -- Non-canonical signature: wrong type (BS.index s 0 /= 0x30) || -- Non-canonical signature: wrong length marker (BS.index s 1 /= len - 2) || -- Non-canonical signature: S length misplaced (5 + rlen >= len) || -- Non-canonical signature: R+S length mismatch (rlen + slen + 6 /= len) || -- Non-canonical signature: R value type mismatch (BS.index s 2 /= 0x02) || -- Non-canonical signature: R length is zero (rlen == 0) || -- Non-canonical signature: R value negative (testBit (BS.index s 4) 7) || -- Non-canonical signature: R value excessively padded ( rlen > 1 && BS.index s 4 == 0 && not (testBit (BS.index s 5) 7) ) || -- Non-canonical signature: S value type mismatch (BS.index s (fromIntegral rlen+4) /= 0x02) || -- Non-canonical signature: S length is zero (slen == 0) || -- Non-canonical signature: S value negative (testBit (BS.index s (fromIntegral rlen+6)) 7) || -- Non-canonical signature: S value excessively padded ( slen > 1 && BS.index s (fromIntegral rlen+6) == 0 && not (testBit (BS.index s (fromIntegral rlen+7)) 7) ) where s = encode' sig len = fromIntegral $ BS.length s rlen = BS.index s 3 slen = BS.index s (fromIntegral rlen + 5)