Repository: algorand/js-algorand-sdk
Pull request #735 (2023-01-16 23:31:03)

API: verifyTealSign utility function
Introduce a new function `verifyTealSign` which can be used to verify the output of its pair method, `tealSign`.

Some applications might benefit from having this utility function, either for testing purposes or not, and it would save developers the work of importing the `nacl` library and doing the verification manually by themselves.

CLAassistant: [![CLA assistant check](https://cla-assistant.io/pull/badge/not_signed)](https://cla-assistant.io/algorand/js-algorand-sdk?pullRequest=735) <br/>Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our [Contributor License Agreement](https://cla-assistant.io/algorand/js-algorand-sdk?pullRequest=735) before we can accept your contribution.<br/><sub>You have signed the CLA already but the status is still pending? Let us [recheck](https://cla-assistant.io/check/algorand/js-algorand-sdk?pullRequest=735) it.</sub>
bbroder-algo: I don't have any problem with this nacl helper function, and LGTM, but I am not particularly qualified for JS.  

Patch:
diff --git a/src/logicsig.ts b/src/logicsig.ts
index c63e6af..f1ffc37 100644
--- a/src/logicsig.ts
+++ b/src/logicsig.ts
@@ -495,6 +495,29 @@ export function tealSign(
   return nacl.sign(toBeSigned, sk);
 }
 
+/**
+ * verifyTealSign verifies a signature as would the ed25519verify opcode
+ * @param data - buffer with original signed data
+ * @param programHash - string representation of teal program hash (= contract address for LogicSigs)
+ * @param sig - uint8array with the signature to verify (produced by tealSign/tealSignFromProgram)
+ * @param pk - uint8array with public key to verify against
+ */
+export function verifyTealSign(
+  data: Uint8Array | Buffer,
+  programHash: string,
+  sig: Uint8Array,
+  pk: Uint8Array
+) {
+  const parts = utils.concatArrays(
+    address.decodeAddress(programHash).publicKey,
+    data
+  );
+  const toBeSigned = Buffer.from(
+    utils.concatArrays(SIGN_PROGRAM_DATA_PREFIX, parts)
+  );
+  return nacl.verify(toBeSigned, sig, pk);
+}
+
 /**
  * tealSignFromProgram creates a signature compatible with ed25519verify opcode from raw program bytes
  * @param sk - uint8array with secret key
diff --git a/src/main.ts b/src/main.ts
index 2fa4d21..c2a9eab 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -160,6 +160,7 @@ export {
   logicSigFromByte,
   tealSign,
   tealSignFromProgram,
+  verifyTealSign,
 } from './logicsig';
 export {
   signMultisigTransaction,


Test patch:
diff --git a/tests/7.AlgoSDK.js b/tests/7.AlgoSDK.js
index 94686e9..8f8ba12 100644
--- a/tests/7.AlgoSDK.js
+++ b/tests/7.AlgoSDK.js
@@ -967,22 +967,18 @@ describe('Algosdk (AKA end to end)', () => {
   });
 
   describe('tealSign', () => {
-    it('should produce verifiable signature', () => {
-      const data = Buffer.from('Ux8jntyBJQarjKGF8A==', 'base64');
-      const seed = Buffer.from(
-        '5Pf7eGMA52qfMT4R4/vYCt7con/7U3yejkdXkrcb26Q=',
-        'base64'
-      );
-      const prog = Buffer.from('ASABASI=', 'base64');
+    const data = Buffer.from('Ux8jntyBJQarjKGF8A==', 'base64');
+    const prog = Buffer.from('ASABASI=', 'base64');
+    const addr = new algosdk.LogicSig(prog).address();
 
-      const keys = nacl.keyPairFromSeed(seed);
-      const pk = keys.publicKey;
-      const sk = keys.secretKey;
-      const addr = new algosdk.LogicSig(prog).address();
-      const sig1 = algosdk.tealSign(sk, data, addr);
-      const sig2 = algosdk.tealSignFromProgram(sk, data, prog);
+    const seed = Buffer.from(
+      '5Pf7eGMA52qfMT4R4/vYCt7con/7U3yejkdXkrcb26Q=',
+      'base64'
+    );
+    const { publicKey: pk, secretKey: sk } = nacl.keyPairFromSeed(seed);
 
-      assert.deepStrictEqual(sig1, sig2);
+    it('should produce a verifiable signature', () => {
+      const sig = algosdk.tealSign(sk, data, addr);
 
       const parts = utils.concatArrays(
         algosdk.decodeAddress(addr).publicKey,
@@ -991,7 +987,21 @@ describe('Algosdk (AKA end to end)', () => {
       const toBeVerified = Buffer.from(
         utils.concatArrays(Buffer.from('ProgData'), parts)
       );
-      const verified = nacl.verify(toBeVerified, sig1, pk);
+      const verified = nacl.verify(toBeVerified, sig, pk);
+      assert.equal(verified, true);
+    });
+
+    it('should produce a verifiable signature from a program', () => {
+      const sig1 = algosdk.tealSign(sk, data, addr);
+      const sig2 = algosdk.tealSignFromProgram(sk, data, prog);
+
+      assert.deepStrictEqual(sig1, sig2);
+    });
+
+    it('should verify a valid signature', () => {
+      const sig = algosdk.tealSign(sk, data, addr);
+
+      const verified = algosdk.verifyTealSign(data, addr, sig, pk);
       assert.equal(verified, true);
     });
   });