Skip to content

Commit

Permalink
remove purescript-bytestring dep (#41)
Browse files Browse the repository at this point in the history
* remove purescript-bytestring dep

* tidy
  • Loading branch information
martyall authored Apr 21, 2024
1 parent 2c91435 commit aaa64b1
Show file tree
Hide file tree
Showing 10 changed files with 97 additions and 131 deletions.
34 changes: 1 addition & 33 deletions packages.dhall
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,4 @@ let upstream =
https://github.com/purescript/package-sets/releases/download/psc-0.15.15-20240416/packages.dhall
sha256:ca727657c01cc31d0e79c2113b59126b9826f4b56d20a8193be3c725599fb754


let additions =
{ bytestrings =
{ dependencies =
[ "arrays"
, "console"
, "effect"
, "exceptions"
, "foldable-traversable"
, "integers"
, "leibniz"
, "maybe"
, "newtype"
, "node-buffer"
, "partial"
, "prelude"
, "quickcheck"
, "quickcheck-laws"
, "quotient"
, "unsafe-coerce"
]
, repo =
"https://github.com/rightfold/purescript-bytestrings"
, version = "6733a32fca306015b3428e9985ffac65325a9864"
}
, quotient =
{ dependencies = [ "prelude", "quickcheck" ]
, repo = "https://github.com/rightfold/purescript-quotient.git"
, version = "v3.0.0"
}
}

in upstream // additions
in upstream
2 changes: 0 additions & 2 deletions spago.dhall
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
, dependencies =
[ "argonaut"
, "arrays"
, "bytestrings"
, "effect"
, "either"
, "foldable-traversable"
Expand All @@ -19,7 +18,6 @@
, "ordered-collections"
, "partial"
, "prelude"
, "quotient"
, "simple-json"
, "strings"
, "unfoldable"
Expand Down
30 changes: 16 additions & 14 deletions src/Network/Ethereum/Core/HexString.purs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ module Network.Ethereum.Core.HexString
, fromUtf8
, toAscii
, fromAscii
, toByteString
, fromByteString
, toBuffer
, fromBuffer
, generator
) where

Expand All @@ -27,7 +27,7 @@ import Control.Monad.Gen (class MonadGen, oneOf)
import Data.Argonaut as A
import Data.Array (fold, fromFoldable, replicate, unsafeIndex)
import Data.Array.NonEmpty as NEA
import Data.ByteString as BS
import Node.Buffer.Immutable as B
import Data.Either (Either(..), either)
import Data.List.Lazy (replicateM)
import Data.Maybe (Maybe(..), fromJust)
Expand Down Expand Up @@ -137,33 +137,35 @@ nullWord = HexString "0000000000000000000000000000000000000000000000000000000000
-- | This breaks at the first null octet, following the web3 function `toUft8`.
-- Since 'split' always returns a nonempty list, this index is actually safe.
toUtf8 :: HexString -> String
toUtf8 hx = flip BS.toString UTF8 $ bs (unHex hx)
toUtf8 hx = B.toString UTF8 $ bs (unHex hx)
where
bs :: String -> BS.ByteString
bs hxstr = unsafePartial fromJust $ BS.fromString hxstr Hex
bs :: String -> B.ImmutableBuffer
bs hxstr = B.fromString hxstr Hex

-- | Takes a hex string and produces the corresponding ASCII decoded string.
toAscii :: HexString -> String
toAscii hx = flip BS.toString ASCII $ unsafePartial $ fromJust $ BS.fromString (unHex hx) Hex
toAscii hx = B.toString ASCII $ B.fromString (unHex hx) Hex

-- | Get the 'HexString' corresponding to the UTF8 encoding.
fromUtf8 :: String -> HexString
fromUtf8 s = unsafePartial fromJust $
let
s' = unsafePartial $ split (Pattern "\x0000") s `unsafeIndex` 0
in
BS.fromString s' UTF8 >>= (pure <<< flip BS.toString Hex) >>= mkHexString
mkHexString $ B.toString Hex $ B.fromString s' UTF8

-- | Get the 'HexString' corresponding to the ASCII encoding.
fromAscii :: String -> HexString
fromAscii s = unsafePartial fromJust $
BS.fromString s ASCII >>= (pure <<< flip BS.toString Hex) >>= mkHexString
fromAscii s = unsafePartial fromJust
$ mkHexString
$ B.toString Hex
$ B.fromString s ASCII

toByteString :: HexString -> BS.ByteString
toByteString hx = unsafePartial fromJust (BS.fromString (unHex hx) Hex)
toBuffer :: HexString -> B.ImmutableBuffer
toBuffer hx = B.fromString (unHex hx) Hex

fromByteString :: BS.ByteString -> HexString
fromByteString bs = unsafePartial fromJust $ mkHexString (BS.toString bs Hex)
fromBuffer :: B.ImmutableBuffer -> HexString
fromBuffer bs = unsafePartial $ fromJust $ mkHexString $ B.toString Hex bs

--------------------------------------------------------------------------------

Expand Down
18 changes: 8 additions & 10 deletions src/Network/Ethereum/Core/Keccak256.purs
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,28 @@ module Network.Ethereum.Core.Keccak256

import Prelude

import Data.ByteString (ByteString, fromString)
import Data.Maybe (fromJust)
import Network.Ethereum.Core.HexString (HexString, fromByteString, takeBytes, toByteString)
import Node.Buffer.Immutable (ImmutableBuffer, fromString)
import Network.Ethereum.Core.HexString (HexString, fromBuffer, takeBytes, toBuffer)
import Node.Encoding (Encoding(UTF8))
import Partial.Unsafe (unsafePartial)

--------------------------------------------------------------------------------

-- | A class for things which you can hash. Mostly used as a utility for calculating selectors and
-- | event topics
class Keccak256 a where
keccak256 :: a -> ByteString
keccak256 :: a -> ImmutableBuffer

foreign import _keccak256 :: ByteString -> ByteString
foreign import _keccak256 :: ImmutableBuffer -> ImmutableBuffer

instance Keccak256 ByteString where
instance Keccak256 ImmutableBuffer where
keccak256 = _keccak256

instance Keccak256 String where
keccak256 = keccak256 <<< unsafePartial fromJust <<< flip fromString UTF8
keccak256 s = keccak256 $ fromString s UTF8

instance Keccak256 HexString where
keccak256 = keccak256 <<< toByteString
keccak256 = keccak256 <<< toBuffer

-- | convert a string representing a type signature into a selector
toSelector :: String -> HexString
toSelector = takeBytes 4 <<< fromByteString <<< keccak256
toSelector = takeBytes 4 <<< fromBuffer <<< keccak256
10 changes: 5 additions & 5 deletions src/Network/Ethereum/Core/RLP.purs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ module Network.Ethereum.Core.RLP
) where

import Prelude
import Data.ByteString (ByteString)
import Node.Buffer.Immutable (ImmutableBuffer)
import Network.Ethereum.Core.BigNumber (BigNumber)
import Network.Ethereum.Core.HexString (HexString, unHex)
import Network.Ethereum.Core.Signatures (Address, unAddress)
import Unsafe.Coerce (unsafeCoerce)

class RLPEncode a where
rlpEncode :: a -> ByteString
rlpEncode :: a -> ImmutableBuffer

data RLPObject
= RLPNull
Expand All @@ -21,7 +21,7 @@ data RLPObject
| RLPAddress Address
| RLPInt Int
| RLPBigNumber BigNumber
| RLPByteString ByteString
| RLPBuffer ImmutableBuffer
| RLPArray (Array RLPObject)

data RLPVal = RLPVal
Expand All @@ -38,13 +38,13 @@ transRLP obj = case obj of
RLPHexString hx -> mkRLPVal $ "0x" <> (unHex hx)
RLPAddress addr -> transRLP <<< RLPHexString $ unAddress addr
RLPBigNumber bn -> mkRLPVal bn
RLPByteString bs -> mkRLPVal bs
RLPBuffer bs -> mkRLPVal bs
RLPArray as -> mkRLPVal $ map transRLP as
where
mkRLPVal :: forall a. a -> RLPVal
mkRLPVal = unsafeCoerce

