Logic Signatures

A LogicSignature (or Smart Signature) acts as a signature that is verified by a smart contract instead of a public key see Algorand docs for more information.

A Beaker LogicSignature is initialized with either a PyTeal Expr or a function that returns an Expr.

verify_lsig = beaker.LogicSignature(
    pt.Seq(
        pt.Assert(
            # Don't let it be rekeyed
            pt.Txn.rekey_to() == pt.Global.zero_address(),
            # Don't take a fee from me
            pt.Txn.fee() == pt.Int(0),
            # Make sure I've signed an app call
            pt.Txn.type_enum() == pt.TxnType.ApplicationCall,
            # Make sure I have the args I expect [method_selector, hash_value, signature]
            pt.Txn.application_args.length() == pt.Int(3),
        ),
        eth_ecdsa_validate(pt.Txn.application_args[1], pt.Txn.application_args[2]),
    ),
    build_options=beaker.BuildOptions(avm_version=6),
)

A LogicSignatureTemplate is initialized by passing a PyTeal Expr or a function that returns an Expr and a dictionary of template variables that should be provided at runtime.

lsig = beaker.LogicSignatureTemplate(
    lsig_validate,
    runtime_template_variables={"user_addr": pt.TealType.bytes},
)
class beaker.logic_signature.LogicSignature[source]

LogicSignature allows the definition of a logic signature program.

A LogicSignature may include constants, subroutines, and :ref:TemplateVariables as attributes

The evaluate method is the entry point to the application and must be overridden in any subclass to call the necessary logic.

__init__(expr_or_func: collections.abc.Callable[[], pyteal.Expr] | pyteal.Expr, *, build_options: beaker.build_options.BuildOptions | None = None)[source]
class beaker.logic_signature.LogicSignatureTemplate[source]

LogicSignature allows the definition of a logic signature program.

A LogicSignature may include constants, subroutines, and :ref:TemplateVariables as attributes

The evaluate method is the entry point to the application and must be overridden in any subclass to call the necessary logic.

__init__(expr_or_func: collections.abc.Callable[[...], pyteal.Expr] | pyteal.Expr, *, runtime_template_variables: dict[str, pyteal.TealType], build_options: beaker.build_options.BuildOptions | None = None)[source]

initialize the logic signature and identify relevant attributes

class beaker.logic_signature.RuntimeTemplateVariable[source]

A Template Variable to be used as an attribute on LogicSignatures that need some hardcoded well defined behavior.

If no name is supplied, the attribute name it was assigned to is used.

__init__(stack_type: TealType, name: str)[source]

initialize the TemplateVariable and the scratch var it is stored in

property token: str

returns the name of the template variable that should be present in the output TEAL

Logic Signature Example

from typing import Literal

import pyteal as pt

import beaker

Signature = pt.abi.StaticBytes[Literal[64]]


def lsig_validate(user_addr: pt.Expr) -> pt.Expr:
    """Simple program to check an ed25519 signature given a message and signature"""
    return pt.Seq(
        # Borrow the msg and sig from the app call arguments
        (msg := pt.abi.String()).decode(pt.Txn.application_args[2]),
        (sig := pt.abi.make(Signature)).decode(pt.Txn.application_args[3]),
        # Assert that the sig matches
        pt.Assert(pt.Ed25519Verify_Bare(msg.get(), sig.get(), user_addr)),
        pt.Int(1),
    )


lsig = beaker.LogicSignatureTemplate(
    lsig_validate,
    runtime_template_variables={"user_addr": pt.TealType.bytes},
)


app = beaker.Application("SigCheckerApp")


@app.external
def check(
    signer_address: pt.abi.Address, msg: pt.abi.String, sig: Signature
) -> pt.Expr:
    sig_checker_pc = beaker.precompiled(lsig)
    # The lsig will take care of verifying the signature
    # all we need to do is check that its been used to sign this transaction
    return pt.Assert(
        pt.Txn.sender() == sig_checker_pc.address(user_addr=signer_address.get())
    )