惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

U
Unit 42
K
Kaspersky official blog
L
LangChain Blog
有赞技术团队
有赞技术团队
V
Visual Studio Blog
T
The Blog of Author Tim Ferriss
Microsoft Azure Blog
Microsoft Azure Blog
Stack Overflow Blog
Stack Overflow Blog
美团技术团队
Vercel News
Vercel News
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
G
Google Developers Blog
宝玉的分享
宝玉的分享
月光博客
月光博客
爱范儿
爱范儿
The Register - Security
The Register - Security
S
SegmentFault 最新的问题
M
MIT News - Artificial intelligence
F
Full Disclosure
Engineering at Meta
Engineering at Meta
阮一峰的网络日志
阮一峰的网络日志
Hugging Face - Blog
Hugging Face - Blog
A
About on SuperTechFans
WordPress大学
WordPress大学
D
Docker
Y
Y Combinator Blog
N
News and Events Feed by Topic
P
Proofpoint News Feed
Apple Machine Learning Research
Apple Machine Learning Research
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Recorded Future
Recorded Future
IT之家
IT之家
C
CXSECURITY Database RSS Feed - CXSecurity.com
Security Latest
Security Latest
Spread Privacy
Spread Privacy
D
Darknet – Hacking Tools, Hacker News & Cyber Security
F
Fortinet All Blogs
AWS News Blog
AWS News Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
P
Proofpoint News Feed
C
CERT Recently Published Vulnerability Notes
D
DataBreaches.Net
Recent Announcements
Recent Announcements
博客园 - Franky
Google DeepMind News
Google DeepMind News
小众软件
小众软件
B
Blog RSS Feed
I
InfoQ
Attack and Defense Labs
Attack and Defense Labs
云风的 BLOG
云风的 BLOG

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
How AI Can Help You Recover Your Bitcoin
David Au Yeu · 2026-05-16 · via DEV Community

Introduction

When people talk about Artificial Intelligence today, the conversation usually revolves around chatbots, image generators, coding assistants, or office productivity.

But a recent news shared by Yahoo!Tech caught my attention for a very different reason.

According to the report, an X user known as cprkrn claimed that after being locked out of his Bitcoin wallet for 11 years, he finally recovered access with the help of Claude AI.

The wallet reportedly contained 5 BTC. Based on the approximate market price mentioned in the report, that was worth more than HKD 3 million.

The interesting part was not that AI "hacked Bitcoin".

It did not.

Instead, the user reportedly had:

  • An old computer
  • Old wallet files
  • Some forgotten notes
  • A seed phrase
  • A long-forgotten password pattern
  • Many years of messy digital history

AI helped connect the dots.

This is not a story about breaking cryptography.

It is a story about AI-assisted memory reconstruction.

And that opens up a powerful idea:

AI may not break encryption, but it can help us rediscover the human context around things we forgot.

This article explores:

  • How AI can reduce password search space
  • Why this is different from brute force cracking
  • How old notes can become useful signals
  • How to build a safe educational C# demo
  • How to use Ollama and Kimi as the LLM engine
  • Why privacy and ethics matter

Important:

This project is for education and simulation only.

It does not recover real Bitcoin wallets.

It does not parse real wallet.dat files.

It does not crack encryption.

It must not be used against anyone else’s accounts, wallets, devices, or data.

What Actually Happened Conceptually

The reported Bitcoin recovery story can be understood like this:

Old computer files
    ↓
Old wallet file discovered
    ↓
Old notes and memory fragments analyzed
    ↓
Possible password patterns reconstructed
    ↓
Seed phrase / wallet artifacts matched
    ↓
Wallet access recovered

Enter fullscreen mode Exit fullscreen mode

The important distinction is this:

AI did not defeat Bitcoin cryptography.
AI helped organize messy human memory.

Enter fullscreen mode Exit fullscreen mode

Bitcoin itself relies on strong cryptographic systems.

But humans often create passwords based on:

  • Emotions
  • Old events
  • Favorite words
  • Personal habits
  • Dates
  • Naming formats
  • Repeated patterns

That is where AI becomes useful.

