summaryrefslogtreecommitdiff
path: root/ToxAddress.hs
diff options
context:
space:
mode:
Diffstat (limited to 'ToxAddress.hs')
-rw-r--r--ToxAddress.hs91
1 files changed, 70 insertions, 21 deletions
diff --git a/ToxAddress.hs b/ToxAddress.hs
index c95c221b..6a724d0f 100644
--- a/ToxAddress.hs
+++ b/ToxAddress.hs
@@ -1,3 +1,4 @@
1{-# LANGUAGE ApplicativeDo #-}
1{-# LANGUAGE BangPatterns #-} 2{-# LANGUAGE BangPatterns #-}
2{-# LANGUAGE CPP #-} 3{-# LANGUAGE CPP #-}
3{-# LANGUAGE DataKinds #-} 4{-# LANGUAGE DataKinds #-}
@@ -13,7 +14,18 @@
13{-# LANGUAGE ScopedTypeVariables #-} 14{-# LANGUAGE ScopedTypeVariables #-}
14{-# LANGUAGE TupleSections #-} 15{-# LANGUAGE TupleSections #-}
15{-# LANGUAGE TypeApplications #-} 16{-# LANGUAGE TypeApplications #-}
16module ToxAddress (NodeInfo(..),NodeId(..),nodeInfo,nodeAddr,zeroID,key2id,id2key,getIP) where 17module ToxAddress
18 ( NodeInfo(..)
19 , NodeId
20 , nodeInfo
21 , nodeAddr
22 , zeroID
23 , key2id
24 , id2key
25 , getIP
26 , xorNodeId
27 , testNodeIdBit
28 , sampleNodeId) where
17 29
18import Control.Applicative 30import Control.Applicative
19import Control.Monad 31import Control.Monad
@@ -43,6 +55,9 @@ import qualified Text.ParserCombinators.ReadP as RP
43import Text.Read 55import Text.Read
44import Data.Bits 56import Data.Bits
45import ToxCrypto 57import ToxCrypto
58import Foreign.Ptr
59import Data.Function
60import System.Endian
46 61
47-- | perform io for hashes that do allocation and ffi. 62-- | perform io for hashes that do allocation and ffi.
48-- unsafeDupablePerformIO is used when possible as the 63-- unsafeDupablePerformIO is used when possible as the
@@ -56,22 +71,34 @@ unsafeDoIO = unsafeDupablePerformIO
56unsafeDoIO = unsafePerformIO 71unsafeDoIO = unsafePerformIO
57#endif 72#endif
58 73
59unpackPublicKey :: PublicKey -> [Word64] 74unpackPublicKey :: ByteArrayAccess bs => bs -> [Word64]
60unpackPublicKey bs = loop 0 75unpackPublicKey bs = loop 0
61 where loop i 76 where loop i
62 | i == 4 = [] 77 | i == (BA.length bs `div` 8) = []
63 | otherwise = 78 | otherwise =
64 let !v = unsafeDoIO $ BA.withByteArray bs (\p -> peekElemOff p i) 79 let !v = unsafeDoIO $ BA.withByteArray bs (\p -> fromBE64 <$> peekElemOff p i)
65 in v : loop (i+1) 80 in v : loop (i+1)
66 81
67newtype NodeId = NodeId PublicKey 82packPublicKey :: BA.ByteArray bs => [Word64] -> bs
68 deriving (Eq,ByteArrayAccess) -- (Eq,Ord,ByteArrayAccess, Bits, Hashable) 83packPublicKey ws = BA.allocAndFreeze (8 * length ws) $
84 flip fix ws $ \loop ys ptr -> case ys of
85 [] -> return ()
86 x:xs -> do poke ptr (toBE64 x)
87 loop xs (plusPtr ptr 8)
88
89newtype NodeId = NodeId [Word64]
90 deriving (Eq,Ord) -- ByteArrayAccess) -- (Eq,Ord,ByteArrayAccess, Bits, Hashable)
91
69 92
70key2id :: PublicKey -> NodeId 93key2id :: PublicKey -> NodeId
71key2id = NodeId 94key2id = NodeId . unpackPublicKey
95
96bs2id :: ByteString -> NodeId
97bs2id bs = NodeId . unpackPublicKey $ throwCryptoError . publicKey $ bs
72 98
73id2key :: NodeId -> PublicKey 99id2key :: NodeId -> PublicKey
74id2key (NodeId key) = key 100id2key (NodeId key) = throwCryptoError . publicKey $ (packPublicKey key :: BA.Bytes)
101
75 102
76{- 103{-
77id2key :: NodeId -> PublicKey 104id2key :: NodeId -> PublicKey
@@ -87,33 +114,55 @@ key2id pk = case S.decode (BA.convert pk) of
87 114
88-} 115-}
89 116
117{-
90instance Ord NodeId where 118instance Ord NodeId where
91 compare (NodeId a) (NodeId b) = compare (unpackPublicKey a) (unpackPublicKey b) 119 compare (NodeId a) (NodeId b) = compare (unpackPublicKey a) (unpackPublicKey b)
120-}
92 121
93zeroID :: NodeId 122zeroID :: NodeId
94zeroID = NodeId $ throwCryptoError $ publicKey $ B.replicate 32 0 123zeroID = NodeId $ replicate 4 0 -- throwCryptoError $ publicKey $ B.replicate 32 0
95 124
96instance Read NodeId where 125instance Read NodeId where
97 readsPrec _ str 126 readsPrec _ str
98 | (bs, xs) <- Base16.decode $ C8.pack str 127 | (bs, xs) <- Base16.decode $ C8.pack str
99 , CryptoPassed pub <- publicKey bs -- B.length bs == 32 128 , CryptoPassed pub <- publicKey bs -- B.length bs == 32
100 = [ (NodeId pub, drop 64 str) ] 129 = [ (key2id pub, drop 64 str) ]
101 | otherwise = [] 130 | otherwise = []
102 131
103instance Show NodeId where 132instance Show NodeId where
104 show (NodeId bs) = C8.unpack $ Base16.encode $ BA.convert bs 133 show nid = C8.unpack $ Base16.encode $ BA.convert $ id2key nid
105 134
106instance S.Serialize NodeId where 135instance S.Serialize NodeId where
107 get = NodeId <$> getPublicKey 136 get = key2id <$> getPublicKey
108 put (NodeId bs) = putPublicKey bs 137 put nid = putPublicKey $ id2key nid
109
110instance Bits NodeId where -- TODO
111 138
112instance Hashable NodeId where 139instance Hashable NodeId where
113 hashWithSalt salt (NodeId key) = hashWithSalt salt (BA.convert key :: ByteString) 140 hashWithSalt salt (NodeId key) = salt `xor` fromIntegral (byteSwap64 $ head key)
114 141
115instance FiniteBits NodeId where 142-- instance FiniteBits NodeId where finiteBitSize _ = 256
116 finiteBitSize _ = 256 143
144testNodeIdBit :: NodeId -> Word -> Bool
145testNodeIdBit (NodeId ws) i
146 | fromIntegral i < 256 -- 256 bits
147 , (q, r) <- quotRem (fromIntegral i) 64
148 = testBit (ws !! q) (63 - r)
149 | otherwise = False
150
151xorNodeId :: NodeId -> NodeId -> NodeId
152xorNodeId (NodeId xs) (NodeId ys) = NodeId $ zipWith xor xs ys
153
154sampleNodeId :: Applicative m => (Int -> m ByteString) -> NodeId -> (Int,Word8,Word8) -> m NodeId
155sampleNodeId gen (NodeId self) (q,m,b)
156 | q <= 0 = bs2id <$> gen 32
157 | q >= 32 = pure (NodeId self)
158 | let (qw,r) = (q+7) `divMod` 8 -- How many Word64 to prepend?
159 bw = shiftL (fromIntegral b) (8*(7-r))
160 mw = bw - 1 :: Word64
161 (hd, t0 : _) = splitAt (qw-1) self
162 h = xor bw (complement mw .&. t0)
163 = flip fmap (gen $ 8 * (4 - (qw-1)) ) $ \bs ->
164 let (w:ws) = unpackPublicKey bs
165 in NodeId $ hd ++ (h .|. (w .&. mw)) : ws
117 166
118data NodeInfo = NodeInfo 167data NodeInfo = NodeInfo
119 { nodeId :: NodeId 168 { nodeId :: NodeId
@@ -156,7 +205,7 @@ instance FromJSON NodeInfo where
156 <|> maybe empty (return . IPv4) (ip4str >>= readMaybe) 205 <|> maybe empty (return . IPv4) (ip4str >>= readMaybe)
157 let (bs,_) = Base16.decode (C8.pack nidstr) 206 let (bs,_) = Base16.decode (C8.pack nidstr)
158 guard (B.length bs == 32) 207 guard (B.length bs == 32)
159 return $ NodeInfo (NodeId $ throwCryptoError . publicKey $ bs) ip (fromIntegral (portnum :: Word16)) 208 return $ NodeInfo (bs2id bs) ip (fromIntegral (portnum :: Word16))
160 209
161getIP :: Word8 -> S.Get IP 210getIP :: Word8 -> S.Get IP
162getIP 0x02 = IPv4 <$> S.get 211getIP 0x02 = IPv4 <$> S.get
@@ -199,7 +248,7 @@ instance Read NodeInfo where
199 RP.char '@' RP.+++ RP.satisfy isSpace 248 RP.char '@' RP.+++ RP.satisfy isSpace
200 addrstr <- parseAddr 249 addrstr <- parseAddr
201 nid <- case Base16.decode $ C8.pack hexhash of 250 nid <- case Base16.decode $ C8.pack hexhash of
202 (bs,_) | B.length bs==32 -> return (NodeId $ throwCryptoError . publicKey $ bs) 251 (bs,_) | B.length bs==32 -> return (bs2id bs)
203 _ -> fail "Bad node id." 252 _ -> fail "Bad node id."
204 return (nid,addrstr) 253 return (nid,addrstr)
205 (nid,addrstr) <- ( nodeidAt RP.+++ ( (zeroID,) <$> parseAddr) ) 254 (nid,addrstr) <- ( nodeidAt RP.+++ ( (zeroID,) <$> parseAddr) )