-- | -- Module: Covenant.Prim -- Copyright: (C) MLabs 2025 -- License: Apache 2.0 -- Maintainer: koz@mlabs.city, sean@mlabs.city -- -- Contains definitions relating to Plutus primitive functions in Covenant -- programs. -- -- @since 1.0.0 module Covenant.Prim ( OneArgFunc (..), typeOneArgFunc, TwoArgFunc (..), typeTwoArgFunc, ThreeArgFunc (..), typeThreeArgFunc, SixArgFunc (..), typeSixArgFunc, ) where import Covenant.DeBruijn (DeBruijn (S, Z)) import Covenant.Index (ix0, ix1) import Covenant.Type ( AbstractTy, CompT (Comp0, Comp1, Comp2), CompTBody (ReturnT, (:--:>)), ValT (ThunkT), boolT, byteStringT, dataType1T, dataType2T, dataTypeT, g1T, g2T, integerT, mlResultT, stringT, tyvar, unitT, ) import Test.QuickCheck (Arbitrary (arbitrary), elements) -- | All one-argument primitives provided by Plutus. -- -- = Note -- -- We exclude the @MkNilData@ and @MkNilPairData@ primitives from this list for -- several reasons. For clarity, we list these below. Firstly, the reason why -- these primitives still exist at all is historical: Plutus now has the ability -- to directly \'lift\' empty list constants into itself. Secondly, while these -- primitives /could/ still be used instead of direct lifts, there is never a -- reason to prefer them, as they are less efficient than embedding a constant -- directly. -- -- For all of these reasons, we do not represent these primitives in the ASG. -- -- @since 1.0.0 data OneArgFunc = LengthOfByteString | Sha2_256 | Sha3_256 | Blake2b_256 | EncodeUtf8 | DecodeUtf8 | -- | @since 1.1.0 FstPair | -- | @since 1.1.0 SndPair | -- | @since 1.1.0 HeadList | -- | @since 1.1.0 TailList | -- | @since 1.1.0 NullList | -- | @since 1.1.0 MapData | -- | @since 1.1.0 ListData | -- | @since 1.1.0 IData | -- | @since 1.1.0 BData | -- | @since 1.1.0 UnConstrData | -- | @since 1.1.0 UnMapData | -- | @since 1.1.0 UnListData | -- | @since 1.1.0 UnIData | -- | @since 1.1.0 UnBData | -- | @since 1.1.0 SerialiseData | BLS12_381_G1_neg | BLS12_381_G1_compress | BLS12_381_G1_uncompress | BLS12_381_G2_neg | BLS12_381_G2_compress | BLS12_381_G2_uncompress | Keccak_256 | Blake2b_224 | ComplementByteString | CountSetBits | FindFirstSetBit | Ripemd_160 deriving stock ( -- | @since 1.0.0 Eq, -- | @since 1.0.0 Ord, -- | @since 1.0.0 Show ) -- | Does not shrink. -- -- @since 1.0.0 instance Arbitrary OneArgFunc where {-# INLINEABLE arbitrary #-} arbitrary = elements [ LengthOfByteString, Sha2_256, Sha3_256, Blake2b_256, EncodeUtf8, DecodeUtf8, FstPair, SndPair, HeadList, TailList, NullList, MapData, ListData, IData, BData, UnConstrData, UnMapData, UnListData, UnIData, UnBData, SerialiseData, BLS12_381_G1_neg, BLS12_381_G1_compress, BLS12_381_G1_uncompress, BLS12_381_G2_neg, BLS12_381_G2_compress, BLS12_381_G2_uncompress, Keccak_256, Blake2b_224, ComplementByteString, CountSetBits, FindFirstSetBit, Ripemd_160 ] -- | Produce the type of a single-argument primop. -- -- @since 1.0.0 typeOneArgFunc :: OneArgFunc -> CompT AbstractTy typeOneArgFunc = \case LengthOfByteString -> Comp0 $ byteStringT :--:> ReturnT integerT Sha2_256 -> hashingT Sha3_256 -> hashingT Blake2b_256 -> hashingT EncodeUtf8 -> Comp0 $ stringT :--:> ReturnT byteStringT DecodeUtf8 -> Comp0 $ byteStringT :--:> ReturnT stringT FstPair -> Comp2 $ pairT aT bT :--:> ReturnT aT SndPair -> Comp2 $ pairT aT bT :--:> ReturnT bT HeadList -> Comp1 $ listT aT :--:> ReturnT aT TailList -> Comp1 $ listT aT :--:> ReturnT (listT aT) NullList -> Comp1 $ listT aT :--:> ReturnT boolT MapData -> Comp0 $ listT (pairT dataT dataT) :--:> ReturnT dataT ListData -> Comp0 $ listT dataT :--:> ReturnT dataT IData -> Comp0 $ integerT :--:> ReturnT dataT BData -> Comp0 $ byteStringT :--:> ReturnT dataT UnConstrData -> Comp0 $ dataT :--:> ReturnT (pairT integerT (listT dataT)) UnMapData -> Comp0 $ dataT :--:> ReturnT (listT (pairT dataT dataT)) UnListData -> Comp0 $ dataT :--:> ReturnT (listT dataT) UnIData -> Comp0 $ dataT :--:> ReturnT integerT UnBData -> Comp0 $ dataT :--:> ReturnT byteStringT SerialiseData -> Comp0 $ dataT :--:> ReturnT byteStringT BLS12_381_G1_neg -> Comp0 $ g1T :--:> ReturnT g1T BLS12_381_G1_compress -> Comp0 $ g1T :--:> ReturnT byteStringT BLS12_381_G1_uncompress -> Comp0 $ byteStringT :--:> ReturnT g1T BLS12_381_G2_neg -> Comp0 $ g2T :--:> ReturnT g2T BLS12_381_G2_compress -> Comp0 $ g2T :--:> ReturnT byteStringT BLS12_381_G2_uncompress -> Comp0 $ byteStringT :--:> ReturnT g2T Keccak_256 -> hashingT Blake2b_224 -> hashingT ComplementByteString -> Comp0 $ byteStringT :--:> ReturnT byteStringT CountSetBits -> Comp0 $ byteStringT :--:> ReturnT integerT FindFirstSetBit -> Comp0 $ byteStringT :--:> ReturnT integerT Ripemd_160 -> hashingT where hashingT :: CompT AbstractTy hashingT = Comp0 $ byteStringT :--:> ReturnT byteStringT -- | All two-argument primitives provided by Plutus. -- -- @since 1.0.0 data TwoArgFunc = AddInteger | SubtractInteger | MultiplyInteger | DivideInteger | QuotientInteger | RemainderInteger | ModInteger | EqualsInteger | LessThanInteger | LessThanEqualsInteger | AppendByteString | ConsByteString | IndexByteString | EqualsByteString | LessThanByteString | LessThanEqualsByteString | AppendString | EqualsString | ChooseUnit | Trace | -- | @since 1.1.0 MkCons | -- | @since 1.1.0 ConstrData | -- | @since 1.1.0 EqualsData | -- | @since 1.1.0 MkPairData | BLS12_381_G1_add | BLS12_381_G1_scalarMul | BLS12_381_G1_equal | BLS12_381_G1_hashToGroup | BLS12_381_G2_add | BLS12_381_G2_scalarMul | BLS12_381_G2_equal | BLS12_381_G2_hashToGroup | BLS12_381_millerLoop | BLS12_381_mulMlResult | BLS12_381_finalVerify | ByteStringToInteger | ReadBit | ReplicateByte | ShiftByteString | RotateByteString deriving stock ( -- | @since 1.0.0 Eq, -- | @since 1.0.0 Ord, -- | @since 1.0.0 Show ) -- | Does not shrink. -- -- @since 1.0.0 instance Arbitrary TwoArgFunc where {-# INLINEABLE arbitrary #-} arbitrary = elements [ AddInteger, SubtractInteger, MultiplyInteger, DivideInteger, QuotientInteger, RemainderInteger, ModInteger, EqualsInteger, LessThanInteger, LessThanEqualsInteger, AppendByteString, ConsByteString, IndexByteString, EqualsByteString, LessThanByteString, LessThanEqualsByteString, AppendString, EqualsString, ChooseUnit, Trace, MkCons, ConstrData, EqualsData, MkPairData, BLS12_381_G1_add, BLS12_381_G1_scalarMul, BLS12_381_G1_equal, BLS12_381_G1_hashToGroup, BLS12_381_G2_add, BLS12_381_G2_scalarMul, BLS12_381_G2_equal, BLS12_381_G2_hashToGroup, BLS12_381_millerLoop, BLS12_381_mulMlResult, BLS12_381_finalVerify, ByteStringToInteger, ReadBit, ReplicateByte, ShiftByteString, RotateByteString ] -- | Produce the type of a two-argument primop. -- -- @since 1.0.0 typeTwoArgFunc :: TwoArgFunc -> CompT AbstractTy typeTwoArgFunc = \case AddInteger -> combineT integerT SubtractInteger -> combineT integerT MultiplyInteger -> combineT integerT DivideInteger -> combineT integerT QuotientInteger -> combineT integerT RemainderInteger -> combineT integerT ModInteger -> combineT integerT EqualsInteger -> compareT integerT LessThanInteger -> compareT integerT LessThanEqualsInteger -> compareT integerT AppendByteString -> combineT byteStringT ConsByteString -> Comp0 $ integerT :--:> byteStringT :--:> ReturnT byteStringT IndexByteString -> Comp0 $ byteStringT :--:> integerT :--:> ReturnT integerT EqualsByteString -> compareT byteStringT LessThanByteString -> compareT byteStringT LessThanEqualsByteString -> compareT byteStringT AppendString -> combineT stringT EqualsString -> compareT stringT ChooseUnit -> Comp1 $ unitT :--:> aT :--:> ReturnT aT Trace -> Comp1 $ stringT :--:> aT :--:> ReturnT aT MkCons -> Comp1 $ aT :--:> listT aT :--:> ReturnT (listT aT) ConstrData -> Comp0 $ integerT :--:> listT dataT :--:> ReturnT dataT EqualsData -> compareT dataT MkPairData -> Comp0 $ dataT :--:> dataT :--:> ReturnT (pairT dataT dataT) BLS12_381_G1_add -> combineT g1T BLS12_381_G1_scalarMul -> Comp0 $ integerT :--:> g1T :--:> ReturnT g1T BLS12_381_G1_equal -> compareT g1T BLS12_381_G1_hashToGroup -> Comp0 $ byteStringT :--:> byteStringT :--:> ReturnT g1T BLS12_381_G2_add -> combineT g2T BLS12_381_G2_scalarMul -> Comp0 $ integerT :--:> g2T :--:> ReturnT g2T BLS12_381_G2_equal -> compareT g2T BLS12_381_G2_hashToGroup -> Comp0 $ byteStringT :--:> byteStringT :--:> ReturnT g2T BLS12_381_millerLoop -> Comp0 $ g1T :--:> g2T :--:> ReturnT mlResultT BLS12_381_mulMlResult -> combineT mlResultT BLS12_381_finalVerify -> Comp0 $ mlResultT :--:> mlResultT :--:> ReturnT boolT ByteStringToInteger -> Comp0 $ boolT :--:> byteStringT :--:> ReturnT integerT ReadBit -> Comp0 $ byteStringT :--:> integerT :--:> ReturnT boolT ReplicateByte -> Comp0 $ integerT :--:> integerT :--:> ReturnT byteStringT ShiftByteString -> Comp0 $ byteStringT :--:> integerT :--:> ReturnT byteStringT RotateByteString -> Comp0 $ byteStringT :--:> integerT :--:> ReturnT byteStringT where combineT :: ValT AbstractTy -> CompT AbstractTy combineT t = Comp0 $ t :--:> t :--:> ReturnT t compareT :: ValT AbstractTy -> CompT AbstractTy compareT t = Comp0 $ t :--:> t :--:> ReturnT boolT -- | All three-argument primitives provided by Plutus. -- -- @since 1.0.0 data ThreeArgFunc = VerifyEd25519Signature | VerifyEcdsaSecp256k1Signature | VerifySchnorrSecp256k1Signature | IfThenElse | -- | @since 1.1.0 ChooseList | -- | @since 1.1.0 CaseList | IntegerToByteString | AndByteString | OrByteString | XorByteString | WriteBits | ExpModInteger deriving stock ( -- | @since 1.0.0 Eq, -- | @since 1.0.0 Ord, -- | @since 1.0.0 Show ) -- | Does not shrink. -- -- @since 1.0.0 instance Arbitrary ThreeArgFunc where {-# INLINEABLE arbitrary #-} arbitrary = elements [ VerifyEd25519Signature, VerifyEcdsaSecp256k1Signature, VerifySchnorrSecp256k1Signature, IfThenElse, ChooseList, CaseList, IntegerToByteString, AndByteString, OrByteString, XorByteString, WriteBits, ExpModInteger ] -- | Produce the type of a three-argument primop. -- -- @since 1.0.0 typeThreeArgFunc :: ThreeArgFunc -> CompT AbstractTy typeThreeArgFunc = \case VerifyEd25519Signature -> signatureT VerifyEcdsaSecp256k1Signature -> signatureT VerifySchnorrSecp256k1Signature -> signatureT IfThenElse -> Comp1 $ boolT :--:> aT :--:> aT :--:> ReturnT aT ChooseList -> Comp2 $ listT aT :--:> bT :--:> bT :--:> ReturnT bT CaseList -> Comp2 $ bT :--:> ThunkT (Comp0 $ aTOuter :--:> listT aTOuter :--:> ReturnT bTOuter) :--:> listT aT :--:> ReturnT bT IntegerToByteString -> Comp0 $ boolT :--:> integerT :--:> integerT :--:> ReturnT byteStringT AndByteString -> bitwiseT OrByteString -> bitwiseT XorByteString -> bitwiseT WriteBits -> Comp0 $ byteStringT :--:> listT integerT :--:> boolT :--:> ReturnT byteStringT ExpModInteger -> Comp0 $ integerT :--:> integerT :--:> integerT :--:> ReturnT integerT where signatureT :: CompT AbstractTy signatureT = Comp0 $ byteStringT :--:> byteStringT :--:> byteStringT :--:> ReturnT boolT bitwiseT :: CompT AbstractTy bitwiseT = Comp0 $ boolT :--:> byteStringT :--:> byteStringT :--:> ReturnT byteStringT -- | All six-argument primitives provided by Plutus. -- -- @since 1.1.0 data SixArgFunc = ChooseData | CaseData deriving stock ( -- | @since 1.0.0 Eq, -- | @since 1.0.0 Ord, -- | @since 1.0.0 Show ) -- | Does not shrink. -- -- @since 1.1.0 instance Arbitrary SixArgFunc where {-# INLINEABLE arbitrary #-} arbitrary = elements [ChooseData, CaseData] -- | Produce the type of a six-argument primop. -- -- @since 1.1.0 typeSixArgFunc :: SixArgFunc -> CompT AbstractTy typeSixArgFunc = \case ChooseData -> Comp1 $ dataT :--:> aT :--:> aT :--:> aT :--:> aT :--:> aT :--:> ReturnT aT CaseData -> Comp1 $ ThunkT (Comp0 $ integerT :--:> listT dataT :--:> ReturnT aTOuter) :--:> ThunkT (Comp0 $ listT (pairT dataT dataT) :--:> ReturnT aTOuter) :--:> ThunkT (Comp0 $ listT dataT :--:> ReturnT aTOuter) :--:> ThunkT (Comp0 $ integerT :--:> ReturnT aTOuter) :--:> ThunkT (Comp0 $ byteStringT :--:> ReturnT aTOuter) :--:> dataT :--:> ReturnT aT -- Helpers dataT :: ValT AbstractTy dataT = dataTypeT "Data" listT :: ValT AbstractTy -> ValT AbstractTy listT = dataType1T "List" pairT :: ValT AbstractTy -> ValT AbstractTy -> ValT AbstractTy pairT = dataType2T "Pair" aT :: ValT AbstractTy aT = tyvar Z ix0 aTOuter :: ValT AbstractTy aTOuter = tyvar (S Z) ix0 bT :: ValT AbstractTy bT = tyvar Z ix1 bTOuter :: ValT AbstractTy bTOuter = tyvar (S Z) ix1