diff --git a/ethereum/circuits/lib/src/misc/arrays.nr b/ethereum/circuits/lib/src/misc/arrays.nr index 802332531..ed252a54f 100644 --- a/ethereum/circuits/lib/src/misc/arrays.nr +++ b/ethereum/circuits/lib/src/misc/arrays.nr @@ -32,12 +32,7 @@ pub(crate) fn memcpy_up_to_length(dest: &mut [TItem; D } } -/// Fills destination array with content of source array starting from the starting position. -/// -/// # Arguments -/// * `dest` - Destination array -/// * `src` - Source array -/// * `offset` - Offset in source array +// Fills destination array with content of source array starting from the starting position. pub(crate) fn memcpy(dest: &mut [TItem; DEST_LEN], src: [TItem; SRC_LEN], offset: u64) { memcpy_up_to_length(dest, src, offset, DEST_LEN); } diff --git a/ethereum/circuits/lib/src/misc/bytes.nr b/ethereum/circuits/lib/src/misc/bytes.nr index f86440609..c03cff138 100644 --- a/ethereum/circuits/lib/src/misc/bytes.nr +++ b/ethereum/circuits/lib/src/misc/bytes.nr @@ -71,20 +71,11 @@ pub fn shift_right_by_one(arr: &mut [u8; N]) { } } -/// Left-shift for byte arrays -/// Returns an appropriately shifted byte array. -/// -/// # Arguments -/// * `input` - Byte array -/// * `n` - Amount to left-shift elements by -/// -/// # Quirks -/// The empty slots are set to 0. +// Left-shift the byte array pub(crate) fn left_byte_shift(input: [u8; N], n: u64) -> [u8; N] { let mut out = [0; N]; for i in 0..N { - // Restrict indices to be shifted, i.e. ∀i: i+n < N, out[i] ← input[i+n]. let index_ind = (((i + n) as u32) < (N as u32)) as u64; out[i] = (index_ind as u8) * input[index_ind * (i + n)]; } @@ -92,11 +83,7 @@ pub(crate) fn left_byte_shift(input: [u8; N], n: u64) -> [u8; N] { out } -/// Function for expressing a big-endian byte array as a right-padded one. -/// Returns a right-padded byte array together with the actual byte length of the number. -/// -/// # Arguments -/// * `in_value` - Byte array representing a number in big-endian form. +// Converts big-endian byte array to a right-padded one. pub(crate) fn byte_value(in_value: [u8; N]) -> BoundedVec { let mut value_length = 0; diff --git a/ethereum/circuits/lib/src/rlp/decode.nr b/ethereum/circuits/lib/src/rlp/decode.nr index 913ef536d..8c6a06b26 100644 --- a/ethereum/circuits/lib/src/rlp/decode.nr +++ b/ethereum/circuits/lib/src/rlp/decode.nr @@ -1,14 +1,11 @@ use dep::std::wrapping_sub; -use crate::rlp::types::{RlpList, RlpFragment, RlpHeader}; +use crate::rlp::types::{RlpList, RlpFragment, RlpHeader, STRING, LIST}; use crate::misc::fragment::Fragment; -/// Max number of bytes required to represent length of a string or list +// Maximum number of bytes required to represent entity length. +// This means that this library can only decode RLP entities with a length of up to 2^16 bytes. global MAX_LEN_IN_BYTES: u64 = 2; -/// RLP data type enum -global STRING: u64 = 0; -global LIST: u64 = 1; - pub fn extract_payload_len(data: Fragment, lenlen: u64) -> u64 { assert(lenlen <= MAX_LEN_IN_BYTES, "Length of length exceeds maximum"); assert(lenlen <= data.length, "Length of length exceeds input length"); @@ -31,25 +28,25 @@ pub fn decode_to_rlp_header(data: Fragment) -> RlpHeader { if (prefix < 0x80) { // single byte RlpHeader { offset: 0, length: 1, data_type: STRING } - } else if (prefix < 0xb8) { // 0-55 byte string + } else if (prefix < 0xb8) { // [0, 55] byte string let offset = 1; let length = wrapping_sub(prefix, 0x80) as u64; assert(offset + length <= N, "Decoded length of short string exceeds input length"); RlpHeader { offset, length, data_type: STRING } - } else if (prefix < 0xc0) { // >55-byte string + } else if (prefix < 0xc0) { // > 55 byte string let offset = wrapping_sub(1 + prefix, 0xb7) as u64; let length = extract_payload_len(data, wrapping_sub(prefix, 0xb7) as u64); assert(offset + length <= N, "Decoded length of long string exceeds input length"); RlpHeader { offset, length, data_type: STRING } - } else if (prefix < 0xf8) { // 0-55 byte list + } else if (prefix < 0xf8) { // [0, 55] byte list let offset = 1; let length = wrapping_sub(prefix, 0xc0) as u64; assert(offset + length <= N, "Decoded length of short list exceeds input length"); RlpHeader { offset, length, data_type: LIST } - } else { // >55-byte list + } else { // > 55 byte list let offset = wrapping_sub(1 + prefix, 0xf7) as u64; let length = extract_payload_len(data, wrapping_sub(prefix, 0xf7) as u64); assert(offset + length <= N, "Decoded length of long list exceeds input length"); @@ -68,9 +65,7 @@ pub fn decode_string(input: Fragment) -> RlpFragment { RlpFragment { offset, length, data_type: STRING } } -/// Returns an RLP list look-up table. -/// For string elements, the offset points to the payload, whereas the offset -/// of a list element points to the RLP header of that element. +// Strings are decoded and offsets point to the start of raw values, while list offsets point to the start of the RLP header. pub fn decode_list(data: Fragment) -> RlpList { let mut rlp_list: RlpList = BoundedVec::new(); @@ -87,12 +82,15 @@ pub fn decode_list(data: Fragment) -> RlpList let RlpHeader {offset: field_off, length: field_len, data_type: field_type} = decode_to_rlp_header(header); - let fragment = RlpFragment { - offset: current_offset + (1 - field_type) * field_off, // If the ith slot contains a list, include its RLP header. - length: field_len + field_type * field_off, // If the ith slot contains a list, include the length of its header. - data_type: field_type - }; - rlp_list.push(fragment); + let mut offset = current_offset; + let mut length = field_len; + if (field_type == STRING) { + offset += field_off; + } else { + length += field_off; + } + + rlp_list.push(RlpFragment { offset, length, data_type: field_type }); current_offset += field_off + field_len; } @@ -102,8 +100,7 @@ pub fn decode_list(data: Fragment) -> RlpList rlp_list } -/// RLP list decoder for lists of strings of length < 56 bytes. -/// Returns an RLP list look-up table. +// The version of decode_list that is cheaper to call, but only works for lists of small strings (<= 55 bytes). pub fn decode_list_of_small_strings(data: Fragment) -> RlpList { let mut rlp_list: RlpList = BoundedVec::new(); @@ -119,9 +116,7 @@ pub fn decode_list_of_small_strings(data: Fragment) -> Rlp let first_byte = data.at(current_offset); let (field_off, field_len) = get_small_string_offset_and_length(first_byte); - - let fragment = RlpFragment { offset: current_offset + field_off, length: field_len, data_type: STRING }; - rlp_list.push(fragment); + rlp_list.push(RlpFragment { offset: current_offset + field_off, length: field_len, data_type: STRING }); current_offset += field_off + field_len; } diff --git a/ethereum/circuits/lib/src/rlp/decode_test.nr b/ethereum/circuits/lib/src/rlp/decode_test.nr index 633bfbd59..4cc6b90f0 100644 --- a/ethereum/circuits/lib/src/rlp/decode_test.nr +++ b/ethereum/circuits/lib/src/rlp/decode_test.nr @@ -43,7 +43,7 @@ mod extract_payload_len { } mod decode_string { - use crate::rlp::decode::{decode_string, STRING}; + use crate::rlp::{decode::decode_string, types::STRING}; use crate::misc::{arrays::resize, fragment::Fragment}; use crate::rlp::types::RlpFragment; @@ -90,7 +90,7 @@ mod decode_string { } mod decode_list { - use crate::rlp::{decode::{decode_list, RlpList, STRING}, types::RlpFragment}; + use crate::rlp::{decode::{decode_list, RlpList}, types::{RlpFragment, STRING}}; use crate::misc::{bounded_vecs::bounded_vec_from_array, fragment::Fragment}; #[test] @@ -134,7 +134,7 @@ mod decode_list { } mod decode_list_of_small_strings { - use crate::rlp::decode::{decode_list_of_small_strings, RlpList, RlpFragment, STRING}; + use crate::rlp::{decode::{decode_list_of_small_strings, RlpList, RlpFragment}, types::STRING}; use crate::misc::{bounded_vecs::bounded_vec_from_array, fragment::Fragment}; #[test] @@ -221,7 +221,7 @@ mod get_small_string_offset_and_length { } mod decode_to_rlp_header { - use crate::rlp::decode::{decode_to_rlp_header, RlpHeader, STRING, LIST}; + use crate::rlp::{decode::{decode_to_rlp_header, RlpHeader}, types::{STRING, LIST}}; use crate::misc::{arrays::resize, fragment::Fragment}; #[test] diff --git a/ethereum/circuits/lib/src/rlp/types.nr b/ethereum/circuits/lib/src/rlp/types.nr index f95a94e06..fbeec4dba 100644 --- a/ethereum/circuits/lib/src/rlp/types.nr +++ b/ethereum/circuits/lib/src/rlp/types.nr @@ -1,15 +1,18 @@ use crate::misc::{arrays::sub_array_equals_up_to_length, fragment::Fragment}; -use crate::rlp::decode::STRING; use crate::misc::bytes::byte_value; use dep::u2b::{u64_to_u8, u32_to_u8}; use crate::misc::types::{Bytes32, BYTES32_LENGTH, Address, ADDRESS_LENGTH}; +// Enum for RLP data type +global STRING: u64 = 0; +global LIST: u64 = 1; + type RlpList = BoundedVec; struct RlpHeader { offset: u64, length: u64, - data_type: u64 // STRING or LIST + data_type: u64 } impl Eq for RlpHeader { @@ -21,7 +24,7 @@ impl Eq for RlpHeader { struct RlpFragment { offset: u64, length: u64, - data_type: u64 // STRING or LIST + data_type: u64 } impl RlpFragment { diff --git a/ethereum/circuits/lib/src/rlp/types_test.nr b/ethereum/circuits/lib/src/rlp/types_test.nr index a293edb6f..974f5fbb9 100644 --- a/ethereum/circuits/lib/src/rlp/types_test.nr +++ b/ethereum/circuits/lib/src/rlp/types_test.nr @@ -1,6 +1,6 @@ mod rlp_fragment { mod assert_eq_bytes { - use crate::rlp::{decode::{STRING, LIST}, types::RlpFragment}; + use crate::rlp::types::{STRING, LIST, RlpFragment}; use crate::misc::{arrays::alter_fragment, fragment::Fragment}; global bytes = Fragment::new_with_length(2, [0x12, 0x34, 0x00]); @@ -42,7 +42,7 @@ mod rlp_fragment { } mod assert_eq_bounded_vec { - use crate::rlp::{decode::{STRING, LIST}, types::RlpFragment}; + use crate::rlp::types::{STRING, LIST, RlpFragment}; use crate::misc::{arrays::alter_array, fragment::Fragment}; global bytes = [0x12, 0x34]; @@ -82,7 +82,7 @@ mod rlp_fragment { } mod assert_empty_string { - use crate::rlp::{decode::{STRING, LIST}, types::RlpFragment}; + use crate::rlp::types::{STRING, LIST, RlpFragment}; global fragment = RlpFragment { offset: 0, length: 0, data_type: STRING }; @@ -109,7 +109,7 @@ mod rlp_fragment { } mod assert_eq_u1 { - use crate::rlp::{decode::STRING, types::RlpFragment}; + use crate::rlp::types::{STRING, RlpFragment}; use crate::misc::fragment::Fragment; global bit_value: u1 = 0x01; @@ -142,7 +142,7 @@ mod rlp_fragment { } mod assert_eq_u8 { - use crate::rlp::{decode::STRING, types::RlpFragment}; + use crate::rlp::types::{STRING, RlpFragment}; use crate::misc::fragment::Fragment; global value = 0x10; @@ -169,7 +169,7 @@ mod rlp_fragment { } mod assert_eq_u32 { - use crate::rlp::{decode::STRING, types::RlpFragment}; + use crate::rlp::types::{STRING, RlpFragment}; use crate::misc::fragment::Fragment; global value = 0x10000000; @@ -194,7 +194,7 @@ mod rlp_fragment { } mod assert_eq_u64 { - use crate::rlp::{decode::STRING, types::RlpFragment}; + use crate::rlp::types::{STRING, RlpFragment}; use crate::misc::fragment::Fragment; global value = 0x1000000000000000; @@ -219,7 +219,7 @@ mod rlp_fragment { } mod assert_eq_u128 { - use crate::rlp::{decode::STRING, types::RlpFragment}; + use crate::rlp::types::{STRING, RlpFragment}; use crate::misc::fragment::Fragment; global value = U128::from_integer(0x10000000000000000000000000000000); @@ -244,7 +244,7 @@ mod rlp_fragment { } mod assert_eq_address { - use crate::rlp::{decode::STRING, types::RlpFragment}; + use crate::rlp::types::{STRING, RlpFragment}; use crate::misc::types::Address; use crate::misc::{arrays::alter_array, fragment::Fragment}; use crate::fixtures::mainnet::frontier::first::state_proof::state_proof as state_proof; @@ -273,7 +273,7 @@ mod rlp_fragment { } mod assert_eq_bytes32 { - use crate::rlp::{decode::STRING, types::RlpFragment}; + use crate::rlp::types::{STRING, RlpFragment}; use crate::misc::types::Bytes32; use crate::misc::{arrays::alter_array, fragment::Fragment}; use crate::fixtures::mainnet::frontier::first::header::hash;