Brute Force vs AI-Assisted Reasoning

A brute force approach looks like this:

Try every possible combination.
Try millions, billions, or trillions of passwords.
Hope one works.

Enter fullscreen mode Exit fullscreen mode

This is expensive, slow, and usually unrealistic.

AI-assisted reasoning works differently.

Instead of attacking the encryption directly, it attacks the uncertainty around the human-created password.

It looks for clues such as:

  • Old notes
  • Diary fragments
  • File names
  • Repeated words
  • Emotional context
  • Important years
  • Formatting habits
  • Common personal patterns

So the workflow becomes:

Messy notes
    ↓
LLM analysis
    ↓
Ranked password candidates
    ↓
Local verification

Enter fullscreen mode Exit fullscreen mode

That last step is important.

The LLM should generate candidates.

The actual verification should happen locally.

The Sample Exercise

For this article, we will create a safe simulation.

We will pretend that we found two old text files from an old computer:

old_notes.txt
diary_fragment.txt

Enter fullscreen mode Exit fullscreen mode

These files contain clues.

The hidden mock password will be:

memory_police_2014

Enter fullscreen mode Exit fullscreen mode

But in a real recovery situation, we would not know that.

The goal of the demo is to see whether an LLM can infer likely candidates from the notes.

Sample File 1: old_notes.txt

2014 - bought BTC when it was around 230 USD
Used police story as password theme before
Memory + river + sunset were words I liked back then
Laptop password had underscore format
Sometimes I append the year to important accounts

Enter fullscreen mode Exit fullscreen mode

Sample File 2: diary_fragment.txt

Can't believe I finally bought Bitcoin.
Police documentary inspired me that week.
Maybe I should combine memory and police somehow.
Don't forget 2014 was important.

Enter fullscreen mode Exit fullscreen mode

These notes are simple, but they contain strong human signals:

Clue Possible Meaning
memory likely password word
police likely password word
2014 likely suffix
underscore format likely separator
"combine memory and police" likely word order
BTC price 230 possible alternative suffix

A human might miss the pattern.

An LLM can rank it immediately.

The Prompt We Give to the LLM

Here is the kind of prompt we will send to the model:

You are assisting in a password reconstruction exercise for a simulated wallet recovery.

This is an educational exercise using fake data.
The wallet is a local mock wallet owned by the user.

Your task:
1. Read the recovered historical notes.
2. Identify recurring words, themes, years, and formatting habits.
3. Generate 15 structured password candidates ranked by likelihood.
4. Prefer underscore separators if the notes suggest that style.
5. Consider important years or numbers as suffixes.
6. Do not brute force.
7. Do not generate random unrelated strings.
8. Return JSON only.

Recovered notes:

[old_notes.txt and diary_fragment.txt content here]

Enter fullscreen mode Exit fullscreen mode

The key idea is:

Do not ask the model to crack anything.
Ask the model to reason from context.

Enter fullscreen mode Exit fullscreen mode

Example LLM Result

In my test using Kimi through Ollama, the model generated a ranked candidate list similar to this:

Rank Password Candidate Rationale
1 memory_police_2014 Direct use of "combine memory and police" + underscore + year
2 police_memory_2014 Reverse order variation
3 memory_river_sunset Uses three liked words
4 police_story_2014 Police story theme + year
5 river_sunset_memory Alternative ordering of liked words
6 memory_documentary_2014 Memory + documentary clue
7 memory_river_2014 Liked word + year
8 sunset_memory_2014 Liked word + year
9 police_river_2014 Cross-combination
10 river_memory_2014 Alternative pair
11 police_sunset_2014 Cross-combination
12 memory_2014 Minimal pattern
13 police_memory_230 Uses BTC price clue
14 memory_police_230 Price-based variation
15 sunset_river_2014 Nature-themed pair + year

The important thing is not the exact output.

The important thing is that the model did not generate random strings like:

xJ9#qPz882!

Enter fullscreen mode Exit fullscreen mode

Instead, it generated human-plausible candidates from the notes.

That is the value of AI here.

Demo Architecture

