Last active
October 24, 2023 13:42
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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