# Operators

This is a basic description of each operator. If you want tangible examples for how to use them, check out the Examples page.

The operators in the Modules section, as well as `if`

, `qq`

, and `unquote`

are only part of Chialisp, not the compiled CLVM representation.

Additionally, they do not have an intrinsic cost, since they are compiled to CLVM and not actually executed on their own.

## Chialisp Modules

Statement | Format | Description |
---|---|---|

mod | `(mod A B)` | Compiles module with args A and body B. |

include | `(include A.clib)` | Includes file A containing a list of statements. |

defun | `(defun A B C)` | Function named A with args B and body C. |

defun-inline | `(defun-inline A B C)` | Inline function named A with args B and body C. |

lambda | `(lambda A B)` | Lambda function with args A and body B. |

defmacro | `(defmacro A B C)` | Macro named A with args B and body C. |

defconstant | `(defconstant A B)` | Constant A with value B. |

## Arithmetic

Operator | Format | Description |
---|---|---|

+ | `(+ A B ...)` | Adds multiple atoms. |

- | `(- A B ...)` | Subtracts multiple atoms. |

* | `(* A B ...)` | Multiplies multiple atoms. |

/ | `(/ A B)` | Divides two atoms. |

divmod | `(divmod A B)` | Calculates quotient and remainder in cons pair. |

### Negative Division

The `/`

operator cannot be used to divide negative numbers. Previously this worked, but used the wrong method of dividing negative integers. The operator was soft-forked at block height 2,300,000 to prevent this.

You should use `divmod`

instead in situations where you need to divide negative numbers.

For example:

Chialisp

## Comparison

Operator | Format | Description |
---|---|---|

= | `(= A B)` | True if both atoms are equal. |

> | `(> A B)` | True if the first atom is greater as a number. |

>s | `(>s A B)` | True if the first atom is greater as a string of bytes. |

not | `(not A)` | True if the atom is false. |

all | `(all A B ...)` | True if all of the atoms are non-zero. |

any | `(any A B ...)` | True if any of the atoms are non-zero. |

## Control Flow

Operator | Format | Description |
---|---|---|

if | `(if A B C)` | Chialisp only - If A is true, then B, otherwise C. Lazy evaluated. |

i - if | `(i A B C)` | If A is true, then B, otherwise C. |

x - exit | `(x ...)` | Terminate the program with zero or more values. |

### If Operator

The `if`

operator is lazy evaluated. This means that code paths are not evaluated unless they need to be.

Usually this is the intended behavior, but if it isn't, you can use the `i`

operator instead.

If you would like to replicate the lazy evaluation of the `if`

operator in CLVM, you can wrap the `i`

operator like this:

CLVM

Essentially, this runs the branch the condition matches as a program (with the current environment). Depending on how much code is executed in each branch, this may be more cost effective than executing both branches.

## Evaluation

Operator | Format | Description |
---|---|---|

qq - quasi-quote | `(qq A)` | Chialisp only - Quote an expression except for anything inside `unquote` . |

unquote | `(unquote A)` | Chialisp only - Unquote an expression nested within `qq` . |

q - quote | `(q . A)` | Treats A as a value rather than a program. |

a - apply | `(a A B)` | Evaluate value A as a program with value B as its environment. |

@ - environment | `(@ A)` | Chialisp only - Access value A from the environment. |

### Environment Operator

The `@`

operator acts in a similar fashion to unquoted atoms in CLVM. If `@`

is used plainly as a value, its value is the whole environment.

## Lists

Operator | Format | Description |
---|---|---|

f - first | `(f A)` | First value in list A. |

r - rest | `(r A)` | Rest of the values in list A. |

c - cons | `(c A B)` | Cons pair of A and B, or prepend A to list B. |

l - list predicate | `(l A)` | True if A is a list, not nil. Can be used to check length. |

## Atoms

Operator | Format | Description |
---|---|---|

sha256 | `(sha256 A B ...)` | Calculates the sha256 hash of the atoms. |

concat | `(concat A B ...)` | Concatenates the bytes of the atoms. |

strlen | `(strlen A)` | Returns the length of the atom. |

substr | `(substr A B C)` | Slice of bytes A between B and C, exclusive. |

logand | `(logand A B ...)` | Bitwise and of the atoms. |

logior | `(logior A B ...)` | Bitwise logical or of the atoms. |

logxor | `(logxor A B ...)` | Bitwise xor of the atoms. |

lognot | `(lognot A)` | Bitwise not of A. |

ash - arithmetic shift | `(ash A B)` | Arithmetic shift A by B bits. |

lsh - logical shift | `(lsh A B)` | Logical shift A by B bits. |

## BLS12-381

Operator | Format | Description |
---|---|---|

