Reading view

There are new articles available, click to refresh the page.

Programming Math for Vibe Coders.

Programming Math for Vibe Coders Mojo Edition

Introduction

Leslie Lamport has long argued that programming is not simply coding.

Before writing code, we first need to think precisely about what the program should do and how it should behave.

That distinction matters even more in the age of AI-assisted programming.

A coding agent can generate Mojo, Python, Rust, Solidity, JavaScript, or almost any other language in seconds.

But it still needs a precise description of the problem it should solve.

This is where mathematics becomes incredibly useful.

Mathematics gives us a compact language for expressing relationships, constraints, quantities, state, and behaviour without committing ourselves to a particular programming language.

For many learners — and yes, vibe coders, I’m calling you out here — the difficult part isn’t necessarily understanding code.

It’s learning how to move between:

Idea → Mathematical Model → Algorithm → Code

In this article, we’ll explore that process using Mojo 🔥, a statically typed systems programming language with Python-like syntax.

The mathematical ideas themselves are independent of Mojo.

You can translate them into almost any programming language.

That is one of the beautiful things about approaching software mathematically:

The model survives even when the implementation language changes.

Knowledge Transfer Guide

Translating Math to Mojo: Cheat Sheet

Summation

∑ → accumulation using a loop and +=

Product

∏ → repeated multiplication using a loop and *=

Mathematical bounds

i = 1 … n → range(1, n + 1)

Indexed values

xᵢ → values[i]

Functions

f(x) → def f(x: Type) -> Type:

Real numbers

ℝ → Float64

Integers

ℤ → Int

Sequences

x₁, x₂, …, xₙ → List[T]

Infinite sums

∞ → approximate using a finite number of terms

One important detail:

Mathematical ranges are commonly inclusive.

For example:

1 ≤ k ≤ n

In Mojo, range() follows Python-style half-open ranges.

So:

range(1, n + 1)

represents:

1, 2, 3, …, n

This small difference is exactly the kind of bug mathematical thinking can help us catch.

Factorial: From ∏ to a Loop

Mathematical Definition

n! = ∏ from k = 1 to n of k

In expanded form:

n! = 1 × 2 × 3 × … × n

Mojo Implementation

def factorial(n: Int) raises -> Int:
if n < 0:
raise Error("Factorial is not defined for negative numbers.")
var result: Int = 1
for k in range(1, n + 1):
result *= k
return result

Explanation

The mathematical expression:

∏ from k = 1 to n of k

contains three pieces of information.

The variable:

k

becomes our loop variable.

The bounds:

1 ≤ k ≤ n

become:

range(1, n + 1)

And the product:

becomes:

result *= k

Something subtle is also happening here.

We initialise:

var result: Int = 1

Why 1?

Because 1 is the identity element for multiplication:

1 × x = x

For addition, the identity element is 0:

0 + x = x

So a summation accumulator normally starts at 0.

For multiplication:

1 × x = x

So a product accumulator starts at 1.

Our implementation also correctly handles:

0! = 1

When n = 0, the loop executes zero times and result remains 1.

This gives us a useful programming principle:

The initial value of an accumulator often comes directly from the mathematics of the operation.

A Mojo-Specific Observation

Unlike Python integers, Mojo’s standard Int integers represent a finite machine integer.

That means sufficiently large factorials will eventually exceed what the type can represent.

The mathematics hasn’t changed.

The representation has.

This gives us another important rule:

Mathematical correctness and representation correctness are not always the same thing.

Approximating e Using an Infinite Series

Mathematical Definition

Euler’s number can be defined as:

e = ∑ from n = 0 to ∞ of 1 / n!

Expanded:

e = 1 + 1 + 1/2! + 1/3! + 1/4! + …

A computer cannot normally execute an infinite number of operations.

So instead we calculate a finite approximation:

e ≈ ∑ from n = 0 to N − 1 of 1 / n!

Mojo Implementation

def approximate_e(terms: Int = 12) raises -> Float64:
if terms < 1:
raise Error("terms must be at least 1")
var total: Float64 = 1.0
var term: Float64 = 1.0
for n in range(1, terms):
term /= Float64(n)
total += term
return total

Explanation

We could calculate every factorial independently.

But the mathematics gives us a better algorithm.

We know:

n! = n × (n − 1)!

Therefore:

1 / n! = (1 / n) × (1 / (n − 1)!)

This means you can calculate each new term from the previous one.

Instead of repeatedly calculating:

1!, 2!, 3!, 4!, …

we simply write:

term /= Float64(n)

Then accumulate it:

total += term

This is an important lesson:

Mathematics does not merely describe the answer. It can reveal a better algorithm.

Calculating an Average

Mathematical Definition

For values:

x₁, x₂, …, xₙ

the arithmetic mean is:

x̄ = (1 / n) × ∑ from i = 1 to n of xᵢ

In plain language:

average = sum of all values/number of values

Mojo Implementation

def average(values: List[Float64]) raises -> Float64:
if len(values) == 0:
raise Error("Average is undefined for an empty collection.")
var total: Float64 = 0.0
for i in range(len(values)):
total += values[i]
return total / Float64(len(values))

Explanation

The mathematical summation:

∑ xᵢ

becomes an accumulator:

var total: Float64 = 0.0

followed by:

for i in range(len(values)):
total += values[i]

Then:

1 / n

becomes:

total / Float64(len(values))

Notice the explicit conversion:

Float64(len(values))

len(values) gives us an integer.

Our calculation produces a floating-point result.

The code therefore states the numerical representation explicitly.

This is one place where Mojo’s type system makes mathematical intent more visible.

The Empty Collection Problem

Suppose:

n = 0

Our formula would require division by zero.

So the average of an empty collection is undefined.

This would therefore be misleading:

if len(values) == 0:
return 0.0

Zero is not the average of an empty collection.

There simply is no average.

So instead we use:

raise Error("Average is undefined for an empty collection.")

Another useful rule follows:

Edge cases should follow the mathematical definition, not whatever value is convenient for the implementation.

Computing Variance

Variance measures how far values tend to spread from their mean.

First calculate the mean:

μ = (1 / n) × ∑ from i = 1 to n of xᵢ

Then calculate the population variance:

σ² = (1 / n) × ∑ from i = 1 to n of (xᵢ − μ)²

Mojo Implementation

def variance(values: List[Float64]) raises -> Float64:
if len(values) == 0:
raise Error("Variance is undefined for an empty collection.")
var total: Float64 = 0.0
for i in range(len(values)):
total += values[i]
var mean = total / Float64(len(values))
var squared_difference_sum: Float64 = 0.0
for i in range(len(values)):
var difference = values[i] - mean
squared_difference_sum += difference * difference
return squared_difference_sum / Float64(len(values))

Translating the Equation

Take this part:

(xᵢ − μ)²

The current value:

xᵢ

becomes:

values[i]

Subtract the mean:

xᵢ − μ

becomes:

var difference = values[i] - mean

Square the difference:

(xᵢ − μ)²

becomes:

difference * difference

The summation:

∑ (xᵢ − μ)²

becomes:

squared_difference_sum += difference * difference

And finally divide by n:

squared_difference_sum / Float64(len(values))

Population Variance vs Sample Variance

Small mathematical differences matter.

Population variance uses:

σ² = (1 / n) × ∑(xᵢ − μ)²

Sample variance usually uses:

s² = (1 / (n − 1)) × ∑(xᵢ − x̄)²

The implementation difference may appear tiny.

Population:

Float64(len(values))

Sample:

Float64(len(values) - 1)

But mathematically these represent different quantities.

This is exactly why specification matters.

A coding agent told:

Calculate variance.

has to make assumptions.

A coding agent given:

σ² = (1 / n) × ∑(xᵢ − μ)²

has much less room to guess.

The Bigger Lesson

At first these examples may look simple.

∏ becomes multiplication inside a loop.

∑ becomes accumulation.

xᵢ becomes an indexed value.

f(x) becomes a function.

But a more important idea underlies all of this.

We are learning to move through four layers:

Problem → Mathematical Model → Algorithm → Code

Most vibe coding jumps directly from:

Problem → AI-Generated Code

That works surprisingly often.

Until it doesn’t.

The problem is ambiguity.

Natural language might say:

Execute when everyone agrees.

We can express that more precisely.

Let:

P = {p₁, p₂, …, pₙ}

represent all participants.

Let:

A ⊆ P

represent the participants who have accepted.

Then we can define:

Ready(I) ⇔ A = P

In plain language:

The intent is ready exactly when the set of accepting participants equals the set of required participants.

Now add time:

Ready(I) ⇔ A = P AND t < expiry(I)

Now we have expressed two requirements:

  1. Everyone must accept.
  2. The intent must not have expired.

An AI coding agent can translate that into Mojo, Solidity, Rust, Python, TypeScript, or another language.

The implementation language can change.

The specification remains.

From Vibe Coding to Specification

This suggests a different way of thinking about AI-assisted software development.

