Try   HackMD

Bundler anti-replay attack scheme (researching)

background

In the account abstraction of 4337, in order to prevent replay attacks, a nonce variable is introduced into the AA wallet contract, which must be updated every time Tx is executed, thereby increasing the Gas overhead

direction:

  • We need to meet our anti-replay attack requirements in a relatively Gas-saving way
  • Combining Tx's nonce + chainId two fields
    • The nonce in the tx of each account should increase monotonically by +1
    • chainId is bound to the corresponding network
      • It can be solved by adding chainId to the off-chain signature parameter, and using block.chainId to calculate the hash comparison on the chain

plan

  • The correctness of the nonce of the user Tx is guaranteed by ZKP
  • The EP contract does not need to maintain the nonce for each user separately, but maintains two StateHash and RecrusiveStateHash values ​​in the Verify contract (great gas savings)

StateHash, RecrusiveStateHash iterative maintenance process

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Questions to be confirmed

  • Performance improvement of off-chain ZKP
    • Need to choose the appropriate merkel data structure
  • Process security audit (not found yet)
  • DA problem with user Nonce
    • The user's actual nonce is all stored off-chain, and nodes need to ensure data availability
    • When the EP contract executes Tx, it needs to log a nonce, which is convenient for users to build the state of the nonce by themselves – by Wen Bo

Pseudocode description

Prove process circom syntax description:

signal input UserAddress[N];

signal input CurUserNonce[N];
signal input CurRecrusiveStateHash;
signal input PreRecrusiveStateHash;
signal input CurStateHash;

signal input NewUserNonce[N];
signal output NewRecrusiveStateHash;
signal output NewStateHash;
signal output PubCurStateHash;
signal output PubCurRecrusiveStateHash;

assert(MerkelHash(CurUserNonce[N]) == CurHash);

assert(Hash(PreRecrusiveStateHash, CurHash) == CurRecrusiveStateHash);

for(var i = 0; i < N;i ++) {
    assert(CurUserNonce[i] + 1 == NewUserNonce[i]);
}


NewStateHash <== MerkelHash(NewUserNonce[N]);
NewRecrusiveStateHash <== Hash(CurRecrusiveStateHash, NewStateHash);
PubCurStateHash <== MerkleHash(CurUserNonce[N]);
PubCurRecrusiveStateHash <== CurRecrusiveStateHash;

Prove results:

ProofData;
PublicInputs:{
    NewStateHash,
    NewRecrusiveStateHash,
    PubCurStateHash,
    PubCurRecrusiveStateHash,
}

The process of updating the status after Verify (EVM environment):


require(Verify(ProofData,PublicInputs)==True);

require(self.CurStateHash == PublicInputs.PubCurStateHash);
require(self.CurRecrusiveStateHash == PublicInputs.PubCurRecrusiveStateHash);

self.CurStateHash = PublicInputs.NewStateHash;
self.CurRecrusiveStateHash = PublicInputs.PubCurRecrusiveStateHash;