Problem with ed25519verify - General - Algorand
Problem with ed25519verify
post by pogginicolo98 on Oct 19, 2022
Hi everyone!
As described in the title I’m having trouble using the Ed25519Verify function.
I’m not understanding the following error and even doing some research I haven’t found useful information to solve it:
algosdk.error.AlgodHTTPError: TransactionPool.Remember: transaction L5SNG7ALALAM5RMTAZDIYIBJ3TWIIXL5BMOABV3STIC2CRD4BWLQ: logic eval error: pc=383 dynamic cost budget exceeded, executing ed25519verify: local program cost was 42. Details: pc=383, opcodes=txna ApplicationArgs 2
txna ApplicationArgs 3
ed25519verify
I think the problem is that the function is computationally too expensive but also reducing the method to a single Assert with Ed25519Verify() and an Approve() does not change.
Below I report part of the code of my smart contract and the Python code i use to create the transaction:
Smart contract
@Subroutine(TealType.none)
def delegate_vote():
return Seq(
Assert(
Ed25519Verify(Txn.application_args[1], Txn.application_args[2], Txn.application_args[3]),
),
Approve()
)
Transaction
def sign_param(hash, app_account, private_key):
to_sign = (
b"ProgData"
+ encoding.decode_address(app_account)
+ hash
)
signature = sign_bytes(to_sign, private_key)
return signature
op = "test_ed25519verify"
param = "data"
hash = base64.b64encode(sha256(param.encode("utf-8")).digest())
sign = sign_param(hash, app_account, delegator['private_key'])
app_args = [op, hash, str(sign), delegator['address']]
vote_txn = make_app_call_txn(client, app_id, sender['address'], app_args)
In ** make_app_call_txn ** I encode of the app_args and the final result is the following:
[b’test_ed25519verify’, b’Om6weQ85rIfJTzhWst0sXREOaBFgImGpqSPTuyOtyLc=‘, b’MsmsZbtLNwycFXlfLpba4llJk0EW27OumW6jZaKWkRwBGg56QjeSujDi8JgIv14XNOsWZj4CROtwolrVQfsiBw==’, b’JG3IBNG4LBCPAVYB5VISGIS3QCL4LLFVP3K6UIKBFB3MESVRE7Y5BNYUBA’]
post by Ben on Oct 19, 2022
You can make additional “noop” app calls to increase your opcode budget, note that you’ll need to appropriately handle them in the contract and probably add some nonce to the note field since they’ll probably be identical besides that and you’ll get an error message saying something like “transaction already in ledger”.
post by pogginicolo98 on Oct 20, 2022
Thanks, your solution solved the budget opcode problem, but I still have problems running the Ed25519Verify function correctly. In order to give you as much info as possible, I will post the entire code I’m running.
Smart contract:
from pyteal import *
from lib.pyteal_helpers import program
def approval():
op_test_ed25519_verify = Bytes("ed25519_verify")
op_increase_budget = Bytes("increase budget")
@Subroutine(TealType.none)
def test_ed25519_verify():
return Seq(
Assert(
Ed25519Verify(Txn.application_args[1], Txn.application_args[2], Txn.accounts[1]),
),
Approve()
)
@Subroutine(TealType.none)
def increase_budget():
return Seq(
Approve()
)
return program.event(
init=Approve(),
delete=Approve(),
update=Approve(),
close_out=Approve(),
opt_in=Approve(),
no_op=Seq(
Cond(
[\
Txn.application_args[0] == op_test_ed25519_verify,\
test_ed25519_verify()\
],
[\
Txn.application_args[0] == op_increase_budget,\
increase_budget()\
],
),
Reject(),
),
)
def clear():
return Approve()
After compile, deploy and optin I run this Python script:
import base64
from algosdk import encoding
from algosdk.future import transaction
from hashlib import sha256
from lib.utils.accounts import load_account
from lib.utils.clients import get_algod_client
from lib.utils.transaction_composer import load_sc
def sign_data(data, app_account, private_key):
to_sign = (
b"ProgData"
+ encoding.decode_address(app_account)
+ data
)
signing_key = transaction.SigningKey(base64.b64decode(private_key)[:32])
signed = signing_key.sign(to_sign)
return signed.signature
def noop_call(client, sender, data_signer, sc):
print(f'Testing Ed25519Verify...')
# Transaction to test Ed25519Verify
op = "ed25519_verify"
param = "data"
data = sha256(param.encode('utf-8')).digest()
signed_data = sign_data(data, sc['account'], data_signer['private_key'])
app_args = [op.encode("utf-8"), base64.b64encode(data), base64.b64encode(signed_data)]
sp_params = client.suggested_params()
accounts = [data_signer['address']]
ed25519_verify_txn = transaction.ApplicationNoOpTxn(sender['address'], sp_params, sc['id'], app_args, accounts)
# Transaction to increase opcode budget n.1
op = "increase budget"
note = "txn 1".encode("utf-8")
app_args = [op.encode("utf-8")]
sp_params = client.suggested_params()
increase_budget_1_txn = transaction.ApplicationNoOpTxn(sender['address'], sp_params, sc['id'], app_args, note=note)
# Transaction to increase opcode budget n.2
note = "txn 2".encode("utf-8")
sp_params = client.suggested_params()
increase_budget_2_txn = transaction.ApplicationNoOpTxn(sender['address'], sp_params, sc['id'], app_args, note=note)
group_id = transaction.calculate_group_id([ed25519_verify_txn, increase_budget_1_txn, increase_budget_2_txn])
ed25519_verify_txn.group = group_id
increase_budget_1_txn.group = group_id
increase_budget_2_txn.group = group_id
signed_txn_1 = ed25519_verify_txn.sign(sender['private_key'])
signed_txn_2 = increase_budget_1_txn.sign(sender['private_key'])
signed_txn_3 = increase_budget_2_txn.sign(sender['private_key'])
signed_txns = [signed_txn_1, signed_txn_2, signed_txn_3]
tx_id = client.send_transactions(signed_txns)
try:
transaction_response = transaction.wait_for_confirmation(client, tx_id, 2)
except Exception as err:
print(err)
return
print(f'Test Ed25519Verify successful')
def main():
client = get_algod_client()
sender = load_account("master")
data_signer = load_account("user")
sc = load_sc('test')
noop_call(client, sender, data_signer, sc)
if __name__ == '__main__':
main()
These are my app_args:
[b’ed25519_verify’, b’Om6weQ85rIfJTzhWst0sXREOaBFgImGpqSPTuyOtyLc=‘, b’nHwAgzHAwbefshLVGVNtFgMrUsszk+lFLlbwy6zzbhjoshU4I0aoGLMBDwbL9iRaWqPybkSSgB5gLRRE0KlYDw==’]
This is the error:
algosdk.error.AlgodHTTPError: TransactionPool.Remember: transaction ZQCM3NINZTTIU6K2OQPPZVN5G2A2XK54FR4PJXU6FZSFI4Q47ZWA: logic eval error: invalid signature. Details: pc=129, opcodes=txna ApplicationArgs 2
txna Accounts 1
ed25519verify
I think the problem is how I sign data or the format of app_args is wrong. The sign_data() function is an adapted version of the one you posted some time ago in another topic: [https://github.com/algorand-devrel/decipher-drop/blob/main/util.py#L82-L92]
post by Ben on Oct 20, 2022
I see at least 1 issue, that is using the app_addr to prefix the data, the method requires the hash of the contract not the app address. While for lsigs the address is the hash of the program, applications addresses are the hash of the app id. You can get the hash of the approval program when you compile it or you can use the new op as of AVM7 ed25519verify_bare which doesn’t require any special prefixing prior to hashing.
post by pogginicolo98 on Oct 20, 2022
Thanks, I used ed25519verify_bare and with your suggestions I was able to verify the signature correctly!