Agent Governance ToolkitAgent Governance Toolkit 4.1.0 · Python 3.10+
Dashboard
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
47 small wins to finish your pathNext lesson →

Signing an action and verifying it

Signing turns the bytes of an action into a short signature that only the agent's private key could produce, so anyone with the public key can confirm the action came from that agent and was not changed.

Last updated: 14 Oct, 2026 · Agent Governance Toolkit 4.1.0

The An agent that can prove who it is lesson gave the shop agent a key pair. This lesson uses it. The agent signs the exact bytes of a refund request, and a verifier checks that signature. The point is the contrast: the real request verifies, and a request with one digit changed does not.

Signing the bytes of an action

sign takes bytes and returns a signature as text. verify_signature takes the same bytes and that signature and returns a bool. Both run on the Ed25519 key the identity already holds.

python
signature = shop.sign(action_bytes)      # -> str
ok = shop.verify_signature(action_bytes, signature)   # -> bool

Signing the refund request and then verifying it twice, once against the real bytes and once against tampered bytes, shows what the signature binds to.

ExampleThe real request verifies; a changed one does not
# sign the exact bytes of the action the agent intends to take
action = b"refund order A-2291 amount 40"
signature = shop.sign(action)

# change one digit and the same signature no longer matches
tampered = b"refund order A-2291 amount 9999"
print("verify(correct): ", shop.verify_signature(action, signature))
print("verify(tampered):", shop.verify_signature(tampered, signature))

What the signature is

The signature is a string you can store next to the action or send alongside it. It is a fixed length for this curve, whatever the action, and it is different on every run because the key pair is fresh each time the identity is made.

ExampleA signature is fixed-length text, ready to store
# the signature is portable text, the same length for any action
print("type  :", type(signature).__name__)
print("length:", len(signature))

Reading the two checks

  • The correct bytes verify. verify_signature on the exact action that was signed returns True: the public key confirms the private key produced this signature.
  • The tampered bytes fail. Changing the amount from 40 to 9999 makes verify_signature return False, even though the signature itself is untouched. The signature binds to the bytes.
  • Nothing was decrypted. A signature is not encryption; the action is still readable. What it adds is proof of who sent it and that it arrived unchanged.

Signing vs sending the action alone

Action with a signatureAction on its own
Proves the senderYes, only the private key signsNo, anyone can claim it
Catches a changed payloadYes, verification failsNo, a changed amount looks the same
Needs a shared secretNo, the public key verifiesNot applicable
Readable by the receiverYes, it is not encryptedYes

Where signing an action helps

  • A refund or a payment an agent sends downstream, where the receiver must know the amount was not altered in transit.
  • A message between two agents, so each can confirm the other sent it.
  • An audit record a reviewer might challenge, where a signature ties the logged action to the agent that signed it.
Watch out. sign takes bytes, not a string. Encode text first with .encode(), and sign the same canonical bytes you verify later. Sign a dict by serialising it the same way both times, or a reordered key will verify as tampered.
Try it yourself
  • Sign a status request such as b"order_status A-2291" and verify it comes back True.
  • Verify the refund signature against a second identity's verify_signature and watch it fail.
  • Encode a Python string with .encode(), sign the bytes, and verify the round trip.

Little by little, you're building something great.