Instead of:

Natural Language → Generated Code

we can use:

Natural Language → Mathematical Intent → Specification → Generated Code → Tests

The goal isn’t necessarily for every programmer to become a mathematician.

The goal is to understand enough mathematical language to describe software behaviour precisely.

Because the future skill may not be memorising every programming language’s syntax.

It may be something more fundamental:

Learning to express intent precisely enough that humans, machines, and proofs agree on what the program is supposed to do.


Programming Math for Vibe Coders. was originally published in Coinmonks on Medium, where people are continuing the conversation by highlighting and responding to this story.

Claude Isn’t Killing Bitcoin. It’s Exposing a Bigger Problem.

What increasingly capable AI means for Bitcoin security, crypto infrastructure, developers, and the future of cybersecurity

image generated by Chatgtp

On May 13, 2026, a post on X exploded across crypto Twitter with the kind of energy usually reserved for exchange collapses and ETF approvals.

A user going by the name @cprkrn claimed that Anthropic’s Claude had just “cracked” a Bitcoin wallet he’d been locked out of for nearly a decade. Five BTC worth roughly $400,000 at the time had been sitting dormant since 2015. The post racked up more than six million views within hours. The implication spreading across timelines was both thrilling and terrifying: if an AI can break Bitcoin cryptography, nothing in the blockchain is safe.

The story was wrong. And the correction is actually more interesting than the original claim.

What Actually Happened

The user had an old wallet backup buried somewhere on a hard drive from his college years. He’d forgotten the password. He’d tried commercial recovery services, brute-force tools like Hashcat, and open-source software called btcrecover spending around $15 in GPU compute on failed attempts over the years.

What Claude did, according to detailed accounts published by CoinDesk, Decrypt, and recovery specialists who reviewed the screenshots, was function as a digital forensic analyst. It helped the user search through years of archived computer files, identified an older wallet.dat backup that predated the password change, and found a one-line bug in the btcrecover tool where it was concatenating a shared key with the password in the wrong order.

The old backup. A password the owner had already written down. A recovery process that finally found the right path. That’s what unlocked the wallet.

Bitcoin’s underlying cryptography was not broken. The wallet was ultimately unlocked using a password the owner had already written down. The blockchain didn’t flinch.

But dismissing the story as pure hype misses the point. The interesting part is what Claude actually succeeded at: navigating a messy collection of old files and finding information the owner had lost track of. That capability matters far beyond one forgotten wallet.

What Bitcoin Actually Depends On

Before discussing the threat landscape, it’s worth being precise about what “breaking Bitcoin” would actually mean.

Bitcoin’s security rests on a set of mathematical properties. Private keys are large random numbers. Public keys are derived from them using elliptic curve cryptography. Digital signatures prove ownership without revealing the private key. Transactions are hashed and chained together in a structure that makes retroactive modification computationally impractical. Nodes across the network verify every transaction against consensus rules.

Breaking Bitcoin’s core cryptography would mean something specific: finding a private key from a public key, or forging a digital signature, or reversing a cryptographic hash. None of this happened in the wallet incident. No Bitcoin signature was forged, no private key was derived from a public key, and no cryptographic primitive was broken.

Claude didn’t come close to any of that. Finding a backup file is not the same problem as breaking elliptic curve cryptography. One is a file search with clever pattern recognition. The other is an open problem in mathematics that thousands of researchers haven’t solved.

The distinction matters because it changes what you should actually be worried about.

The Part Nobody Talks About: The Ecosystem Problem

Here’s where it gets genuinely uncomfortable.

Bitcoin’s core protocol has held up remarkably well as a cryptographic system. But users don’t interact with Bitcoin’s mathematical primitives directly. They interact with wallets, mobile apps, browser extensions, hardware devices, exchange accounts, recovery tools, signing software, developer libraries, cloud infrastructure, and a long chain of software dependencies that somebody built and somebody else is maintaining.

Every layer in that stack is human-built software. Human-built software contains bugs.

Think about it this way: the vault itself might be unbreakable. But the key management system, the backup process, the recovery tool, the wallet application, the browser extension, The vault can be extremely strong while the systems around it remain vulnerable: the key-management process, recovery tool, wallet application, browser extension, or exchange account.

Breaking the safe and finding the key under the doormat are entirely different operations. The May 2026 story was the second kind. Claude found the doormat. The safe remained closed.

The uncomfortable part of this is that most of what can go wrong with Bitcoin doesn’t require touching the underlying cryptography at all. Exchange hacks, phishing attacks, compromised wallet software, malicious browser extensions, and insecure key storage can cause serious financial losses without anyone breaking SHA-256

What Anthropic’s Research Actually Shows

Around the same time as the wallet recovery story, Anthropic was publishing something more quietly significant.

As of May 22, 2026, Anthropic’s coordinated vulnerability disclosure dashboard listed 1,596 vulnerabilities disclosed across 281 open-source projects, with 97 known to have been patched. Those disclosures followed independent human triage and review; the 1,596 figure represents only a subset of the vulnerabilities Mythos Preview identified.

Anthropic and its Project Glasswing partners identified more than 10,000 high- or critical-severity vulnerabilities in critical software systems. The full scan covered more than 1,000 open-source projects, flagging 23,019 potential issues, of which 6,202 were initially rated high or critical severity.

The Anthropic research also included a case study around CVE-2026–2796, a vulnerability in Firefox’s JavaScript engine. Claude Opus 4.6 found 22 vulnerabilities in Firefox over two weeks in collaboration with Mozilla, and as part of that work, Anthropic evaluated whether Claude could go further and write an exploit. The model succeeded but the context matters enormously. The exploit Claude wrote only works within a testing environment that intentionally removes some of the security features of modern web browsers. This was controlled security research, not a demonstration that Claude can compromise arbitrary real-world browsers on demand.

A separate July 2026 disclosure made the security discussion more concrete. Anthropic said three Claude models gained unauthorized access to systems belonging to three organizations during cybersecurity evaluations after a testing environment unexpectedly had internet access. The models exploited basic weaknesses rather than breaking advanced cryptography or relying on previously unknown vulnerabilities. The incident is important for a different reason: it showed how quickly a configuration mistake can turn an AI security test into contact with real systems.

Why 1,596 Vulnerabilities Is Interesting but Not 1,596 Attacks

Numbers like these tend to travel through security reporting in ways that lose important context.

A discovered vulnerability is not an exploited vulnerability. A reported vulnerability is not a patched vulnerability. A patched vulnerability is not a deployed patch. Each step in that chain requires human effort, coordination, and time and the chain is longer than most people assume.

Many vulnerabilities, when examined closely, turn out to be:

  • Difficult or impractical to exploit from a real attacker’s position
  • Already mitigated by other security controls in the system
  • Dependent on a very specific combination of conditions that rarely occur in practice
  • Patched quickly once reported, before any attacker finds them independently

Each vulnerability report still needs human review. Researchers have to reproduce the issue, rate its severity, check whether a fix already exists, and give maintainers enough detail to repair the code safely.

What the numbers clearly show is the scale of AI-assisted vulnerability discovery across large software ecosystems. Whether that discovery translates into improved security or increased exposure depends almost entirely on what happens next.

The Speed Problem

This is where the analysis gets harder.

Historically, finding vulnerabilities in complex software required specialized knowledge, patience, access to source code or binaries, manual code review, and often years of experience in a particular kind of system. The barrier wasn’t just skill it was time.

AI is compressing that timeline. Not to zero, and not uniformly across all vulnerability types. But meaningfully.

As Anthropic noted in its Project Glasswing update, finding vulnerabilities has become vastly more straightforward with Mythos Preview. The bottleneck in fixing bugs is now the human capacity to triage, report, design patches, and deploy them.

This creates a race condition that the security community is only beginning to reckon with.

On the defensive side, the race looks like this: AI-assisted discovery → human validation → responsible disclosure → maintainer notification → patch development → patch deployment → user update. Every step after “AI-assisted discovery” still runs at human speed.

On the offensive side, the risk is that the same discovery capabilities that help researchers find vulnerabilities also help adversaries find them potentially before defenders know they exist, and potentially before patches can be developed and distributed.

For crypto and DeFi infrastructure, this matters specifically because the software stack is large, often under-maintained, and financially incentivized as a target. Wallet libraries, exchange backends, signing tools, RPC endpoints, bridge contracts any weakness in these systems represents a potential path to funds, and the rewards for finding that path are substantial.

The Developer Angle: AI-Generated Code

There’s a second-order problem that deserves its own discussion.

Developers are increasingly writing software using AI assistants. Claude, GitHub Copilot, Cursor, and similar tools generate large amounts of code that gets reviewed, adapted, and shipped. This is useful. It also creates a specific class of risk.

AI models can generate code that looks correct and passes initial review but contains subtle security issues: incorrect cryptographic library usage, unsafe handling of secrets, missing input validation, authentication logic that works in the common case but fails at edges, dependency choices that introduce known vulnerabilities.

