Skip to content
This repository has been archived by the owner on Jan 9, 2025. It is now read-only.

Commit

Permalink
feat: enable ec_add / ec_mul (#1398)
Browse files Browse the repository at this point in the history
<!--- Please provide a general summary of your changes in the title
above -->

<!-- Give an estimate of the time you spent on this PR in terms of work
days.
Did you spend 0.5 days on this PR or rather 2 days?  -->

Time spent on this PR:

## Pull request type

<!-- Please try to limit your pull request to one type,
submit multiple pull requests if needed. -->

Please check the type of change your PR introduces:

- [ ] Bugfix
- [ ] Feature
- [ ] Code style update (formatting, renaming)
- [ ] Refactoring (no functional changes, no api changes)
- [ ] Build related changes
- [ ] Documentation content changes
- [ ] Other (please describe):

## What is the current behavior?

<!-- Please describe the current behavior that you are modifying,
or link to a relevant issue. -->

Resolves #1230
Resolves #1231 
Resolves #1365

## What is the new behavior?

<!-- Please describe the behavior or changes that are being added by
this PR. -->

- Adds ECMUL and ECADD execution from Cairo1Helpers
- Fixes an issue where __reverted__ precompile execution was not
consuming all gas due to a mismanagement of error codes
- note: reverted != execution fails silently (see ec_recover vs. ec_add,
for example)
- Fixes an issue where external_precompiles would not fail with error
EXCEPTIONAL_HALT

<!-- Reviewable:start -->
- - -
This change is [<img src="https://reviewable.io/review_button.svg"
height="34" align="absmiddle"
alt="Reviewable"/>](https://reviewable.io/reviews/kkrt-labs/kakarot/1398)
<!-- Reviewable:end -->
  • Loading branch information
enitrat authored Sep 24, 2024
1 parent 87153b8 commit 414e4da
Show file tree
Hide file tree
Showing 21 changed files with 259 additions and 1,283 deletions.
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ endif

.PHONY: build test coverage clean

# 154615699 corresponds to release v0.1.7 of Kakarot SSJ.
KKRT_SSJ_RELEASE_ID = 154615699
# 176384150 corresponds to release v0.1.13 of Kakarot SSJ.
KKRT_SSJ_RELEASE_ID = 176384150
# Kakarot SSJ artifacts for precompiles.
KKRT_SSJ_BUILD_ARTIFACT_URL = $(shell curl -L https://api.github.com/repos/kkrt-labs/kakarot-ssj/releases/${KKRT_SSJ_RELEASE_ID} | jq -r '.assets[0].browser_download_url')
KATANA_VERSION = v1.0.0-alpha.11
KATANA_VERSION = v1.0.0-alpha.12
ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))

BUILD_DIR = build
Expand All @@ -35,7 +35,7 @@ $(SSJ_ZIP):
fetch-ef-tests:
poetry run python ./kakarot_scripts/ef_tests/fetch.py

setup: fetch-ssj-artifacts
setup:
poetry install

test: deploy
Expand Down
11 changes: 7 additions & 4 deletions kakarot_scripts/utils/starknet.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,12 @@ def get_deployments():

@cache
def get_artifact(contract_name):
# Cairo 0 artifacts
artifacts = list(BUILD_DIR.glob(f"*{contract_name}*.json"))
if artifacts:
return Artifact(sierra=None, casm=artifacts[0])

# Cairo 1 artifacts
artifacts = list(CAIRO_DIR.glob(f"**/*{contract_name}.*.json")) or list(
BUILD_DIR_SSJ.glob(f"**/*{contract_name}.*.json")
)
Expand All @@ -255,10 +261,7 @@ def get_artifact(contract_name):
)
return Artifact(sierra=sierra, casm=casm)

artifacts = list(BUILD_DIR.glob(f"**/*{contract_name}*.json"))
if not artifacts:
raise FileNotFoundError(f"No artifact found for {contract_name}")
return Artifact(sierra=None, casm=artifacts[0])
raise FileNotFoundError(f"No artifact found for {contract_name}")


@cache
Expand Down
2 changes: 1 addition & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ packages = [{ include = "kakarot_scripts" }, { include = "tests" }]

[tool.poetry.dependencies]
python = ">=3.10,<3.11"
starknet-py = "^0.23.0"
cairo-lang = "0.13.1"
python-dotenv = "^0.21.0"
async-lru = "^2.0.4"
toml = "^0.10.2"
scikit-learn = "^1.5.1"
seaborn = "^0.13.2"
boto3 = "^1.35.12"
starknet-py = "0.23.0"

[tool.poetry.group.dev.dependencies]
pytest = "^8.1.1"
Expand Down
55 changes: 55 additions & 0 deletions solidity_contracts/src/EvmPrecompiles/EvmPrecompiles.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @title EVM Precompiles Integration
/// @notice Contract for integration testing of EVM precompiles.
/// @dev Implements functions for ECADD and ECMUL precompiles.
contract EvmPrecompiles {
/// @dev Address of the ECADD precompile
address private constant ECADD_PRECOMPILE = address(0x06);
/// @dev Address of the ECMUL precompile
address private constant ECMUL_PRECOMPILE = address(0x07);

/// @dev Gas cost for ECADD call is 150
uint256 private constant ECADD_GAS = 150;
/// @dev Gas cost for ECMUL call is 6000
uint256 private constant ECMUL_GAS = 6000;

/*//////////////////////////////////////////////////////////////
FUNCTIONS FOR PRECOMPILES
//////////////////////////////////////////////////////////////*/
/// @notice Performs elliptic curve addition
/// @param x1 X coordinate of the first point
/// @param y1 Y coordinate of the first point
/// @param x2 X coordinate of the second point
/// @param y2 Y coordinate of the second point
/// @return success True if the operation was successful, false otherwise
/// @return x X coordinate of the result point
/// @return y Y coordinate of the result point
function ecAdd(uint256 x1, uint256 y1, uint256 x2, uint256 y2) external view returns (bool, uint256 x, uint256 y) {
bytes memory input = abi.encodePacked(x1, y1, x2, y2);
(bool success, bytes memory result) = ECADD_PRECOMPILE.staticcall{gas: ECADD_GAS}(input);
if (!success) {
return (false, 0, 0);
}
(x, y) = abi.decode(result, (uint256, uint256));
return (true, x, y);
}

/// @notice Performs elliptic curve scalar multiplication
/// @param x1 X coordinate of the point
/// @param y1 Y coordinate of the point
/// @param s Scalar for multiplication
/// @return success True if the operation was successful, false otherwise
/// @return x X coordinate of the result point
/// @return y Y coordinate of the result point
function ecMul(uint256 x1, uint256 y1, uint256 s) external view returns (bool, uint256 x, uint256 y) {
bytes memory input = abi.encodePacked(x1, y1, s);
(bool success, bytes memory result) = ECMUL_PRECOMPILE.staticcall{gas: ECMUL_GAS}(input);
if (!success) {
return (false, 0, 0);
}
(x, y) = abi.decode(result, (uint256, uint256));
return (true, x, y);
}
}
25 changes: 18 additions & 7 deletions src/kakarot/interpreter.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -76,19 +76,30 @@ namespace Interpreter {
tempvar caller_code_address = parent_context.evm.message.code_address.evm;
}
tempvar caller_address = evm.message.caller;
let (
output_len, output, gas_used, precompile_reverted
) = Precompiles.exec_precompile(
let (output_len, output, gas_used, revert_code) = Precompiles.exec_precompile(
evm.message.code_address.evm,
evm.message.calldata_len,
evm.message.calldata,
caller_code_address,
caller_address,
);
let evm = EVM.charge_gas(evm, gas_used);
let evm_reverted = is_not_zero(evm.reverted);
let success = (1 - precompile_reverted) * (1 - evm_reverted);
let evm = EVM.stop(evm, output_len, output, 1 - success);

let precompile_reverted = is_not_zero(revert_code);
if (precompile_reverted != FALSE) {
// No need to charge gas as precompiles can only trigger EXCEPTIONAL_REVERT
// which will consume the entire gas of the context.
let evm = EVM.stop(evm, output_len, output, revert_code);
tempvar range_check_ptr = range_check_ptr;
tempvar evm = evm;
} else {
// Charge gas before stopping
let evm = EVM.charge_gas(evm, gas_used);
let evm = EVM.stop(evm, output_len, output, evm.reverted);
tempvar range_check_ptr = range_check_ptr;
tempvar evm = evm;
}
let range_check_ptr = [ap - 2];
let evm = cast([ap - 1], model.EVM*);
let is_cairo_precompile_called = PrecompilesHelpers.is_kakarot_precompile(
evm.message.code_address.evm
);
Expand Down
58 changes: 0 additions & 58 deletions src/kakarot/precompiles/ecadd.cairo

This file was deleted.

55 changes: 0 additions & 55 deletions src/kakarot/precompiles/ecmul.cairo

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ from utils.utils import Helpers
from kakarot.memory import Memory
from kakarot.evm import EVM

// @title DataCopy precompile
// @title Identity precompile
// @custom:precompile
// @custom:address 0x04
// @notice This precompile serves as a cheaper way to copy data in memory
namespace PrecompileDataCopy {
namespace PrecompileIdentity {
const PRECOMPILE_ADDRESS = 0x04;
const GAS_COST_DATACOPY = 15;
const GAS_IDENTITY = 15;
const GAS_IDENTITY_WORD = 3;
// @notice Run the precompile.
// @param input_len The length of input array.
Expand All @@ -34,6 +35,6 @@ namespace PrecompileDataCopy {
output_len: felt, output: felt*, gas_used: felt, reverted: felt
) {
let (minimum_word_size) = Helpers.minimum_word_count(input_len);
return (input_len, input, 3 * minimum_word_size + GAS_COST_DATACOPY, 0);
return (input_len, input, GAS_IDENTITY_WORD * minimum_word_size + GAS_IDENTITY, 0);
}
}
Loading

0 comments on commit 414e4da

Please sign in to comment.