Arithmetic Operators
Compact provides three arithmetic operators: addition, subtraction, and multiplication. Division is not supported.
Note: The official Midnight documentation uses bounded notation like
Uint<0..n>to describe types. In code examples, we use the shorthandUint<64>, which is equivalent toUint<0..2^64>— the upper bound of the bounded form is exclusive (verified with toolchain 0.31.1).
Available Operators
| Operator | Name | Result Type (for Uint<0..m> and Uint<0..n>, exclusive bounds) |
|---|---|---|
+ | Addition | Uint<0..m+n-1> (max value (m-1)+(n-1)) |
- | Subtraction | Uint<0..m> (left operand’s bound) |
* | Multiplication | Uint<0..(m-1)*(n-1)+1> (max value (m-1)*(n-1)) |
Verified with toolchain 0.31.1:
Uint<0..10> + Uint<0..20>infersUint<0..29>, andUint<0..10> * Uint<0..20>infersUint<0..172>— the compiler widens to exactly cover the largest possible result.
Basic Arithmetic
pragma language_version >= 0.16;
export circuit add(a: Uint<64>, b: Uint<64>): Uint<64> {
return (a + b) as Uint<64>;
}
export circuit subtract(a: Uint<64>, b: Uint<64>): Uint<64> {
return (a - b) as Uint<64>;
}
export circuit multiply(a: Uint<64>, b: Uint<64>): Uint<64> {
return (a * b) as Uint<64>;
}
Type Widening
When you perform arithmetic on unsigned integers, Compact computes a result type based on the operand bounds:
- For
Uint<0..m> + Uint<0..n>, the result type isUint<0..m+n-1>(covers max value(m-1)+(n-1)) - For
Uint<0..m> * Uint<0..n>, the result type isUint<0..(m-1)*(n-1)+1>(covers max value(m-1)*(n-1)) - For
Uint<0..m> - Uint<0..n>, the result type isUint<0..m>
If the computed bound exceeds the implementation’s maximum unsigned integer, it is a static type error.
When the result type doesn’t match the expected type, you may need a cast:
pragma language_version >= 0.16;
export circuit sumExample(): Uint<64> {
const a: Uint<64> = 100;
const b: Uint<64> = 200;
// The result of a + b has a wider type than Uint<64>
// Cast to fit the return type
const result: Uint<64> = (a + b) as Uint<64>;
return result;
}
Field Arithmetic
If either operand has type Field, the result type is Field. Field arithmetic uses modular arithmetic - overflow and underflow wrap modulo the field modulus:
pragma language_version >= 0.16;
export circuit fieldMath(): Field {
const a: Field = 100;
const b: Field = 200;
// Result type is Field
const sum: Field = a + b;
const product: Field = a * b;
return product;
}
Practical Example: Counter
pragma language_version >= 0.16;
export ledger count: Uint<64>;
export circuit increment(): [] {
count = (count + 1) as Uint<64>;
}
export circuit addAmount(amount: Uint<64>): [] {
// Disclose parameter before using in ledger operation
const dAmount = disclose(amount);
count = (count + dAmount) as Uint<64>;
}
export circuit getCount(): Uint<64> {
return count;
}
Key Points
- No division operator - Compact doesn’t support
/ - Result types are computed from bounds -
+and*produce wider types; casts may be needed depending on usage - Field arithmetic wraps - Overflow/underflow wrap modulo the field modulus
- Subtraction can underflow - If
b > aat runtime,a - braises a runtime error (no wraparound forUint)