-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Create ArithmeticLib, Add UnsignedInt and SignedInt Custom Types
- Loading branch information
Showing
6 changed files
with
268 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity 0.8.26; | ||
|
||
library ArithmeticLib { | ||
function convertWithSize(bytes32 b, uint16 sizeInBytes, uint8 sizeInBits) public pure returns (bytes32 to) { | ||
assembly { | ||
/// TODO: add custom error here - sizeInBytes cannot be zero/cannot be bigger than 256 bits | ||
if or(eq(sizeInBytes, 0), gt(sizeInBytes, 0x100)) { revert(0x00, 0x00) } | ||
|
||
/// TODO: add custom error here - sizeInBytes has to be multiple of eight | ||
if gt(mod(sizeInBytes, 0x8), 0) { revert(0x00, 0x00) } | ||
} | ||
|
||
uint8 sizeCap = cap(sizeInBits); | ||
|
||
assembly { | ||
/// TODO: add custom error here - size cap cannot be bigger than given size in bytes | ||
if gt(sizeCap, sizeInBytes) { revert(0x00, 0x00) } | ||
|
||
to := b | ||
} | ||
} | ||
|
||
/// NOTE: finds the nearest bit cap in multiple of eight | ||
function cap(uint8 bitSize) public pure returns (uint8 res) { | ||
assembly { | ||
for { let i := 0x0 } lt(i, 0x21) { i := add(i, 1) } { | ||
let tmp := mul(add(i, 1), 8) | ||
if or(gt(tmp, bitSize), eq(tmp, bitSize)) { | ||
res := tmp | ||
break | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity 0.8.26; | ||
|
||
import { ArithmeticLib } from "../libraries/ArithmeticLib.sol"; | ||
|
||
type SignedInt is bytes32; | ||
|
||
using { | ||
addSignedInt as +, | ||
subSignedInt as -, | ||
mulSignedInt as *, | ||
divSignedInt as /, | ||
modSignedInt as %, | ||
expSignedInt as ^ | ||
} for SignedInt global; | ||
|
||
function addSignedInt(SignedInt left, SignedInt right) pure returns (SignedInt res) { | ||
assembly { | ||
res := add(left, right) | ||
} | ||
} | ||
|
||
function subSignedInt(SignedInt left, SignedInt right) pure returns (SignedInt res) { | ||
assembly { | ||
res := sub(left, right) | ||
} | ||
} | ||
|
||
function mulSignedInt(SignedInt left, SignedInt right) pure returns (SignedInt res) { | ||
assembly { | ||
switch or(iszero(left), iszero(right)) | ||
case 0 { res := 0 } | ||
case 1 { res := mul(left, right) } | ||
} | ||
} | ||
|
||
function divSignedInt(SignedInt left, SignedInt right) pure returns (SignedInt res) { | ||
assembly { | ||
res := div(left, right) | ||
} | ||
} | ||
|
||
function modSignedInt(SignedInt left, SignedInt right) pure returns (SignedInt res) { | ||
assembly { | ||
if iszero(right) { | ||
/// TODO: add custom error here - modulo by zero check | ||
revert(0x00, 0x00) | ||
} | ||
|
||
res := mod(left, right) | ||
} | ||
} | ||
|
||
function expSignedInt(SignedInt left, SignedInt right) pure returns (SignedInt res) { | ||
assembly { | ||
res := exp(left, right) | ||
} | ||
} | ||
|
||
using SignedIntLib for SignedInt global; | ||
|
||
library SignedIntLib { | ||
function convertWithSize(SignedInt u, uint16 sizeInBytes) public pure returns (int256 to) { | ||
bytes32 result = ArithmeticLib.convertWithSize(SignedInt.unwrap(u), sizeInBytes, sizeInBits(u)); | ||
|
||
assembly { | ||
to := result | ||
} | ||
} | ||
|
||
function sizeInBits(SignedInt s) public pure returns (uint8 size) { | ||
assembly { | ||
let tmp | ||
let isNegative := sgt(0, s) | ||
let absValue := s | ||
if isNegative { absValue := sub(0, s) } | ||
|
||
for { let i := 0x1f } gt(i, 0x0) { i := sub(i, 1) } { | ||
let b := byte(i, absValue) | ||
|
||
/// Check existency of first nibble | ||
let x := and(b, 0x0f) | ||
if gt(x, 0) { | ||
size := add(size, add(tmp, 0x1)) | ||
tmp := 0x0 | ||
} | ||
if eq(x, 0) { tmp := add(tmp, 0x1) } | ||
|
||
/// Check existency of second nibble | ||
let y := and(b, 0xf0) | ||
if gt(y, 0) { size := add(size, 0x1) } | ||
if eq(y, 0) { tmp := add(tmp, 0x1) } | ||
} | ||
|
||
size := mul(size, 0x4) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity 0.8.26; | ||
|
||
import { ArithmeticLib } from "../libraries/ArithmeticLib.sol"; | ||
|
||
type UnsignedInt is bytes32; | ||
|
||
using { | ||
addUnsignedInt as +, | ||
subUnsignedInt as -, | ||
mulUnsignedInt as *, | ||
divUnsignedInt as /, | ||
modUnsignedInt as %, | ||
expUnsignedInt as ^ | ||
} for UnsignedInt global; | ||
|
||
function addUnsignedInt(UnsignedInt left, UnsignedInt right) pure returns (UnsignedInt res) { | ||
assembly { | ||
res := add(left, right) | ||
|
||
if lt(res, left) { | ||
/// TODO: add custom error here - overflow check | ||
revert(0x00, 0x00) | ||
} | ||
} | ||
} | ||
|
||
function subUnsignedInt(UnsignedInt left, UnsignedInt right) pure returns (UnsignedInt res) { | ||
assembly { | ||
if gt(right, left) { | ||
/// TODO: add custom error here - underflow check | ||
revert(0x00, 0x00) | ||
} | ||
|
||
res := sub(left, right) | ||
} | ||
} | ||
|
||
function mulUnsignedInt(UnsignedInt left, UnsignedInt right) pure returns (UnsignedInt res) { | ||
assembly { | ||
switch or(iszero(left), iszero(right)) | ||
case 0 { res := 0 } | ||
case 1 { res := mul(left, right) } | ||
} | ||
} | ||
|
||
function divUnsignedInt(UnsignedInt left, UnsignedInt right) pure returns (UnsignedInt res) { | ||
assembly { | ||
if eq(right, 0) { | ||
/// TODO: add custom error here - division by zero check | ||
revert(0x00, 0x00) | ||
} | ||
|
||
res := div(left, right) | ||
} | ||
} | ||
|
||
function modUnsignedInt(UnsignedInt left, UnsignedInt right) pure returns (UnsignedInt res) { | ||
assembly { | ||
if iszero(right) { | ||
/// TODO: add custom error here - modulo by zero check | ||
revert(0x00, 0x00) | ||
} | ||
|
||
res := mod(left, right) | ||
} | ||
} | ||
|
||
function expUnsignedInt(UnsignedInt left, UnsignedInt right) pure returns (UnsignedInt res) { | ||
assembly { | ||
res := exp(left, right) | ||
} | ||
} | ||
|
||
using UnsignedIntLib for UnsignedInt global; | ||
|
||
library UnsignedIntLib { | ||
function convertWithSize(UnsignedInt u, uint16 sizeInBytes) public pure returns (uint256 to) { | ||
bytes32 result = ArithmeticLib.convertWithSize(UnsignedInt.unwrap(u), sizeInBytes, sizeInBits(u)); | ||
|
||
assembly { | ||
to := result | ||
} | ||
} | ||
|
||
function sizeInBits(UnsignedInt u) public pure returns (uint8 size) { | ||
assembly { | ||
let tmp | ||
for { let i := 0x1f } gt(i, 0x0) { i := sub(i, 1) } { | ||
let b := byte(i, u) | ||
|
||
/// NOTE: check existency of first nibble | ||
let x := and(b, 0x0f) | ||
if gt(x, 0) { | ||
size := add(size, add(tmp, 0x1)) | ||
tmp := 0x0 | ||
} | ||
if eq(x, 0) { tmp := add(tmp, 0x1) } | ||
|
||
/// NOTE: check existency of second nibble | ||
let y := and(b, 0xf0) | ||
if gt(y, 0) { size := add(size, 0x1) } | ||
if eq(y, 0) { tmp := add(tmp, 0x1) } | ||
} | ||
|
||
size := mul(size, 0x4) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity 0.8.26; | ||
|
||
import { ArithmeticLib } from "../src/libraries/ArithmeticLib.sol"; | ||
import { Test, console } from "forge-std/Test.sol"; | ||
|
||
contract ArithmeticLibTest is Test { } |