0xPolygon / polygon-edge

A Framework for Building Ethereum-compatible Blockchain Networks
https://polygon.technology/solutions/polygon-edge/
Apache License 2.0
1.02k stars 534 forks source link

ECRECOVER for extra_field signatures and sealer #662

Closed startgeek closed 2 years ago

startgeek commented 2 years ago

extra_field parameters are unknown and I cant ecrecover

Description

so this is my assumption: there is a block generated with all of its header's ready to signed and sealed and included in chain I believe there are manipulations to extra_field data before signing and sealing and after this stage a keccake256 of this half-block is used as MESSAGE for signing and verification (BTW I've done this before with BSC which is also is a POA and it worked smoothly. I don't know what I'm missing here) these are steps I took. 1.get a block (remove zeros and RLP.decode the extra_field so you get these 3 parts screenshot 1) Screenshot from 2022-07-28 12-05-53

fields of extradata: Screenshot from 2022-07-28 12-07-58

2.arrange fields in order shown in picture 2 (also for zero values use "0x" and convert of the decimal values to hex); Screenshot from 2022-07-28 12-16-48

  1. add the manipulated extra_data as last field (tried all of combinations imaginable.)
  2. take a keccake256 of this header and use the hash as message
  3. as you can see in picture 3 we have 6 signer and 1 sealer using message generated in step 4 we shall be enable to call ECRECOVER on each signature (signers and sealer) Screenshot from 2022-07-28 12-17-03

Your environment

Expected behaviour

 it should be easy to get the message and verify all signatures but seems impossible

Actual behaviour

with all of combinations I tried always got the wrong public address

Logs

const arrayToBeRlpeed = [  //fields from aBlock is unmodified and other fields converted to hex
    aBlock.parentHash,
    aBlock.sha3Uncles,
    aBlock.miner, //(Im passing this param without modification ex: 0x0000000000000000000... is this ok?)
    aBlock.stateRoot,
    aBlock.transactionsRoot,
    aBlock.receiptsRoot,
    "0x", //difficulty againg 0x is ethreum way for displaying 0 in rlp is this ok?
    "0x020119",
    "0x500000",
    "0x", //gas 0 used in hex (ethereum way)
    "0x62DE5B5D",

    [
        "0xbe3c39725304e9ecb3341f45c90ca4d729dc0cc4",
        "0x0c142c3e47cb5bef3116dab444de22ac08ae4fcc",
        "0xbc978fe9ec3fe248aaca2c3950fc1c3942ad6f02",
        "0xabe63fe9492a3340e933b27160eb47b8598235b2",
        "0x33855298c8cdaafcb9192a179c32240d78807aae",
        "0xb5aaff8eb4535ded9a245e9906a7346351915bfa",
        "0x327fa1a264d965f0da61a721b42fd1677c0e5d8e",
        "0x43e37753b9dfdf86e50fbc84c03d4d67281f7246",
        "0xc00a0ffcba6bcbcbba638755296fe45bbdd5b00c"]
]
const rlpeed = rlp.encode(arrayToBeRlpeed);
// console.log(`rlpeed header selected: ${rlpeed}`);
const hashHeader = keccak256(rlpeed)
console.log(`firstField extra data decoded: `, rlp.decode(aBlock.extraData)[0]);
let messageSigned = rlp.decode(aBlock.extraData)[1].toString("hex")
console.log(`message signed by validator so if we recover the signature we understand who signed the message:`);
console.log(typeof messageSigned);
var two = rlp.decode(aBlock.extraData)[1];
const RSV = ethJsUtil.fromRpcSig(two)
console.log(`  V is: ${RSV.v}`);
console.log(`  R is: ${RSV.r.toString('hex')}`);
console.log(`  S is: ${RSV.s.toString('hex')}`);
const pubKey = ethJsUtil.ecrecover(hashHeader, RSV.v, RSV.r, RSV.s);

console.log(`public key is: ${pubKey.toString('hex')}`);
const addrBuf = ethJsUtil.pubToAddress(pubKey);
// console.log(addrBuf);

const addr = ethJsUtil.bufferToHex(addrBuf);
console.log(addr);

Proposed solution

A sudo-code or a web3.js (since its heavy standard in industry)example starting from a raw block header to signer and/or sealer public address would be awesome and worth million lines of documents

zivkovicmilos commented 2 years ago

Hey @startgeek,

Thank you for opening up an issue 🙏

I'm pretty sure you're not doing anything wrong, it's just that Edge does some additional steps apart from the ones you've mentioned, which is very misleading.

Please check out these methods that we use for creating committed seals and proposer seals (and for recovering them!): https://github.com/0xPolygon/polygon-edge/blob/850212504d9ec2282ab65ed38f27071d33d25121/consensus/ibft/sign.go#L15-L89

I'll move this issue to a discussion since it's only Edge related in terms of an implementation that we sadly, cannot change at this point.