Skip to content

v0.23.0

Compare
Choose a tag to compare
@banacorn banacorn released this 30 Apr 08:39
· 47 commits to main since this release

What’s New?

Introducing 4 new arithmetic operators for UInt!

add :: UInt w -> UInt w -> UInt (w + 1)
addV :: [UInt w] -> UInt v
mul :: UInt w -> UInt w -> UInt (w * 2)
mulV :: UInt w -> UInt w -> UInt v

There are two operators for addition and two for multiplication.

You can probably guess the functions of these operators from their type signatures.

Limitation of the existing operators

The existing addition and multiplication operators have type signatures as follows:

(+) :: UInt w -> UInt w -> UInt w
(*) :: UInt w -> UInt w -> UInt w

These operators produce unsigned integers with fixed widths that must match those of their operands. This can lead to overflow if the values of the operands are too large, with no means to salvage the overflowed bits. That's why we're introducing new operators that allow you to choose the result widths for addressing these limitations.

Let’s take a closer look.

Full Sum Addition

add :: UInt w -> UInt w -> UInt (w + 1)

As the name suggests, this function produces a slightly longer unsigned integer with the carry bit preserved.

Example usage:

example :: Comp (UInt 9)
example = do
    x <- input Public
    y <- input Public
    return (x `add` y)

Variable-width Batch Addition

addV :: [UInt w] -> UInt v

This is the most general form of addition, allowing you to sum a batch of unsigned integers and decide how many carry bits you want to preserve or discard. The result will be zero-extended if it is longer than expected, and truncated if it is shorter than actually produced.

Example usage:

example :: Comp (UInt 10)
example = do
    x <- input Public :: Comp (UInt 8)
    y <- input Public
    z <- input Public
    return [x, y, z]

Full Product Multiplication

Similar to add, but for multiplication. It produces an unsigned integer double the width of its operands, allowing the full product of multiplication to be preserved.

Example usage:

example :: Comp (UInt 16)
example = do
    x <- input Public
    y <- input Public
    return (x `mul` y)

Variable-width Multiplication

This is the most general form of multiplication, allowing you to multiply two unsigned integers and decide how many carry bits you want to preserve or discard. The result will be zero-extended if it is longer than expected, and truncated if it is shorter than actually produced.

Example usage:

example :: Comp (UInt 12)
example = do
    x <- input Public :: Comp (UInt 8)
    y <- input Public
    return (x `mulV` y) -- 4 higher bits discarded

What Else?

As always, bug fixes and performance improvements!

Noticeably, unsigned integer division/modulo should produce less number of constraints that before.

What’s Next?

  • User-defined datatypes with (automatically) structured input/output: Instead of using lists for representing input/output, we want something more structured, like JSON values!
  • Smarter witness generation + user-programmable hints for witness generation.