{-# LANGUAGE DataKinds         #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE TemplateHaskell   #-}
{-# LANGUAGE TypeApplications  #-}
{-# LANGUAGE TypeFamilies      #-}

module PlutusExample.PlutusVersion2.EcdsaSecp256k1Loop
    ( v2EcdsaLoopScript
    , v2EcdsaLoopScriptShortBs
    ) where

import Cardano.Api (PlutusScript, PlutusScriptV2)
import Cardano.Api.Shelley (PlutusScript (..))
import Codec.Serialise (serialise)
import Data.ByteString.Lazy qualified as LBS
import Data.ByteString.Short qualified as SBS
import Plutus.V2.Ledger.Api qualified as PlutusV2
import PlutusTx qualified
import PlutusTx.Builtins qualified as BI
import PlutusTx.Prelude as P hiding (Semigroup (..), unless, (.))
import Prelude ((.))

{-# INLINEABLE mkValidator #-}
mkValidator :: BuiltinData -> BuiltinData -> BuiltinData -> ()
mkValidator :: BuiltinData -> BuiltinData -> BuiltinData -> ()
mkValidator BuiltinData
_datum BuiltinData
red BuiltinData
_txContext =
  case BuiltinData
-> Maybe
     (Integer, BuiltinByteString, BuiltinByteString, BuiltinByteString)
forall a. FromData a => BuiltinData -> Maybe a
PlutusV2.fromBuiltinData BuiltinData
red of
    Maybe
  (Integer, BuiltinByteString, BuiltinByteString, BuiltinByteString)
Nothing -> BuiltinString -> ()
forall a. BuiltinString -> a
P.traceError BuiltinString
"Trace error: Invalid redeemer"
    Just (Integer
n, BuiltinByteString
vkey, BuiltinByteString
msg, BuiltinByteString
sig) ->
      if Integer
n Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< (Integer
1000000 :: Integer) -- large number ensures same bitsize for all counter values
      then BuiltinString -> ()
forall a. BuiltinString -> a
traceError BuiltinString
"redeemer is < 1000000"
      else Integer
-> BuiltinByteString
-> BuiltinByteString
-> BuiltinByteString
-> ()
forall t.
(Eq t, Num t, Enum t) =>
t
-> BuiltinByteString
-> BuiltinByteString
-> BuiltinByteString
-> ()
loop Integer
n BuiltinByteString
vkey BuiltinByteString
msg BuiltinByteString
sig
  where
    loop :: t
-> BuiltinByteString
-> BuiltinByteString
-> BuiltinByteString
-> ()
loop t
i BuiltinByteString
v BuiltinByteString
m BuiltinByteString
s
      | t
i t -> t -> Bool
forall a. Eq a => a -> a -> Bool
== t
1000000 = ()
      | BuiltinByteString -> BuiltinByteString -> BuiltinByteString -> Bool
BI.verifyEcdsaSecp256k1Signature BuiltinByteString
v BuiltinByteString
m BuiltinByteString
s = t
-> BuiltinByteString
-> BuiltinByteString
-> BuiltinByteString
-> ()
loop (t -> t
forall a. Enum a => a -> a
pred t
i) BuiltinByteString
v BuiltinByteString
m BuiltinByteString
s
      | Bool
otherwise = BuiltinString -> ()
forall a. BuiltinString -> a
P.traceError BuiltinString
"Trace error: ECDSA validation failed"

validator :: PlutusV2.Validator
validator :: Validator
validator = CompiledCode (BuiltinData -> BuiltinData -> BuiltinData -> ())
-> Validator
PlutusV2.mkValidatorScript $$(PlutusTx.compile [|| mkValidator ||])

script :: PlutusV2.Script
script :: Script
script = Validator -> Script
PlutusV2.unValidatorScript Validator
validator

v2EcdsaLoopScriptShortBs :: SBS.ShortByteString
v2EcdsaLoopScriptShortBs :: ShortByteString
v2EcdsaLoopScriptShortBs = ByteString -> ShortByteString
SBS.toShort (ByteString -> ShortByteString)
-> (ByteString -> ByteString) -> ByteString -> ShortByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
LBS.toStrict (ByteString -> ShortByteString) -> ByteString -> ShortByteString
forall a b. (a -> b) -> a -> b
$ Script -> ByteString
forall a. Serialise a => a -> ByteString
serialise Script
script

v2EcdsaLoopScript :: PlutusScript PlutusScriptV2
v2EcdsaLoopScript :: PlutusScript PlutusScriptV2
v2EcdsaLoopScript = ShortByteString -> PlutusScript PlutusScriptV2
forall lang. ShortByteString -> PlutusScript lang
PlutusScriptSerialised ShortByteString
v2EcdsaLoopScriptShortBs