Our safe simulation looks like this:

old_notes.txt
diary_fragment.txt
        ↓
Ollama + Kimi model
        ↓
JSON password candidates
        ↓
Local mock wallet verifier
        ↓
Success / failure result

Enter fullscreen mode Exit fullscreen mode

The LLM only sees the notes.

It does not receive:

  • A real wallet file
  • A private key
  • A seed phrase
  • A real password hash
  • A real Bitcoin address

The verification happens locally inside our C# program.

This is safer and cleaner

Technical Setup

This demo uses OllamaApiClient from OllamaSharp. OllamaSharp documents GenerateAsync for single-turn completions and the Chat class for conversational workflows; Ollama’s own API documentation also describes /api/generate and /api/chat streaming endpoints. (awaescher.github.io)

Create a new console app:

dotnet new console -n AiWalletRecoveryDemo
cd AiWalletRecoveryDemo
dotnet add package OllamaSharp

Enter fullscreen mode Exit fullscreen mode

Make sure your Ollama endpoint is running at:

http://localhost:11434

Enter fullscreen mode Exit fullscreen mode

The sample code defaults to:

string modelName = "kimi-k2.6:cloud";

Enter fullscreen mode Exit fullscreen mode

If you used another model, such as kimi-k2.5, pass it as an argument:

dotnet run -- kimi-k2.5

Enter fullscreen mode Exit fullscreen mode

Project Structure

AiWalletRecoveryDemo/
│
├── AiWalletRecoveryDemo.csproj
├── Program.cs
│
└── sample-data/
    ├── old_notes.txt
    ├── diary_fragment.txt
    └── mock_wallet.json

Enter fullscreen mode Exit fullscreen mode

The program will create the sample files automatically if they do not exist.

Full Educational C# Example

Program.cs

using OllamaSharp;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;

internal static class Program
{
    // Educational only:
    // In a real recovery situation, you would NOT know this value.
    // We use it only to create a local mock wallet verifier.
    private const string DemoPassword = "memory_police_2014";

    public static async Task Main(string[] args)
    {
        Console.OutputEncoding = Encoding.UTF8;

        string modelName = args.Length > 0 ? args[0] : "kimi-k2.6:cloud";
        string ollamaApiUrl = args.Length > 1 ? args[1] : "http://localhost:11434";

        string dataDirectory = Path.Combine(Directory.GetCurrentDirectory(), "sample-data");
        string mockWalletPath = Path.Combine(dataDirectory, "mock_wallet.json");

        Console.WriteLine("AI-Assisted Wallet Recovery Simulation");
        Console.WriteLine("---------------------------------------");
        Console.WriteLine($"Ollama URL : {ollamaApiUrl}");
        Console.WriteLine($"Model      : {modelName}");
        Console.WriteLine();

        DemoData.EnsureCreated(dataDirectory, DemoPassword);

        string recoveredNotes = DemoData.ReadAllNotes(dataDirectory);
        var mockWallet = MockWalletVault.Load(mockWalletPath);

        var generator = new OllamaCandidateGenerator(
            ollamaApiUrl: ollamaApiUrl,
            modelName: modelName,
            wikiRootDirectory: dataDirectory);

        IReadOnlyList<PasswordCandidate> candidates;

        try
        {
            candidates = await generator.GenerateCandidatesAsync(recoveredNotes);
        }
        catch (Exception ex)
        {
            Console.WriteLine("LLM generation failed.");
            Console.WriteLine($"Reason: {ex.Message}");
            Console.WriteLine();
            Console.WriteLine("Using deterministic fallback candidates for demo continuity.");
            Console.WriteLine();

            candidates = FallbackCandidateGenerator.Generate();
        }

        var uniqueCandidates = candidates
            .Where(c => !string.IsNullOrWhiteSpace(c.Password))
            .Select(c => c with { Password = c.Password.Trim() })
            .GroupBy(c => c.Password, StringComparer.Ordinal)
            .Select((g, index) => g.First() with { Rank = index + 1 })
            .Take(25)
            .ToList();

        Console.WriteLine("Ranked Password Candidates");
        Console.WriteLine("--------------------------");

        foreach (var candidate in uniqueCandidates)
        {
            Console.WriteLine($"#{candidate.Rank}: {candidate.Password}");
            Console.WriteLine($"    Reason: {candidate.Rationale}");
        }

        Console.WriteLine();
        Console.WriteLine("Testing candidates against local mock wallet...");
        Console.WriteLine();

        PasswordCandidate? successfulCandidate = null;

        foreach (var candidate in uniqueCandidates)
        {
            bool isMatch = mockWallet.Verify(candidate.Password);

            if (isMatch)
            {
                successfulCandidate = candidate;
                break;
            }
        }

        if (successfulCandidate is not null)
        {
            Console.WriteLine($"✅ Mock wallet unlocked with candidate #{successfulCandidate.Rank}:");
            Console.WriteLine(successfulCandidate.Password);
        }
        else
        {
            Console.WriteLine("❌ No candidate unlocked the mock wallet.");
            Console.WriteLine("Try adding more historical notes or stronger clues.");
        }

        Console.WriteLine();
        Console.WriteLine("Simulation complete.");
    }
}

