Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
72524bd
compile
jialinli98 Dec 3, 2025
a1d4b83
more fixes
jialinli98 Dec 5, 2025
fd3714d
fixes
jialinli98 Dec 6, 2025
f44e3eb
more fixes
jialinli98 Dec 7, 2025
03d330d
fixes
jialinli98 Dec 8, 2025
4b19222
fixes
jialinli98 Dec 8, 2025
14972f0
ci
jialinli98 Dec 8, 2025
213aa66
fix
jialinli98 Dec 8, 2025
cfbfd2d
remove circuit tests
jialinli98 Dec 8, 2025
f2aaf16
fix
jialinli98 Dec 8, 2025
79c2ecf
fix
jialinli98 Dec 9, 2025
f40317a
fixes
jialinli98 Dec 9, 2025
8130404
fixes
jialinli98 Dec 9, 2025
61a624f
fixes
jialinli98 Dec 9, 2025
2a9a863
fixes
jialinli98 Dec 9, 2025
add371c
fixes
jialinli98 Dec 9, 2025
5d46de0
fix
jialinli98 Dec 9, 2025
63dee8e
fixes
jialinli98 Dec 10, 2025
8063023
fixes
jialinli98 Dec 10, 2025
fb2f020
fixes
jialinli98 Dec 10, 2025
bef2bf6
fix
jialinli98 Dec 10, 2025
3d281e7
fix
jialinli98 Dec 10, 2025
c2698c0
fix
jialinli98 Dec 10, 2025
e32ff64
Merge branch 'main' of https://github.com/noir-lang/eth-proofs into j…
jialinli98 Dec 10, 2025
6945d30
resolve warnings
jialinli98 Dec 11, 2025
b0c1b95
resolve warnings
jialinli98 Dec 11, 2025
8a2b626
resolve warnings
jialinli98 Dec 11, 2025
aae5836
resolve warnings
jialinli98 Dec 11, 2025
3e2adea
fix typescript compile errors
jialinli98 Dec 11, 2025
a2df451
fix
jialinli98 Dec 11, 2025
5569b3e
vlayer utils
jialinli98 Dec 12, 2025
4609e92
add test to yml
jialinli98 Dec 12, 2025
63a76e7
fixes
jialinli98 Dec 12, 2025
6563c9b
fix
jialinli98 Dec 13, 2025
395a691
fix
jialinli98 Dec 13, 2025
4097cf4
fix
jialinli98 Dec 14, 2025
dc81905
disable some CI build that fails
jialinli98 Dec 14, 2025
85f1d59
replace u256
jialinli98 Dec 15, 2025
78060fb
Revert "replace u256"
jialinli98 Dec 15, 2025
d681289
Revert "Revert "replace u256""
jialinli98 Dec 15, 2025
112f08f
fix
jialinli98 Dec 15, 2025
652767f
set min version to 1.0.0-beta.17
jialinli98 Dec 15, 2025
a720f8c
test fix
jialinli98 Dec 15, 2025
340ff96
readme
jialinli98 Dec 15, 2025
72e9613
16 bytes for u128
jialinli98 Dec 18, 2025
365e219
fix
jialinli98 Dec 19, 2025
0502176
Merge branch 'main' of https://github.com/noir-lang/eth-proofs into j…
jialinli98 Dec 19, 2025
2c1079c
merge
jialinli98 Dec 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion ethereum/circuits/lib/Nargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ authors = ["Arkadiusz Konior, Marek Kirejczyk"]
compiler_version = ">=0.30.0"

[dependencies]
keccak256 = {tag = "v0.1.1", git = "https://github.com/noir-lang/keccak256" }
keccak256 = {tag = "v0.1.1", git = "https://github.com/noir-lang/keccak256" }
bignum = {tag = "v0.8.3", git = "https://github.com/noir-lang/noir-bignum" }
27 changes: 19 additions & 8 deletions ethereum/circuits/lib/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,22 +237,33 @@ U256 is a structure to use as a type for big numbers.
It is used when dealing with numbers up to 2<sup>256</sup>. They can exceed Field maximum value.
In particular it is a word size in ETH and therefore it is a basic type used in both storage and slot values calculations.

