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

module PlutusExample.PlutusVersion2.SchnorrSecp256k1Loop
    ( v2SchnorrLoopScript
    , v2SchnorrLoopScriptShortBs
    ) 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.verifySchnorrSecp256k1Signature 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: Schnorr 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

v2SchnorrLoopScriptShortBs :: SBS.ShortByteString
v2SchnorrLoopScriptShortBs :: ShortByteString
v2SchnorrLoopScriptShortBs = 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

v2SchnorrLoopScript :: PlutusScript PlutusScriptV2
v2SchnorrLoopScript :: PlutusScript PlutusScriptV2
v2SchnorrLoopScript = ShortByteString -> PlutusScript PlutusScriptV2
forall lang. ShortByteString -> PlutusScript lang
PlutusScriptSerialised ShortByteString
v2SchnorrLoopScriptShortBs