public sealed class OllamaCandidateGenerator
{
    private readonly OllamaApiClient _ollamaClient;
    private readonly string _wikiRootDirectory;

    public OllamaCandidateGenerator(
        string ollamaApiUrl = "http://localhost:11434",
        string modelName = "kimi-k2.6:cloud",
        string? wikiRootDirectory = null)
    {
        _ollamaClient = new OllamaApiClient(new Uri(ollamaApiUrl))
        {
            SelectedModel = modelName
        };

        _wikiRootDirectory = wikiRootDirectory ?? Directory.GetCurrentDirectory();
    }

    public async Task<IReadOnlyList<PasswordCandidate>> GenerateCandidatesAsync(
        string recoveredNotes,
        CancellationToken cancellationToken = default)
    {
        string prompt = BuildPrompt(recoveredNotes);

        var responseBuilder = new StringBuilder();

        await foreach (var stream in _ollamaClient.GenerateAsync(
            prompt,
            context: null,
            cancellationToken: cancellationToken))
        {
            if (!string.IsNullOrEmpty(stream?.Response))
            {
                responseBuilder.Append(stream.Response);
            }
        }

        string rawResponse = responseBuilder.ToString();

        var candidates = ParseCandidates(rawResponse);

        if (candidates.Count == 0)
        {
            throw new InvalidOperationException(
                "The model did not return valid password candidates.");
        }

        return candidates;
    }

    private string BuildPrompt(string recoveredNotes)
    {
        return $$"""
You are assisting in a password reconstruction exercise for a simulated wallet recovery.

This is an educational exercise using fake data.
The mock wallet belongs to the user.
Do not provide hacking instructions.
Do not suggest brute force tools.
Do not suggest unauthorized access.
Do not generate random unrelated strings.

Your task:
1. Read the recovered historical notes.
2. Identify recurring words, themes, dates, numbers, and formatting habits.
3. Generate exactly 15 structured password candidates ranked by likelihood.
4. Prefer underscore separators if the notes suggest that style.
5. Consider important years or numbers as suffixes.
6. Prefer candidates that follow explicit diary wording.
7. Return valid JSON only.
8. Do not wrap the JSON in Markdown.

Return this JSON shape:

{
  "candidates": [
    {
      "rank": 1,
      "password": "example_candidate",
      "rationale": "Short explanation"
    }
  ]
}

Recovered notes:

{{recoveredNotes}}
""";
    }

    private static IReadOnlyList<PasswordCandidate> ParseCandidates(string rawResponse)
    {
        string json = ExtractJsonObject(rawResponse);

        var options = new JsonSerializerOptions
        {
            PropertyNameCaseInsensitive = true
        };

        var parsed = JsonSerializer.Deserialize<CandidateResponse>(json, options);

        return parsed?.Candidates?
            .OrderBy(c => c.Rank)
            .ToList()
            ?? new List<PasswordCandidate>();
    }

