Docs
Library
Math

Math

Generally, all types that are usable in o1js are also usable out-of-the-box in protokit. But there are some caveats to dealing with bounded integers (UInt64, UInt32).

Integers

By default, o1js exposes two classes UInt64 and UInt32 to protect you from overflows that can happen if you use Field directly. Unfortunately, these don't work well with Protokit since they use the hard-failing o1js assertions instead of the protokit-specific assert. This leads to your application being non-complete and being unable to include failed transactions in settlements.

To overcome this, we created a number of classes in @proto-kit/library that handle all of that for you while providing the same interface as the vanilla variants.

  • UInt32
  • UInt64
  • UInt112
  • UInt224

In addition to the methods known from o1js, we implement the sqrtMod() and sqrtFloor() functions to help facilitate square-root calculations.

⚠️

Make sure to import from @proto-kit/library when using UInt32 and UInt64

Creating protokit UInts

There are multiple ways of creating UInts, each of them with their own properties. This example uses UInt64, but can be used with any other UInt the same way.

The most straight forward one is using UInt64.from(). This accepts UInt64 | string | bigint | number. It should be used for creation of a constant or for copying a existing UInt.

// Using string
const uint1 = UInt64.from("5");
// Using number
const uint2 = UInt64.from(5);
// Using another UInt64
const uint3 = UInt64.from(uint1);

To convert a Field into a UInt, you can use both the Safe and Unsafe fromField() function.

// Creates a UInt64 and performs necessary range checks on the given `field`
UInt64.Safe.fromField(field);
 
// Creates a UInt64 without performing range checks.
// This safes constraints, but relies on the given field to be ensured to be in range
UInt64.Unsafe.fromField(Field(1));

Because range checks (which are used under the hood to enable the safety of UInts) are very expensive, these different methods of creating and transforming UInts are a way for developers to optimize and decrease proving effort.

Transforming UInts

Sometimes we need to go from a specific UInt bit-range to a different one. Let's say we want to go from UInt32 to UInt64 and back.

The upward direction is trivial and will not generate additional constraints

const uint64 = UInt64.Unsafe.fromField(uint32.value);

Going down to UInt32 again, we need to range-check the 64-bit number to ensure it is within 32-bits. Therefore, we need to use the Safe.fromField method.

const uint32 = UInt32.Safe.fromField(uint64.value);

For some UInts, simpler conversion functions exist.

  • UInt32.toUInt64()
  • UInt112.toUInt224()

Converting to o1js UInt64

Every UInt from the @proto-kit/library package also has a conversion function to turn it into a o1js UInt64

// Will fail the transaction if the value of uint exceeds 64 bits
const o1jsUint = uint.toO1UInt64()
 
// If the value of `uint` exceeds 64 bits, it will take the maximum value fitting into 64 bits
const o1jsUint2 = uint.toO1UInt64Clamped()