packages feed

bitcoin-keys-0.1: lib/Bitcoin/Keys.hs

{-# LANGUAGE CPP #-}

-- | This module exports tools for working with Bitcoin keys.
module Bitcoin.Keys
  ( -- * Private
    I.Prv
  , I.parsePrv
  , I.prvRaw
  , I.prvToPub

   -- * Public
  , I.Pub
  , parsePub
  , I.pubCompressed
  , I.pubUncompressed

   -- * Tweak
  , I.Tweak
  , I.parseTweak
  , I.pubAddTweak
  , I.prvAddTweak
  ) where

import Control.Applicative
import Control.Monad
import Data.Bits
import qualified Data.ByteString as B

#ifdef ghcjs_HOST_OS
import qualified Bitcoin.Keys.GHCJS as I
#else
import qualified Bitcoin.Keys.GHC as I
#endif

-- | Construct a 'I.Pub' key from either its compressed or uncompressed SEC-encoded
-- bytes.
--
-- * Compressed keys are 33 bytes. The leftmost byte is @0x02@ if the @y@
-- coordinate is even, or @0x03@ if odd. The remaining 32 bytes
-- are the big-endian encoded @x@ coordinate.
--
-- * Uncompressed keys are 65 bytes. The leftmost byte is @0x04@. The next 32
-- bytes are the big-endian encoded @x@ cordinate. The next 32 bytes are the
-- big-endian encoded @y@ coordinate.
--
-- Returns 'Nothing' if something is not satisfied.
parsePub :: B.ByteString -> Maybe I.Pub
{-# INLINE parsePub #-}
parsePub b = I.parsePubCompressed b <|> parsePubUncompressed b

-- | Builds a public key from its uncompressed SEC-encoded bytes.
--
-- Uncompressed keys are 65 bytes. The leftmost byte is @0x04@. The next 32
-- bytes are the big-endian encoded @x@ cordinate. The next 32 bytes are the
-- big-endian encoded @y@ coordinate.
--
-- Returns 'Nothing' if something is not satisfied.
parsePubUncompressed :: B.ByteString -> Maybe I.Pub
{-# INLINE parsePubUncompressed #-}
parsePubUncompressed b = do
  guard (B.length b == 65 && B.index b 0 == 0x04)
  let w0 = 0x02 + (B.index b 64 .&. 0x01)
  I.parsePubCompressed (B.cons w0 (B.take 32 (B.drop 1 b)))