    private static string ExtractJsonObject(string text)
    {
        string cleaned = text.Trim();

        cleaned = Regex.Replace(
            cleaned,
            "^```
{% endraw %}
(?:json)?\\s*",
            "",
            RegexOptions.IgnoreCase);

        cleaned = Regex.Replace(
            cleaned,
            "\\s*
{% raw %}
```$",
            "",
            RegexOptions.IgnoreCase);

        int start = cleaned.IndexOf('{');
        int end = cleaned.LastIndexOf('}');

        if (start < 0 || end <= start)
        {
            throw new FormatException("No JSON object found in model response.");
        }

        return cleaned.Substring(start, end - start + 1);
    }
}

public sealed record PasswordCandidate
{
    [JsonPropertyName("rank")]
    public int Rank { get; init; }

    [JsonPropertyName("password")]
    public string Password { get; init; } = "";

    [JsonPropertyName("rationale")]
    public string Rationale { get; init; } = "";
}

public sealed class CandidateResponse
{
    [JsonPropertyName("candidates")]
    public List<PasswordCandidate> Candidates { get; set; } = new();
}

public sealed class MockWalletVault
{
    private static readonly JsonSerializerOptions JsonOptions = new()
    {
        WriteIndented = true,
        PropertyNameCaseInsensitive = true
    };

    [JsonPropertyName("description")]
    public string Description { get; set; } =
        "Educational mock wallet. This is not a real Bitcoin wallet.";

    [JsonPropertyName("saltBase64")]
    public string SaltBase64 { get; set; } = "";

    [JsonPropertyName("passwordHashBase64")]
    public string PasswordHashBase64 { get; set; } = "";

    public static MockWalletVault CreateFromPassword(string password)
    {
        byte[] salt = RandomNumberGenerator.GetBytes(16);
        byte[] hash = HashPassword(password, salt);

        return new MockWalletVault
        {
            SaltBase64 = Convert.ToBase64String(salt),
            PasswordHashBase64 = Convert.ToBase64String(hash)
        };
    }

    public static MockWalletVault Load(string path)
    {
        string json = File.ReadAllText(path);

        return JsonSerializer.Deserialize<MockWalletVault>(json, JsonOptions)
            ?? throw new InvalidOperationException("Unable to load mock wallet.");
    }

    public void Save(string path)
    {
        string json = JsonSerializer.Serialize(this, JsonOptions);
        File.WriteAllText(path, json);
    }

    public bool Verify(string candidatePassword)
    {
        byte[] salt = Convert.FromBase64String(SaltBase64);
        byte[] expectedHash = Convert.FromBase64String(PasswordHashBase64);
        byte[] actualHash = HashPassword(candidatePassword, salt);

        return CryptographicOperations.FixedTimeEquals(actualHash, expectedHash);
    }

    private static byte[] HashPassword(string password, byte[] salt)
    {
        // Educational local verifier.
        // This is not Bitcoin Core wallet encryption.
        using var pbkdf2 = new Rfc2898DeriveBytes(
            password,
            salt,
            iterations: 100_000,
            hashAlgorithm: HashAlgorithmName.SHA256);

        return pbkdf2.GetBytes(32);
    }
}

public static class DemoData
{
    private const string OldNotesFileName = "old_notes.txt";
    private const string DiaryFileName = "diary_fragment.txt";
    private const string MockWalletFileName = "mock_wallet.json";

    private const string OldNotesText = """
2014 - bought BTC when it was around 230 USD
Used police story as password theme before
Memory + river + sunset were words I liked back then
Laptop password had underscore format
Sometimes I append the year to important accounts
""";

    private const string DiaryFragmentText = """
Can't believe I finally bought Bitcoin.
Police documentary inspired me that week.
Maybe I should combine memory and police somehow.
Don't forget 2014 was important.
""";

    public static void EnsureCreated(string dataDirectory, string demoPassword)
    {
        Directory.CreateDirectory(dataDirectory);

        string oldNotesPath = Path.Combine(dataDirectory, OldNotesFileName);
        string diaryPath = Path.Combine(dataDirectory, DiaryFileName);
        string mockWalletPath = Path.Combine(dataDirectory, MockWalletFileName);

        if (!File.Exists(oldNotesPath))
        {
            File.WriteAllText(oldNotesPath, OldNotesText);
        }

        if (!File.Exists(diaryPath))
        {
            File.WriteAllText(diaryPath, DiaryFragmentText);
        }

        if (!File.Exists(mockWalletPath))
        {
            var wallet = MockWalletVault.CreateFromPassword(demoPassword);
            wallet.Save(mockWalletPath);
        }
    }

    public static string ReadAllNotes(string dataDirectory)
    {
        var builder = new StringBuilder();

        foreach (string file in Directory
            .EnumerateFiles(dataDirectory, "*.txt", SearchOption.AllDirectories)
            .OrderBy(f => f))
        {
            builder.AppendLine($"--- {Path.GetFileName(file)} ---");
            builder.AppendLine(File.ReadAllText(file));
            builder.AppendLine();
        }

        return builder.ToString();
    }
}

public static class FallbackCandidateGenerator
{
    public static IReadOnlyList<PasswordCandidate> Generate()
    {
        return new List<PasswordCandidate>
        {
            new()
            {
                Rank = 1,
                Password = "memory_police_2014",
                Rationale = "Direct implementation of diary note: combine memory and police, underscore format, year suffix."
            },
            new()
            {
                Rank = 2,
                Password = "police_memory_2014",
                Rationale = "Reverse order variation using the same strong clues."
            },
            new()
            {
                Rank = 3,
                Password = "memory_river_sunset",
                Rationale = "Uses three liked words with underscore formatting."
            },
            new()
            {
                Rank = 4,
                Password = "police_story_2014",
                Rationale = "References previous police story theme and important year."
            },
            new()
            {
                Rank = 5,
                Password = "river_sunset_memory",
                Rationale = "Alternative ordering of liked words."
            },
            new()
            {
                Rank = 6,
                Password = "memory_documentary_2014",
                Rationale = "Combines memory with police documentary clue and year."
            },
            new()
            {
                Rank = 7,
                Password = "memory_river_2014",
                Rationale = "Liked word pair plus year suffix."
            },
            new()
            {
                Rank = 8,
                Password = "sunset_memory_2014",
                Rationale = "Liked word combination plus year."
            },
            new()
            {
                Rank = 9,
                Password = "police_river_2014",
                Rationale = "Cross-combination of police theme, liked word, and year."
            },
            new()
            {
                Rank = 10,
                Password = "river_memory_2014",
                Rationale = "Alternative liked word pair plus year."
            },
            new()
            {
                Rank = 11,
                Password = "police_sunset_2014",
                Rationale = "Cross-combination of police theme, liked word, and year."
            },
            new()
            {
                Rank = 12,
                Password = "memory_2014",
                Rationale = "Minimal pattern using important word and year."
            },
            new()
            {
                Rank = 13,
                Password = "police_memory_230",
                Rationale = "Uses BTC price clue instead of year."
            },
            new()
            {
                Rank = 14,
                Password = "memory_police_230",
                Rationale = "Price-based variation of the strongest phrase."
            },
            new()
            {
                Rank = 15,
                Password = "sunset_river_2014",
                Rationale = "Nature-themed pair plus year suffix."
            }
        };
    }
}

Enter fullscreen mode Exit fullscreen mode

Example Output

Your result may vary depending on the model, but a successful run may look like this:

This is exactly the concept we want to demonstrate.

The model does not break encryption.

It simply turns messy personal history into a ranked list of likely hypotheses.

What AI Actually Contributes

The difference between brute force and AI reasoning is not magic.

It is context.

Brute force says:

Try everything.

Enter fullscreen mode Exit fullscreen mode

AI-assisted reasoning says:

Try what the human was most likely to create.

Enter fullscreen mode Exit fullscreen mode

In this exercise, the LLM extracted:

Signal Extracted Insight
memory important word
police important theme
combine memory and police likely word pairing
underscore format separator style
2014 likely suffix
BTC price 230 alternative numeric suffix
diary wording word order clue

This changes the search problem from:

Trillions of random guesses

Enter fullscreen mode Exit fullscreen mode

to:

15 structured candidates

Enter fullscreen mode Exit fullscreen mode

That is the power.

AI reduces chaos.

Why This Is Not "AI Cracking Bitcoin"

This point is very important.

Bitcoin was not broken.

Cryptography was not defeated.

The AI did not discover a private key from the blockchain.

The AI did not reverse SHA-256.

The AI did not bypass wallet encryption.

Instead, the AI helped with:

  • Pattern recognition
  • File interpretation
  • Note summarization
  • Candidate ranking
  • Human memory reconstruction

That is a completely different category.

A good analogy is this:

Encryption is the locked safe.
AI helps you search your old notebooks for the combination.

Enter fullscreen mode Exit fullscreen mode

The safe is still strong.

The weakness is human memory.

Privacy Warning

This is where we need to be careful.

If you use a cloud model, do not upload:

  • Real seed phrases
  • Private keys
  • Real wallet files
  • Password databases
  • Full disk images
  • Sensitive personal documents

Even if your intention is legitimate, sending secrets to a cloud model can create serious privacy risk.

A safer workflow is:

Sensitive file stays local
    ↓
You extract non-secret clues
    ↓
LLM generates candidate ideas
    ↓
Verification happens locally

Enter fullscreen mode Exit fullscreen mode

For example, instead of sending this:

seed phrase: apple apple apple ...
wallet.dat file attached

Enter fullscreen mode Exit fullscreen mode

Send only sanitized hints like:

I often used words related to memory, police, river, and 2014.
I used underscores in passwords at that time.

Enter fullscreen mode Exit fullscreen mode

The LLM should help with reasoning.

It should not become a place where secrets are stored.

How This Pattern Applies Beyond Bitcoin

This same AI-assisted recovery pattern can apply to many areas:

  • Old encrypted ZIP archives
  • Forgotten developer keystores
  • Legacy configuration files
  • Personal knowledge archives
  • Digital estate planning
  • Old project recovery
  • Family photo backup restoration
  • Enterprise documentation reconstruction

The common pattern is:

Messy historical data
    ↓
AI-assisted organization
    ↓
Ranked hypotheses
    ↓
Local verification

Enter fullscreen mode Exit fullscreen mode

This is why I find the story so interesting.

It shows AI being used not as a chatbot, but as a digital archaeologist.

Security Lessons

There is also a defensive lesson here.

If AI can infer human password patterns from old notes, then we should avoid creating passwords from personal context.

Better practices:

  • Use a password manager
  • Use long random passwords
  • Avoid emotional or memorable phrases
  • Avoid years, birthdays, and repeated themes
  • Do not store seed phrases digitally
  • Use hardware wallets for serious crypto storage
  • Keep offline backups in physically secure locations
  • Separate password hints from actual recovery material

Human-style passwords are easy to remember.

That is exactly why they can be guessed.

Conclusion

The reported Bitcoin recovery story is not about AI defeating cryptography.

It is about AI helping a person reconstruct forgotten context.

That may become one of AI's most underrated uses.

Not replacing humans.

Not magically solving everything.

But helping us search, organize, and reason through the complexity we created over years of digital life.

In this demo, we used:

  • Old notes
  • A diary fragment
  • Ollama
  • Kimi
  • C#
  • A local mock wallet verifier

And we simulated the same core idea safely:

Forgotten memory → AI reasoning → candidate ranking → local verification

Enter fullscreen mode Exit fullscreen mode

The future of AI may not only be automation.

It may also be recovery.

Recovering old knowledge.

Recovering lost context.

Recovering forgotten work.

Recovering what we once knew but could no longer find.

AI did not break the lock.

It helped us remember where we left the key.

References

  • OllamaSharp documentation for GenerateAsync, Chat, and OllamaApiClient. (awaescher.github.io)
  • Ollama API documentation for /api/generate and /api/chat. (github.com)

Love C# & AI!

Learn more:

  1. Chat and Generate | OllamaSharp
  2. ollama/docs/api.md at main · ollama/ollama · GitHub