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

feat(levm): implement precompile ecpairing #1560

Open
wants to merge 105 commits into
base: main
Choose a base branch
from

Conversation

maximopalopoli
Copy link
Contributor

Motivation

The goal is to implement the ecpairing precompile.

Description

I put a clippy allow for a *= in a math type because it is not handled like conventional multiplication (it has its own implementation).
The implementation makes pass all EF tests related.

ilitteri and others added 30 commits December 10, 2024 13:07
…ass/ethrex into precompiles_support_scaffolding
The tests were not passing because the addresses assigned for the
 contracts were the reserved for the precompiles
@maximopalopoli maximopalopoli added the levm Lambda EVM implementation label Dec 23, 2024
@maximopalopoli maximopalopoli self-assigned this Dec 23, 2024
@maximopalopoli maximopalopoli marked this pull request as ready for review December 23, 2024 18:57
@maximopalopoli maximopalopoli requested a review from a team as a code owner December 23, 2024 18:57
Copy link
Contributor

@lima-limon-inc lima-limon-inc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great Job Maxi!!
You're killing it
✋ 🤚

Comment on lines 911 to 914
.checked_mul(34000)
.ok_or(OutOfGasError::GasCostOverflow)?;
groups_cost
.checked_add(45000)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quick question Maxi, could these values be put into constants?

Would that make sense in this context?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


#[test]
fn ecpairing_test() {
let calldata = hex::decode("2cf44499d5d27bb186308b7af7af02ac5bc9eeb6a3d147c186b21fb1b76e18da2c0f001f52110ccfe69108924926e45f0b0c868df0e7bde1fe16d3242dc715f61fb19bb476f6b9e44e2a32234da8212f61cd63919354bc06aef31e3cfaff3ebc22606845ff186793914e03e21df544c34ffe2f2f3504de8a79d9159eca2d98d92bd368e28381e8eccb5fa81fc26cf3f048eea9abfdd85d7ed3ab3698d63e4f902fe02e47887507adf0ff1743cbac6ba291e66f59be6bd763950bb16041a0a85e000000000000000000000000000000000000000000000000000000000000000130644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd451971ff0471b09fa93caaf13cbf443c1aede09cc4328f5a62aad45f40ec133eb4091058a3141822985733cbdddfed0fd8d6c104e9e9eff40bf5abfef9ab163bc72a23af9a5ce2ba2796c1f4e453a370eb0af8c212d9dc9acd8fc02c2e907baea223a8eb0b0996252cb548a4487da97b02422ebc0e834613f954de6c7e0afdc1fc").unwrap();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could there be some comment / link explaining what this bytecode means/is trying to test?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

@JereSalo JereSalo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice. I think some things can be improved regarding to code clarity for now, we can improve it even more in the future but for now this looks good.

Ok(Bytes::from([0u8; 64].to_vec()))
} else if first_point_is_zero {
// If first point is zero, return is second point
// If first point is zero, response is second point
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

response?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe output

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -421,27 +428,20 @@ pub fn ecadd(
.concat();
Ok(Bytes::from(res))
} else if second_point_is_zero {
// If second point is zero, return is first point
// If second point is zero, response is first point
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let first_point = BN254Curve::create_point_from_affine(first_point_x, first_point_y)
.map_err(|_| PrecompileError::ParsingInputError)?;
let res = [first_point.x().to_bytes_be(), first_point.y().to_bytes_be()].concat();
Ok(Bytes::from(res))
} else {
// If none of the points is zero, return is the sum of both in the EC
// If none of the points is zero, response is the sum of both in the EC
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return Err(VMError::PrecompileError(PrecompileError::ParsingInputError));
}

let groups_number = calldata.len() / 192;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this variable name can be improved. Maybe something like "quantity of inputs" or "amount of inputs" would be more accurate.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe groups_amount? inputs_amount is good also.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

increase_precompile_consumed_gas(gas_for_call, gas_cost, consumed_gas)?;

let mut mul: FieldElement<Degree12ExtensionField> = QuadraticExtensionFieldElement::one();
for group_number in 0..groups_number {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this would be like input index, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines 539 to 543
// Infinite is defined by (0,0). Any other zero-combination is invalid
if (U256::from_big_endian(first_point_x) == U256::zero()
&& U256::from_big_endian(first_point_y) != U256::zero())
|| (U256::from_big_endian(first_point_x) != U256::zero()
&& U256::from_big_endian(first_point_y) == U256::zero())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this like an exclusive or?
I don't really know if this is equivalent but it might be:

if (U256::from_big_endian(first_point_x) == U256::zero())
    ^ (U256::from_big_endian(first_point_y) == U256::zero())

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines 559 to 562
if (U256::from_big_endian(second_point_x_first_part) == U256::zero()
&& U256::from_big_endian(second_point_x_second_part) != U256::zero())
|| (U256::from_big_endian(second_point_x_first_part) != U256::zero()
&& U256::from_big_endian(second_point_x_second_part) == U256::zero())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines 553 to 556
let second_point_x_first_part =
group_data.get(96..128).ok_or(InternalError::SlicingError)?;
let second_point_x_second_part =
group_data.get(64..96).ok_or(InternalError::SlicingError)?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This got me confused. From 64..96 we have x2 and from 96..128 we have y2 according to evm codes. Why does this look different?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I gave it that name because of the place they occupy in the vector, maybe it is not very clear. I could give it another name, but I focused on the fact that, after all, it is a component of what will be the second point.

Comment on lines 575 to 578
if (U256::from_big_endian(second_point_y_first_part) == U256::zero()
&& U256::from_big_endian(second_point_y_second_part) != U256::zero())
|| (U256::from_big_endian(second_point_y_first_part) != U256::zero()
&& U256::from_big_endian(second_point_y_second_part) == U256::zero())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

)
.map_err(|_| InternalError::ConversionError)?;

// Check if the curve belongs to the curve (this happens if it's lower than the prime)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is not clear enough, at least for me that I'm not very knowledgeable about this precompile. "The curve belongs to the curve"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
levm Lambda EVM implementation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants