-
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
Simple replay attack protection #155
Comments
Out of curious: why make |
It was a carry-over from Bitcoin's Electrum wallet. |
Relevant Classic ECIP discussion on this subject. Even more here. As far as I understand it, they're considering adding the blockhash of the nearest fork to the signing process. I'm not competent to speak on the cryptographic parts of this idea, but I'll note a philosophical difference between this and ECIP-1011. Here, picking CHAIN_ID requires human intervention to choose which community it belongs in, whereas a machine can compute the right blockhash to stick in if it detects even a minor fork. In any case, the existence of two incompatible replay protection systems will hardly cause them to fail in their intended function. It's just a kind of balkanization of code that, IMHO, would be harmful for a future cross-chain metaetheral world. I'm not saying that doing our own system would be wrong, but that there's a non-zero cost to having different systems. |
To clarify, does "continue to be usable to send transactions on all chains" mean that we would retain the old transaction signing scheme as valid, in addition to the new signing scheme? If so, the specification-paragraph should be updated to reflect that. |
Yes, the old scheme is still valid in addition to the new one. |
@vbuterin The mention of ETC confuses me as I thought this issue was being raised to address up-coming forks to ensure replay attacks cannot happen again should the current chain survive in some form. Is that what this issue is created to address? |
@rebroad: This will work just as well for ETH/ETC replay attack prevention. As it is, that's the bigger need. |
Instead of using a 'chain ID' that has a limited namespace of 8 bits, and has to be changed on each fork, I'd like to propose two alternatives:
|
Is this only a protection against simple replay attacks or all attacks in a simple way? Please clarify for the non whitepaper safe fellows. |
The latter; "all attacks in a simple way". |
i quite like both of @Arachnid 's suggestions, though think they are as well working in tandem with this proposal; this would allow for alt-etherea, private/consortium chains and testnets to avoid clashing rather than just non-forks. |
This new testcase aims to reproduce ethereum/EIPs#155
Not sure, if the provided serialization for the signed transaction is correct (or I am misunderstanding this proposal?): import rlp
from ethereum.utils import decode_hex
# the 'signed tx' from above
eip155_signed = "f86e098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a7640000801ca1a019ae791bb8378a38bb83f5b930fe78a0320cec27d86e5e258c69f0fa9541eb8da1a02bd8e0c5bde4c0800238ce5a59d2f3ce723f1e84a62cab53d961fe3b019d19fc"
list(map(rlp.utils.big_endian_to_int, rlp.decode(decode_hex(eip155_signed))[-3:]))
# [28,
# 18538350366433071197493567112980778422885435717274618683086050914661715717254029,
# 18546566920747953154222317575156555315715115874101297527539304425414456214624764] edit: this is the serialization my implementation expects: signed_tx = "f86c098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a76400008026a019ae791bb8378a38bb83f5b930fe78a0320cec27d86e5e258c69f0fa9541eb8da02bd8e0c5bde4c0800238ce5a59d2f3ce723f1e84a62cab53d961fe3b019d19fc"
list(map(rlp.utils.big_endian_to_int, rlp.decode(decode_hex(signed_tx))[-3:]))
# [38,
# 11616088462479929722209511590713166362238170772128436772837473395614974864269,
# 19832642777361886450959973766490059191918327598807281226090984148355472235004] |
If We have also Ethereum network id number. Can we use the same value? |
This new testcase aims to reproduce ethereum/EIPs#155
@konradkonrad yep you're right, that tx got serialized incorrectly. I updated it. |
Guys, could you please adjust the formula in this issue? |
To people who never split their coins (e.g. all original ETH), are any of these updates any danger? Excuse my ignorance pls. Thanks. |
@mohsenghajar: If all goes to plan, this will make things safer, as transactions will be limited to one chain. It will be easier to split afterwards, hopefully. |
It seems like this example has been modified in implementation, please correct me if im wrong.
Consider a transaction with nonce = 9, gasprice = 20 * 10^9, startgas = 21000, to = 0x3535353535353535353535353535353535353535, value = 10^18, data='' (empty). The "signing data" becomes: The "signing hash" becomes: After signing make sure v is either 37 (18x2+1) or 38(18x2+2) based on 0 or 1 then v,r,s becomes: then the signed tx becomes: |
Updated, sorry about that! |
Does anyone have problem testing signed tx against https://github.com/ethereum/tests/blob/develop/TransactionTests/EIP155/ttTransactionTestEip155VitaliksTests.json? For me, my temp implementation cannot pass test 1 ~ 11 (Vitalik_11) for simple RLP hash (not sign, but just assume the transaction is already signed and encode the 9 elements, with v, r, s read from the JSON file). Vitalik_12, Vitalik_13 and Vitalik_14 pass. They have normal-looking r and s values. For 1 ~ 11, each test has identical or slightly different r/s values. Update: all test worked. |
hi @kvhnuke .. quick question regarding your output.. I get the same values, but only if Rather than including a lot of inline code, here are links: My question largely boils down to another earlier comment. When
PS) the example at the top of this EIP seems to be inconsistent.. the final value for its "signed tx" was copied from the value in your comment.. but none of the preceding data values that show the intermediate steps leading to this final value match the rest of the data in your comment (or the data observed when running the above test code). idk if anybody else has permission to make edits, but (imho) that should be corrected. |
For context: ETC uses |
This EIP is now located at https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md. Please go there for the correct specification. The text in this issue may be incorrect or outdated, and is not maintained. |
Perhaps I'm missing something. EP-155 states: "If block.number >= FORK_BLKNUM and v = CHAIN_ID * 2 + 35 or v = CHAIN_ID * 2 + 36, then when computing the hash of a transaction for purposes of signing or recovering, instead of hashing only the first six elements (ie. nonce, gasprice, startgas, to, value, data), hash nine elements, with v " These are instructions for the hashing party, but not the the original signing party. Therefore, the question arises: when signing a transaction, should one use the first equation (with 35) or second equation (with 36). Practically speaking, sometimes the former works and sometimes the latter without any clear rationale. Thanks Nir The |
@nt11: 35/36 encodes the low bit of R.y, which is needed to recover the
public key. Note that you need to flip that bit when doing low s
normalisation.
|
@jhoenicke could you please elaborate a bit on the meaning of "R.y" and "low s normalization"? I wasn't able to find either terms. Thanks in advance! |
@talbp : An ECDSA signature (r,s) is computed from a random nonce k: compute R = kG and set r = (R.x mod ORDER) and throw away R.y. To recover the public key one can use the formula 1/r(sR-hG), but that requires to recover R from the signature. If R.x < ORDER (which is almost always the case), then the missing part is R.y and there are two possibilities (one with low bit 0, one with low bit 1). low s normalization: If (r,s) is a valid signature then (r,(ORDER-s)) is also a valid signature, but it uses the "other R". Ethereum (and Bitcoin) require for some time that one always uses the smaller value for s, and then one has to flip R.y bit. |
Too late to the party, but why hash 9 values with the last two fixed to |
It's worth noting that if you do not use RFC 6979 you will get non-deterministic signatures that differ from the example. |
EDITOR UPDATE (2017-08-15): This EIP is now located at https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md. Please go there for the correct specification. The text below may be incorrect or outdated, and is not maintained.
Parameters
FORK_BLKNUM
: TBACHAIN_ID
: 1Specification
If
block.number >= FORK_BLKNUM
andv = CHAIN_ID * 2 + 35
orv = CHAIN_ID * 2 + 36
, then when computing the hash of a transaction for purposes of signing or recovering, instead of hashing only the first six elements (ie. nonce, gasprice, startgas, to, value, data), hash nine elements, withv
replaced byCHAIN_ID
,r = 0
ands = 0
. The currently existing signature scheme usingv = 27
andv = 28
remains valid and continues to operate under the same rules as it does now.Example
Consider a transaction with
nonce = 9
,gasprice = 20 * 10**9
,startgas = 21000
,to = 0x3535353535353535353535353535353535353535
,value = 10**18
,data=''
(empty).The "signing data" becomes:
The "signing hash" becomes:
If the transaction is signed with the private key
0x4646464646464646464646464646464646464646464646464646464646464646
, then the v,r,s values become:Notice the use of 37 instead of 27. The signed tx would become:
Rationale
This would provide a way to send transactions that work on ethereum without working on ETC or the Morden testnet. ETC is encouraged to adopt this EIP but replacing
CHAIN_ID
with a different value, and all future testnets, consortium chains and alt-etherea are encouraged to adopt this EIP replacingCHAIN_ID
with a unique value.The text was updated successfully, but these errors were encountered: