Skip to content

Signature Verification

Verification basics

import { verifyEnvelope, createSignedEnvelope } from '@pqsafe/agent-pay'
const { publicKey, secretKey } = await generateKeyPair()
const signed = createSignedEnvelope(envelope, secretKey)
// Should always be true if envelope wasn't mutated
const valid = verifyEnvelope(signed, publicKey)

Debugging verifyEnvelope() === false

1. Check for envelope mutation

The most common cause: the envelope object was modified after createSignedEnvelope().

// ❌ Bug
const env = createSpendEnvelope({ ... })
const signed = createSignedEnvelope(env, secretKey)
env.memo = 'changed' // Mutates the original object!
verifyEnvelope(signed, publicKey) // false
// ✅ Fix: freeze the envelope object
const env = Object.freeze(createSpendEnvelope({ ... }))
const signed = createSignedEnvelope(env, secretKey)

2. Verify key pair consistency

// Generate once and persist both keys together
const { publicKey, secretKey } = await generateKeyPair()
// ❌ Wrong: verifying with a different publicKey
const other = await generateKeyPair()
verifyEnvelope(signed, other.publicKey) // false — mismatched key pair
// ✅ Correct: use the publicKey that corresponds to the secretKey used for signing
verifyEnvelope(signed, publicKey) // true

3. Cross-runtime serialization

If you’re serializing a SignedEnvelope to JSON and deserializing it, ensure you’re not losing precision:

import { deserializeSignedEnvelope, serializeSignedEnvelope } from '@pqsafe/agent-pay'
// Use the SDK's serialization helpers — don't use JSON.stringify directly
const json = serializeSignedEnvelope(signed)
const restored = deserializeSignedEnvelope(json)
verifyEnvelope(restored, publicKey) // true

4. Cross-language verification

TypeScript-signed envelopes can be verified in Python:

from pqsafe_agent_pay import verify_envelope, deserialize_signed_envelope
# Load from JSON
signed = deserialize_signed_envelope(json_string)
is_valid = verify_envelope(signed, public_key_hex)
print(is_valid) # True

Debug helper

import { debugEnvelopeSignature } from '@pqsafe/agent-pay'
const debug = debugEnvelopeSignature(signed, publicKey)
console.log(debug)
// {
// valid: false,
// canonicalJson: '{"agentId":"...","allowedRails":["airwallex"],...}',
// signatureLength: 6586,
// publicKeyLength: 3904,
// error: 'Canonical JSON hash mismatch — envelope was likely mutated after signing',
// }