foreign import _rlpEncode :: RLPVal -> ByteString
foreign import _rlpEncode :: RLPVal -> ImmutableBuffer

instance RLPEncode RLPObject where
rlpEncode = _rlpEncode <<< transRLP
60 changes: 31 additions & 29 deletions src/Network/Ethereum/Core/Signatures.purs
Original file line number Diff line number Diff line change
Expand Up @@ -28,76 +28,76 @@ import Prelude
import Control.Monad.Gen (class MonadGen)
import Data.Argonaut (JsonDecodeError(..))
import Data.Argonaut as A
import Data.ByteString as BS
import Node.Buffer.Immutable as B
import Data.Either (Either(..), either)
import Data.Function.Uncurried (Fn2, Fn3, runFn2, runFn3)
import Data.Generic.Rep (class Generic)
import Data.Maybe (Maybe(..), fromJust)
import Data.Show.Generic (genericShow)
import Effect (Effect)
import Foreign (ForeignError(..), fail)
import Network.Ethereum.Core.HexString (HexString, dropBytes, fromByteString, nullWord, numberOfBytes, takeBytes, toByteString)
import Network.Ethereum.Core.HexString (HexString, dropBytes, fromBuffer, nullWord, numberOfBytes, takeBytes, toBuffer)
import Network.Ethereum.Core.HexString as Hex
import Network.Ethereum.Core.Keccak256 (keccak256)
import Partial.Unsafe (unsafePartial)
import Simple.JSON (class ReadForeign, readImpl, class WriteForeign, writeImpl)
import Type.Quotient (mkQuotient)
import Node.Encoding (Encoding(UTF8))

-- | Opaque PrivateKey type
newtype PrivateKey = PrivateKey BS.ByteString
newtype PrivateKey = PrivateKey B.ImmutableBuffer

instance Show PrivateKey where
show (PrivateKey pk) = show $ fromByteString pk
show (PrivateKey pk) = show $ fromBuffer pk

derive instance Eq PrivateKey

-- | Opaque PublicKey type
newtype PublicKey = PublicKey BS.ByteString
newtype PublicKey = PublicKey B.ImmutableBuffer

instance Show PublicKey where
show (PublicKey pk) = show $ fromByteString pk
show (PublicKey pk) = show $ fromBuffer pk

derive instance Eq PublicKey

foreign import isValidPublic
:: BS.ByteString
:: B.ImmutableBuffer
-> Boolean

foreign import isValidPrivate
:: BS.ByteString
:: B.ImmutableBuffer
-> Boolean

-- | Get the underlying `HexString` representation of a PublicKey.
unPublicKey
:: PublicKey
-> HexString
unPublicKey (PublicKey pk) = fromByteString pk
unPublicKey (PublicKey pk) = fromBuffer pk

-- | Attempt to construct a PublicKey from a HexString
mkPublicKey
:: HexString
-> Maybe PublicKey
mkPublicKey publicKey =
let
publicKeyBS = toByteString publicKey
publicKeyB = toBuffer publicKey
in
if isValidPublic publicKeyBS then Just $ PublicKey publicKeyBS
if isValidPublic publicKeyB then Just $ PublicKey publicKeyB
else Nothing

-- | Get the underlying `HexString` representation of a PrivateKey
unPrivateKey
:: PrivateKey
-> HexString
unPrivateKey (PrivateKey pk) = fromByteString pk
unPrivateKey (PrivateKey pk) = fromBuffer pk

mkPrivateKey
:: HexString
-> Maybe PrivateKey
mkPrivateKey privateKey =
let
privateKeyBS = toByteString privateKey
privateKeyB = toBuffer privateKey
in
if isValidPrivate privateKeyBS then Just $ PrivateKey privateKeyBS
if isValidPrivate privateKeyB then Just $ PrivateKey privateKeyB
else Nothing

-- | Produce the `PublicKey` for the corresponding `PrivateKey`.
Expand Down Expand Up @@ -160,7 +160,7 @@ publicToAddress
-> Address
publicToAddress (PublicKey publicKey) =
let
addrHex = fromByteString $ keccak256 publicKey
addrHex = fromBuffer $ keccak256 publicKey
in
unsafePartial fromJust <<< mkAddress $ dropBytes 12 addrHex

Expand All @@ -177,40 +177,42 @@ derive instance Eq Signature
instance Show Signature where
show = genericShow

foreign import ecSign :: Fn2 PrivateKey BS.ByteString { r :: BS.ByteString, s :: BS.ByteString, v :: Int }
foreign import ecSign :: Fn2 PrivateKey B.ImmutableBuffer { r :: B.ImmutableBuffer, s :: B.ImmutableBuffer, v :: Int }

-- | Sign the message with a `PrivateKey`
signMessage
:: PrivateKey
-> BS.ByteString
-> B.ImmutableBuffer
-> Signature
signMessage privateKey message =
let
{ r, s, v } = runFn2 ecSign privateKey message
in
Signature
{ r: fromByteString r
, s: fromByteString s
{ r: fromBuffer r
, s: fromBuffer s
, v
}

-- | Prefix a message with the "Ethereum Signed Message" prefix
toEthSignedMessage :: BS.ByteString -> Maybe BS.ByteString
toEthSignedMessage bs = do
let x19 = BS.singleton (mkQuotient 25) -- 0x19 == 25 dec
pfx <- BS.fromString "Ethereum Signed Message:\n" BS.UTF8
lenStr <- BS.fromString (show $ BS.length bs) BS.UTF8
pure $ x19 <> pfx <> lenStr <> bs
toEthSignedMessage :: B.ImmutableBuffer -> B.ImmutableBuffer
toEthSignedMessage bs =
let
x19 = B.fromArray [ 25 ] -- 0x19 == 25 dec
pfx = B.fromString "Ethereum Signed Message:\n" UTF8
lenStr = B.fromString (show $ B.size bs) UTF8
in
B.concat [ x19, pfx, lenStr, bs ]

foreign import ecRecover :: Fn3 BS.ByteString BS.ByteString Int PublicKey
foreign import ecRecover :: Fn3 B.ImmutableBuffer B.ImmutableBuffer Int PublicKey

-- | Recover the sender of the message from the `Signature`.
recoverSender
:: BS.ByteString
:: B.ImmutableBuffer
-> Signature
-> PublicKey
recoverSender messageHash (Signature { v, r, s }) =
runFn3 ecRecover messageHash (toByteString r <> toByteString s) v
runFn3 ecRecover messageHash (B.concat [ toBuffer r, toBuffer s ]) v

-- | Used in Ethereum to prevent replay attacks
newtype ChainId = ChainId Int
Expand Down
4 changes: 2 additions & 2 deletions test/Common.purs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module Common where

import Prelude

import Data.ByteString as BS
import Node.Buffer.Immutable as B
import Data.Generic.Rep (class Generic)
import Data.Maybe (Maybe(..), maybe)
import Data.Show.Generic (genericShow)
Expand Down Expand Up @@ -48,7 +48,7 @@ instance Show RawTransaction where
makeTransactionMessage
:: Sig.ChainId
-> RawTransaction
-> BS.ByteString
-> B.ImmutableBuffer
makeTransactionMessage (Sig.ChainId chainId) (RawTransaction tx) =
let
txWithChainId =
Expand Down
Loading

0 comments on commit aaa64b1

Please sign in to comment.