From 27775eab2727fd0c4268f628035763972cf461dc Mon Sep 17 00:00:00 2001 From: guipublic Date: Thu, 1 Feb 2024 14:46:56 +0000 Subject: [PATCH 1/3] document u128 --- .../noirc_evaluator/src/ssa/ir/instruction.rs | 3 ++ .../docs/noir/concepts/data_types/integers.md | 49 +++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs index 331a02a6974..9dd7313592e 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs @@ -476,6 +476,9 @@ impl Instruction { } Instruction::Truncate { value, bit_size, max_bit_size } => { if let Some((numeric_constant, typ)) = dfg.get_numeric_constant_with_type(*value) { + if bit_size == max_bit_size { + return SimplifiedTo(*value); + } let integer_modulus = 2_u128.pow(*bit_size); let truncated = numeric_constant.to_u128() % integer_modulus; SimplifiedTo(dfg.make_constant(truncated.into(), typ)) diff --git a/docs/docs/noir/concepts/data_types/integers.md b/docs/docs/noir/concepts/data_types/integers.md index 7d1e83cf4e9..27d703cb543 100644 --- a/docs/docs/noir/concepts/data_types/integers.md +++ b/docs/docs/noir/concepts/data_types/integers.md @@ -51,6 +51,55 @@ If you are using the default proving backend with Noir, both even (e.g. _u2_, _i ::: + +## 128 bits Unsigned Integers + +The built-in structure `U128` allows you to use 128-bit unsigned integers almost like a native integer type. However, there are some differences to keep in mind: +- You cannot cast between a native integer and `U128` +- There is a higher performance cost when using `U128`, compared to a native type. + +Conversion between unsigned integer types and U128 are done through the use of `from_integer` and `to_integer` functions. + +```rust +fn main() { + let x = U128::from_integer(23); + let y = U128::from_hex("0x7"); + let z = x + y; + assert(z.to_integer() == 30); +} +``` + +`U128` is implemented with two 64 bits limbs, representing the low and high bits, which explains the performance cost. You should expect `U128` to be twice more costly for addition and four times more costly for multiplication. +You can construct a U128 from its limbs: +```rust +fn main(x: u64, y: u64) { + let x = U128::from_u64s_be(x,y); + assert(z.hi == x as Field); + assert(z.lo == y as Field); +} +``` + +Note that the limbs are stored as Field elements in order to avoid unnecessary conversions. +A part from this, most operations will work as usual: + +```rust +fn main(x: U128, y: U128) { + // multiplication + let c = x * y; + //addition and subtraction + let c = c - x + y; + // division + let c = x / y; + // bit operation; + let c = x & y | y; + // bit shift + let c = x << y; + // comparisons; + let c = x < y; + let c = x == y; +} +``` + ## Overflows Computations that exceed the type boundaries will result in overflow errors. This happens with both signed and unsigned integers. For example, attempting to prove: From 09f0afec1f11b20652aaeb85e9f43ce6d42ae2d7 Mon Sep 17 00:00:00 2001 From: guipublic Date: Thu, 1 Feb 2024 14:56:31 +0000 Subject: [PATCH 2/3] remove code change --- compiler/noirc_evaluator/src/ssa/ir/instruction.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs index 9dd7313592e..331a02a6974 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs @@ -476,9 +476,6 @@ impl Instruction { } Instruction::Truncate { value, bit_size, max_bit_size } => { if let Some((numeric_constant, typ)) = dfg.get_numeric_constant_with_type(*value) { - if bit_size == max_bit_size { - return SimplifiedTo(*value); - } let integer_modulus = 2_u128.pow(*bit_size); let truncated = numeric_constant.to_u128() % integer_modulus; SimplifiedTo(dfg.make_constant(truncated.into(), typ)) From 25cb8a353604b604e1c494954d6a97935a2df373 Mon Sep 17 00:00:00 2001 From: guipublic Date: Tue, 6 Feb 2024 17:38:57 +0000 Subject: [PATCH 3/3] code review --- docs/docs/noir/concepts/data_types/integers.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/noir/concepts/data_types/integers.md b/docs/docs/noir/concepts/data_types/integers.md index 27d703cb543..b95cd8dc837 100644 --- a/docs/docs/noir/concepts/data_types/integers.md +++ b/docs/docs/noir/concepts/data_types/integers.md @@ -80,13 +80,13 @@ fn main(x: u64, y: u64) { ``` Note that the limbs are stored as Field elements in order to avoid unnecessary conversions. -A part from this, most operations will work as usual: +Apart from this, most operations will work as usual: ```rust fn main(x: U128, y: U128) { // multiplication let c = x * y; - //addition and subtraction + // addition and subtraction let c = c - x + y; // division let c = x / y;