[There](.src/uint256.nr) is an unoptimized implementation of this type using two U128 structures. Optimized version will appear in Noir.
This library uses `U256` from the [noir-bignum](https://github.com/noir-lang/noir-bignum) library. The [`uint256.nr`](./src/uint256.nr) module provides conversion utilities between `U256` and `Bytes32`/`Field` types.

Traits implemented for U256:
Traits implemented for U256 (from bignum library):

- Add
- Eq
- Serde
- Serde (via this library's implementation)

```rust
global u128_number = 0x10000000000000000000000000000000;
use dep::bignum::bignum::BigNum;
use dep::bignum::U256;
use crate::uint256::{from, from_field};

let big_number = U256::new(u128_number, u128_number);
// Create U256 values
let zero = U256::zero();
let one = U256::from(1);
let big_number = U256::modulus().udiv(U256::from(16));

let sum = big_number + U256::one();
assert_eq(sum, U256 { high: u128_number, low: u128_number + U128::one()});
// Convert from Bytes32
let bytes: Bytes32 = [0x10; 32];
let u256_from_bytes = from(bytes);

let serialized: [Field; 4] = big_number.serialize();
// Convert from Field
let field_value: Field = 100;
let u256_from_field = from_field(field_value);

// Serialization (uses 3 limbs)
let serialized: [Field; 3] = big_number.serialize();
assert_eq(U256::deserialize(serialized), big_number);
```
18 changes: 11 additions & 7 deletions ethereum/circuits/lib/src/serde.nr
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ use crate::receipt::{
MAX_PREFIXED_KEY_NIBBLE_LEN as RECEIPT_MAX_PREFIXED_KEY_NIBBLE_LEN,
MAX_VALUE_LEN_M as RECEIPT_MAX_VALUE_LEN_M,
};
use crate::uint256::U256;
use dep::bignum::bignum::BigNum;
use dep::bignum::U256 as u256;

pub trait Serde<let LEN: u32> {
fn serialize(self) -> [Field; LEN];
Expand All @@ -34,15 +35,18 @@ impl Serde<U128_SERIALIZED_LEN> for u128 {
}
}

pub(crate) global U256_SERIALIZED_LEN: u32 = 2;
pub(crate) global u256_SERIALIZED_LEN: u32 = 3;

impl Serde<U256_SERIALIZED_LEN> for U256 {
fn serialize(self) -> [Field; U256_SERIALIZED_LEN] {
[self.low as Field, self.high as Field]
impl Serde<u256_SERIALIZED_LEN> for u256 {
fn serialize(self) -> [Field; u256_SERIALIZED_LEN] {
self.get_limbs().map(|x: u128| x as Field)
}

fn deserialize(data: [Field; U256_SERIALIZED_LEN]) -> Self {
U256 { low: data[0] as u128, high: data[1] as u128 }
fn deserialize(data: [Field; u256_SERIALIZED_LEN]) -> Self {
for i in 0..u256_SERIALIZED_LEN {
data[i].assert_max_bit_size::<120>();
}
u256::from_limbs(data.map(|x: Field| x as u128))
}
}

Expand Down
20 changes: 12 additions & 8 deletions ethereum/circuits/lib/src/serde_test.nr
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,32 @@ mod U128_ {

#[test]
fn simple() {
let value: u128 = 100;
let value: u128 = 100;
let serialized: [Field; U128_SERIALIZED_LEN] = value.serialize();

assert_eq(serialized[0] as u128, value);
assert_eq(u128::deserialize(serialized), value);
assert_eq(serialized[0] as u128, value);
assert_eq(u128::deserialize(serialized), value);
}
}

mod U256 {
use crate::serde::Serde;
use crate::serde::U256_SERIALIZED_LEN;
use crate::uint256::U256;
use crate::serde::u256_SERIALIZED_LEN;
use crate::uint256::from_field;
use dep::bignum::bignum::BigNum;
use dep::bignum::U256;

global u128_number: u128 = 0x10000000000000000000000000000000;
global u128_number: Field = 0x10000000000000000000000000000000;

#[test]
fn simple() {
let value = U256::new(u128_number, u128_number);
let serialized: [Field; U256_SERIALIZED_LEN] = value.serialize();

assert_eq(serialized[0] as u128, u128_number);
assert_eq(serialized[1] as u128, u128_number);
let value = from_field(u128_number);
let serialized: [Field; u256_SERIALIZED_LEN] = value.serialize();
let s = serialized.map(|x: Field| x as u128);
assert_eq(U256::from_limbs(s), value);
assert_eq(U256::deserialize(serialized), value);
}
}
Expand Down
92 changes: 15 additions & 77 deletions ethereum/circuits/lib/src/uint256.nr
Original file line number Diff line number Diff line change
@@ -1,86 +1,24 @@
use crate::misc::arrays::memcpy_up_to_length;
use crate::misc::bytes32::field_to_bytes32;
use crate::misc::types::Bytes32;
use dep::std::ops::Add;
use dep::bignum::bignum::BigNum;
use dep::bignum::U256 as u256;

global uint128_overflow_value: Field = 340282366920938463463374607431768211456; // 2^128

pub struct U256 {
pub(crate) high: u128,
pub(crate) low: u128,
}

impl U256 {
pub fn new(high: u128, low: u128) -> Self {
Self { high, low }
}

pub fn zero() -> Self {
Self { high: 0, low: 0 }
}

pub fn one() -> Self {
Self { high: 0, low: 1 }
}

pub fn from_field(field: Field) -> Self {
U256::from(field_to_bytes32(field))
}
}

impl From<Bytes32> for U256 {
fn from(bytes: Bytes32) -> Self {
let mut high_bytes = [0; 16];
memcpy_up_to_length(&mut high_bytes, bytes, 16, 16);
let high = Field::from_le_bytes::<16>(high_bytes) as u128;

let mut low_bytes = [0; 16];
memcpy_up_to_length(&mut low_bytes, bytes, 0, 16);
let low = Field::from_le_bytes::<16>(low_bytes) as u128;

U256::new(high, low)
}
}

impl Into<Bytes32> for U256 {
fn into(self) -> Bytes32 {
let mut bytes = [0; 32];
memcpy_up_to_length(&mut bytes, (self.low as Field).to_le_bytes::<16>(), 0, 16);

let high_bytes = (self.high as Field).to_le_bytes::<16>();
for i in 0..16 {
bytes[i + 16] = high_bytes[i];
}

bytes
pub fn from(bytes: Bytes32) -> u256 {
let mut bytes33 = [0; 33];
for i in 0..32 {
bytes33[i + 1] = bytes[i];
}
u256::from_be_bytes(bytes33)
}

impl Eq for U256 {
fn eq(self, other: U256) -> bool {
(self.high == other.high) & (self.low == other.low)
pub fn into(u256: u256) -> Bytes32 {
let bytes = u256.to_be_bytes();
let mut bytes32 = [0; 32];
for i in 0..32 {
bytes32[i] = bytes[i + 1];
}
bytes32
}

impl Add for U256 {
fn add(self, other: Self) -> Self {
let lo: Field = self.low as Field + other.low as Field;

let mut low = 0;
let mut carry = 0;
if (lo.lt(uint128_overflow_value)) {
low = lo;
} else {
low = lo - uint128_overflow_value;
carry = 1;
}

let hi: Field = self.high as Field + other.high as Field + carry;
assert(hi.lt(uint128_overflow_value), "attempt to add with overflow");

let high = hi as u128;
let low = low as u128;

Self { high, low }
}
pub fn from_field(field: Field) -> u256 {
u256::from(field)
}
117 changes: 19 additions & 98 deletions ethereum/circuits/lib/src/uint256_test.nr
Original file line number Diff line number Diff line change
@@ -1,135 +1,56 @@
use crate::uint256::U256;

global high: u128 = 0x10000000000000000000000000000000;
global low: u128 = 0;

global big_number: U256 = U256::new(high, low);

#[test]
fn success() {
assert_eq(big_number.high, high);
assert_eq(big_number.low, low);
}

#[test]
fn new() {
let big_number = U256::new(high, low);
assert_eq(big_number.high, high);
assert_eq(big_number.low, low);
}

#[test]
fn zero_and_one() {
let zero = U256::zero();
assert_eq(zero.high, 0);
assert_eq(zero.low, 0);

let one = U256::one();
assert_eq(one.high, 0);
assert_eq(one.low, 1);
}

mod from_bytes32 {
use crate::uint256::U256;
global high: u128 = 0x10000000000000000000000000000000;
global low: u128 = 0;
global limit: u128 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
use crate::uint256::from;
use dep::bignum::bignum::BigNum;
use dep::bignum::U256;

global big_number: U256 = U256::new(high, low);
global limit_u256: U256 = U256::new(limit, limit);
global limit_u256: U256 = U256::zero() - U256::one();

global big_number: U256 = U256::modulus().udiv(U256::from(16));

#[test]
fn zero() {
let bytes = [0x00; 32];
assert_eq(U256::from(bytes), U256::zero());
assert_eq(from(bytes), U256::zero());
}

#[test]
fn success() {
let mut bytes = [0x00; 32];
bytes[31] = 0x10;
assert_eq(U256::from(bytes), big_number);
bytes[0] = 0x10;
assert_eq(from(bytes), big_number);
}

#[test]
fn u256_limit() {
let bytes = [0xff; 32];
assert_eq(U256::from(bytes), limit_u256);
assert_eq(from(bytes), limit_u256);
}
}

mod into_bytes32 {
use crate::uint256::U256;
global high: u128 = 0x10000000000000000000000000000000;
global low: u128 = 0;
global limit: u128 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
use crate::uint256::into;
use dep::bignum::bignum::BigNum;
use dep::bignum::U256;

global big_number: U256 = U256::new(high, low);
global limit_u256: U256 = U256::new(limit, limit);
global big_number: U256 = U256::modulus().udiv(U256::from(16));
global limit_u256: U256 = U256::zero() - U256::one();

#[test]
fn zero() {
let bytes = [0x00; 32];
assert_eq(U256::into(U256::zero()), bytes);
assert_eq(into(U256::zero()), bytes);
}

#[test]
fn success() {
let mut bytes = [0x00; 32];
bytes[31] = 0x10;
assert_eq(U256::into(big_number), bytes);
bytes[0] = 0x10;
assert_eq(into(big_number), bytes);
}

#[test]
fn u256_limit() {
let bytes = [0xff; 32];
assert_eq(U256::into(limit_u256), bytes);
}
}

#[test]
fn eq() {
assert_eq(big_number, big_number);

let big_number2 = U256::new(high, low);
assert_eq(big_number, big_number2);
}

#[test]
fn not_eq() {
let big_number2 = U256 { high, low: high };
assert(big_number != big_number2);

let big_number3 = U256 { high: low, low };
assert(big_number != big_number3);
}

mod trait_add {
use crate::uint256::U256;
global high: u128 = 0x10000000000000000000000000000000;
global low: u128 = 0;
global limit: u128 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;

global big_number: U256 = U256::new(high, low);
global limit_u256: U256 = U256::new(limit, limit);

#[test]
fn sum() {
let sum = big_number + big_number;

assert_eq(sum, U256 { high: 0x20000000000000000000000000000000, low });
}

#[test]
fn sum_with_carry() {
let big_number = U256 { high, low: limit };
let sum = big_number + U256::one();

assert_eq(sum, U256 { high: 0x10000000000000000000000000000001, low });
}

#[test(should_fail_with = "attempt to add with overflow")]
fn sum_overflow() {
let _ = limit_u256 + U256::one();
assert_eq(into(limit_u256), bytes);
}
}
3 changes: 2 additions & 1 deletion vlayer/ethereum/circuits/lib/Nargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ compiler_version = ">=0.30.0"

[dependencies]
ethereum = { path = "../../../../ethereum/circuits/lib" }
keccak256 = {tag = "v0.1.1", git = "https://github.com/noir-lang/keccak256" }
keccak256 = {tag = "v0.1.1", git = "https://github.com/noir-lang/keccak256" }
bignum = {tag = "v0.8.3", git = "https://github.com/noir-lang/noir-bignum" }
Loading