Skip to content

Commit

Permalink
docs: add ecrecover example (#256)
Browse files Browse the repository at this point in the history
adds an example for using `ecrecover`
  • Loading branch information
sarahschwartz authored Nov 21, 2024
1 parent 75fc958 commit 0db5a66
Showing 1 changed file with 83 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,24 +55,76 @@ contract TestSignatureChecker {
}
```

## Verifying AA signatures
## Validating Signatures with ECRecover

Our SDK provides two methods within `utils` to verify the signature of an account:
[`isMessageSignatureCorrect`](https://sdk.zksync.io/js/ethers/api/v6/utilities#ismessagesignaturecorrect) and [`isTypedDataSignatureCorrect`](https://sdk.zksync.io/js/ethers/api/v6/utilities#istypeddatasignaturecorrect).
The [`ecrecover`](/zk-stack/components/prover/circuits/ecrecover)
method is also available to validate standard secp256k1 signatures.
This method recovers the signer’s public key from a given digital signature.

```ts
import { utils, EIP712Signer } from "zksync-ethers";
Below is an example implementation of how `ecrecover` can be used to validate a given signature in a smart account.

const isValidMessageSignature = await utils.isMessageSignatureCorrect(provider, ADDRESS, message, messageSignature);
```solidity
function isValidSignature(
bytes32 _hash,
bytes memory _signature
) public view override returns (bytes4 magic) {
magic = EIP1271_SUCCESS_RETURN_VALUE;
if (_signature.length != 65) {
// Signature is invalid anyway, but we need to proceed with the signature verification as usual
// in order for the fee estimation to work correctly
_signature = new bytes(65);
// Making sure that the signatures look like a valid ECDSA signature and are not rejected rightaway
// while skipping the main verification process.
_signature[64] = bytes1(uint8(27));
}
const isValidTypesSignature = await utils.isTypedDataSignatureCorrect(provider, ADDRESS, await eip712Signer.getDomain(), utils.EIP712_TYPES, EIP712Signer.getSignInput(tx), typedSignature);
```
// extract ECDSA signature
uint8 v;
bytes32 r;
bytes32 s;
// Signature loading code
// we jump 32 (0x20) as the first slot of bytes contains the length
// we jump 65 (0x41) per signature
// for v we load 32 bytes ending with v (the first 31 come from s) then apply a mask
assembly {
r := mload(add(_signature, 0x20))
s := mload(add(_signature, 0x40))
v := and(mload(add(_signature, 0x41)), 0xff)
}
Currently these methods only support verifying ECDSA signatures, but very soon they will support EIP1271 signature verification as well.
if (v != 27 && v != 28) {
magic = bytes4(0);
}
Both of these methods return `true` or `false` depending on whether the message signature is correct.
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (
uint256(s) >
0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0
) {
magic = bytes4(0);
}
It is **not recommended** to use the `ethers.js` library to verify user signatures.
address recoveredAddress = ecrecover(_hash, v, r, s);
// Note, that we should abstain from using the require here in order to allow for fee estimation to work
if (recoveredAddress != owner) {
magic = bytes4(0);
}
if(recoveredAddress == address(0)){
magic = bytes4(0);
}
}
```

## Validating Secp256r1 Signatures

Expand All @@ -99,10 +151,29 @@ bytes memory input = abi.encodePacked(
(bool __, bytes memory output) = P256.staticcall(input);
// if signature is valid:
// output = 0x0000000000000000000000000000000000000000000000000000000000000001
// output == 0x0000000000000000000000000000000000000000000000000000000000000001
// if signature is NOT valid:
// output.length == 0
```

You can find a more in-depth example showing how
it can be used in the ["Signing Transactions with WebAuthn"](https://code.zksync.io/tutorials/signing-transactions-with-webauthn) tutorial.

## Offchain Signature Verification

The `zksync-ethers` SDK provides two methods within `utils` to verify standard signatures of an account:
[`isMessageSignatureCorrect`](https://sdk.zksync.io/js/ethers/api/v6/utilities#ismessagesignaturecorrect) and [`isTypedDataSignatureCorrect`](https://sdk.zksync.io/js/ethers/api/v6/utilities#istypeddatasignaturecorrect).

```ts
import { utils, EIP712Signer } from "zksync-ethers";

const isValidMessageSignature = await utils.isMessageSignatureCorrect(provider, ADDRESS, message, messageSignature);

const isValidTypesSignature = await utils.isTypedDataSignatureCorrect(provider, ADDRESS, await eip712Signer.getDomain(), utils.EIP712_TYPES, EIP712Signer.getSignInput(tx), typedSignature);
```

Currently these methods only support verifying ECDSA and EIP1271 signatures.

Both of these methods return `true` or `false` depending on whether the message signature is correct.

It is **not recommended** to use the `ethers.js` library to verify user signatures, as it does not support verifying EIP1271 signatures.

0 comments on commit 0db5a66

Please sign in to comment.