-
Notifications
You must be signed in to change notification settings - Fork 773
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
EVM: Generic BLS Interface / Use JS Implementation (@noble/curves) as Default #3471
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files
Flags with carried forward coverage won't be shown. Click here to find out more. |
75d14f1
to
a3f2a1e
Compare
I've done something wrong with my fork builds of This is a known issue though and should go away once |
So if one is running npx vitest run test/precompiles/eip-2537-bls.spec.ts from the |
a3f2a1e
to
4190d5a
Compare
Instructions on how to run the Ensure
To run the state tests:
Note: blockchain tests cannot be ran, it throws some error about a header field missing, so it runs on partial Prague. State tests output:
The tests all pass on our current master (so with MCL)! |
Oh wait, nvm, I can of course test using |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some comments, but this looks extremely good in general, especially how MCL / Noble is now decoupled, I love it!
|
||
export const zeroByteCheck = ( | ||
opts: PrecompileInput, | ||
zeroByteRanges: number[][], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: this will thus slice the array exclusive of zeroByteRanges[x][1]
. So for instance the array [[0,1]]
will only check the 0th byte, not the byte at position 1. Is this correct? (And can docs be added for this method?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think this should be all correct, actually this only copies your former code into a new function 😂, see this commit 62f15f2.
So this is a BLS specific zero byte check, applying this part of the EIP:
And specificall this "Due to the size of p, the top 16 bytes are always zeroes." part, see that the input subarrays always have a length of 16 bytes.
I'll give this and the other methods some documentation.
zeroByteRanges[index][0] + pairStart, | ||
zeroByteRanges[index][1] + pairStart | ||
) | ||
if (!(equalsBytes(slicedBuffer, ZERO_BYTES_16) === true)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this constant ZERO_BYTES_16
here and not zeros(x)
where x
is the expected length of the zero byte array?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See answer above.
packages/evm/src/types.ts
Outdated
* An interface for the MCL WASM implementation https://github.com/herumi/mcl-wasm | ||
* is shipped with this library, see the following test file for an example on | ||
* how to use: | ||
* https://github.com/ethereumjs/ethereumjs-monorepo/blob/master/packages/evm/test/precompiles/eip-2537-bls.spec.ts |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test file does not have tests which specifically use MCL. Did you intend to use a permalink here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you intend to permalink to the test which specifically runs on this PR (and later thus likely on master). Could you also point to the specific lines in this permalink? Especially the mcl init and the mcl curve settings should be initialized before being passed into the EVM.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I initially wanted to just add a code example here (which I think is the better solution) and then I tried and the linter complained and I was just lazy and therfore added the test link. 😂 Will go back to the code version, this now worked this time anyhow (no idea why).
mcl.setMapToMode(mcl.IRTF) // set the right map mode; otherwise mapToG2 will return wrong values. | ||
mcl.verifyOrderG1(true) // subgroup checks for G1 | ||
mcl.verifyOrderG2(true) // subgroup checks for G2 | ||
const mclbls = new MCLBLS(mcl) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can maybe improve here (I also now see why we export MCLBLS / NobleBLS). Can we add a static method to the interfaces which inits these BLSs? Then we can init the MCL using MCLBLS.init(mcl)
and write those settings there
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a great idea, will directly add! 👍 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I now went for a non-static init() version, I find it a bit nicer if the out asny initialization (so await mcl.init(mcl.BLS12_381)
) is not also wrapped and can be done separately by the user, guess both ways would work and be fine though, for this one I find the typing also a bit nicer. The optional init()
method from the interface is the automatically called from within the EVM constructor if present.
import * as mcl from 'mcl-wasm'
await mcl.init(mcl.BLS12_381)
const evm = await EVM.create({ mcl: new MCLBLS(mcl) })
38563a2
to
3eab6a4
Compare
… folder structure
…ted set of abstractions
…w VM evmOpts option
…straction) -> Fixes VM state tests
1c997ed
to
cbb8041
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This review is on top of my previous review, got 2 small comments, LGTM in general 😄
* @param pairStart | ||
* @returns | ||
*/ | ||
export const zeroByteCheck = ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: this does zero byte checks, but only if the range of these zero bytes is 16 zero bytes, so the name is a bit misleading.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, will rename to leading16ZeroBytesCheck
packages/vm/test/tester/index.ts
Outdated
@@ -45,6 +45,7 @@ import type { bn128 } from '@ethereumjs/evm' | |||
* --expected-test-amount: number. If passed, check after tests are ran if at least this amount of tests have passed (inclusive) | |||
* --verify-test-amount-alltests: number. If passed, get the expected amount from tests and verify afterwards if this is the count of tests (expects tests are ran with default settings) | |||
* --reps: number. If passed, each test case will be run the number of times indicated | |||
* --bls: string. Use MCL as a bls library if passed (default: Noble) (state tests only) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we also add this for blockchain tests?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Following on this, is there a reason we wouldn't want to use MCL by default in the test runner? I don't know how many BLS related tests there are but anything that slows down the tests seems undesirable to me since these are the main bottleneck in our CI right now, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was a bit lazy and I feel that every new code is this messy test runner is a bit of "lost code" 😂, so I decided to skip. But I can very well add, makes sense for practical reasons and shouldn't be so much extra work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@acolytec3 Yes, guess we can do that for the VM as long as we keep running tests for both implementations in the EVM.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great overall. One item regarding comments in the noble.ts
that should be clarified.
return G1 | ||
} | ||
|
||
// input: a mcl G1 point |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need all these mcl
references? I'm assuming these are obsolete in this file, right? Can they be replaced with something like noble/curves
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't think that a noble/curves
reference is needed here, will just completely remove
packages/vm/test/tester/index.ts
Outdated
@@ -45,6 +45,7 @@ import type { bn128 } from '@ethereumjs/evm' | |||
* --expected-test-amount: number. If passed, check after tests are ran if at least this amount of tests have passed (inclusive) | |||
* --verify-test-amount-alltests: number. If passed, get the expected amount from tests and verify afterwards if this is the count of tests (expects tests are ran with default settings) | |||
* --reps: number. If passed, each test case will be run the number of times indicated | |||
* --bls: string. Use MCL as a bls library if passed (default: Noble) (state tests only) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Following on this, is there a reason we wouldn't want to use MCL by default in the test runner? I don't know how many BLS related tests there are but anything that slows down the tests seems undesirable to me since these are the main bottleneck in our CI right now, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EVM lint failed, should pass now, still LGTM 😄 👍
Follow-up on #3350
Goal of this PR is to move over to use a JavaScript BLS implementation for the BLS precompiles (EIP-2537). For this the direct usage of the MCL library in the precompile files as well as the tight MCL library coupling (by adding as a property to the EVM) is replaced by using a generic
EVMBLSInterface
. It will likely be possible later on to fully allow switching the implementation, not sure if we want to go that far, we'll see.This first push is for testing with the official test suite after setting up the base structures (as well as some temporary double structures like the doubled mcl code for gradual implementation which will go away at the end).