{-# LANGUAGE DataKinds,GADTs #-} module Network.EasyBitcoin.Internal.Signatures ( detSignMsg , Signature() , checkSig )where import Network.EasyBitcoin.Keys import Network.EasyBitcoin.Internal.Keys import Network.EasyBitcoin.Internal.Words import Network.EasyBitcoin.Internal.CurveConstants import Network.EasyBitcoin.Internal.ByteString import Network.EasyBitcoin.Internal.Words import Network.EasyBitcoin.Internal.HashFunctions import qualified Data.ByteString as BS import Data.Binary (Binary, get, put, Word64,Word32,Word16) import Data.Binary.Get ( getWord64be , getWord32be , getWord64le , getWord8 , getWord16le , getWord32le , getByteString , Get ) import Data.Binary.Put( putWord64be , putWord32be , putWord32le , putWord64le , putWord16le , putWord8 , putByteString ) import Control.Monad import GHC.Word import Control.Applicative import Data.Bits import Control.DeepSeq (NFData, rnf) import Control.Monad (unless, guard) import Data.Maybe -- | Sign a message using ECDSA deterministic signatures as defined by -- RFC 6979 detSignMsg :: Word256 -> Key Private net -> Signature detSignMsg n (ExtendedPrv _ _ _ _ (PrvKey x)) = detSignMsg_ n x detSignMsg_ :: Word256 -> FieldN -> Signature detSignMsg_ h d = go $ hmacDRBGNew (enc d) (encode' h) BS.empty where enc::FieldN -> BS.ByteString enc x = encode' (fromIntegral x ::Word256) go ws = case hmacDRBGGen ws 32 BS.empty of (ws', Just k) -> let kI = bsToInteger k p = mulPoint (fromInteger kI) curveG sigM = unsafeSignMsg h d (fromInteger kI,p) in if (isIntegerValidKey kI) then fromMaybe (go ws') sigM else go ws' (_ , Nothing) -> error "detSignMsg: No suitable K value found" -- Signs a message by providing the nonce unsafeSignMsg :: Word256 -> FieldN -> (FieldN, Point) -> Maybe Signature unsafeSignMsg _ 0 _ = Nothing unsafeSignMsg h d (k,p) = do let (x,_) = getAffine p -- 4.1.3.3 r = (fromIntegral x :: FieldN) --guard (r /= 0) -- is it necesary? e = (fromIntegral h :: FieldN) -- double check this work! s' = (e + r*d)/k -- Canonicalize signatures: s <= order/2 -- maxBound/2 = (maxBound+1)/2 = order/2 (because order is odd) s = if s' > (maxBound `div` 2) then (-s') else s' -- 4.1.3.4 / 4.1.3.5 --guard (s /= 0) -- 4.1.3.7 return $ Signature r s -- Section 4.1.4 http://www.secg.org/download/aid-780/sec1-v2.pdf -- | Verify an ECDSA signature checkSig :: Word256 -> Signature -> Key Public net -> Bool checkSig h sig ( ExtendedPub _ _ _ _ key) = checkSig_ h sig key where -- 4.1.4.1 (r and s can not be zero) checkSig_ _ (Signature 0 _) _ = False checkSig_ _ (Signature _ 0) _ = False checkSig_ h (Signature r s) q = case Just $ getAffine p of Nothing -> False Just (x,_) -> (fromIntegral x :: FieldN) == r where -- 4.1.4.2 / 4.1.4.3 e = (fromIntegral h :: FieldN) -- 4.1.4.4 s' = inverseN s u1 = e*s' u2 = r*s' -- 4.1.4.5 (u1*G + u2*q) p = shamirsTrick u1 curveG u2 (pubKeyPoint q) data Signature = Signature { sigR :: !FieldN , sigS :: !FieldN } deriving (Read, Show, Eq) -------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------- instance Binary Signature where get = do t <- getWord8 -- 0x30 is DER sequence type unless (t == 0x30) (fail $ "Bad DER identifier byte " ++ (show t) ++ ". Expecting 0x30") l <- getWord8 -- Length = (33 + 1 identifier byte + 1 length byte) * 2 isolate (fromIntegral l) $ Signature <$> get <*> get put (Signature 0 _) = error "0 is an invalid r value in a Signature" put (Signature _ 0) = error "0 is an invalid s value in a Signature" put (Signature r s) = do putWord8 0x30 let c = runPut' $ put r >> put s putWord8 (fromIntegral $ BS.length c) -- error .show $ (r,s) putByteString c shamirsTrick :: FieldN -> Point -> FieldN -> Point -> Point shamirsTrick r1 p1 r2 p2 = addPoint (mulPoint r1 p1) (mulPoint r2 p2) ------------------------------------------------------------------------------------------------------------------------------ quadraticResidue :: FieldP -> [FieldP] quadraticResidue x = guard (y^(2 :: Int) == x) >> [y, (-y)] where q = (curveP + 1) `div` 4 y = x^q