summaryrefslogtreecommitdiff
path: root/dht/src/Crypto/XEd25519.hs
diff options
context:
space:
mode:
authorJames Crayne <jim.crayne@gmail.com>2019-09-28 13:43:29 -0400
committerJoe Crayne <joe@jerkface.net>2020-01-01 19:27:53 -0500
commit11987749fc6e6d3e53ea737d46d5ab13a16faeb8 (patch)
tree5716463275c2d3e902889db619908ded2a73971c /dht/src/Crypto/XEd25519.hs
parentadd2c76bced51fde5e9917e7449ef52be70faf87 (diff)
Factor out some new libraries
word64-map: Data.Word64Map network-addr: Network.Address tox-crypto: Crypto.Tox lifted-concurrent: Control.Concurrent.Lifted.Instrument Control.Concurrent.Async.Lifted.Instrument psq-wrap: Data.Wrapper.PSQInt Data.Wrapper.PSQ minmax-psq: Data.MinMaxPSQ tasks: Control.Concurrent.Tasks kad: Network.Kademlia Network.Kademlia.Bootstrap Network.Kademlia.Routing Network.Kademlia.CommonAPI Network.Kademlia.Persistence Network.Kademlia.Search
Diffstat (limited to 'dht/src/Crypto/XEd25519.hs')
-rw-r--r--dht/src/Crypto/XEd25519.hs185
1 files changed, 185 insertions, 0 deletions
diff --git a/dht/src/Crypto/XEd25519.hs b/dht/src/Crypto/XEd25519.hs
new file mode 100644
index 00000000..372f31a8
--- /dev/null
+++ b/dht/src/Crypto/XEd25519.hs
@@ -0,0 +1,185 @@
1module Crypto.XEd25519 where
2
3import Control.Arrow
4import Data.Bits
5import Data.ByteArray as BA
6import Data.Memory.PtrMethods (memCopy)
7import Crypto.Hash
8import Crypto.ECC.Edwards25519
9import Crypto.Error
10import qualified Crypto.PubKey.Ed25519 as Ed25519
11import Foreign.Marshal
12import Foreign.Ptr
13import Foreign.Storable
14import qualified Crypto.PubKey.Curve25519 as X25519
15
16import Crypto.XEd25519.FieldElement
17import Crypto.Nonce
18
19
20data SecretKey = SecretKey { secretScalar :: Scalar }
21
22data PublicKey = PublicKey Ed25519.PublicKey
23 deriving Eq
24
25type Nonce = Nonce32
26
27newtype EncodedPoint = EncodedPoint Point
28
29instance ByteArrayAccess SecretKey where
30 length _ = 32
31 withByteArray (SecretKey scalar) = withByteArray (scalarEncode scalar :: Bytes)
32
33instance ByteArrayAccess PublicKey where
34 length _ = 32
35 withByteArray (PublicKey edpub) = withByteArray edpub
36
37instance ByteArrayAccess EncodedPoint where
38 length _ = 32
39 withByteArray (EncodedPoint pt) f =
40 withByteArray (pointEncode pt :: Bytes) f
41
42
43data Signature = Signature EncodedPoint Scalar
44
45instance ByteArrayAccess Signature where
46 length _ = 64
47 withByteArray (Signature pt scalar) f =
48 withByteArray pt $ \ptptr -> do
49 withByteArray (SecretKey scalar) $ \scalarptr -> do
50 allocaBytes 64 $ \ptr -> do
51 memCopy ptr ptptr 32
52 memCopy (ptr `plusPtr` 32) scalarptr 32
53 f (castPtr ptr)
54
55
56padding :: Bytes
57padding = 0xFE `BA.cons` BA.replicate 31 0xFF
58
59sign :: ByteArrayAccess dta => dta -> Nonce -> SecretKey -> PublicKey -> Signature
60sign dta nonce sec pub = Signature rB s
61 where
62 rB = ge_p3_tobytes $ ge_scalarmult_base r
63
64 r = sc_reduce $ hashFinalize $ (`hashUpdate` padding)
65 >>> (`hashUpdate` sec)
66 >>> (`hashUpdate` dta)
67 >>> (`hashUpdate` nonce) $ hashInit
68
69 h = sc_reduce $ hashFinalize $ (`hashUpdate` rB)
70 >>> (`hashUpdate` pub)
71 >>> (`hashUpdate` dta) $ hashInit
72
73 -- s = r + ha (mod q)
74 s = sc_muladd h (secretScalar sec) r
75
76
77
78ge_p3_tobytes :: Point -> EncodedPoint
79ge_p3_tobytes = EncodedPoint
80
81ge_scalarmult_base :: Scalar -> Point
82ge_scalarmult_base = toPoint
83
84sc_muladd :: Scalar -> Scalar -> Scalar -> Scalar
85sc_muladd a b c = scalarAdd (scalarMul a b) c
86
87sc_reduce :: Digest SHA512 -> Scalar
88sc_reduce digest = x where CryptoPassed x = scalarDecodeLong digest -- ???
89
90-- Scalar is internally, at least on 64bit machines, represented as 5
91-- 56-bit words in little-endian order, each encoded as a Word64.
92sc_neg :: Scalar -> Scalar
93sc_neg = scalarMul sc_neg1
94
95verify :: ByteArrayAccess dta => PublicKey -> dta -> Signature -> Bool
96verify pub dta signature = Ed25519.verify ed_pub dta ed_sig
97 where
98 CryptoPassed ed_pub = Ed25519.publicKey pub'
99 CryptoPassed ed_sig = Ed25519.signature signature'
100
101 -- Get the sign bit from the s part of the signature.
102 sign_bit = BA.index signature 63 .&. 0x80
103
104 -- Set the sign bit to zero in the s part of the signature.
105 signature' :: Bytes
106 signature' = BA.copyAndFreeze signature $ \ptr -> do
107 let at63 = plusPtr ptr 63
108 byte63 <- peek at63
109 poke at63 $ byte63 .&. (0x7F `asTypeOf` sign_bit)
110
111 -- Restore the sign bit on the verification key, which should have 0 as its
112 -- current sign bit.
113 pub' :: Bytes
114 pub' = BA.copyAndFreeze pub $ \ptr -> do
115 let at31 = plusPtr ptr 31
116 byte31 <- peek at31
117 poke at31 $ (byte31 .&. 0x7F) .|. sign_bit
118
119
120-- typedef crypto_int32 fe[10];
121--
122-- fe means field element. Here the field is \Z/(2^255-19).
123-- An element t, entries t[0]...t[9], represents the integer
124-- t[0]+2^26 t[1]+2^51 t[2]+2^77 t[3]+2^102 t[4]+...+2^230 t[9].
125-- Bounds on each t[i] vary depending on context.
126
127-- mont_pub_to_ed_pub
128toSigningKey :: X25519.PublicKey -> PublicKey
129toSigningKey mont_pub0 = PublicKey ed_pub
130 where
131 -- Read the public key as a field element
132 mont_pub = fe_frombytes mont_pub0
133
134 -- Convert the Montgomery public key to a twisted Edwards public key
135 fe_ONE = fe_1
136
137 -- Calculate the parameters (u - 1) and (u + 1)
138 mont_pub_minus_one = fe_sub mont_pub fe_ONE
139 mont_pub_plus_one0 = fe_add mont_pub fe_ONE
140
141 -- Prepare inv(u + 1)
142 mont_pub_plus_one = fe_invert mont_pub_plus_one0
143
144 -- Calculate y = (u - 1) * inv(u + 1) (mod p)
145 ed_pub0 = fe_mul mont_pub_minus_one mont_pub_plus_one
146 ed_pub = fe_tobytes ed_pub0
147
148-- mont_priv_to_ed_pair
149toSigningKeyPair :: X25519.SecretKey -> (SecretKey,PublicKey)
150toSigningKeyPair mont_priv0 = (SecretKey ed_priv, PublicKey ed_pub)
151 where
152 -- Prepare a buffer for the twisted Edwards private key
153 ed_priv1 = (throwCryptoError . scalarDecodeLong :: X25519.SecretKey -> Scalar) mont_priv0
154
155 -- Get the twisted edwards public key, including the sign bit
156 ed_pub0 = ge_p3_tobytes $ ge_scalarmult_base ed_priv1
157
158 -- Save the sign bit for later
159 sign_bit = (BA.index ed_pub0 31 `shiftR` 7) .&. 1
160
161 -- Force the sign bit to zero
162 pub' :: Bytes
163 pub' = BA.copyAndFreeze ed_pub0 $ \ptr -> do
164 let at31 = plusPtr ptr 31
165 byte31 <- peek at31
166 poke at31 $ (byte31 .&. 0x7F) `asTypeOf` sign_bit
167
168 CryptoPassed ed_pub = Ed25519.publicKey pub'
169
170
171 -- Prepare the negated private key
172 ed_priv_neg = sc_neg ed_priv1
173
174 -- Get the correct private key based on the sign stored above
175 ed_priv = if sign_bit/=0 then ed_priv_neg
176 else ed_priv1
177
178-- sc_zero = throwCryptoError $ scalarDecodeLong (b::Bytes)
179-- where
180-- b = BA.pack $ encodeLittleEndian $ 2^252 + 27742317777372353535851937790883648493
181
182sc_neg1 :: Scalar
183sc_neg1 = throwCryptoError $ scalarDecodeLong (b::Bytes)
184 where
185 b = BA.pack $ encodeLittleEndian $ 2^252 + 27742317777372353535851937790883648492