Skip to content

Instantly share code, notes, and snippets.

@ctibo
Last active October 24, 2023 13:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ctibo/bc65f6f42428f2faa805fce1991f9008 to your computer and use it in GitHub Desktop.
Save ctibo/bc65f6f42428f2faa805fce1991f9008 to your computer and use it in GitHub Desktop.
Helper method that verifies if the signature part of a signed transaction is valid
/**
* VERIFY SIGNED TXN
* Helper method that verifies if the signature part
* of a signed transaction is valid
*
* REQUIREMENTS
* Install the required packages first
* Run: npm i algosdk @noble/ed25519 @noble/hashes
*
* USAGE
* import verifySignedTxn from 'verifySignedTxn';
* const isValid = await verifySignedTxn( mySignedTxnBtyes );
* ==================================================
*/
import algosdk, { SignedTransaction } from "algosdk";
import * as ed from '@noble/ed25519';
import { sha512 } from '@noble/hashes/sha512';
ed.etc.sha512Sync = (...m) => sha512(ed.etc.concatBytes(...m));
const NODE_API_URL = 'https://mainnet-api.algonode.cloud';
/**
* Verify Signed Transaction
* ==================================================
*/
export default async function verifySignedTxn(txnBuffer: Uint8Array) {
const signed = algosdk.decodeSignedTransaction(txnBuffer)
if (!signed || !signed.txn || !signed.sig || !signed.sgnr) return false;
const signer = signed.sgnr;
const signerAddr = algosdk.encodeAddress(signer);
const from = signed.txn.from.publicKey;
const fromAddr = algosdk.encodeAddress(from);
const authAddr = await getAuthAddress(fromAddr);
if (signerAddr !== authAddr) return false;
const sig = Buffer.from(signed.sig);
const txnBytes = algosdk.decodeUnsignedTransaction(
algosdk.encodeUnsignedTransaction( signed.txn )
).toByte();
const txnMsg = Buffer.from(
concatUint8Arrays( signed.txn.tag, txnBytes)
).toString('hex');
const isVerified = ed.verify(sig, txnMsg, signer);
return isVerified;
}
/**
* Helpers
* ==================================================
*/
// get the auth address of an account
async function getAuthAddress(addr: string) {
try {
const response = await fetch(`${ NODE_API_URL }/v2/accounts/${ addr }?exclude=all`);
const account = await response.json();
return account['auth-addr'] || account.address || 'NOT_FOUND';
}
catch {
return 'NOT_FOUND';
}
}
// https://github.com/algorand/js-algorand-sdk/blob/7965d1c194186e5c7b8a86756c546f2ec35291cd/src/utils/utils.ts#L83
function concatUint8Arrays(...arrs: ArrayLike<number>[]) {
const size = arrs.reduce((sum, arr) => sum + arr.length, 0);
const c = new Uint8Array(size);
let offset = 0;
for (let i = 0; i < arrs.length; i++) {
c.set(arrs[i], offset);
offset += arrs[i].length;
}
return c;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment