-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCrypto.hs
More file actions
102 lines (84 loc) · 3.17 KB
/
Crypto.hs
File metadata and controls
102 lines (84 loc) · 3.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
{-# LANGUAGE OverloadedStrings #-}
module Crypto (
DSA.PublicKey,
DSA.PrivateKey,
DSA.Signature,
Crypto.verify,
Crypto.hash,
Crypto.sign,
Digest,
SHA256,
KeyPair(..),
MerkleTree,
MerkleRoot,
merkle_root,
regKeys,
hexPubKey_,
getPubKey_
) where
import Crypto.PubKey.ECC.Prim
import Crypto.PubKey.ECC.Types
import Crypto.Number.Serialize
import Crypto.Hash
import Crypto.Hash.MerkleTree
import qualified Crypto.PubKey.ECC.ECDSA as DSA
import qualified Crypto.PubKey.ECC.Generate as EG
import Data.Monoid
import Data.ByteString (ByteString)
import Data.ByteString.Char8
import Data.ByteString.Base16
import Math.NumberTheory.Moduli.Sqrt
-- | Using Curve SEC-p256k1 for all DSA processes: y^2 = x^3 + 7
--
-- from bitcoin wiki: https://en.bitcoin.it/wiki/Secp256k1
-- secp256k1 refers to the parameters of the elliptic curve used in Bitcoin's public-key cryptography,
-- and is defined in Standards for Efficient Cryptography (SEC) (Certicom Research, http://www.secg.org/sec2-v2.pdf).
secp256k1 :: Curve
secp256k1 = getCurveByName SEC_p256k1
p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
type KeyPair = (DSA.PublicKey, DSA.PrivateKey)
-- | Register an Eliptic Curve KeyPair, from the secp256k1 Curve
regKeys :: IO KeyPair
regKeys = EG.generate secp256k1
-- return $ KeyPair secp256k1 (public_q p) (private_d s)
-- | Hex version, uncompressed form of Public Key from a Pair
-- 64 hex bytes in long: 32 bytes of x-coordinate + 32 of y-coordinate
hexPubKey :: DSA.PublicKey -> ByteString
hexPubKey k = encode (i2osp x <> i2osp y) where
Point x y = DSA.public_q k
-- | Hex version, compressed form of Public Key from a Pair
-- 33 hex bytes in long: 1 flag-byte calculate from y + 32 bytes of x-coordinate
hexPubKey_ :: DSA.PublicKey -> ByteString
hexPubKey_ k = append (trans y) $ encode (i2osp x) where
Point x y = DSA.public_q k
trans n = if even n then "02" else "03"
-- | Extract public hex-address to Original Public Key
getPubKey_ :: ByteString -> Maybe DSA.PublicKey
getPubKey_ k = if (isPointValid_ x y) then Just $ DSA.PublicKey secp256k1 (Point x y) else Nothing where
y = y_from_x f x
x = os2ip . fst $ decode s
(f, s) = Data.ByteString.Char8.splitAt 2 k
-- | Calculate y-coordinate from a flag & x-coordinate
y_from_x "02" x
| even (sqrt_mod x) = sqrt_mod x
| otherwise = p - sqrt_mod x
y_from_x "03" x
| odd (sqrt_mod x) = sqrt_mod x
| otherwise = p - sqrt_mod x
y_from_x _ x = 0
-- | Modular Square Root, hard to explain..
sqrt_mod x = sqrtModP' (mod y2 p) p where y2 = x^3 + 7
-- | Check if (Point x y) is valid with secp256k1 Curve or not
isPointValid_ x y = isPointValid secp256k1 (Point x y)
-- | Hash raw data with SHA256 hash function
hash :: ByteString -> Digest SHA256
hash m = hashWith SHA256 m
-- | Return mekle root of hashed leaves
merkle_root :: [ByteString] -> ByteString
merkle_root = mtHash . mkMerkleTree
-- | Sign with SHA256 hash function
sign :: DSA.PrivateKey -> Digest SHA256 -> IO DSA.Signature
sign pk m = DSA.sign pk SHA256 m
-- | Verify with SHA256 hash function
verify :: DSA.PublicKey -> DSA.Signature -> Digest SHA256 -> Bool
verify = DSA.verify SHA256