Skip to content
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

modexp big integers arithmetics #124

Merged
merged 56 commits into from
Oct 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
7e59313
Initial new implementation
ilitteri Sep 22, 2023
9206d42
Fix compilation error
ilitteri Sep 22, 2023
9f11e74
Implementation of add operation for big integers (#136)
IAvecilla Sep 26, 2023
db34989
Implement Big UInt Left Shift (#139)
ilitteri Sep 26, 2023
c954c0c
Implement Big UInt Right Shift (#137)
ilitteri Sep 26, 2023
16558cb
Implement Big UInt Bitwise Or for modexp (#135)
jpcenteno Sep 27, 2023
b1645c0
Implement big uint conditional select for modexp (#148)
jpcenteno Sep 27, 2023
02db93f
Implement mul operation for big UInts (#151)
IAvecilla Sep 29, 2023
2ff02cc
Substraction with borrow (#149)
fkrause98 Oct 2, 2023
b86bed6
Refactor `modexp` reimplementation (#156)
ilitteri Oct 3, 2023
4a6a723
Biguint division (#159)
jpcenteno Oct 5, 2023
06df32c
Implement mul mod operation for big UInts (#161)
IAvecilla Oct 6, 2023
1fc184d
Add parseCallData function
fkrause98 Oct 6, 2023
174b160
Add function to left-pad big uints
IAvecilla Oct 9, 2023
92010d6
Merge branch 'main' of github.com:lambdaclass/zksync_era_precompiles …
ilitteri Oct 9, 2023
776dc1d
Remove console log function
IAvecilla Oct 9, 2023
3c0f00c
Change left padding functions for big uints to not work in place
IAvecilla Oct 10, 2023
1b8b2f6
Add `parseCalldata` function (#168)
ilitteri Oct 10, 2023
b775975
Remove redundant parse call data declaration
fkrause98 Oct 10, 2023
ebc92a8
Free memory pointer (#169)
fkrause98 Oct 10, 2023
55ace22
Start parsing the input calldata
IAvecilla Oct 10, 2023
bfbcbae
Correctly parse call data
fkrause98 Oct 10, 2023
4fabd3c
Add left pad steps for modexp inputs
IAvecilla Oct 11, 2023
1f51a9e
Add pad if needed function
fkrause98 Oct 11, 2023
730931e
Modexp for big UInts skeleton (#164)
jpcenteno Oct 12, 2023
54fe792
Add simple integration
fkrause98 Oct 12, 2023
2ecd8a3
Fix calldata buffer in zero check
IAvecilla Oct 12, 2023
027ccfe
Uncomment checks for base cases
IAvecilla Oct 12, 2023
01f69aa
Fix result length to match with mod length
IAvecilla Oct 12, 2023
b7da051
Fix condition in parse call data
IAvecilla Oct 12, 2023
cbb07c4
Update test assertions with new test node updates
IAvecilla Oct 12, 2023
41e541c
Add comment for tests with a temp patch
IAvecilla Oct 12, 2023
9f8dd97
Fix modexp result length
IAvecilla Oct 17, 2023
1152581
Fix limb amount for modexp operands
IAvecilla Oct 17, 2023
84fabdb
Clean sratch buffers in each iteration
IAvecilla Oct 17, 2023
938f5a6
Clean sratch buffers for every operation
IAvecilla Oct 17, 2023
da8f686
Remove unused functions
IAvecilla Oct 18, 2023
4f6f6ae
Delete free memory pointer usage and calculate pointers manually
IAvecilla Oct 18, 2023
385fbf2
Replace all mul operations for shifts to improve gas usage
IAvecilla Oct 18, 2023
961c3aa
Include basic optimizations
IAvecilla Oct 19, 2023
633447a
Add optimizations for reminder calculations
IAvecilla Oct 20, 2023
cc40942
Add small improvement for main loop in modular exp
IAvecilla Oct 20, 2023
4defc61
Add temporary fix for modexp test
IAvecilla Oct 23, 2023
0e358ba
Add modex reference script
fkrause98 Oct 23, 2023
3308d02
Remove unnecesary memory stores
IAvecilla Oct 23, 2023
d0d6f93
Reduce iterations in rem function
IAvecilla Oct 23, 2023
7415f53
Compilation fix
jrchatruc Oct 23, 2023
076a3ac
Print gas used on tests
jrchatruc Oct 24, 2023
ac55dd1
Add build script to create gas reports
IAvecilla Oct 24, 2023
d108ae1
Save gas used for each test of the precompiles
IAvecilla Oct 24, 2023
7e176fc
Add aux functions to write lines in each report
IAvecilla Oct 24, 2023
060e371
Merge main
IAvecilla Oct 30, 2023
30b0cd7
Merge branch 'main' into modexp_reimplementation
IAvecilla Oct 30, 2023
012a453
Fix tests lint
IAvecilla Oct 30, 2023
466ebb4
Fix lint in test utils
IAvecilla Oct 30, 2023
b79857b
Change L1 url
IAvecilla Oct 30, 2023
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
1 change: 1 addition & 0 deletions docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@
- [Optimizations](ecpairing/optimizations.md)
- [ModExp]()
- [Specification](modexp/spec.md)
- [API Docs](modexp/api.md)
- [Optimizations](modexp/optimizations.md)
27 changes: 27 additions & 0 deletions docs/src/modexp/api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# API Docs

## Big Unsigned Integers Arithmetic

### `bigUIntAdd`

### `bigUIntSubWithBorrow`

### `bigUIntMul`

### `bigUIntBitOr`

```
+------------+-----------------------+-------------------------------+-------------------------------+-------------------------------+-----------------+-----------------+--------------------------------------+
| Iteration | currentOffset | lhsCurrentPtr | rhsCurrentPtr | resCurrentPtr | lhsCurrentValue | rhsCurrentValue | resCurrentValue |
+------------+-----------------------+-------------------------------+-------------------------------+-------------------------------+-----------------+-----------------+--------------------------------------+
| 0 | +0x00 | lhsPtr + 0x00 | rhsPtr + 0x00 | resPtr + 0x00 | lhs[0] | rhs[0] | or(lhs[0], rhs[0]) |
| 1 | +0x20 | lhsPtr + 0x20 | rhsPtr + 0x20 | resPtr + 0x20 | lhs[1] | rhs[1] | or(lhs[1], rhs[1]) |
| 2 | +0x40 | lhsPtr + 0x40 | rhsPtr + 0x40 | resPtr + 0x40 | lhs[2] | rhs[2] | or(lhs[2], rhs[2]) |
| | | | | | | | |
| ... | ... | ... | ... | ... | ... | ... | ... |
| | | | | | | | |
| nLimbs - 1 | +(0x20 * (nLimbs - 1) | lhsPtr + (0x20 * (nLimbs - 1) | rhsPtr + (0x20 * (nLimbs - 1) | resPtr + (0x20 * (nLimbs - 1) | lhs[nLimbs - 1] | rhs[nLimbs - 1] | or(lhs[nLimbs - 1], rhs[nLimbs - 1]) |
+------------+-----------------------+-------------------------------+-------------------------------+-------------------------------+-----------------+-----------------+--------------------------------------+
```

### `bigUIntCondSelect`
883 changes: 727 additions & 156 deletions precompiles/Modexp.yul

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions scripts/modexp_reference.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#! /usr/bin/python3
def modular_pow(base, exponent, modulus):
if modulus == 1:
return 0

result = 1
base %= modulus

while exponent > 0:
print(f"Exponent: {hex(exponent)}, result: {hex(result)}, base: {hex(base)}")
if exponent % 2 == 1:
result = (result * base) % modulus
exponent >>= 1
base = (base * base) % modulus

return result

# Example usage:
base = 390298093899999943928098409885853890809480289080848908498808490890809858888590
exponent = 328010176336108753607932954472681594880
modulus = 328083392909999939299399093209090192209
result = modular_pow(base, exponent, modulus)
33 changes: 33 additions & 0 deletions tests/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use std::fs::OpenOptions;
use std::io::Write;

fn main() {
let directory = "gas_reports";
if !std::path::Path::new(directory).exists() {
std::fs::create_dir(directory).unwrap();
}

let precompiles_report_list: Vec<String> = vec![
"modexp".to_string(),
"ecadd".to_string(),
"ecmul".to_string(),
"ecpairing".to_string(),
"p256verify".to_string(),
"secp256k1verify".to_string(),
];
precompiles_report_list
.into_iter()
.for_each(|mut precompile_name| {
let file_path = format!("{}/{}_report.md", directory, precompile_name);
precompile_name.push_str("_report.md");
let mut file = OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open(file_path)
.unwrap();

writeln!(file, "| Test case | Gas used |").unwrap();
writeln!(file, "| --------- | -------- |").unwrap();
});
}
90 changes: 57 additions & 33 deletions tests/tests/ecadd_tests.rs

Large diffs are not rendered by default.

360 changes: 237 additions & 123 deletions tests/tests/ecmul_tests.rs

Large diffs are not rendered by default.

53 changes: 35 additions & 18 deletions tests/tests/ecpairing_tests.rs

Large diffs are not rendered by default.

509 changes: 309 additions & 200 deletions tests/tests/modexp_tests.rs

Large diffs are not rendered by default.

17 changes: 12 additions & 5 deletions tests/tests/p256verify_tests.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use zksync_web3_rs::types::{Address, Bytes, H160};

mod test_utils;
use test_utils::{era_call, parse_call_result};
use test_utils::{era_call, parse_call_result, write_p256verify_gas_result};

pub const P256VERIFTY_PRECOMPILE_ADDRESS: Address = H160([
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Expand All @@ -27,7 +26,8 @@ async fn p256verify_valid_signature_one() {
)
.await
.unwrap();
let (era_output, _) = parse_call_result(&era_response);
let (era_output, gas_used) = parse_call_result(&era_response);
write_p256verify_gas_result(gas_used);
assert_eq!(era_output, Bytes::from(RESPONSE_VALID))
}

Expand All @@ -40,7 +40,8 @@ async fn p256verify_valid_signature_two() {
)
.await
.unwrap();
let (era_output, _) = parse_call_result(&era_response);
let (era_output, gas_used) = parse_call_result(&era_response);
write_p256verify_gas_result(gas_used);
assert_eq!(era_output, Bytes::from(RESPONSE_VALID))
}

Expand All @@ -53,7 +54,8 @@ async fn p256verify_invalid_signature() {
)
.await
.unwrap();
let (era_output, _) = parse_call_result(&era_response);
let (era_output, gas_used) = parse_call_result(&era_response);
write_p256verify_gas_result(gas_used);
assert_eq!(era_output, Bytes::from(RESPONSE_INVALID))
}

Expand Down Expand Up @@ -82,6 +84,7 @@ async fn p256verify_invalid_s() {
.err()
.unwrap()
.to_string();

assert_eq!(era_response, EXECUTION_REVERTED)
}

Expand All @@ -96,6 +99,7 @@ async fn p256verify_public_key_inf() {
.err()
.unwrap()
.to_string();

assert_eq!(era_response, EXECUTION_REVERTED)
}

Expand All @@ -110,6 +114,7 @@ async fn p256verify_public_key_x_not_in_field() {
.err()
.unwrap()
.to_string();

assert_eq!(era_response, EXECUTION_REVERTED)
}

Expand All @@ -124,6 +129,7 @@ async fn p256verify_public_key_y_not_in_field() {
.err()
.unwrap()
.to_string();

assert_eq!(era_response, EXECUTION_REVERTED)
}

Expand All @@ -138,5 +144,6 @@ async fn p256verify_public_key_not_in_curve() {
.err()
.unwrap()
.to_string();

assert_eq!(era_response, EXECUTION_REVERTED)
}
17 changes: 9 additions & 8 deletions tests/tests/secp256k1verify_tests.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
use zksync_web3_rs::types::{Address, Bytes, H160};

mod test_utils;
use test_utils::{era_call, parse_call_result, write_secp256k1verify_gas_result};

pub const SECP256K1VERIFTY_PRECOMPILE_ADDRESS: Address = H160([
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x20,
]);

mod test_utils;
use test_utils::era_call;

use crate::test_utils::parse_call_result;

const RESPONSE_VALID: [u8; 32] = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
];
Expand All @@ -29,7 +27,8 @@ async fn secp256k1verify_valid_signature_one() {
)
.await
.unwrap();
let (era_output, _) = parse_call_result(&era_response);
let (era_output, gas_used) = parse_call_result(&era_response);
write_secp256k1verify_gas_result(gas_used);
assert_eq!(era_output, Bytes::from(RESPONSE_VALID))
}

Expand All @@ -42,7 +41,8 @@ async fn secp256k1verify_valid_signature_two() {
)
.await
.unwrap();
let (era_output, _) = parse_call_result(&era_response);
let (era_output, gas_used) = parse_call_result(&era_response);
write_secp256k1verify_gas_result(gas_used);
assert_eq!(era_output, Bytes::from(RESPONSE_VALID))
}

Expand All @@ -55,7 +55,8 @@ async fn secp256k1verify_invalid_signature() {
)
.await
.unwrap();
let (era_output, _) = parse_call_result(&era_response);
let (era_output, gas_used) = parse_call_result(&era_response);
write_secp256k1verify_gas_result(gas_used);
assert_eq!(era_output, Bytes::from(RESPONSE_INVALID))
}

Expand Down
44 changes: 43 additions & 1 deletion tests/tests/test_utils.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::env;
use std::{env, fs::OpenOptions, io::Write};
use zksync_web3_rs::{
providers::{Http, Middleware, Provider, ProviderError},
types::{transaction::eip2718::TypedTransaction, Address, Bytes, Eip1559TransactionRequest},
Expand All @@ -21,6 +21,48 @@ pub fn parse_call_result(bytes: &[u8]) -> (Bytes, u32) {
(output.into(), gas_used)
}

fn write_line_to_report(used_gas: u32, report_to_write: &str) {
let mut file = OpenOptions::new()
.append(true)
.open(report_to_write)
.unwrap();

let curr_thread = std::thread::current();
let test_name = curr_thread.name().unwrap();

writeln!(file, "| {test_name} | {used_gas} |").unwrap();
}

#[allow(dead_code)]
pub fn write_modexp_gas_result(used_gas: u32) {
write_line_to_report(used_gas, "gas_reports/modexp_report.md");
}

#[allow(dead_code)]
pub fn write_ecadd_gas_result(used_gas: u32) {
write_line_to_report(used_gas, "gas_reports/ecadd_report.md");
}

#[allow(dead_code)]
pub fn write_ecmul_gas_result(used_gas: u32) {
write_line_to_report(used_gas, "gas_reports/ecmul_report.md");
}

#[allow(dead_code)]
pub fn write_ecpairing_gas_result(used_gas: u32) {
write_line_to_report(used_gas, "gas_reports/ecpairing_report.md");
}

#[allow(dead_code)]
pub fn write_p256verify_gas_result(used_gas: u32) {
write_line_to_report(used_gas, "gas_reports/p256verify_report.md");
}

#[allow(dead_code)]
pub fn write_secp256k1verify_gas_result(used_gas: u32) {
write_line_to_report(used_gas, "gas_reports/secp256k1verify_report.md");
}

pub fn eth_provider() -> Provider<Http> {
let url: String =
env::var("ZKSYNC_WEB3_RS_L1_PROVIDER_URL").unwrap_or(DEFAULT_L1_PROVIDER_URL.to_owned());
Expand Down