# Multifunctions¶

## Multiencoding¶

The *multiencode* function takes a `DataValue`

and a set of preferences, and
tries to encode it in a bytestring according to those preferences. Preferences
determine which encoding scheme(s) is/are chosen, and whether or not we attempt
to convert between virtual machine representations (requiring compilation, which
may not be supported in all cases). Multiformat codes will be included to
indicate which formats are in use (see
here
for a longer description of how this works). In general, canonical commitments
to data and code are made over the output of *multiencode*. Multiencoding is
also used before storing data or sending it over the network. Any party should
be able to take any piece of stored or sent data and a type and attempt to
deserialise it with *multidecode*.

```
multiencode : Preferences -> DataValue -> Bytestring
```

## Multidecoding¶

The *multidecode* function takes a value in bytestring representation and tries
to decode it into an internal representation, according to the multiformat
information and the encoding schemes known by the decoding party. Attempting to
decode unknown formats will result in an error.

```
multidecode : Bytestring -> DataType -> Maybe DataValue
```

## Equality¶

Note that, in general, equality of multiencoded representations implies equality of data values, but equality of data values does not imply equality of multiencoded representations (as different encoding schemes may be used). Phrased more succinctly:

`multiencode a = multiencode b`

→`a = b`

`multiencode a /= multiencode b`

does not imply`a != b`

## Usage¶

In general, canonical commitments to data and code are made over the output of
*multiencode*. Implication (1) guarantees that (subject to the usual
cryptographic assumptions) equality of two succinct commitments (cryptographic
hash function applied to the multiencoded value) implies equality of the data
values so encoded and committed to.

Multiencoding is also used before storing data or sending it over the network.
Any party who knows the encoding scheme table should be able to take any piece
of stored or sent data and deserialise it with *multidecode*.

## Multievaluation¶

The *multievaluate* function evaluates the application of a function to a value.
Whenever *multievaluate* encounters a `FunctionV n f`

, it looks up the
appropriate virtual machine as specified by the natural index \(n\), decodes \(f\)
using \(decode_n\), then calls \(evaluate_n\), tracking and summing the gas used in
subsequent evaluations.

Note

This implies a uniform gas scale, which we elide the details of for now, but would probably require e.g. benchmarking on the hardware in question.

```
multievaluate :
DataValue ->
[DataValue] ->
Natural ->
Maybe (DataValue, Natural)
```

#### Recursive multievaluation¶

What if one VM is passed a data value including a `FunctionV`

represented in a
different VM? The VM in question can treat this code as data - in the sense that
it can examine, introspect, modify it, etc. - but it cannot treat this code as
code, since it doesn't know how to interpret functions represented in another VM
(in general). However, we can allow one VM to call another easily enough simply
by passing a pointer to `multievaluate`

itself into the evaluation context.
Then, when it encounters a function encoded for a different VM which it wishes
to evaluate, the VM can simply call `multievaluate`

, tracking gas consumption as
appropriate. This technique can also be used to allow for something such as a
data query, where data queries are represented as functions understood by a
specific, specialized VM.

Note

There's some ABI/FFI memory layout logic to be figured out here - `multievaluate`

must be called with a function and arguments formatted as `DataValue`

s - this should be specified in detail.

#### Multicompilation¶

What if we wish to convert functions between different VM representations? We
can define a *multicompile* function which attempts to compile functions
represented in a data value based on a set of preferences. For example,
preferences could be to convert all functions to a particular VM, or to convert
where conversions are known in some order of preference. Compilation will fail
if unknown VM conversions are attempted.

Multicompilation depends on a known set of conversions \(compile_{i,j}\) which convert between \(VM_i.t\) and \(VM_j.t\) representations of functions, which must preserve extensional equality under evaluation.

```
multicompile :
Preferences ->
DataValue ->
Maybe DataValue
```

##### Equality proofs¶

With multicompilation, we can create evidence that `a = b`

, where `a`

and `b`

are arbitrary data values, including functions (where ```
multiencode a /=
multiencode b
```

). This evidence would consist simply of a proof that
`multicompile prefs a = b`

for some preferences `prefs`

. This proof could be of
varying practical forms - the verifier could simply run `multicompile`

themselves, the verifier could trust another's run of `multicompile`

, or the
verifier could check a succinct proof of computational correctness. Many details
are elided here for now.

#### Smart multievaluation¶

With multicompilation and equality proofs, we can also define a version of
`multievaluate`

which uses available evidence + preferences intelligently at
evaluation time to use certain known-to-be-equivalent versions of functions
(e.g. compiled versions) instead of others. Then known optimized versions of
functions can be used, and even something like “JIT” compilation can happen e.g.
asychronously once certain statistical thresholds are met. Optionally, this
“smart multievaluate” can *also* use known proofs of the results of certain
evaluations (instead of repeating the evaluations), where provable VMs are
involved.