Skip to content

Commit

Permalink
Merge pull request #28 from f-o-a-m/even-hexstrings
Browse files Browse the repository at this point in the history
Standardize HexString
  • Loading branch information
martyall authored Apr 29, 2022
2 parents 0655cd4 + e9cd6bd commit 332c4eb
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 36 deletions.
47 changes: 17 additions & 30 deletions src/Network/Ethereum/Core/HexString.purs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ module Network.Ethereum.Core.HexString
, asSigned
, mkHexString
, unHex
, hexLength
, dropHex
, takeHex
, numberOfBytes
, dropBytes
, takeBytes
, nullWord
, getPadLength
, padLeftSigned
Expand Down Expand Up @@ -45,7 +45,6 @@ import Network.Ethereum.Core.BigNumber (BigNumber, toString, hexadecimal)
import Node.Encoding (Encoding(Hex, UTF8, ASCII))
import Partial.Unsafe (unsafePartial)
import Simple.JSON (class ReadForeign, class WriteForeign)
import Text.Parsing.Parser.String (class StringLike)

--------------------------------------------------------------------------------
-- * Signed Values
Expand All @@ -58,13 +57,6 @@ derive instance eqSign :: Eq Sign
-- | Represents values that can be either positive or negative.
data Signed a = Signed Sign a

instance showSigned :: Show a => Show (Signed a) where
show (Signed s a) = s' <> show a
where
s' = case s of
Pos -> ""
Neg -> "-"

instance eqSigned :: Eq a => Eq (Signed a) where
eq (Signed s a) (Signed s' a') = (s `eq` s') && (a `eq` a')

Expand All @@ -83,17 +75,13 @@ asSigned a = Signed Pos a
newtype HexString = HexString String

instance showHexString :: Show HexString where
show (HexString hx) = "0x" <> hx

instance hexStringEq :: Eq HexString where
eq (HexString h1) (HexString h2) = S.toLower h1 == S.toLower h2
show (HexString s) = "0x" <> s

derive newtype instance hexStringEq :: Eq HexString
derive newtype instance hexStringOrd :: Ord HexString
derive newtype instance semigpStringEq :: Semigroup HexString
derive newtype instance monoidStringEq :: Monoid HexString

derive newtype instance stringLikeHexString :: StringLike HexString

_encode :: HexString -> String
_encode = append "0x" <<< unHex

Expand Down Expand Up @@ -147,15 +135,14 @@ mkHexString str | S.length str `mod` 2 /= 0 = Nothing
then go tail
else Nothing

-- | Compute the length of the hex string, which is twice the number of bytes it represents
hexLength :: HexString -> Int
hexLength (HexString hx) = S.length hx
numberOfBytes :: HexString -> Int
numberOfBytes (HexString hx) = S.length hx `div` 2

takeHex :: Int -> HexString -> HexString
takeHex n (HexString hx) = HexString $ S.take n hx
takeBytes :: Int -> HexString -> HexString
takeBytes n (HexString hx) = HexString $ S.take (2 * n) hx

dropHex :: Int -> HexString -> HexString
dropHex n (HexString hx) = HexString $ S.drop n hx
dropBytes :: Int -> HexString -> HexString
dropBytes n (HexString hx) = HexString $ S.drop (2 * n) hx

nullWord :: HexString
nullWord = HexString "0000000000000000000000000000000000000000000000000000000000000000"
Expand All @@ -168,23 +155,23 @@ nullWord = HexString "0000000000000000000000000000000000000000000000000000000000
-- | Computes the number of 0s needed to pad a bytestring of the input length
getPadLength :: Int -> Int
getPadLength len =
let n = len `mod` 64
in if n == 0 then 0 else 64 - n
let n = len `mod` 32
in if n == 0 then 0 else 32 - n

-- | Pad a `Signed HexString` on the left until it has length == 0 mod 64.
padLeftSigned :: Signed HexString -> HexString
padLeftSigned (Signed s hx) =
let padLength = getPadLength $ hexLength hx
let padLength = getPadLength $ numberOfBytes hx
sgn = if s `eq` Pos then '0' else 'f'
padding = unsafePartial fromJust <<< mkHexString <<< fromCharArray <<< replicate padLength $ sgn
padding = unsafePartial fromJust <<< mkHexString <<< fromCharArray <<< replicate (2 * padLength) $ sgn
in padding <> hx

-- | Pad a `Signed HexString` on the right until it has length 0 mod 64.
padRightSigned :: Signed HexString -> HexString
padRightSigned (Signed s hx) =
let padLength = getPadLength $ hexLength hx
let padLength = getPadLength $ numberOfBytes hx
sgn = if s `eq` Pos then '0' else 'f'
padding = unsafePartial fromJust <<< mkHexString <<< fromCharArray <<< replicate padLength $ sgn
padding = unsafePartial fromJust <<< mkHexString <<< fromCharArray <<< replicate (2 * padLength) $ sgn
in hx <> padding

-- | Pad a `HexString` on the left with '0's until it has length == 0 mod 64.
Expand Down
4 changes: 2 additions & 2 deletions src/Network/Ethereum/Core/Keccak256.purs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import Prelude

import Data.ByteString (ByteString, fromString)
import Data.Maybe (fromJust)
import Network.Ethereum.Core.HexString (HexString, fromByteString, takeHex, toByteString)
import Network.Ethereum.Core.HexString (HexString, fromByteString, takeBytes, toByteString)
import Node.Encoding (Encoding(UTF8))
import Partial.Unsafe (unsafePartial)

Expand All @@ -32,4 +32,4 @@ instance keccak256HexString :: Keccak256 HexString where

-- | convert a string representing a type signature into a selector
toSelector :: String -> HexString
toSelector = takeHex 8 <<< fromByteString <<< keccak256
toSelector = takeBytes 4 <<< fromByteString <<< keccak256
8 changes: 4 additions & 4 deletions src/Network/Ethereum/Core/Signatures.purs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import Data.Maybe (Maybe(..), fromJust)
import Effect (Effect)
import Foreign (ForeignError(..), fail)
import Foreign.Class (class Decode, class Encode, decode, encode)
import Network.Ethereum.Core.HexString (HexString, takeHex, nullWord, dropHex, hexLength, toByteString, fromByteString)
import Network.Ethereum.Core.HexString (HexString, takeBytes, nullWord, dropBytes, numberOfBytes, toByteString, fromByteString)
import Network.Ethereum.Core.Keccak256 (keccak256)
import Partial.Unsafe (unsafePartial)
import Simple.JSON (class ReadForeign, class WriteForeign)
Expand Down Expand Up @@ -140,10 +140,10 @@ unAddress :: Address -> HexString
unAddress (Address a) = a

mkAddress :: HexString -> Maybe Address
mkAddress hx = if hexLength hx == 40 then Just <<< Address $ hx else Nothing
mkAddress hx = if numberOfBytes hx == 20 then Just <<< Address $ hx else Nothing

nullAddress :: Address
nullAddress = Address $ takeHex 40 nullWord
nullAddress = Address $ takeBytes 20 nullWord

-- | Produce the `Address` corresponding to the `PrivateKey`.
privateToAddress
Expand All @@ -157,7 +157,7 @@ publicToAddress
-> Address
publicToAddress (PublicKey publicKey) =
let addrHex = fromByteString $ keccak256 publicKey
in unsafePartial fromJust <<< mkAddress $ dropHex 24 addrHex
in unsafePartial fromJust <<< mkAddress $ dropBytes 12 addrHex

newtype Signature =
Signature { r :: HexString
Expand Down

0 comments on commit 332c4eb

Please sign in to comment.