point_add | `(point_add p1 p2 ...)` | Adds two or more G1 points (public keys) together. Renamed to g1_add in CHIP-0011. |

pubkey_for_exp | `(pubkey_for_exp A)` | Maps an exponent (secret key) to a G1 point (public key). |

## Softfork

The purpose of the `softfork`

operator is to enable the ability to define new CLVM operators without creating a hard fork. For example, suppose we want to add secp256k1 operators like `+s`

for adding two points on this ECDSA curve for bitcoin compatibility. We can't just do this in vanilla CLVM, because that would make the program `(+s A B)`

return different values before and after the soft fork. So instead, we can hide it under `softfork`

.

The syntax is defined as follows:

`(softfork cost extension program arguments)`

- The
`cost`

must equal the cost of executing the program with the specified arguments, otherwise an exception is raised. The minimum cost of the operator is 140. - The
`extension`

is an unsigned (up to 32-bit in size) integer indicating the set of extensions available in the softfork guard. - The
`program`

is executed with the specified`arguments`

. The output is always either null or termination of the program if it failed.

Here is a CLVM example using the `coinid`

operator described in the CHIP-0011 Operators section:

`(softfork`

(q . 1265) ; expected cost (including cost of softfork itself)

(q . 0) ; extension 0

(q a ; defer execution of if-branches

(i

(=

(coinid

(q . 0x1234500000000000000000000000000000000000000000000000000000000000)

(q . 0x6789abcdef000000000000000000000000000000000000000000000000000000)

(q . 123456789)

)

(q . 0x69bfe81b052bfc6bd7f3fb9167fec61793175b897c16a35827f947d5cc98e4bc)

)

(q . 0) ; if coin ID matches, return 0

(q x) ; if coin ID mismatches, raise

)

(q . ())) ; environment to apply

(q . ()) ; environment to softfork

)

Pre-softfork, this always passes and returns `()`

at a cost of `cost`

(or 140, whichever is higher).

Post-softfork, this also returns `()`

at a cost of `cost`

, but may also fail if the coin id doesn't match. We can't export the result outside the `softfork`

boundary, but we can compare it to something inside and raise if it doesn't match.

We take the cost of running the program inside the `softfork`

boundary and ensure it exactly matches `cost`

, and raise an exception if it's wrong. That way, the program really does have the same cost pre-softfork and post-softfork (or it fails post-softfork).

## CHIP-0011 Operators

These operators will be usable within the `softfork`

operator starting at block height 4,510,000.

At block height 5,496,000, the operators can be used directly as well.

Operator | Format | Description |
---|---|---|

g1_add | `(g1_add p1 p2 ...)` | Adds two or more G1 points (public keys) together. |

g1_subtract | `(g1_subtract p1 p2 ...)` | Subtracts one or more G1 points (public keys) from a base G1 point. |

g1_multiply | `(g1_multiply p1 p2)` | Multiplies a G1 point (public key) by a scalar value. |

g1_negate | `(g1_negate point)` | Negates a G1 point (public key). |

g2_add | `(g2_add p1 p2 ...)` | Adds two or more G2 points (signatures) together. |

g2_subtract | `(g2_subtract p1 p2 ...)` | Subtracts one or more G2 points (signatures) from a base G2 point. |

g2_multiply | `(g2_multiply p1 p2)` | Multiplies a G2 point (signature) by a scalar value. |

g2_negate | `(g2_negate point)` | Negates a G2 point (signature). |

g1_map | `(g1_map data dst)` | Hashes the data to a G1 point with sha256 and ExpandMsgXmd. DST is optional. |

g2_map | `(g2_map data dst)` | Hashes the data to a G2 point with sha256 and ExpandMsgXmd. DST is optional. |

bls_pairing_identity | `(bls_pairing_identity g1 g2 ...)` | Returns nil if the pairing of all pairs is the identity, otherwise raises an exception. |

bls_verify | `(bls_verify g2 g1 msg ...)` | Nil if signature g2 is valid with public key g1 and message, otherwise raises an exception. |

coinid | `(coinid parent_id puzzle_hash amount)` | Validates inputs and calculates the coin id with a parent coin id, puzzle hash, and amount. |

modpow | `(modpow base exponent modulus)` | Computes `(base ^ exponent) % modulus` . Base may be negative, exponent must not be, modulus must not be 0. |

% | `(% numerator denominator)` | Computes the remainder of the numerator divided by the denominator. |

secp256k1_verify | `(secp256k1_verify pubkey msg_hash signature)` | Verifies a signature that uses the secp256k1 curve. |

secp256r1_verify | `(secp256r1_verify pubkey msg_hash signature)` | Verifies a signature that uses the secp256r1 curve. |