A development team using AI to build crypto infrastructure while AI is simultaneously being used to find vulnerabilities in that infrastructure is operating in a narrowing window. The generation and discovery capabilities are developing in parallel, and the margin for unreviewed code reaching production is shrinking.

This doesn’t mean AI-generated code is categorically insecure. Plenty of human-written code contains the same types of problems. The difference is that AI can generate large volumes of code quickly, which means errors can propagate widely before anyone catches them.

What Claude Has NOT Done

Given the title of this article, it’s worth being explicit.

The evidence discussed here does not show that Claude has:

  • Broken Bitcoin’s SHA-256 hashing
  • Broken the elliptic curve cryptography underlying Bitcoin’s digital signatures
  • Defeated Bitcoin’s proof-of-work consensus mechanism
  • Made the Bitcoin blockchain invalid or reversible
  • Cracked any Bitcoin wallet by attacking the underlying cryptographic primitives
  • Demonstrated the ability to freely compromise arbitrary real-world systems

The May 2026 wallet story was AI-assisted digital forensics locating an existing backup and fixing a bug in a recovery tool. The CVE-2026–2796 exploit worked only in a deliberately weakened test environment. The 1,596 disclosed vulnerabilities reflect findings that still required human review, triage, and disclosure before any of them reached the public.

The concerning developments are real. They just aren’t what the viral headlines described.

What Developers and Users Should Actually Do

For developers building on or around crypto infrastructure, the practical response to this threat landscape is less dramatic than the coverage suggests, but it does require more rigor than was comfortable a few years ago.

Keep dependencies updated and use automated scanning tools to track CVEs in your dependency tree. Review security-critical code manually, especially anything touching key management, signing flows, transaction construction, or secret handling. Use static analysis. Monitor security advisories for libraries you depend on. Protect CI/CD systems a compromised build pipeline is a more practical attack surface than breaking any cryptographic primitive. Where significant funds are involved, prefer hardware-backed security. Test your signing flows thoroughly. Maintain an incident response plan.

Treat AI-generated security-critical code with the same skepticism you’d apply to code from an external contributor you don’t know well. Verify the logic, not just the syntax.

For ordinary Bitcoin and crypto users, the advice is more straightforward.

Use reputable, widely-audited wallets. Store seed phrases and private keys offline, written on paper in a secure physical location. Never upload a seed phrase, private key, wallet file, or recovery phrase to an AI chatbot or any online service not Claude, not ChatGPT, not anything. The wallet recovery story worked because the user had already-owned credentials. Giving those credentials to an AI service creates a new exposure that didn’t exist before. Use hardware wallets for significant holdings. Enable strong account security everywhere. Verify software downloads against official sources. Keep your devices updated.

The Actual Problem Being Exposed

Claude isn’t killing Bitcoin. Bitcoin’s underlying mathematics hasn’t changed. Private keys derived from strong entropy are no easier to find than they were five years ago.

What is changing is the cost and speed of finding weaknesses in the software infrastructure that surrounds the mathematics. Wallets, exchanges, libraries, recovery tools, browser extensions, APIs the ecosystem built on top of the cryptographic foundation is large, complex, and maintained by a relatively small number of developers who are now operating in a security environment that moves faster than it used to.

The wolfSSL vulnerability found by Mythos Preview is a useful example. wolfSSL is an open-source cryptography library used in a wide range of software and embedded systems. A flaw in that library doesn’t break the underlying mathematics of cryptography. It creates a practical path to harm through the software that implements cryptographic operations, rather than through the mathematical operations themselves. That’s a meaningful distinction, and it’s the one that deserves attention.

The trajectory is clear enough that drawing conclusions about the next several years isn’t difficult. AI will continue improving at reading unfamiliar codebases, tracing data flows, identifying patterns that precede vulnerabilities, and generating test cases. The researchers using these tools will find more problems faster. The developers writing new code with AI assistance will introduce new problems that also get found faster. The race between discovery and remediation will tighten.

The weakest link in most secure systems has rarely been the mathematics at the center. It’s been the software built around it, the processes used to operate it, and the humans making decisions about both. That observation isn’t new. What’s new is the speed at which the gap between “weakness exists” and “weakness is found” is narrowing.

Bitcoin’s cryptography is holding. The question is whether everything humans have built around it can keep up.


Claude Isn’t Killing Bitcoin. It’s Exposing a Bigger Problem. was originally published in Coinmonks on Medium, where people are continuing the conversation by highlighting and responding to this story.

❌