-- |
-- Module      : Crypto.Store.PKCS8.EC
-- License     : BSD-style
-- Maintainer  : Olivier Chéron <olivier.cheron@gmail.com>
-- Stability   : experimental
-- Portability : unknown
--
-- Additional EC utilities.
module Crypto.Store.PKCS8.EC
    ( numBytes
    , curveSizeBytes
    , curveOrderBytes
    , curveNameOID
    , getSerializedPoint
    , module Data.X509.EC
    ) where

import           Data.ASN1.OID
import qualified Data.ByteString as B
import           Data.Maybe (fromMaybe)

import Data.X509
import Data.X509.EC

import Crypto.Number.Basic (numBits, numBytes)
import Crypto.Number.Serialize (i2ospOf_)
import Crypto.PubKey.ECC.Prim
import Crypto.PubKey.ECC.Types

import Crypto.Store.CMS.Util

-- | Number of bytes necessary to serialize n bits.
bitsToBytes :: Int -> Int
bitsToBytes :: Int -> Int
bitsToBytes Int
n = (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
7) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
8

-- | Number of bytes to serialize a field element.
curveSizeBytes :: Curve -> Int
curveSizeBytes :: Curve -> Int
curveSizeBytes = Int -> Int
bitsToBytes (Int -> Int) -> (Curve -> Int) -> Curve -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Curve -> Int
curveSizeBits

-- | Number of bytes to serialize a scalar.
curveOrderBytes :: Curve -> Int
curveOrderBytes :: Curve -> Int
curveOrderBytes = Int -> Int
bitsToBytes (Int -> Int) -> (Curve -> Int) -> Curve -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Int
numBits (Integer -> Int) -> (Curve -> Integer) -> Curve -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CurveCommon -> Integer
ecc_n (CurveCommon -> Integer)
-> (Curve -> CurveCommon) -> Curve -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Curve -> CurveCommon
common_curve

-- | Transform a private scalar to a point in uncompressed format.
getSerializedPoint :: Curve -> PrivateNumber -> SerializedPoint
getSerializedPoint :: Curve -> Integer -> SerializedPoint
getSerializedPoint Curve
curve Integer
d = ByteString -> SerializedPoint
SerializedPoint (Point -> ByteString
serializePoint Point
pt)
  where
    pt :: Point
pt = Curve -> Integer -> Point
pointBaseMul Curve
curve Integer
d
    bs :: Integer -> ByteString
bs = Int -> Integer -> ByteString
forall ba. ByteArray ba => Int -> Integer -> ba
i2ospOf_ (Curve -> Int
curveSizeBytes Curve
curve)

    serializePoint :: Point -> ByteString
serializePoint Point
PointO      = Word8 -> ByteString
B.singleton Word8
0
    serializePoint (Point Integer
x Integer
y) = Word8 -> ByteString -> ByteString
B.cons Word8
4 (ByteString -> ByteString -> ByteString
B.append (Integer -> ByteString
bs Integer
x) (Integer -> ByteString
bs Integer
y))

-- | Return the OID associated to a curve name.
curveNameOID :: CurveName -> OID
curveNameOID :: CurveName -> OID
curveNameOID CurveName
name =
    OID -> Maybe OID -> OID
forall a. a -> Maybe a -> a
fromMaybe ([Char] -> OID
forall a. HasCallStack => [Char] -> a
error ([Char] -> OID) -> [Char] -> OID
forall a b. (a -> b) -> a -> b
$ [Char]
"PKCS8: OID unknown for EC curve " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ CurveName -> [Char]
forall a. Show a => a -> [Char]
show CurveName
name)
        (OIDTable CurveName -> CurveName -> Maybe OID
forall a. Eq a => OIDTable a -> a -> Maybe OID
lookupOID OIDTable CurveName
curvesOIDTable CurveName
name)

curvesOIDTable :: OIDTable CurveName
curvesOIDTable :: OIDTable CurveName
curvesOIDTable =
    [ (CurveName
SEC_p112r1, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
6])
    , (CurveName
SEC_p112r2, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
7])
    , (CurveName
SEC_p128r1, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
28])
    , (CurveName
SEC_p128r2, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
29])
    , (CurveName
SEC_p160k1, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
9])
    , (CurveName
SEC_p160r1, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
8])
    , (CurveName
SEC_p160r2, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
30])
    , (CurveName
SEC_p192k1, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
31])
    , (CurveName
SEC_p192r1, [Integer
1,Integer
2,Integer
840,Integer
10045,Integer
3,Integer
1,Integer
1])
    , (CurveName
SEC_p224k1, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
32])
    , (CurveName
SEC_p224r1, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
33])
    , (CurveName
SEC_p256k1, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
10])
    , (CurveName
SEC_p256r1, [Integer
1,Integer
2,Integer
840,Integer
10045,Integer
3,Integer
1,Integer
7])
    , (CurveName
SEC_p384r1, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
34])
    , (CurveName
SEC_p521r1, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
35])
    , (CurveName
SEC_t113r1, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
4])
    , (CurveName
SEC_t113r2, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
5])
    , (CurveName
SEC_t131r1, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
22])
    , (CurveName
SEC_t131r2, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
23])
    , (CurveName
SEC_t163k1, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
1])
    , (CurveName
SEC_t163r1, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
2])
    , (CurveName
SEC_t163r2, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
15])
    , (CurveName
SEC_t193r1, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
24])
    , (CurveName
SEC_t193r2, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
25])
    , (CurveName
SEC_t233k1, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
26])
    , (CurveName
SEC_t233r1, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
27])
    , (CurveName
SEC_t239k1, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
3])
    , (CurveName
SEC_t283k1, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
16])
    , (CurveName
SEC_t283r1, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
17])
    , (CurveName
SEC_t409k1, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
36])
    , (CurveName
SEC_t409r1, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
37])
    , (CurveName
SEC_t571k1, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
38])
    , (CurveName
SEC_t571r1, [Integer
1,Integer
3,Integer
132,Integer
0,Integer
39])
    ]