Skip to content

Add RLP and TrieProof libraries #5680

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 25 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions .changeset/khaki-hats-leave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'openzeppelin-solidity': minor
---

`Bytes`: Add a `nibbles` function to split each byte into two nibbles.
5 changes: 5 additions & 0 deletions .changeset/lovely-cooks-add.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'openzeppelin-solidity': minor
---

`RLP`: Add library for Ethereum's Recursive Length Prefix encoding/decoding.
5 changes: 5 additions & 0 deletions .changeset/major-feet-write.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'openzeppelin-solidity': minor
---

`Math`: Add `reverseBitsUint256`, `reverseBitsUint128`, `reverseBitsUint64`, `reverseBitsUint32`, and `reverseBits16` functions to reverse byte order for converting between little-endian and big-endian representations.
5 changes: 5 additions & 0 deletions .changeset/shaky-phones-mix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'openzeppelin-solidity': minor
---

`TrieProof`: Add library for verifying Ethereum Merkle-Patricia trie inclusion proofs.
5 changes: 5 additions & 0 deletions .changeset/whole-cats-find.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'openzeppelin-solidity': minor
---

`Bytes`: Add a `clz` function to count the leading zero bytes in a `uint256` value.
22 changes: 22 additions & 0 deletions contracts/utils/Bytes.sol
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,28 @@ library Bytes {
return result;
}

/// @dev Split each byte in `value` into two nibbles (4 bits each).
function nibbles(bytes memory value) internal pure returns (bytes memory) {
uint256 length = value.length;
bytes memory nibbles_ = new bytes(length * 2);
for (uint256 i = 0; i < length; i++) {
(nibbles_[i * 2], nibbles_[i * 2 + 1]) = (value[i] & 0xf0, value[i] & 0x0f);
}
return nibbles_;
}

/// @dev Counts the number of leading zero bytes in a uint256.
function clz(uint256 x) internal pure returns (uint256) {
if (x == 0) return 32; // All 32 bytes are zero
uint256 r = 0;
if (x > 0xffffffffffffffffffffffffffffffff) r = 128; // Upper 128 bits
if ((x >> r) > 0xffffffffffffffff) r |= 64; // Next 64 bits
if ((x >> r) > 0xffffffff) r |= 32; // Next 32 bits
if ((x >> r) > 0xffff) r |= 16; // Next 16 bits
if ((x >> r) > 0xff) r |= 8; // Next 8 bits
return 31 ^ (r >> 3); // Convert to leading zero bytes count
}

/**
* @dev Reads a bytes32 from a bytes array without bounds checking.
*
Expand Down
86 changes: 86 additions & 0 deletions contracts/utils/Memory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

/**
* @dev Utilities to manipulate memory.
*
* Memory is a contiguous and dynamic byte array in which Solidity stores non-primitive types.
* This library provides functions to manipulate pointers to this dynamic array.
*
* WARNING: When manipulating memory, make sure to follow the Solidity documentation
* guidelines for https://docs.soliditylang.org/en/v0.8.20/assembly.html#memory-safety[Memory Safety].
*/
library Memory {
type Pointer is bytes32;

/// @dev Returns a memory pointer to the current free memory pointer.
function getFreePointer() internal pure returns (Pointer ptr) {
assembly ("memory-safe") {
ptr := mload(0x40)
}
}

/// @dev Sets the free memory pointer to a specific value.
///
/// WARNING: Everything after the pointer may be overwritten.
function setFreePointer(Pointer ptr) internal pure {
assembly ("memory-safe") {
mstore(0x40, ptr)
}
}

/// @dev Returns a memory pointer to the content of a buffer. Skips the length word.
function contentPointer(bytes memory buffer) internal pure returns (Pointer) {
bytes32 ptr;
assembly ("memory-safe") {
ptr := add(buffer, 32)
}
return asPointer(ptr);
}

/// @dev Copies `length` bytes from `srcPtr` to `destPtr`.
function copy(Pointer destPtr, Pointer srcPtr, uint256 length) internal pure {
assembly ("memory-safe") {
mcopy(destPtr, srcPtr, length)
}
}

/// @dev Extracts a byte from a memory pointer.
function extractByte(Pointer ptr) internal pure returns (bytes1 v) {
assembly ("memory-safe") {
v := byte(0, mload(ptr))
}
}

/// @dev Extracts a word from a memory pointer.
function extractWord(Pointer ptr) internal pure returns (uint256 v) {
assembly ("memory-safe") {
v := mload(ptr)
}
}

/// @dev Adds an offset to a memory pointer.
function addOffset(Pointer ptr, uint256 offset) internal pure returns (Pointer) {
return asPointer(bytes32(uint256(asBytes32(ptr)) + offset));
}

/// @dev Pointer to `bytes32`.
function asBytes32(Pointer ptr) internal pure returns (bytes32) {
return Pointer.unwrap(ptr);
}

/// @dev `bytes32` to pointer.
function asPointer(bytes32 value) internal pure returns (Pointer) {
return Pointer.wrap(value);
}

/// @dev `bytes` to pointer.
function asPointer(bytes memory value) internal pure returns (Pointer) {
bytes32 ptr;
assembly ("memory-safe") {
ptr := value
}
return asPointer(ptr);
}
}
5 changes: 4 additions & 1 deletion contracts/utils/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ Miscellaneous contracts and libraries containing utility functions you can use t
* {CAIP2}, {CAIP10}: Libraries for formatting and parsing CAIP-2 and CAIP-10 identifiers.
* {Blockhash}: A library for accessing historical block hashes beyond the standard 256 block limit utilizing EIP-2935's historical blockhash functionality.
* {Time}: A library that provides helpers for manipulating time-related objects, including a `Delay` type.

* {RLP}: Library for encoding and decoding data in Ethereum's Recursive Length Prefix format.

[NOTE]
====
Because Solidity does not support generic types, {EnumerableMap} and {EnumerableSet} are specialized to a limited number of key-value types.
Expand Down Expand Up @@ -137,3 +138,5 @@ Ethereum contracts have no native concept of an interface, so applications must
{{Blockhash}}

{{Time}}

{{RLP}}
Loading
Loading