<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: g.okc</title>
    <description>The latest articles on DEV Community by g.okc (@gustavo89587).</description>
    <link>https://dev.to/gustavo89587</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3991621%2F12912b9e-0692-4573-ab16-5b1148b0e07f.png</url>
      <title>DEV Community: g.okc</title>
      <link>https://dev.to/gustavo89587</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gustavo89587"/>
    <language>en</language>
    <item>
      <title>Harvest Now, Decrypt Later: Why Your Encrypted Data Is Already At Risk</title>
      <dc:creator>g.okc</dc:creator>
      <pubDate>Tue, 30 Jun 2026 14:00:04 +0000</pubDate>
      <link>https://dev.to/gustavo89587/harvest-now-decrypt-later-why-your-encrypted-data-is-already-at-risk-341o</link>
      <guid>https://dev.to/gustavo89587/harvest-now-decrypt-later-why-your-encrypted-data-is-already-at-risk-341o</guid>
      <description>&lt;p&gt;Most engineers think quantum computing is a future problem. It isn't — it's a present problem with a future trigger.&lt;/p&gt;

&lt;p&gt;The attack that's already happening&lt;/p&gt;

&lt;p&gt;"Harvest Now, Decrypt Later" (HNDL) is not theoretical. Nation-state actors and sophisticated threat groups are already capturing encrypted traffic today — TLS sessions, VPN tunnels, encrypted backups — and storing it. They don't need to break the encryption now. They just need to wait.&lt;/p&gt;

&lt;p&gt;When a sufficiently powerful quantum computer arrives — estimates range from 8 to 15 years — every RSA and ECDSA-encrypted payload captured today becomes readable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Today:        [Encrypted data] → Captured and stored by adversary
+10 years:     Quantum computer breaks RSA-2048
Result:        All captured data from today is now plaintext

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means data encrypted right now with RSA-2048 or ECDSA has an expiration date on its confidentiality — and that date is not decided by you.&lt;/p&gt;

&lt;p&gt;Why this matters more than people think&lt;/p&gt;

&lt;p&gt;Most threat models assume "if it's encrypted, it's safe." HNDL breaks that assumption for any data with a long confidentiality requirement:&lt;/p&gt;

&lt;p&gt;Healthcare records (often need 50+ years of confidentiality)&lt;br&gt;
Government and military communications&lt;br&gt;
Financial transaction histories&lt;br&gt;
Legal and contractual records&lt;br&gt;
Audit logs that need to remain verifiable for compliance&lt;/p&gt;

&lt;p&gt;If your data needs to stay confidential for more than a decade, it's already vulnerable — today, not in the future.&lt;/p&gt;

&lt;p&gt;What NIST is doing about it&lt;/p&gt;

&lt;p&gt;NIST finalized three post-quantum cryptography standards in 2024:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv3kb5wyoe5yc37wm49x1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv3kb5wyoe5yc37wm49x1.png" alt=" " width="777" height="262"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These are lattice-based and hash-based algorithms believed to be resistant to attacks from both classical and quantum computers.&lt;/p&gt;
&lt;h2&gt;
  
  
  The migration problem
&lt;/h2&gt;

&lt;p&gt;Here's the part most articles skip: knowing you need to migrate isn't the same as knowing what to migrate.&lt;/p&gt;

&lt;p&gt;Most organizations have no real inventory of where RSA, ECDSA, and other quantum-vulnerable algorithms are used in their stack. Crypto-agility — the ability to swap algorithms without architectural rewrites — is rare in legacy systems.&lt;/p&gt;
&lt;h2&gt;
  
  
  A practical first step: audit before you migrate
&lt;/h2&gt;

