JSFiddle - React, Tailwind, and code Playground
HTML
<script src="https://unpkg.com/bsv@1.5.3/bsv.min.js"></script>
<script src="https://unpkg.com/bsv@1.5.3/bsv-message.min.js"></script>
JavaScript
const Buffer = bsv.deps.Buffer;
const Address = bsv.Address;
const Signature = bsv.crypto.Signature;
const ECDSA = bsv.crypto.ECDSA;
const Script = bsv.Script;
const sha256 = bsv.crypto.Hash.sha256;
/*
Accepts the hex encoded format of a Twetch post OP_RETURN output and returns the public key of the signer.
*/
function recoverPublicKey(hex){
//Decode raw hex from tx output
const script = Script.fromHex(hex);
//Pop signature off the end
const signature = script.chunks.pop().buf.toString();
//Pop address off the end
const address = script.chunks.pop().buf.toString();
//If unsafe OP_RETURN skip 1 chunk, else skip 2, remove ecdsa chunks and extract buffers
const chunks = script.chunks.splice(script.chunks[0].opcodenum === 0 ? 2 : 1, script.chunks.length-5).map(c => c.buf);
//Grab string parts and validate
const parts = sha256(Buffer.from(chunks.map(c => c.toString()).join(' '))).toString('hex');
let partsValid = bsvMessage.verify(parts, address, signature);
//Grab buffer parts and validate
const bufferParts = sha256(Buffer.concat(chunks.map(c => Buffer.from(c)))).toString('hex');
let bufferPartsValid = bsvMessage.verify(bufferParts, address, signature);
let m;
if(partsValid){
m = bsvMessage(parts).magicHash();
} else if(bufferPartsValid){
m = bsvMessage(bufferParts).magicHash()
} else {
throw (new Error("Invalid signature"));
}
//Try to recover the pubkey
const sig = bsv.crypto.Signature.fromCompact(bsv.deps.Buffer.from(signature, 'base64'));
const ecdsa = new bsv.crypto.ECDSA();
ecdsa.hashbuf = m;
ecdsa.sig = sig;
const publicKey = ecdsa.toPublicKey();
if(Address.fromPublicKey(publicKey).toString() === address){
return publicKey.toString('hex');
} else {
throw(new Error("Address mismatch. Recovery failed."));
}
}
const twetchHex =...