Ed25519verify_bare Implementation

Have implemented a smart signature contract account where funds in the escrow can be pulled by the receiver only if the receiver’s address has been signed by a secret key, yielding a signature, which is then verified against the related public key (embedded in the contract).

Following are the relevant snippets - I’m missing something in the interplay between calling the contract and the ed25519verify_bare TEAL code - any suggestions appreciated

— Public/Secret Key Setup —

const keys = nacl.sign.keyPair();
const publicKeyBytes = keys.publicKey;
const secretKeyBytes = keys.secretKey;

const recipientAddress = “OKKGIO…”; // Valid Account Address

const signature = nacl.sign.detached(Buffer.from(recipientAddress), secretKeyBytes);
const verify = nacl.sign.detached.verify(Buffer.from(recipientAddress), signature, publicKeyBytes);

console.log(‘verify’, verify); // Verified!

– SDK –

const pubKey = Buffer.from(publicKeyBytes).toString(“base64”);
// NOTE pubKey gets injected into the TEAL as below, pre-compilation

let smartSigArgs = ;
smartSigArgs.push(Buffer.from(“rcv”));
smartSigArgs.push(signature); // arg 1 below

const smartSig = new algosdk.LogicSigAccount(compiledCodeBytes, smartSigArgs);

— TEAL —
gtxn 1 AssetReceiver // same as recipientAddress above
arg 1 // Signature
pushbytes b64 ${pubKey}
ed25519verify_bare
bz handle_fail // Always fails

Most likely the issue is that OKKGIO… is an encoded address with checksum.
The address stored in AssetReceiver is a 32-byte public key.

See how to switch between the two there: Encoding and Decoding - Algorand Developer Portal

To debug smart contracts, I strongly recommend using tealdbg or goal clear dryrun and check that each field matches what you are expecting. Doing so you would see that the message you are signing in the JS is different from the one you are verifying in TEAL.

1 Like

Yes - that appears to be it. The TEAL is unchanged, but it worked after replacing:

const signature = nacl.sign.detached(Buffer.from(recipientAddress), secretKeyBytes);

with:

const signature = nacl.sign.detached( algosdk.decodeAddress(recipientAddress).publicKey, secretKeyBytes);

So, the lesson is understanding the difference between what is presented as the address vs. what is being processed behind the scenes.

Thanks for the insights!
Paul

2 Likes