module EVM.Sign where
import Data.ByteString qualified as BS
import Data.Maybe (fromMaybe)
import Data.Word
import Crypto.Hash qualified as Crypto
import Crypto.PubKey.ECC.ECDSA (signDigestWith, PrivateKey(..), Signature(..))
import Crypto.PubKey.ECC.Types (getCurveByName, CurveName(..), Point(..))
import Crypto.PubKey.ECC.Generate (generateQ)
import Witch (unsafeInto)
import EVM.ABI (encodeAbiValue, AbiValue(..))
import EVM.Types
import EVM.Expr (exprToAddr)
import EVM.Precompiled
deriveAddr :: Integer -> Maybe Addr
deriveAddr :: Integer -> Maybe Addr
deriveAddr Integer
sk =
case Point
pubPoint of
Point
PointO -> forall a. Maybe a
Nothing
Point Integer
x Integer
y ->
let pub :: ByteString
pub = [ByteString] -> ByteString
BS.concat [ Integer -> ByteString
encodeInt Integer
x, Integer -> ByteString
encodeInt Integer
y ]
addr :: Expr 'EWord
addr = W256 -> Expr 'EWord
Lit forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word256 -> W256
W256 forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Word256
word256 forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> ByteString -> ByteString
BS.drop Int
12 forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> ByteString -> ByteString
BS.take Int
32 forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
keccakBytes forall a b. (a -> b) -> a -> b
$ ByteString
pub
in Expr 'EWord -> Maybe Addr
exprToAddr Expr 'EWord
addr
where
curve :: Curve
curve = CurveName -> Curve
getCurveByName CurveName
SEC_p256k1
pubPoint :: Point
pubPoint = Curve -> Integer -> Point
generateQ Curve
curve Integer
sk
encodeInt :: Integer -> ByteString
encodeInt = AbiValue -> ByteString
encodeAbiValue forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Word256 -> AbiValue
AbiUInt Int
256 forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Num a => Integer -> a
fromInteger
sign :: W256 -> Integer -> (Word8, W256, W256)
sign :: W256 -> Integer -> (Word8, W256, W256)
sign W256
hash Integer
sk = (Word8
v, W256
r, W256
s)
where
curve :: Curve
curve = CurveName -> Curve
getCurveByName CurveName
SEC_p256k1
priv :: PrivateKey
priv = Curve -> Integer -> PrivateKey
PrivateKey Curve
curve Integer
sk
digest :: Digest Keccak_256
digest = forall a. a -> Maybe a -> a
fromMaybe
(forall a. HasCallStack => [Char] -> a
internalError forall a b. (a -> b) -> a -> b
$ [Char]
"could produce a digest from " forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> [Char]
show W256
hash)
(forall a ba.
(HashAlgorithm a, ByteArrayAccess ba) =>
ba -> Maybe (Digest a)
Crypto.digestFromByteString (W256 -> ByteString
word256Bytes W256
hash))
sig :: Signature
sig = PrivateKey -> Digest Keccak_256 -> Signature
ethsign PrivateKey
priv Digest Keccak_256
digest
r :: W256
r = forall target source.
(HasCallStack, TryFrom source target, Show source, Typeable source,
Typeable target) =>
source -> target
unsafeInto forall a b. (a -> b) -> a -> b
$ Signature -> Integer
sign_r Signature
sig
s :: W256
s = forall target source.
(HasCallStack, TryFrom source target, Show source, Typeable source,
Typeable target) =>
source -> target
unsafeInto Integer
lowS
v :: Word8
v = if W256 -> W256 -> W256 -> W256 -> Maybe Addr
ecrec W256
28 W256
r W256
s W256
hash forall a. Eq a => a -> a -> Bool
== Integer -> Maybe Addr
deriveAddr Integer
sk
then Word8
28
else Word8
27
secpOrder :: Integer
secpOrder = Integer
0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 :: Integer
lowS :: Integer
lowS = if Signature -> Integer
sign_s Signature
sig forall a. Ord a => a -> a -> Bool
> Integer
secpOrder forall a. Integral a => a -> a -> a
`div` Integer
2
then Integer
secpOrder forall a. Num a => a -> a -> a
- Signature -> Integer
sign_s Signature
sig
else Signature -> Integer
sign_s Signature
sig
ethsign :: PrivateKey -> Crypto.Digest Crypto.Keccak_256 -> Signature
ethsign :: PrivateKey -> Digest Keccak_256 -> Signature
ethsign PrivateKey
sk Digest Keccak_256
digest = Integer -> Signature
go Integer
420
where
go :: Integer -> Signature
go Integer
k = case forall hash.
HashAlgorithm hash =>
Integer -> PrivateKey -> Digest hash -> Maybe Signature
signDigestWith Integer
k PrivateKey
sk Digest Keccak_256
digest of
Maybe Signature
Nothing -> Integer -> Signature
go (Integer
k forall a. Num a => a -> a -> a
+ Integer
1)
Just Signature
sig -> Signature
sig
ecrec :: W256 -> W256 -> W256 -> W256 -> Maybe Addr
ecrec :: W256 -> W256 -> W256 -> W256 -> Maybe Addr
ecrec W256
v W256
r W256
s W256
e = forall target source.
(HasCallStack, TryFrom source target, Show source, Typeable source,
Typeable target) =>
source -> target
unsafeInto forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> W256
word forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> ByteString -> Int -> Maybe ByteString
EVM.Precompiled.execute Int
1 ByteString
input Int
32
where input :: ByteString
input = [ByteString] -> ByteString
BS.concat (W256 -> ByteString
word256Bytes forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [W256
e, W256
v, W256
r, W256
s])