diff options
Diffstat (limited to 'ToxAddress.hs')
-rw-r--r-- | ToxAddress.hs | 91 |
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 #-} |
16 | module ToxAddress (NodeInfo(..),NodeId(..),nodeInfo,nodeAddr,zeroID,key2id,id2key,getIP) where | 17 | module 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 | ||
18 | import Control.Applicative | 30 | import Control.Applicative |
19 | import Control.Monad | 31 | import Control.Monad |
@@ -43,6 +55,9 @@ import qualified Text.ParserCombinators.ReadP as RP | |||
43 | import Text.Read | 55 | import Text.Read |
44 | import Data.Bits | 56 | import Data.Bits |
45 | import ToxCrypto | 57 | import ToxCrypto |
58 | import Foreign.Ptr | ||
59 | import Data.Function | ||
60 | import 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 | |||
56 | unsafeDoIO = unsafePerformIO | 71 | unsafeDoIO = unsafePerformIO |
57 | #endif | 72 | #endif |
58 | 73 | ||
59 | unpackPublicKey :: PublicKey -> [Word64] | 74 | unpackPublicKey :: ByteArrayAccess bs => bs -> [Word64] |
60 | unpackPublicKey bs = loop 0 | 75 | unpackPublicKey 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 | ||
67 | newtype NodeId = NodeId PublicKey | 82 | packPublicKey :: BA.ByteArray bs => [Word64] -> bs |
68 | deriving (Eq,ByteArrayAccess) -- (Eq,Ord,ByteArrayAccess, Bits, Hashable) | 83 | packPublicKey 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 | |||
89 | newtype NodeId = NodeId [Word64] | ||
90 | deriving (Eq,Ord) -- ByteArrayAccess) -- (Eq,Ord,ByteArrayAccess, Bits, Hashable) | ||
91 | |||
69 | 92 | ||
70 | key2id :: PublicKey -> NodeId | 93 | key2id :: PublicKey -> NodeId |
71 | key2id = NodeId | 94 | key2id = NodeId . unpackPublicKey |
95 | |||
96 | bs2id :: ByteString -> NodeId | ||
97 | bs2id bs = NodeId . unpackPublicKey $ throwCryptoError . publicKey $ bs | ||
72 | 98 | ||
73 | id2key :: NodeId -> PublicKey | 99 | id2key :: NodeId -> PublicKey |
74 | id2key (NodeId key) = key | 100 | id2key (NodeId key) = throwCryptoError . publicKey $ (packPublicKey key :: BA.Bytes) |
101 | |||
75 | 102 | ||
76 | {- | 103 | {- |
77 | id2key :: NodeId -> PublicKey | 104 | id2key :: NodeId -> PublicKey |
@@ -87,33 +114,55 @@ key2id pk = case S.decode (BA.convert pk) of | |||
87 | 114 | ||
88 | -} | 115 | -} |
89 | 116 | ||
117 | {- | ||
90 | instance Ord NodeId where | 118 | instance 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 | ||
93 | zeroID :: NodeId | 122 | zeroID :: NodeId |
94 | zeroID = NodeId $ throwCryptoError $ publicKey $ B.replicate 32 0 | 123 | zeroID = NodeId $ replicate 4 0 -- throwCryptoError $ publicKey $ B.replicate 32 0 |
95 | 124 | ||
96 | instance Read NodeId where | 125 | instance 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 | ||
103 | instance Show NodeId where | 132 | instance 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 | ||
106 | instance S.Serialize NodeId where | 135 | instance 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 | |||
110 | instance Bits NodeId where -- TODO | ||
111 | 138 | ||
112 | instance Hashable NodeId where | 139 | instance 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 | ||
115 | instance FiniteBits NodeId where | 142 | -- instance FiniteBits NodeId where finiteBitSize _ = 256 |
116 | finiteBitSize _ = 256 | 143 | |
144 | testNodeIdBit :: NodeId -> Word -> Bool | ||
145 | testNodeIdBit (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 | |||
151 | xorNodeId :: NodeId -> NodeId -> NodeId | ||
152 | xorNodeId (NodeId xs) (NodeId ys) = NodeId $ zipWith xor xs ys | ||
153 | |||
154 | sampleNodeId :: Applicative m => (Int -> m ByteString) -> NodeId -> (Int,Word8,Word8) -> m NodeId | ||
155 | sampleNodeId 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 | ||
118 | data NodeInfo = NodeInfo | 167 | data 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 | ||
161 | getIP :: Word8 -> S.Get IP | 210 | getIP :: Word8 -> S.Get IP |
162 | getIP 0x02 = IPv4 <$> S.get | 211 | getIP 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) ) |