1

I'm trying to create a signature using web3.py with the following

private_key = "0x..."
message = "0x..."

w3.eth.account.sign_message(encode_defunct(hexstr=message), private_key=private_key)

SignedMessage(
messageHash=HexBytes('0x0977453c547a8ec8b97e6960c174171c26cc316fe3eb42e9c1f43d906988f2f7'), 
r=3826115209918881089309465947057239465610262098443411688798455982011613167534, 
s=57607373686102894909527198656322533582090341098386235608665690313545458942055, 
v=27, 
signature=HexBytes('0x08758124b2dde0a220b9e86a982343f8daf868c1b3d99eade5c74a72cce3bfae7f5c9e3803b0bef93e2d55c08d0f428976712fbaeee8a40ab1c223b8c67c80671b')
)

But I'm not getting the correct output for verifying with erecover on chain. I'm comparing with the js version which is correct:

const signMessage = (types, values, signer) => {
  const message = web3.eth.abi.encodeParameters(types, values);

  const hash = web3.utils.keccak256(message);
  const { r, s, v } = web3.eth.accounts.sign(hash, signer);
  const signature = web3.eth.abi.encodeParameters(
    ["bytes32", "bytes32", "uint8"],
    [r, s, v]
  );

  return { message, signature };
};

{
  message: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000539000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000bb800000000000000000000000090f79bf6eb2c4f870365e785982e1f101e93b9060000000000000000000000000000000000000000000000000000000063f932b3000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000dba8c9e398042c00000000000000000000000000000000000000000000000000000000000000000',
  hash: '0x2cf410e76a0941e26af6f72a6a8d1cd85dccb68013cb75f79d6953d64df67519',
  signature: '0x822093256039a3f9a7cfeaef298b437a48ce819fbe2595b74f8b00bed01553bc64524f75795487183f0db628859d5dae0c7c80ea2b1b6dd1331f9101052ad705000000000000000000000000000000000000000000000000000000000000001b'
}

The message I'm getting from the js side and the private key is being passed as a string, but I am not getting the same signature that I'm getting from the js version.

I looked at this and this as well as the docs and still am not sure how to do this.

1 Answer 1

2

The issue is two fold, one that the hash should be passed, not the message. The other is that the signature is returned packed.

w3.eth.account.sign_message(encode_defunct(hexstr=hash), private_key=private_key)

SignedMessage(
messageHash=HexBytes('0x3418e4d525f194127a8568abe10ce8e85baacfc3a1787c7146b7dc17b3da4d3a'), 
r=84118226279719248546434396845856688871337333924969201322918159090204879128334, 
s=18459783198555716597479201270128233159415607675680227670410186427526995028124, 
v=28, 
signature=HexBytes('0xb9f93a970439f33211fc5761ec7df5065eea37fb99b73ebc2f71d2fda3e8870e28cfddf5cdec9fcb3c6f4b6339258904b639e0975dd511da00e858ba9acca89c1c'))

You can see that the v value is packed in the signature, this must be unpacked.

Packed signature from web3.py

0xb9f93a970439f33211fc5761ec7df5065eea37fb99b73ebc2f71d2fda3e8870e28cfddf5cdec9fcb3c6f4b6339258904b639e0975dd511da00e858ba9acca89c1c

Versus unpacked

0xb9f93a970439f33211fc5761ec7df5065eea37fb99b73ebc2f71d2fda3e8870e28cfddf5cdec9fcb3c6f4b6339258904b639e0975dd511da00e858ba9acca89c000000000000000000000000000000000000000000000000000000000000001c

So just pad 62 0's before the 1c (28) or 1b (27).

signed_message = w3.eth.account.sign_message(encode_defunct(hexstr=hash), private_key=private_key)
signature = signed_message.signature.hex()
if signature[130:] == '1c':
    signature = signature[:130] + '000000000000000000000000000000000000000000000000000000000000001c'
else:
    signature = signature[:130] + '000000000000000000000000000000000000000000000000000000000000001b'
return signature

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.