According Noir docs the function has the following signature:
fn verify_signature(_public_key_x : [u8; 32], _public_key_y : [u8; 32], _signature: [u8; 64], _message: [u8]) -> bool
How can this be used with metamask sign function?
29 Likes
You can recover the public key from the signature and slice it.
import { ethers } from "ethers";
async function main() {
// hardhat wallet 0
const sender = new ethers.Wallet(
"ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
);
console.log("\x1b[34m%s\x1b[0m", "signing message π: ", message);
const signature = await sender.signMessage(message); // get the signature of the message, this will be 130 bytes (concatenated r, s, and v)
console.log("signature π: ", signature);
let pubKey_uncompressed = ethers.utils.recoverPublicKey(digest, signature);
console.log("uncompressed pubkey: ", pubKey_uncompressed);
// recoverPublicKey returns `0x{hex"4"}{pubKeyXCoord}{pubKeyYCoord}` - so slice 0x04 to expose just the concatenated x and y
// see https://github.com/indutny/elliptic/issues/86 for a non-explanation explanation π
let pubKey = pubKey_uncompressed.slice(4);
let pub_key_x = pubKey.substring(0, 64);
console.log("public key x coordinate π: ", pub_key_x);
let pub_key_y = pubKey.substring(64);
console.log("public key y coordinate π: ", pub_key_y);
}
main();
60 Likes
Thank you for recoverPublicKey
. it was something I was missing.
But now I struggle to get the input to noir .
My code is :
import React, { useState } from "react";
import { ethers } from "ethers";
import { BarretenbergBackend } from "@noir-lang/backend_barretenberg";
import { Noir } from "@noir-lang/noir_js";
import circuit from "../../circuit/target/circuit.json";
function SignatureComponent() {
const [message, setMessage] = useState("");
const [signatureData, setSignatureData] = useState(null);
const backend = new BarretenbergBackend(circuit);
const noir = new Noir(circuit, backend);
const hexStringToByteArray = (hexString) => {
if (hexString.startsWith("0x")) {
hexString = hexString.slice(2);
}
const byteArray = [];
for (let i = 0; i < hexString.length; i += 2) {
byteArray.push(parseInt(hexString.substring(i, i + 2), 16));
}
return byteArray;
};
const signMessage = async () => {
try {
if (!window.ethereum)
throw new Error("Ethereum wallet (e.g., MetaMask) not detected!");
await window.ethereum.request({ method: "eth_requestAccounts" });
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = await provider.getSigner();
const signature = await signer.signMessage(message);
const messageHash = ethers.utils.hashMessage(message);
const recoveredPublicKey = ethers.utils.recoverPublicKey(
messageHash,
signature
);
const publicKeyBytes = ethers.utils.arrayify(recoveredPublicKey);
const publicKeyX = publicKeyBytes.slice(0, 32);
const publicKeyY = publicKeyBytes.slice(32, 64);
setSignatureData({
publicKeyX: ethers.utils.hexlify(publicKeyX),
publicKeyY: ethers.utils.hexlify(publicKeyY),
signature: signature,
message: message,
messageHash: messageHash,
});
const publicKeyXBytes = hexStringToByteArray(ethers.utils.hexlify(publicKeyX));
const publicKeyYBytes = hexStringToByteArray(ethers.utils.hexlify(publicKeyY));
const signatureBytes = hexStringToByteArray(signature).slice(0, 64);
const messageHashBytes = hexStringToByteArray(messageHash);
const input = {
hashed_message: messageHashBytes,
pub_key_x: publicKeyXBytes,
pub_key_y: publicKeyYBytes,
signature: signatureBytes,
};
const proof = await noir.generateFinalProof(input);
const verification = await noir.verifyFinalProof(proof);
if(verification){ console.log("Verified") } else throw "Not-Verified";
} catch (error) {
console.error(error);
alert("Error signing message: " + error.message);
}
};
return (
<div>
<input
type="text"
value={message}
onChange={(e) => setMessage(e.target.value)}
placeholder="Enter a message to sign"
/>
<button onClick={signMessage}>Sign Message</button>
{signatureData && (
<div>
<p>Public Key X: {signatureData.publicKeyX}</p>
<p>Public Key Y: {signatureData.publicKeyY}</p>
<p>Signature: {signatureData.signature}</p>
<p>Message: {signatureData.message}</p>
<p>messageHash: {signatureData.messageHash}</p>
</div>
)}
</div>
);
}
export default SignatureComponent;
but I get error Error: invalid type: integer
1, expected struct Range at line 1 column 595
in const proof = await noir.generateFinalProof(input);
Note: Ethers version is 5.7.2
40 Likes
Letβs move this discussion to the discord where more people will see it and itβs better for tech support. tag me there with @joshc
28 Likes