&lt;p&gt;Before touching a single line of cryptographic code, you need an inventory. What algorithms are you actually running? Where? With what risk level?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -X POST https://vortex-dfs.onrender.com/v1/pqc/audit \
  -H "Content-Type: application/json" \
  -d '{"content": "RSA-2048 signing, ECDH key exchange, AES-128, SHA-1"}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "quantum_risk": {
    "score": 0.78,
    "band": "critical",
    "harvest_now_decrypt_later": true,
    "estimated_threat_horizon": "2030-2035"
  },
  "recommendations": [
    {
      "from": "RSA / ECDSA / DSA",
      "to": "ML-DSA (CRYSTALS-Dilithium)",
      "nist_standard": "FIPS 204",
      "priority": "critical"
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This scans any text, config file, or codebase snippet and returns a quantum risk score with specific migration recommendations mapped to NIST standards.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bottom line
&lt;/h2&gt;

&lt;p&gt;You don't need a quantum computer to be at risk from quantum computing. You need data worth protecting for more than a decade and an adversary patient enough to wait.&lt;/p&gt;

&lt;p&gt;The migration window is now — not when the quantum computer arrives, but while there's still time to act before it does.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post is part of ongoing research at Okamoto Security Labs on post-quantum cryptographic infrastructure. Try the audit API: okamotosecurytlabs.com.br&lt;/em&gt;&lt;/p&gt;

</description>
      <category>harvest</category>
      <category>ai</category>
      <category>data</category>
      <category>security</category>
    </item>
    <item>
      <title>How to detect and remove PII from any text payload in Python</title>
      <dc:creator>g.okc</dc:creator>
      <pubDate>Thu, 25 Jun 2026 15:52:49 +0000</pubDate>
      <link>https://dev.to/gustavo89587/how-to-detect-and-remove-pii-from-any-text-payload-in-python-40p4</link>
      <guid>https://dev.to/gustavo89587/how-to-detect-and-remove-pii-from-any-text-payload-in-python-40p4</guid>
      <description>&lt;p&gt;PII leaking into logs, LLM prompts, and audit trails is one of the most common and costly compliance failures.&lt;br&gt;
In this post I'll show you how to detect and strip PII from any text payload in Python — names, emails, SSN, CPF, credit cards — using a production REST API built in Rust with sub-15ms latency.&lt;/p&gt;
&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Most teams realize PII is leaking too late — after a breach, after an audit, or after the data lands in an LLM training set.&lt;/p&gt;
&lt;h2&gt;
  
  
  The solution
&lt;/h2&gt;

&lt;p&gt;One API call before your data touches anything sensitive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;anonymize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://vortex-dfs.onrender.com/v1/shield/anonymize&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Example
&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;anonymize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;John Smith, SSN 123-45-6789, card 4111-1111-1111-1111&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your_key_here&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sanitized&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="c1"&gt;# → "[NAME] [SSN] [CARD]"
&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;risk_score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="c1"&gt;# → 0.94
&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;latency_ms&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="c1"&gt;# → 12.3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Integrate before your LLM pipeline****&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;safe_llm_call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ticket_content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Step 1 — strip PII
&lt;/span&gt;    &lt;span class="n"&gt;clean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;anonymize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ticket_content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Step 2 — safe to send now
&lt;/span&gt;    &lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Summarize this support ticket: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;clean&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sanitized&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What gets detected
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;You can. But:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Regex misses context — &lt;strong&gt;123-45-6789&lt;/strong&gt; alone vs inside a sentence&lt;/li&gt;
&lt;li&gt;No risk scoring — you don't know how sensitive the payload is&lt;/li&gt;
&lt;li&gt;No token map — you can't reverse the anonymization if needed&lt;/li&gt;
&lt;li&gt;Maintenance burden — every new pattern is a new regex&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The API handles all of this and returns an encrypted token map if you need to deanonymize later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get your API key
&lt;/h2&gt;

&lt;p&gt;Starts at $9/week. Key delivered instantly after payment.&lt;br&gt;
&lt;a href="https://okamotosecurytlabs.com.br/" rel="noopener noreferrer"&gt;Here👉&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>security</category>
      <category>privacy</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Why I built a Post-Quantum PII anonymization API (and how it works)</title>
      <dc:creator>g.okc</dc:creator>
      <pubDate>Thu, 25 Jun 2026 00:19:15 +0000</pubDate>
      <link>https://dev.to/gustavo89587/why-i-built-a-post-quantum-pii-anonymization-api-and-how-it-works-137n</link>
      <guid>https://dev.to/gustavo89587/why-i-built-a-post-quantum-pii-anonymization-api-and-how-it-works-137n</guid>
      <description>&lt;p&gt;The problem with most data anonymization tools is that they solve today's threat model, not tomorrow's.&lt;br&gt;
RSA-2048 and ECDSA — the algorithms behind most audit log signatures today — are vulnerable to Shor's algorithm running on a sufficiently large quantum computer. Security researchers estimate we have 8–15 years before that becomes a real attack vector. That sounds like a long time until you realize compliance audit logs need to remain verifiable for decades.&lt;br&gt;
So I built Vortex DFS.&lt;br&gt;
It's a REST API with two core capabilities:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;PII Anonymization&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Send any text payload. Get back sanitized content with an AES-256-GCM encrypted token map for reversibility if needed. Detects names, emails, CPF, SSN, credentials, and more.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Post-Quantum Cryptographic Audit&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Audit events are signed using a lattice-based scheme (LWE — Learning With Errors), which is resistant to quantum attacks. NIST has already standardized this family of algorithms in FIPS 203/204.&lt;br&gt;
The stack:&lt;/p&gt;

&lt;p&gt;Rust + Actix-web (sub-15ms p99 latency)&lt;br&gt;
Supabase PostgreSQL for customer management&lt;br&gt;
Stripe for instant key provisioning&lt;br&gt;
Keys delivered by email in under 60 seconds after payment&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;**&lt;/span&gt;One call to anonymize:&lt;span class="k"&gt;**&lt;/span&gt;
bashcurl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://okamotosecurytlabs.com.br/v1/shield/anonymize &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer YOUR_KEY"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"content": "John Smith, card 4111-1111-1111-1111, SSN 123-45-6789"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;**Response**:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;json&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sanitized"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[NAME] [CARD] [SSN]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"risk_score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.94&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"detections"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"latency_ms"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;12.3&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Who is this for:&lt;/p&gt;

&lt;p&gt;Fintech and healthtech handling sensitive user data&lt;br&gt;
Companies under GDPR/LGPD compliance requirements&lt;br&gt;
Developers building audit pipelines that need to survive quantum&lt;/p&gt;

&lt;p&gt;Starts at $9/week with instant API key delivery.&lt;br&gt;
&lt;a href="https://okamotosecurytlabs.com.br" rel="noopener noreferrer"&gt;Try it:&lt;/a&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>privacy</category>
      <category>security</category>
      <category>showdev</category>
    </item>
    <item>
      <title>How a modular arithmetic oversight turned a cryptographic primitive into a no-op — and what we did about it.</title>
      <dc:creator>g.okc</dc:creator>
      <pubDate>Thu, 18 Jun 2026 23:39:41 +0000</pubDate>
      <link>https://dev.to/gustavo89587/how-a-modular-arithmetic-oversight-turned-a-cryptographic-primitive-into-a-no-op-and-what-we-did-1opc</link>
      <guid>https://dev.to/gustavo89587/how-a-modular-arithmetic-oversight-turned-a-cryptographic-primitive-into-a-no-op-and-what-we-did-1opc</guid>
      <description>&lt;h1&gt;
  
  
  The silent bug that made our post-quantum signatures accept everything
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;How a modular arithmetic oversight turned a cryptographic primitive into a no-op — and what we did about it.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;We were building Vortex DFS, a deterministic security layer for AI systems. The core idea: instead of heuristics, use mathematics. A packet either satisfies the laws of physics and cryptography, or it doesn't.&lt;/p&gt;

&lt;p&gt;Part of that meant implementing a post-quantum signature scheme based on &lt;strong&gt;Learning With Errors (LWE)&lt;/strong&gt; — the mathematical hardness assumption behind NIST's 2024 post-quantum standards. We wanted something auditable, something we could reason about, something that would fail loudly if it was wrong.&lt;/p&gt;

&lt;p&gt;It didn't fail loudly. It failed silently. And it took a test case we almost didn't write to catch it.&lt;/p&gt;




&lt;h2&gt;
  
  
  What we built
&lt;/h2&gt;

&lt;p&gt;The scheme follows the Fiat-Shamir paradigm applied to LWE. The idea is elegant:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key generation:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;s ← small secret vector in Z_q^n
A ← random public matrix in Z_q^(n×n)
b = A·s mod q          (public key)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Signing a message &lt;code&gt;data&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;y ← random commitment vector
w = A·y mod q
c = H(data || w)       (challenge — hash binding)
z = y + c·s mod q      (response)
Signature: (z, c)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Verification:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Recompute: w' = A·z - c·b mod q
Check:     H(data || w') == c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The security intuition: an attacker who doesn't know &lt;code&gt;s&lt;/code&gt; can't produce a &lt;code&gt;z&lt;/code&gt; such that &lt;code&gt;A·z - c·b&lt;/code&gt; hashes back to &lt;code&gt;c&lt;/code&gt;. Solving that requires inverting the LWE problem — which is believed to be hard even for quantum computers.&lt;/p&gt;

&lt;p&gt;We implemented this in Rust. The math looked right. The code compiled. The happy path test passed.&lt;/p&gt;

&lt;p&gt;Then we wrote the test that almost didn't get written.&lt;/p&gt;




&lt;h2&gt;
  
  
  The test we almost skipped
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;test_lwe_wrong_key_rejected&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sk1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pk1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;keygen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0xAAAA&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_sk2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pk2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;keygen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0xBBBB&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Sign with sk2/pk2&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;sig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_sk2&lt;/span&gt;&lt;span class="nf"&gt;.sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;b"dados"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pk2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0x1111&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Verify against pk1 — should FAIL&lt;/span&gt;
    &lt;span class="nd"&gt;assert!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pk1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;b"dados"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;sig&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The assertion failed. A signature made with one keypair was accepted by a completely different public key.&lt;/p&gt;

&lt;p&gt;The signature scheme that was supposed to be post-quantum secure was accepting any signature from any key.&lt;/p&gt;




&lt;h2&gt;
  
  
  Finding the root cause
&lt;/h2&gt;

&lt;p&gt;We added diagnostic output and ran the math in Python to isolate where the failure was happening.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;N&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;257&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;ETA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;

&lt;span class="c1"&gt;# With a typical challenge value c ≈ 245:
&lt;/span&gt;&lt;span class="n"&gt;tol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ETA&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="c1"&gt;# tol = 245 * 2 + 1 = 491
&lt;/span&gt;
&lt;span class="c1"&gt;# But Q = 257, so the entire ring Z_q spans [0, 256]
# Maximum circular distance in Z_q: Q // 2 = 128
&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tol=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;tol&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, Q=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Q&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, tol &amp;gt; Q: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;tol&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Q&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# tol=491, Q=257, tol &amp;gt; Q: True
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tolerance exceeded the size of the ring. We were checking whether the difference between two values in Z₂₅₇ was "small enough" — but our definition of small enough covered the entire space.&lt;/p&gt;

&lt;p&gt;In practice: &lt;code&gt;verify()&lt;/code&gt; was returning &lt;code&gt;True&lt;/code&gt; for every input.&lt;/p&gt;

&lt;p&gt;The root was in our verification function. The original version computed &lt;code&gt;A·z - c·b&lt;/code&gt; and checked whether it was "close to" &lt;code&gt;w&lt;/code&gt; using a tolerance of &lt;code&gt;c × ETA&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// BEFORE — broken&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;tolerance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sig&lt;/span&gt;&lt;span class="py"&gt;.c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ETA&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.all&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nf"&gt;dist_circular&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mod_q&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;az&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="n"&gt;sig&lt;/span&gt;&lt;span class="py"&gt;.w&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;tolerance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;Q = 257&lt;/code&gt; (a deliberately small parameter for a demo implementation) and &lt;code&gt;c&lt;/code&gt; values that can reach up to &lt;code&gt;Q - 1 = 256&lt;/code&gt;, the tolerance &lt;code&gt;c × ETA&lt;/code&gt; can be &lt;code&gt;512&lt;/code&gt; — more than double the entire modulus. The "check" was vacuously true.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this happens mathematically
&lt;/h2&gt;

&lt;p&gt;In a proper LWE-based signature scheme, the public key is &lt;code&gt;b = A·s + e&lt;/code&gt;, where &lt;code&gt;e&lt;/code&gt; is a small error vector. During verification:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A·z - c·b = A·(y + c·s) - c·(A·s + e)
           = A·y + c·A·s - c·A·s - c·e
           = A·y - c·e
           = w - c·e
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So &lt;code&gt;A·z - c·b&lt;/code&gt; isn't exactly &lt;code&gt;w&lt;/code&gt; — it differs by &lt;code&gt;c·e&lt;/code&gt;. The tolerance exists to absorb this error. But the error bound &lt;code&gt;c × ETA&lt;/code&gt; only stays safely below &lt;code&gt;Q/2&lt;/code&gt; when &lt;code&gt;Q&lt;/code&gt; is large relative to &lt;code&gt;c × ETA&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Production parameters (Dilithium uses &lt;code&gt;Q = 8,380,417&lt;/code&gt;) make this gap enormous. Our demo parameter &lt;code&gt;Q = 257&lt;/code&gt; collapsed it completely.&lt;/p&gt;




&lt;h2&gt;
  
  
  The fix
&lt;/h2&gt;

&lt;p&gt;We changed the approach. Instead of checking proximity in the ring, we use hash binding directly.&lt;/p&gt;

&lt;p&gt;The key insight: if &lt;code&gt;b = A·s&lt;/code&gt; (without the public error term), then &lt;code&gt;A·z - c·b = A·y = w&lt;/code&gt; exactly. The verification becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Recompute w' = A·z - c·b mod q
Accept iff H(data || w') == c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No tolerance. No approximation. The hash function does the work — if &lt;code&gt;w'&lt;/code&gt; differs from &lt;code&gt;w&lt;/code&gt; by even a single bit, the hash changes completely.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// AFTER — correct&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;PublicKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;sig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Signature&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Recompute w' = A·z - c·b mod q&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;az&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;i64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;mq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="py"&gt;.a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;sig&lt;/span&gt;&lt;span class="py"&gt;.z&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;)|&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.sum&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="nf"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;i64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="py"&gt;.b&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;bi&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nf"&gt;mq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sig&lt;/span&gt;&lt;span class="py"&gt;.c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;bi&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="nf"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;w_prime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;i64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nf"&gt;mq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;az&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;&lt;span class="nf"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Accept iff H(data || w') == c&lt;/span&gt;
    &lt;span class="nf"&gt;hash_commit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;w_prime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;sig&lt;/span&gt;&lt;span class="py"&gt;.c&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also updated the key generation to remove the public error term, since we no longer need it and its presence was the source of the approximation problem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// b = A·s  (exact — no error term)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;i64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nf"&gt;mq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)|&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.sum&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
    &lt;span class="nf"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Verifying the fix
&lt;/h2&gt;

&lt;p&gt;We ran the same test suite:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[OK] test_lwe_sign_verify            ← valid sig accepted
[OK] test_lwe_tampered_data_rejected ← modified data rejected
[OK] test_lwe_wrong_key_rejected     ← different keypair rejected ✓
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the adversarial cases in Python confirmed the math:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Same keypair → True  ✓
# Different keypair → False  ✓
# Tampered data → False  ✓
# Modified z → False  ✓
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What this means in practice
&lt;/h2&gt;

&lt;p&gt;The original code looked correct. It used the right algorithm name, the right structure, the right variable names. It compiled without warnings. The happy-path test passed. A code reviewer without cryptography expertise would have approved it.&lt;/p&gt;

&lt;p&gt;The failure was invisible until we explicitly tested the adversarial case: &lt;em&gt;what happens when you verify a signature made with the wrong key?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In a deployed system, this would have meant that any packet — from any source, with any signature — would pass authentication. The post-quantum security layer would have been a no-op. Worse, it would have been a no-op that looked like it was working.&lt;/p&gt;




&lt;h2&gt;
  
  
  Three lessons
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Test the adversarial case explicitly.&lt;/strong&gt; Happy-path tests don't find security bugs. For every authentication check, write the test that uses the wrong key, the wrong data, the tampered payload. If the test doesn't exist, the guarantee doesn't exist.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Small parameters expose bugs that large parameters hide.&lt;/strong&gt; &lt;code&gt;Q = 257&lt;/code&gt; made the overflow immediate and visible. With &lt;code&gt;Q = 8,380,417&lt;/code&gt;, the same logical error might pass casual testing because the tolerance stays within bounds in typical cases — but could still be exploitable under crafted inputs. Use small parameters in tests to stress the boundaries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For production, use audited implementations.&lt;/strong&gt; The mathematics in our implementation is correct, but correct mathematics isn't the same as a secure implementation. Dilithium — the NIST-standardized lattice signature scheme — has been analyzed by hundreds of cryptographers over seven years. Use &lt;code&gt;pqcrypto-dilithium&lt;/code&gt; in production. Our implementation is what you study to understand &lt;em&gt;why&lt;/em&gt; it works. Theirs is what you deploy.&lt;/p&gt;




&lt;h2&gt;
  
  
  The production path
&lt;/h2&gt;

&lt;p&gt;If you're building on Vortex DFS and need production-grade post-quantum signatures today:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[dependencies]&lt;/span&gt;
&lt;span class="py"&gt;pqcrypto-dilithium&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.5"&lt;/span&gt;
&lt;span class="py"&gt;pqcrypto-traits&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.3"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;pqcrypto_dilithium&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;dilithium3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;pqcrypto_traits&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;DetachedSignature&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PublicKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SecretKey&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;dilithium3&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;keypair&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;sig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;dilithium3&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;detached_sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;sk&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nd"&gt;assert!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;dilithium3&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;verify_detached_signature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;sig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.is_ok&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same mathematical foundation. NIST-standardized parameters. Seven years of public cryptanalysis.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The bug was a single line — a tolerance calculation that exceeded the modulus. It rendered an entire cryptographic layer meaningless. It was caught by a test case that was almost skipped.&lt;/p&gt;

&lt;p&gt;Security isn't about looking correct. It's about being provably incorrect when something is wrong.&lt;/p&gt;

&lt;p&gt;Vortex DFS is built on that principle. Every packet gets a typed rejection reason. Every layer has an adversarial test. Every guarantee has a corresponding test that tries to break it.&lt;/p&gt;

&lt;p&gt;The code is open source. Read it, break it, tell us what you find.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Vortex DFS is built at Okamoto Security Labs. Apache 2.0.&lt;/em&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Source: &lt;a href="https://github.com" rel="noopener noreferrer"&gt;github.com/okamoto-security-labs/Vortex-DFS&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>computerscience</category>
      <category>cybersecurity</category>
      <category>security</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>g.okc</dc:creator>
      <pubDate>Thu, 18 Jun 2026 23:36:42 +0000</pubDate>
      <link>https://dev.to/gustavo89587/-1554</link>
      <guid>https://dev.to/gustavo89587/-1554</guid>
      <description></description>
    </item>
  </channel>
</rss>
