-
Notifications
You must be signed in to change notification settings - Fork 5.3k
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
Create bigint_modexp.md #198
Changes from 6 commits
fd1d312
22b92a0
61145e3
c4a771e
1c3ee13
60fe651
7138d54
ed73b62
deee02a
dafe13c
4d4d8fb
85f6907
3005564
ca82cd9
f417998
9504333
5f92749
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
### Parameters | ||
|
||
* `GQUADDIVISOR: 20` | ||
|
||
### Specification | ||
|
||
At address 0x00......05, add a precompile that expects input in the following format: | ||
|
||
<length_of_BASE> <length_of_EXPONENT> <length_of_MODULUS> <BASE> <EXPONENT> <MODULUS> | ||
|
||
Where every length is a 32-byte left-padded integer representing the number of bytes to be taken up by the next value. Call data is assumed to be infinitely right-padded with zero bytes, and excess data is ignored. Consumes `floor(max(length_of_MODULUS, length_of_BASE) ** 2 * max(length_of_EXPONENT, 1) / GQUADDIVISOR)` gas, and if there is enough gas, returns an output `(BASE**EXPONENT) % MODULUS` as a byte array with the same length as the modulus. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think so, then we'll get 1 there for exponent of any non-empty length There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The examples disagree then:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why? If the length of the modulus, base and the exponent are 256 bytes, then There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, mixed up |
||
|
||
For example, the input data: | ||
|
||
0000000000000000000000000000000000000000000000000000000000000001 | ||
0000000000000000000000000000000000000000000000000000000000000020 | ||
0000000000000000000000000000000000000000000000000000000000000020 | ||
03 | ||
fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e | ||
fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f | ||
|
||
Represents the exponent `3**(2**256 - 2**32 - 978) % (2**256 - 2**32 - 977)`. By Fermat's little theorem, this equals 1, so the result is: | ||
|
||
0000000000000000000000000000000000000000000000000000000000000001 | ||
|
||
Returned as 32 bytes because the modulus length was 32 bytes. The gas cost would be `32**2 * 32 / 20 = 1638` gas (note that this roughly equals the cost of using the EXP opcode to compute a 32-byte exponent). A 4096-bit RSA exponentiation would cost `256**2 * 256 / 20 = 838860` gas in the worst case, though RSA verification in practice usually uses an exponent of 3 or 65537, which would reduce the gas consumption to 3276 or 6553, respectively. | ||
|
||
This input data: | ||
|
||
0000000000000000000000000000000000000000000000000000000000000000 | ||
0000000000000000000000000000000000000000000000000000000000000020 | ||
0000000000000000000000000000000000000000000000000000000000000020 | ||
fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e | ||
fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f | ||
|
||
Would be parsed as a base of 0, exponent of `2**256 - 2**32 - 978` and modulus of `2**256 - 2**32 - 978`, and so would return 0. Notice how if the length_of_BASE is 0, then it does not interpret _any_ data as the base, instead immediately interpreting the next 32 bytes as length_of_EXPONENT. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. L9: Since There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, modulus is interpreted as |
||
|
||
This input data: | ||
|
||
0000000000000000000000000000000000000000000000000000000000000000 | ||
0000000000000000000000000000000000000000000000000000000000000020 | ||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff | ||
fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe | ||
fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd | ||
|
||
Would parse a base length of 0, a modulus length of 32, and an exponent length of `2**256 - 1`, where the base is empty, the modulus is `2**256 - 2` and the exponent is `(2**256 - 3) * 256**(2**256 - 33)` (yes, that's a really big number). It would then immediately fail, as it's not possible to provide enough gas to make that computation. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is base of length 0, an exponent of length 32 and modulus of length There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems correct. I apply this change. |
||
|
||
This input data: | ||
|
||
0000000000000000000000000000000000000000000000000000000000000001 | ||
0000000000000000000000000000000000000000000000000000000000000002 | ||
0000000000000000000000000000000000000000000000000000000000000020 | ||
03 | ||
ffff | ||
8000000000000000000000000000000000000000000000000000000000000000 | ||
07 | ||
|
||
Would parse as a base of 3, an exponent of 65535, and a modulus of `2**255`, and it would ignore the remaining 0x07 byte. | ||
|
||
This input data: | ||
|
||
0000000000000000000000000000000000000000000000000000000000000001 | ||
0000000000000000000000000000000000000000000000000000000000000002 | ||
0000000000000000000000000000000000000000000000000000000000000020 | ||
03 | ||
ffff | ||
80 | ||
|
||
Would also parse as a base of 3, an exponent of 65535 and a modulus of `2**255`, as it attempts to grab 32 bytes for the modulus starting from 0x80, but then there is no further data so it right pads it with 31 zeroes. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A specification is missing for the case (I prefer having no exceptional faults in the precompiled contracts, except when the gas is not enough.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess it should be 0 because There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, also |
||
|
||
### Rationale | ||
|
||
This allows for efficient RSA verification inside of the EVM, as well as other forms of number theory-based cryptography. Note that adding precompiles for addition and subtraction is not required, as the in-EVM algorithm is efficient enough, and multiplication can be done through this precompile via `a * b = ((a + b)**2 - (a - b)**2) / 4`. | ||
|
||
|
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.
Would it be safe assuming that it is unlikely to have calls consuming gigabytes of data?
If yes, how about making each length field 32 bits wide (or even less):
I understand we have 0 gas for 0 bytes in the payload, but does that make any sense?
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.
"representing the number of bytes to be taken up by the next value" <- I don't think this is correct anymore. It used to be like that in the initial drafts, but not anymore.
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.
Zasss..