Back to Home

AI and Meyer Contracts: Catching Crypto Bugs Before Production

Article demonstrates how applying Design by Contract together with AI agents allows detecting critical logical errors in cryptographic systems before production release. On the example of PKI with hardware TRNG, the detection of two vulnerabilities is shown, which would have been missed by traditional tests.

AI + Meyer Contracts: How to Prevent Cryptographic Catastrophes
Advertisement 728x90

How AI Agents and Design by Contract Catch Crypto Bugs Before Production

AI agents are changing the game in developing secure systems: instead of manually writing code and tests, they generate implementations based on formal contracts. This eliminates the main reason Design by Contract failed—double the work. In a project with hardware TRNG and PKI, two critical vulnerabilities were caught precisely through contract tests that ordinary unit tests would have missed.

Why Tests Miss Logical Errors in Cryptography

Tests only check what the programmer thought of. If they didn't know to verify padding in RSA or entropy quality before feeding it into DRBG—the test won't write itself. That's how a 27-year-old bug in OpenBSD and a 16-year-old vulnerability in FFmpeg slipped past millions of automated checks. Compilers and static analyzers are powerless against logical errors: picking the wrong encryption mode, skipping certificate revocation checks, using outdated standards—all this flies under their radar.

Key problem: tests react to the implementation, not the intent. Contracts capture the intent before any code is written. They set boundaries: what the system must do (postconditions), what's forbidden (invariants), and under what conditions it can be called (preconditions). This isn't just documentation—it's an executable specification.

Google AdInline article slot

Here's what sets the contract approach apart:

  • Formality: PRE/POST/INV are written in machine-readable form, not comments.
  • Early detection: Contract violations fail immediately, not in production.
  • Focus on guarantees: Instead of "how it works"—"what is guaranteed".
  • Single source of truth: The contract doesn't change during development; it's only updated if requirements change.

How the AI Agent Handles the Second Half of the Work

Design by Contract failed in the mainstream due to double the workload: first write the contract, then code, then tests. Under deadlines, contracts were the first casualty. Today, the AI agent takes over implementation and test generation, leaving humans just to formulate the contract. This changes the economics: one line of contract replaces hundreds of lines of code and tests.

The process looks like this:

Google AdInline article slot
  • Human writes invariant: padding == RSA-PSS | RSA-OAEP; PKCS#1 v1.5 == FORBIDDEN.
  • Agent generates the CryptoEngine module, which uses only allowed paddings.
  • Simultaneously, agent creates a contract-test that tries to use PKCS#1 v1.5 and expects an exception.
  • If the test fails—the agent fixes the implementation without touching the contract.
  • Human reviews only 10 lines of contract, not 1000 lines of code.

Advantages:

  • Speed: 11 days of active work on a fullstack embedded project instead of months.
  • Reliability: Contract is the focal point; errors in it are easier to spot than in code.
  • Scalability: One person manages agents in different roles (coder, tester, architect).

Real Case: PKI with Hardware TRNG and Contract Tests

The pki-on-box project includes five modules: STM32G431 (hardware TRNG), Python daemon (DRBG per NIST SP 800-90A), CryptoEngine (key generation), KeyStorage (AES-256-GCM), CA service (X.509 signing). Each module has a formal contract at the interfaces. Two critical vulnerabilities were found before deployment:

  • Wrong padding: Implementation accidentally used PKCS#1 v1.5 instead of RSA-PSS. Bleichenbacher attack allows plaintext recovery via padding oracle—contract test failed immediately.
  • Wrong AES mode: ECB was selected instead of GCM. Contract required authenticated encryption—test failed again.

Project metrics:

Google AdInline article slot
  • 131 commits
  • 62 contract-tests + 15 HW-tests
  • 3 MCU boards (STM32G474, G431, H750)
  • Target platform: RK3328 ARM64
  • AI cost: 1780₽ for 30 sessions
  • Open repository: github.com/vasilievsv/hw.pki-on-box

Contracts at Interfaces: Where Critical Errors Arise

Logical errors arise at module boundaries. DRBG outputs bytes—CryptoEngine must know how to use them. Without a contract—someone picks padding from a StackOverflow example. Here are two key contracts from the project:

contract: key_generation
  PRE:
    - DRBG.seeded == true
    - algorithm ∈ {RSA-2048, ECDSA-P384}
  POST:
    - private_key.encrypted(AES-256-GCM)
    - public_key = derive(private_key)
  INV:
    - padding == RSA-PSS | RSA-OAEP
    - PKCS#1 v1.5 == FORBIDDEN
contract: certificate_issuance
  PRE:
    - issuer_ca.valid() && !revoked()
    - csr.signature.verify() == true
  POST:
    - cert.serial.unique()
    - cert.signature.verify(issuer_ca.public_key) == true
  INV:
    - root_ca.offline == true
    - cert_chain.depth <= max_path_length

Contract test for padding:

def test_rejects_pkcs1v15_padding(self, crypto):
    priv, pub = crypto.generate_rsa_keypair(bits=2048)
    data = b"invariant check"
    sig = crypto.sign_data(priv, data)
    # PSS must rabotat
    pub.verify(sig, data, padding.PSS(...))
    # PKCS1v15 must slomatsya
    with pytest.raises(Exception):
        pub.verify(sig, data, padding.PKCS1v15(), hashes.SHA256())

The test doesn't check functionality—it verifies invariant compliance. If padding changes—the test fails, even if the signature "technically works".

Key Takeaways

  • Contracts > tests: Tests check implementation; contracts check intent. Logical errors are only caught through formal guarantees.
  • AI eliminates double work: Agent generates code and tests from the contract; human focuses on specification.
  • Critical errors at boundaries: Padding, encryption modes, revocation checks—all controlled by invariants at module interfaces.
  • Open verification: Project with hardware TRNG and contract tests available in open repository for audit.
  • Time economics: 11 days for a fullstack embedded system instead of months—thanks to role division and autogen.

— Editorial Team

Advertisement 728x90

Read Next