module Utils where
open import Relation.Binary.PropositionalEquality using (_≡_;refl;cong;sym;trans;cong₂;subst)
open import Function using (const;_∘_)
open import Data.Nat using (ℕ;zero;suc;_≤‴_;_≤_;_+_;_<_)
open _≤_
open _≤‴_
open import Data.Nat.Properties
using (+-suc;m+1+n≢m;+-cancelˡ-≡;m≢1+n+m;m+1+n≢0;+-cancelʳ-≡;+-assoc;+-comm;+-identityʳ)
open import Relation.Binary using (Decidable)
import Data.Integer as I
import Data.List as L
open import Data.Sum using (_⊎_;inj₁;inj₂)
open import Relation.Nullary using (Dec;yes;no;¬_)
open import Data.Empty using (⊥;⊥-elim)
open import Data.Integer using (ℤ; +_)
open import Data.String using (String)
open import Data.Bool using (Bool)
open import Data.Maybe using (Maybe; just; nothing; maybe)
renaming (_>>=_ to mbind) public
open import Data.Unit using (⊤)
{-# FOREIGN GHC import Raw #-}
We cannot use the standard library’s Either as it is not set up to compile the Haskell’s Either and compile pragmas have to go in the same module as definitions.
data Either (A B : Set) : Set where
inj₁ : A → Either A B
inj₂ : B → Either A B
{-# COMPILE GHC Either = data Either (Left | Right) #-}
either : {A B C : Set} → Either A B → (A → C) → (B → C) → C
either (inj₁ a) f g = f a
either (inj₂ b) f g = g b
eitherBind : ∀{A B E} → Either E A → (A → Either E B) → Either E B
eitherBind (inj₁ e) f = inj₁ e
eitherBind (inj₂ a) f = f a
decIf : ∀{A B : Set} → Dec A → B → B → B
decIf (yes p) t f = t
decIf (no ¬p) t f = f
cong₃ : {A B C D : Set} → (f : A → B → C → D)
→ {a a' : A} → a ≡ a'
→ {b b' : B} → b ≡ b'
→ {c c' : C} → c ≡ c'
→ f a b c ≡ f a' b' c'
cong₃ f refl refl refl = refl
≡-subst-removable : ∀ {a p} {A : Set a}
(P : A → Set p) {x y} (p q : x ≡ y) z →
subst P p z ≡ subst P q z
≡-subst-removable P refl refl z = refl
The type n ∔ n' ≡ m takes two naturals n and n' such that they sum to m.
It is helpful when one wants to do m things, while keeping track
of the number of done things (n) and things to do (n').
data _∔_≣_ : ℕ → ℕ → ℕ → Set where
start : (n : ℕ) → 0 ∔ n ≣ n
bubble : ∀{n n' m : ℕ} → n ∔ suc n' ≣ m → suc n ∔ n' ≣ m
unique∔ : ∀{n n' m : ℕ}(p p' : n ∔ n' ≣ m) → p ≡ p'
unique∔ (start _) (start _) = refl
unique∔ (bubble p) (bubble p') = cong bubble (unique∔ p p')
+2∔ : ∀(n m t : ℕ) → n + m ≡ t → n ∔ m ≣ t
+2∔ zero m .(zero + m) refl = start _
+2∔ (suc n) m t p = bubble (+2∔ n (suc m) t (trans (+-suc n m) p))
∔2+ : ∀{n m t : ℕ} → n ∔ m ≣ t → n + m ≡ t
∔2+ (start _) = refl
∔2+ (bubble bt) = trans (sym (+-suc _ _)) (∔2+ bt)
alldone : ∀(n : ℕ) → n ∔ zero ≣ n
alldone n = +2∔ n 0 n (+-identityʳ n)
This introduces the Monad operators.
record Monad (F : Set → Set) : Set₁ where
field
return : ∀{A} → A → F A
_>>=_ : ∀{A B} → F A → (A → F B) → F B
_>>_ : ∀{A B} → F A → F B → F B
as >> bs = as >>= const bs
fmap : ∀{A B} → (A → B) → F A → F B
fmap f as = as >>= (return ∘ f)
open Monad public
instance
MaybeMonad : Monad Maybe
MaybeMonad = record { return = just ; _>>=_ = mbind }
sumBind : {A B C : Set} → A ⊎ C → (A → B ⊎ C) → B ⊎ C
sumBind (inj₁ a) f = f a
sumBind (inj₂ c) f = inj₂ c
SumMonad : (C : Set) → Monad (_⊎ C)
SumMonad A = record { return = inj₁ ; _>>=_ = sumBind }
EitherMonad : (E : Set) → Monad (Either E)
EitherMonad E = record { return = inj₂ ; _>>=_ = eitherBind }
-- one instance to rule them all...
instance
EitherP : {A : Set} → Monad (Either A)
Monad.return EitherP = inj₂
Monad._>>=_ EitherP = eitherBind
withE : {A B C : Set} → (A → B) → Either A C → Either B C
withE f (inj₁ a) = inj₁ (f a)
withE f (inj₂ c) = inj₂ c
dec2Either : {A : Set} → Dec A → Either (¬ A) A
dec2Either (yes p) = inj₂ p
dec2Either (no ¬p) = inj₁ ¬p
record Writer (M : Set)(A : Set) : Set where
constructor _,_
field
wrvalue : A
accum : M
module WriterMonad {M : Set}(e : M)(_∙_ : M → M → M) where
instance
WriterMonad : Monad (Writer M)
Monad.return WriterMonad x = x , e
(WriterMonad Monad.>>= (x , w)) f = let (y , w') = f x in y , (w ∙ w')
tell : (w : M) → Writer M ⊤
tell w = _ , w
data RuntimeError : Set where
gasError : RuntimeError
userError : RuntimeError
runtimeTypeError : RuntimeError
{-# COMPILE GHC RuntimeError = data RuntimeError (GasError | UserError | RuntimeTypeError) #-}
postulate ByteString : Set
{-# FOREIGN GHC import qualified Data.ByteString as BS #-}
{-# COMPILE GHC ByteString = type BS.ByteString #-}
postulate
mkByteString : String → ByteString
-- Agda implementation should only be used as part of deciding builtin equality.
-- See "Decidable Equality of Builtins" in "VerifiedCompilation.Equality".
eqByteString : ByteString → ByteString → Bool
eqByteString _ _ = Bool.true
{-# COMPILE GHC eqByteString = (==) #-}
record _×_ (A B : Set) : Set where
constructor _,_
field
proj₁ : A
proj₂ : B
infixr 4 _,_
infixr 2 _×_
{-# FOREIGN GHC type Pair a b = (a , b) #-}
{-# COMPILE GHC _×_ = data Pair ((,)) #-}
data List (A : Set) : Set where
[] : List A
_∷_ : A → List A → List A
length : ∀ {A} → List A → ℕ
length [] = 0
length (x ∷ xs) = suc (length xs)
map : ∀{A B} → (A → B) → List A → List B
map f [] = []
map f (x ∷ xs) = f x ∷ map f xs
toList : ∀{A} → List A → L.List A
toList [] = L.[]
toList (x ∷ xs) = x L.∷ toList xs
fromList : ∀{A} → L.List A → List A
fromList L.[] = []
fromList (x L.∷ xs) = x ∷ fromList xs
-- Implementation of UPLC's dropList builtin
dropLIST : ∀{A} → ℤ → List A → List A
dropLIST (+ n) l = drop n l
where drop : ∀{A} → ℕ → List A → List A
drop zero xs = xs
drop (suc n) [] = []
drop (suc n) (_ ∷ xs) = drop n xs
dropLIST _ l = l
map-cong : ∀{A B : Set}{xs : L.List A}{f g : A → B}
→ (∀ x → f x ≡ g x)
→ L.map f xs ≡ L.map g xs
map-cong {xs = L.[]} p = refl
map-cong {xs = x L.∷ xs} p = cong₂ L._∷_ (p x) (map-cong p)
infixr 5 _∷_
{-# COMPILE GHC List = data [] ([] | (:)) #-}
postulate Array : Set → Set
{-# FOREIGN GHC import qualified Data.Vector.Strict as Strict #-}
{-# COMPILE GHC Array = type Strict.Vector #-}
variable A : Set
postulate
HSlengthOfArray : Array A → ℤ
HSlistToArray : (ls : List A) → Array A
HSindexArray : Array A → ℤ → A
-- These have to consume the hidden {A : Set} param in the Agda.
{-# COMPILE GHC HSlengthOfArray = \() -> \as -> toInteger (Strict.length as) #-}
{-# COMPILE GHC HSlistToArray = \() -> Strict.fromList #-}
{-# COMPILE GHC HSindexArray = \() -> \as -> \i -> as Strict.! (fromInteger i) #-}
-- This only exists for literal arrays in certificates,
-- much like mkBytestring above.
postulate
mkArray : {A : Set} → List A → Array A
data DATA : Set where
ConstrDATA : I.ℤ → List DATA → DATA
MapDATA : List (DATA × DATA) → DATA
ListDATA : List DATA → DATA
iDATA : I.ℤ → DATA
bDATA : ByteString → DATA
{-# FOREIGN GHC import PlutusCore.Data as D #-}
{-# COMPILE GHC DATA = data Data (D.Constr | D.Map | D.List | D.I | D.B) #-}
-- Agda implementation should only be used as part of deciding builtin equality.
-- See "Decidable Equality of Builtins" in "VerifiedCompilation.Equality".
{-# TERMINATING #-}
eqDATA : DATA → DATA → Bool
eqDATA (ConstrDATA i₁ l₁) (ConstrDATA i₂ l₂) =
(Relation.Nullary.isYes (i₁ Data.Integer.≟ i₂))
Data.Bool.∧
L.and (L.zipWith eqDATA (toList l₁) (toList l₂))
eqDATA (ConstrDATA x x₁) (MapDATA x₂) = Bool.false
eqDATA (ConstrDATA x x₁) (ListDATA x₂) = Bool.false
eqDATA (ConstrDATA x x₁) (iDATA x₂) = Bool.false
eqDATA (ConstrDATA x x₁) (bDATA x₂) = Bool.false
eqDATA (MapDATA x) (ConstrDATA x₁ x₂) = Bool.false
eqDATA (MapDATA m₁) (MapDATA m₂) =
L.and
(L.zipWith
(λ (x₁ , y₁) (x₂ , y₂) → eqDATA x₁ x₂ Data.Bool.∧ eqDATA y₁ y₂)
(toList m₁)
(toList m₂)
)
eqDATA (MapDATA x) (ListDATA x₁) = Bool.false
eqDATA (MapDATA x) (iDATA x₁) = Bool.false
eqDATA (MapDATA x) (bDATA x₁) = Bool.false
eqDATA (ListDATA x) (ConstrDATA x₁ x₂) = Bool.false
eqDATA (ListDATA x) (MapDATA x₁) = Bool.false
eqDATA (ListDATA x) (ListDATA x₁) = L.and (L.zipWith eqDATA (toList x) (toList x₁))
eqDATA (ListDATA x) (iDATA x₁) = Bool.false
eqDATA (ListDATA x) (bDATA x₁) = Bool.false
eqDATA (iDATA x) (ConstrDATA x₁ x₂) = Bool.false
eqDATA (iDATA x) (MapDATA x₁) = Bool.false
eqDATA (iDATA x) (ListDATA x₁) = Bool.false
eqDATA (iDATA i₁) (iDATA i₂) = Relation.Nullary.isYes (i₁ Data.Integer.≟ i₂)
eqDATA (iDATA x) (bDATA x₁) = Bool.false
eqDATA (bDATA x) (ConstrDATA x₁ x₂) = Bool.false
eqDATA (bDATA x) (MapDATA x₁) = Bool.false
eqDATA (bDATA x) (ListDATA x₁) = Bool.false
eqDATA (bDATA x) (iDATA x₁) = Bool.false
-- Warning: eqByteString is always trivially true at the Agda level.
-- See "Decidable Equality of Builtins" in "VerifiedCompilation.Equality".
eqDATA (bDATA b₁) (bDATA b₂) = eqByteString b₁ b₂
{-# COMPILE GHC eqDATA = (==) #-}
postulate Bls12-381-G1-Element : Set
{-# FOREIGN GHC import qualified PlutusCore.Crypto.BLS12_381.G1 as G1 #-}
{-# COMPILE GHC Bls12-381-G1-Element = type G1.Element #-}
-- Agda implementation should only be used as part of deciding builtin equality.
-- See "Decidable Equality of Builtins" in "VerifiedCompilation.Equality".
eqBls12-381-G1-Element : Bls12-381-G1-Element → Bls12-381-G1-Element → Bool
eqBls12-381-G1-Element _ _ = Bool.true
{-# COMPILE GHC eqBls12-381-G1-Element = (==) #-}
postulate Bls12-381-G2-Element : Set
{-# FOREIGN GHC import qualified PlutusCore.Crypto.BLS12_381.G2 as G2 #-}
{-# COMPILE GHC Bls12-381-G2-Element = type G2.Element #-}
-- Agda implementation should only be used as part of deciding builtin equality.
-- See "Decidable Equality of Builtins" in "VerifiedCompilation.Equality".
eqBls12-381-G2-Element : Bls12-381-G2-Element → Bls12-381-G2-Element → Bool
eqBls12-381-G2-Element _ _ = Bool.true
{-# COMPILE GHC eqBls12-381-G2-Element = (==) #-}
postulate Bls12-381-MlResult : Set
{-# FOREIGN GHC import qualified PlutusCore.Crypto.BLS12_381.Pairing as Pairing #-}
{-# COMPILE GHC Bls12-381-MlResult = type Pairing.MlResult #-}
-- Agda implementation should only be used as part of deciding builtin equality.
-- See "Decidable Equality of Builtins" in "VerifiedCompilation.Equality".
eqBls12-381-MlResult : Bls12-381-MlResult → Bls12-381-MlResult → Bool
eqBls12-381-MlResult _ _ = Bool.true
{-# COMPILE GHC eqBls12-381-MlResult = (==) #-}
The kind of types is *. Plutus core core is based on System Fω which
is higher order so we have ⇒ for type level functions. We also have
a kind called # which is used for builtin types.
data Kind : Set where
* : Kind -- type
♯ : Kind -- builtin
_⇒_ : Kind → Kind → Kind -- function kind
{-# COMPILE GHC Kind = data KIND (Star | Sharp | Arrow ) #-}
Let I, J, K range over kinds:
variable I J K : Kind