Compact reference
Compact is a strongly statically typed, bounded smart contract language, designed to be used in combination with TypeScript for writing smart contracts for the three-part structure of Midnight, where contracts have the following components:
- a replicated component on a public ledger
- a zero-knowledge circuit component, confidentially proving the correctness of the former
- a local, off-chain component that can perform arbitrary code
Each contract in Compact can have four kinds of code:
- type declarations, to support all of the following
- declarations of the data that the contract stores in the public ledger
- declarations of
witnessfunctions, to be supplied in TypeScript circuitdefinitions, that serve as the operational core of a smart contract
A contract can also include code from external files, and it can declare and import modules.
Like TypeScript, Compact is an eager call-by-value language.
Compact Types
Compact is statically typed: every expression in a Compact program has a static type. Named circuits and witnesses require a type annotation on each of their parameters, and they require a return type annotation. Anonymous circuit expressions can have optional parameter and return type annotations. Constant binding statements can have an optional type annotation.
The language is strongly typed: the compiler will reject programs that do not type check. It will reject programs where a circuit or witness with a parameter type annotation is called with an incorrectly typed argument for that parameter. It will reject programs where a circuit with a return type annotation returns an incorrectly typed value. If an optional type annotation is omitted, the compiler will infer a type and it will reject programs where no such type can be inferred.
Types consist of built-in primitive types, user-defined types defined in the program, and generic type parameters in scope. When the term "type" occurs in this document without any other qualifier, it means either a primitive type, a user-defined type, or a generic type parameter in scope.
Primitive types
The following are the primitive types of Compact:
-
Booleanis the type of boolean values. There are only two values ofBooleantype. They are the values of the expressionstrueandfalse. -
Uint<m..n>, wheremis the literal0or a generic size parameter in scope and bound to0, and wherenis a natural number literal or a generic size parameter in scope, is the type of bounded unsigned integer values between0andn, both inclusive. (The lower bound is currently required to be0.)Uinttypes with different bounds0..nare different types, although one may be a subtype of the other. In practice, there is a (large) maximum unsigned integer value determined by the zero-knowledge proving system. The Compact implementation will signal an error if aUinttype exceeds this maximum value. -
Uint<n>, wherenis a non-zero natural number literal or a generic size parameter in scope and bound to a non-zero natural number, is the type of sized unsigned integer values with binary representations using up tonbits. This is the same type asUint<0..m>wheremis equal to(2^n)-1. Sized integer types can be seen as a convenience for programmers.Uint<32>, for example, can be more obvious and less error-prone than the equivalentUint<0..4294967295>. Any Compact program that uses sized integer types can be rewritten to one that uses only bounded integer types. -
Fieldis the type of elements in the scalar prime field of the zero-knowledge proving system. -
[T, ...], whereT, ...are zero or more comma-separated types is the type of tuple values with element typesT, .... Note that tuples are heterogeneous: the element types can all be distinct. The length of a tuple type is the number of element types. Tuple types with different lengths are different types. Tuple types with the same lengths but where at least one element has different types are different types although one may be a subtype of the other. -
Vector<n, T>, wherenis a natural number literal or else a generic size parameter in scope andTis a type, is a shorthand notation for the tuple type[T, ...]withnoccurrences of the typeT. Note that a vector type and the corresponding tuple type are two different ways of writing exactly the same type. Unless otherwise specified, type rules for vector types are derived from the rules for the corresponding tuple type. -
Bytes<n>, wherenis a natural number literal or else a generic size parameter in scope, is the type of byte array values of lengthn.Bytestypes with different lengths are different types.Bytestypes are used in the Compact standard library for hashing. String literals in Compact also have aBytestype, wherenis the number of bytes in the UTF-8 encoding of the string. -
Opaque<s>, wheresis a string literal, is the type of opaque values with tags. The syntax of string literals in Compact is the same as in TypeScript.Opaquetypes with different tags are different types. Opaque values can be manipulated in witnesses but they are opaque to circuits. They are represented in circuits as their hash. The allowed tags are currently only"string"and"Uint8Array".