<?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: Haven Messenger</title>
    <description>The latest articles on DEV Community by Haven Messenger (@havenmessenger).</description>
    <link>https://dev.to/havenmessenger</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%2F3891528%2F1736c7dd-a6a7-443a-863c-0abb7d56e358.png</url>
      <title>DEV Community: Haven Messenger</title>
      <link>https://dev.to/havenmessenger</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/havenmessenger"/>
    <language>en</language>
    <item>
      <title>Oblivious Pseudorandom Functions (OPRF): The Quiet Workhorse of Modern Privacy</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Sun, 28 Jun 2026 12:19:34 +0000</pubDate>
      <link>https://dev.to/havenmessenger/oblivious-pseudorandom-functions-oprf-the-quiet-workhorse-of-modern-privacy-mdk</link>
      <guid>https://dev.to/havenmessenger/oblivious-pseudorandom-functions-oprf-the-quiet-workhorse-of-modern-privacy-mdk</guid>
      <description>&lt;p&gt;A pseudorandom function (PRF) is a keyed function whose output looks random to anyone without the key. &lt;code&gt;HMAC&lt;/code&gt; is a familiar example: given a key and an input, it produces an output that is deterministic if you know the key and unpredictable if you do not. The "oblivious" variant adds a constraint that seems almost contradictory at first.&lt;/p&gt;

&lt;p&gt;In an OPRF there are two parties. The client has an input &lt;code&gt;x&lt;/code&gt;. The server has a secret key &lt;code&gt;k&lt;/code&gt;. At the end of the protocol the client learns &lt;code&gt;F(k, x)&lt;/code&gt; and nothing else, and the server learns nothing at all. The server cannot see &lt;code&gt;x&lt;/code&gt;, cannot see the output, and cannot link two requests to the same input. The client gets a correctly keyed result without ever holding the key.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works: blinding
&lt;/h2&gt;

&lt;p&gt;The standard construction lives in a prime-order group, the same kind of elliptic-curve setting used elsewhere in modern cryptography. The trick is called blinding, and the math is short enough to follow.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The client hashes its input onto a curve point, &lt;code&gt;P = H(x)&lt;/code&gt;, and picks a random secret scalar &lt;code&gt;r&lt;/code&gt;. It sends the &lt;strong&gt;blinded&lt;/strong&gt; point &lt;code&gt;P · r&lt;/code&gt; to the server. Because &lt;code&gt;r&lt;/code&gt; is random, the blinded point reveals nothing about &lt;code&gt;x&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The server multiplies by its key: it returns &lt;code&gt;(P · r) · k&lt;/code&gt;. It is operating on a point it cannot interpret.&lt;/li&gt;
&lt;li&gt;The client removes its blind by multiplying by the inverse of &lt;code&gt;r&lt;/code&gt;, leaving &lt;code&gt;P · k&lt;/code&gt;. It hashes that, together with &lt;code&gt;x&lt;/code&gt;, into the final output.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The server applied its secret key to the client's input without ever learning the input, and the client got a key-bound result without ever learning the key. The randomness &lt;code&gt;r&lt;/code&gt; is fresh each time, so two queries for the same &lt;code&gt;x&lt;/code&gt; look unrelated to the server. That unlinkability is the property that makes the rest possible.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;An OPRF turns "ask the server to compute something on my secret" into a safe operation. The server becomes a key-holding oracle that is structurally unable to spy on the questions it answers. That is a different and stronger guarantee than "we promise not to log it."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Three flavors, standardized
&lt;/h2&gt;

&lt;p&gt;The CFRG specified these constructions in &lt;strong&gt;RFC 9497&lt;/strong&gt;, which defines three modes over prime-order groups such as ristretto255 and NIST P-256.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;What it adds&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;OPRF&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The base protocol. Client learns &lt;code&gt;F(k, x)&lt;/code&gt;, server learns nothing.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;VOPRF&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Verifiable. The server attaches a zero-knowledge proof (a DLEQ proof) that it used the one committed key, so a malicious server cannot quietly use a different key per client to deanonymize.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;POPRF&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Partially oblivious. Allows a public input alongside the private one, useful for binding a result to a non-secret label such as a date or a rate-limit bucket.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The verifiable mode is the one that matters for anonymity systems. Without the proof, a server could hand each user a slightly different key, and later tell users apart by which key produced a token. The DLEQ proof, a relative of zero-knowledge proofs, closes that gap by forcing one key for everyone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where OPRFs already run
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Anonymous tokens
&lt;/h3&gt;

&lt;p&gt;Privacy Pass uses a VOPRF so a service can issue you tokens for passing a challenge once, which you later redeem without the service linking redemption back to issuance. You prove you earned a token without revealing which token-earning event was yours. This is how a network can rate-limit or vouch for clients without building a behavioral profile.&lt;/p&gt;

&lt;h3&gt;
  
  
  Password login that hides the password
&lt;/h3&gt;

&lt;p&gt;OPAQUE, the asymmetric password-authenticated key exchange, uses an OPRF at its core. Your password is the client input; the server's OPRF key turns it into a strong secret used to unlock your stored credentials, and the server never sees the password, not even briefly, not even as a hash it could attack offline after a breach. Compare that to traditional password hashing, where the server does receive the password during login.&lt;/p&gt;

&lt;h3&gt;
  
  
  Private breach and set membership checks
&lt;/h3&gt;

&lt;p&gt;Checking whether your password appears in a breach corpus usually relies on k-anonymity, which leaks a hash prefix. An OPRF-based design can do better: the service evaluates its key on your secret without learning it, so you can test membership against its database while revealing neither your query nor letting you enumerate its contents. The same shape underlies many private set intersection protocols, where two parties find their common elements and nothing else.&lt;/p&gt;

&lt;h2&gt;
  
  
  What an OPRF does not give you
&lt;/h2&gt;

&lt;p&gt;It is a two-party building block, not a finished system, and it has clear edges.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The server cannot see the input. It can still see that someone made a request, from some address, at some time. An OPRF protects the contents of the query, not the fact that a query happened.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It is interactive.&lt;/strong&gt; Every evaluation needs a round trip to the key holder. The server is online and load-bearing, even if it is blind.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It does not hide network metadata.&lt;/strong&gt; Address and timing are still visible to the server and the network. Pair it with other measures if those matter.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Online guessing still costs the attacker a query each.&lt;/strong&gt; The OPRF stops offline brute force against a stolen database, which is the major win, but a malicious client can still try inputs one online query at a time, so rate limiting remains necessary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The base mode trusts the server's key choice.&lt;/strong&gt; If you need the deanonymization protection, you need the verifiable mode and its proof, not the plain one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these are flaws. They are the boundary of what a single primitive should claim. The reason OPRFs show up everywhere is that they solve one problem cleanly: letting a server apply a secret key to data it is not allowed to read. Once you can do that, a surprising amount of privacy engineering becomes a matter of composition.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/oprf-oblivious-pseudorandom-functions-explained/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>encryption</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>5G Subscriber Privacy: How SUCI Concealment Fights IMSI-Catchers</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Sat, 27 Jun 2026 12:17:48 +0000</pubDate>
      <link>https://dev.to/havenmessenger/5g-subscriber-privacy-how-suci-concealment-fights-imsi-catchers-15ll</link>
      <guid>https://dev.to/havenmessenger/5g-subscriber-privacy-how-suci-concealment-fights-imsi-catchers-15ll</guid>
      <description>&lt;p&gt;For more than two decades, when your phone introduced itself to a cell tower it could be made to shout its permanent identity in the clear. That single design flaw is what made IMSI-catchers possible. 5G finally encrypts that identity before it leaves your device. The fix is real and worth understanding, and so are the gaps it does not close.&lt;/p&gt;

&lt;p&gt;Every device on a cellular network needs a permanent identity so the network knows whose account to bill and which keys to use. In 2G, 3G, and 4G that identity is the IMSI, the International Mobile Subscriber Identity, a number stored on your SIM. The problem was never the existence of the IMSI. The problem was when and how the network asked for it.&lt;/p&gt;

&lt;p&gt;When a phone first attaches to a network, or when the network loses track of it, the network can request the permanent identity directly. On older generations the phone answered with its IMSI in plaintext over the air. Anyone who could pose as a tower could ask the question and collect the answer. That is the entire trick behind an IMSI-catcher.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Old Attack: Identity in the Clear
&lt;/h2&gt;

&lt;p&gt;An IMSI-catcher, sometimes called a Stingray, is a fake base station. It broadcasts a strong signal that nearby phones prefer, persuades them to attach, and then triggers an identity request. Because the phone would surrender its IMSI before any mutual authentication had taken place, the catcher learned the permanent identity of every device in range. From there it could track who was present at a protest, follow a specific person across the city, or downgrade the connection to intercept traffic.&lt;/p&gt;

&lt;p&gt;The root cause is a sequencing failure. The phone proved nothing about who it was talking to before revealing who it was. 4G added mutual authentication for the session, but the initial identity request still leaked the IMSI in the gap before that authentication completed. The fix had to move the protection earlier, to the identity itself.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The core insight:&lt;/strong&gt; The vulnerability was not weak encryption of traffic. It was that the long-term identifier was sent before the device could verify it was talking to a legitimate network. 5G closes the gap by never sending that identifier in the clear at all.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  SUPI and SUCI: Splitting Identity From Its Wire Form
&lt;/h2&gt;

&lt;p&gt;5G renames and restructures the identity model. The permanent identifier is now the SUPI, the Subscription Permanent Identifier. It plays the role the IMSI used to play, but the standard adds a strict rule: the SUPI must not be transmitted over the radio in the clear.&lt;/p&gt;

&lt;p&gt;Instead the device sends the SUCI, the Subscription Concealed Identifier. The SUCI is an encrypted form of the SUPI. The phone encrypts its permanent identity before sending it, so what travels over the air is ciphertext that only the home network can turn back into the real SUPI. A fake base station can collect SUCIs all day and learn nothing durable, because the value is freshly encrypted each time.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the Concealment Actually Works
&lt;/h2&gt;

&lt;p&gt;The scheme is a textbook use of elliptic-curve public-key cryptography, defined by 3GPP using the ECIES framework. The home network operator has a public and private key pair. The public key is provisioned onto the SIM. The flow looks like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The device generates a fresh ephemeral key pair for this one concealment.&lt;/li&gt;
&lt;li&gt;It performs an elliptic-curve Diffie-Hellman exchange between its ephemeral private key and the operator's public key to derive a shared secret.&lt;/li&gt;
&lt;li&gt;From that secret it derives an encryption key and a MAC key, then encrypts the part of the SUPI that identifies the subscriber and authenticates the result.&lt;/li&gt;
&lt;li&gt;It sends the ciphertext together with its ephemeral public key as the SUCI.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Only the home network holds the private key, so only the home network can run the matching exchange, recover the shared secret, and decrypt the SUPI. Because a new ephemeral key is used each time, two SUCIs generated from the same SUPI look unrelated to an eavesdropper. That unlinkability is the property that defeats passive tracking.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The genius of the design is modest and practical: it does not reinvent cellular security, it just moves one encryption step to before the moment the identity leaves the device. Ephemeral keys make every concealed identity look new.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What 5G Fixes, and What It Does Not
&lt;/h2&gt;

&lt;p&gt;SUCI concealment is a meaningful win against the classic passive IMSI-catcher. But honesty about the threat model requires naming the limits, several of which are significant.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concern&lt;/th&gt;
&lt;th&gt;Status under 5G SUCI&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Passive IMSI harvesting&lt;/td&gt;
&lt;td&gt;Addressed. The permanent identity is never sent in the clear; ephemeral keys make captures unlinkable.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Non-standalone 5G&lt;/td&gt;
&lt;td&gt;Often unprotected. Many early 5G deployments run on a 4G core. The SUCI protection depends on the standalone 5G core being in use.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Downgrade attacks&lt;/td&gt;
&lt;td&gt;Partly open. An attacker can still try to force a phone down to 4G or 2G, where the old IMSI exposure returns.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The temporary identifier (5G-GUTI)&lt;/td&gt;
&lt;td&gt;Depends on the operator. If a network reallocates the temporary ID too rarely, it can become a tracking handle on its own.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Radio-layer fingerprinting&lt;/td&gt;
&lt;td&gt;Out of scope. Identity concealment does nothing about device-level radio fingerprints or signal-based location.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The downgrade gap is the one most worth internalizing. As long as your phone will fall back to 2G or 4G, an attacker who can jam or out-broadcast the 5G signal can drag the connection to a generation where the old exposure applies. This is why some hardened phone configurations let you disable legacy radio access technologies entirely, accepting reduced coverage in exchange for closing the fallback.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where This Sits in Your Threat Model
&lt;/h2&gt;

&lt;p&gt;Cellular identity privacy is a layer below anything an application can touch. Your messaging app cannot influence whether your SUPI is concealed; that is a property of your carrier, your phone's modem, and the network you are standing in. What the 5G design demonstrates is a principle worth carrying everywhere: do not reveal a long-lived identifier before you have verified who is asking, and rotate the wire form so observations cannot be linked.&lt;/p&gt;

&lt;p&gt;That same principle shapes how we think about metadata at Haven. The network operator can see that your phone is online and roughly where it is; that is physics we do not pretend to solve. What we control is the layer above, where the goal is to generate as little linkable identifying data as possible and to keep what we must store encrypted. 5G fixed one old leak by encrypting an identity that used to travel in the open. The broader job, at every layer, is to keep doing exactly that.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/5g-subscriber-privacy-explained/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>encryption</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>BBS Signatures and Anonymous Credentials: Proving Less to Show More</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Fri, 26 Jun 2026 12:17:49 +0000</pubDate>
      <link>https://dev.to/havenmessenger/bbs-signatures-and-anonymous-credentials-proving-less-to-show-more-5cnb</link>
      <guid>https://dev.to/havenmessenger/bbs-signatures-and-anonymous-credentials-proving-less-to-show-more-5cnb</guid>
      <description>&lt;p&gt;A government issues you a digital ID containing your name, date of birth, address, and license number. A bar wants to confirm you are over 21. With an ordinary digital signature, proving one fact means handing over the whole document. BBS signatures break that all-or-nothing bargain, letting you reveal a single field and prove the rest exists without showing it, in a way the verifier cannot use to track you.&lt;/p&gt;

&lt;p&gt;The name BBS comes from Boneh, Boneh and Shacham, the authors of the original 2004 group-signature scheme it descends from. The modern form is a signature over a list of messages rather than a single blob, and it is being standardized through the IETF and the W3C for use in verifiable credentials. What makes it interesting is not the signing itself, but what the holder of the signature can do afterward without going back to the issuer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem With Signing a Whole Document
&lt;/h2&gt;

&lt;p&gt;A normal digital signature covers one message. If your ID is a single signed object, you cannot show part of it: the signature only verifies against the complete, unmodified document. Redact one field and the signature breaks. So selective disclosure with ordinary signatures forces a workaround, and the common one has real downsides.&lt;/p&gt;

&lt;p&gt;The salted-hash approach, used by schemes like SD-JWT, signs a list of hashed, salted attributes. To reveal a field you disclose its salt and value; to hide one you withhold them. This genuinely works and is simpler to deploy, but it has a property worth noticing: every time you present the credential, the verifier sees the same issuer signature. Two presentations to two different verifiers carry the same signature value, so those verifiers can collude and link your visits. The disclosure is selective, but the credential is still a tracking beacon.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The two distinct privacy goals.&lt;/strong&gt; Selective disclosure means showing only the fields you choose. Unlinkability means two showings of the same credential cannot be tied together. Salted-hash schemes give you the first. BBS is built to give you both.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How BBS Achieves Unlinkable Disclosure
&lt;/h2&gt;

&lt;p&gt;BBS signs a vector of messages at once, producing a single compact signature. The clever part is the presentation step. Instead of handing the verifier the issuer's signature directly, the holder generates a zero-knowledge proof that says, in effect: "I possess a valid issuer signature over a set of messages, here are the specific messages I choose to reveal, and I am proving the hidden ones exist and are covered by that signature without showing them."&lt;/p&gt;

&lt;p&gt;Crucially, that proof is freshly randomized every single time. The issuer's actual signature never leaves the holder's device. Each presentation looks like an independent, unrelated proof, so two verifiers comparing notes find nothing in common to link. This rests on pairing-based cryptography over elliptic curves, which is what lets the holder re-randomize while keeping the proof verifiable against the issuer's public key.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;With a normal signature, showing your credential twice creates a link. With BBS, each showing is a fresh proof that the credential exists, carrying no fingerprint the verifier can save.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Predicate Proofs: Proving Without Revealing
&lt;/h2&gt;

&lt;p&gt;Selective disclosure still reveals whole fields. The next step is proving a statement &lt;em&gt;about&lt;/em&gt; a field without revealing the field at all. This is where BBS combines with range proofs and other zero-knowledge gadgets. Instead of disclosing your date of birth, you prove the predicate "this birthdate implies an age of at least 21." The verifier learns one bit, true or false, and nothing else. Not your birthday, not your age, just that you clear the bar.&lt;/p&gt;

&lt;p&gt;This is the property that makes anonymous credentials genuinely privacy-preserving rather than merely tidy. A bouncer who scans a normal ID learns your name, address, and exact age to confirm one thing. A predicate proof reveals only the answer to the question actually being asked. It is the cryptographic form of the principle behind data minimization: collect and reveal the least information that accomplishes the task.&lt;/p&gt;

&lt;h2&gt;
  
  
  BBS Versus the Alternatives
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Selective disclosure&lt;/th&gt;
&lt;th&gt;Unlinkable presentations&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Plain signature (whole doc)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SD-JWT (salted hashes)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No (same signature each time)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BBS signatures&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes (re-randomized proofs)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;BBS is not free. It is more complex to implement correctly, relies on pairing-friendly curves that are less universally supported than the curves behind everyday signatures, and the proof generation is heavier than computing a hash. There is also an honest open question around post-quantum security: pairing-based schemes like BBS are not quantum-resistant, and the post-quantum replacements for anonymous credentials are still maturing. For credentials meant to last decades, that matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where You Will Meet It
&lt;/h2&gt;

&lt;p&gt;BBS is moving from research into deployment in the digital-identity world. It is a candidate signature suite for W3C Verifiable Credentials and is being looked at for digital ID wallets, including some of the mobile driver's license and EU digital identity efforts. The appeal for regulators and privacy advocates alike is that it can satisfy a verification requirement while structurally preventing the verifier from building a profile, which is exactly the property that decides whether a national ID wallet becomes a convenience or a surveillance system.&lt;/p&gt;

&lt;p&gt;The broader lesson reaches past credentials. The pattern BBS embodies, prove the minimum and reveal nothing reusable, is the same instinct that should govern any system handling sensitive data. The strongest privacy designs are the ones that make over-collection cryptographically impossible rather than merely against policy. Whether the question is "are you over 21," "do you hold a valid subscription," or "are you a member of this group," the right answer is a proof that says yes and leaves no trail.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/bbs-anonymous-credentials-explained/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>SHA-3 and the Sponge: Why Keccak Looks Nothing Like SHA-2</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Thu, 25 Jun 2026 12:22:39 +0000</pubDate>
      <link>https://dev.to/havenmessenger/sha-3-and-the-sponge-why-keccak-looks-nothing-like-sha-2-ef6</link>
      <guid>https://dev.to/havenmessenger/sha-3-and-the-sponge-why-keccak-looks-nothing-like-sha-2-ef6</guid>
      <description>&lt;p&gt;Most people assume SHA-3 is to SHA-2 what SHA-256 was to SHA-1: a stronger version of the same idea. It is not. SHA-3 throws out the internal machinery that every previous mainstream hash function shared, and replaces it with a construction called the sponge. Understanding why is the difference between treating a hash as a black box and knowing when it will quietly betray you.&lt;/p&gt;

&lt;p&gt;For thirty years, the dominant hash functions all worked the same way inside. MD5, SHA-1, and the SHA-2 family (SHA-256, SHA-512) are built on the Merkle-Damgard construction: take a fixed-size compression function, chain it across message blocks, and carry a running state from one block to the next. The final state is the digest. It is a clean design, and it powered nearly all of digital signing, certificate chains, and integrity checking from the 1990s onward.&lt;/p&gt;

&lt;p&gt;Then the cracks appeared. Xiaoyun Wang's team published practical collisions for MD5 in 2004 and a theoretical break of SHA-1 not long after. The SHAttered attack in 2017 produced two real PDF files with the same SHA-1 digest. None of this touched SHA-2 directly, which remains unbroken today. But NIST drew the right lesson anyway: if every deployed hash function shares one structural idea, a future attack on that idea would leave no fallback. So in 2007 they opened a public competition for a hash function built on something else.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Competition and the Winner
&lt;/h2&gt;

&lt;p&gt;Sixty-four submissions came in. After five years of public cryptanalysis, NIST selected Keccak in 2012, designed by Guido Bertoni, Joan Daemen, Michael Peeters, and Gilles Van Assche. Daemen was already co-author of AES, so the pedigree was serious. Keccak became the standard SHA-3 in FIPS 202, published in 2015.&lt;/p&gt;

&lt;p&gt;The crucial point is what Keccak deliberately is not. It does not chain a compression function across blocks. It does not carry a small fixed state that an attacker can reason about as a clean intermediate value. It uses a sponge.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a Sponge Actually Does
&lt;/h2&gt;

&lt;p&gt;Picture a large internal state, in standard SHA-3 it is 1600 bits, split conceptually into two regions: the &lt;strong&gt;rate&lt;/strong&gt; (the part the outside world touches) and the &lt;strong&gt;capacity&lt;/strong&gt; (the part it never touches directly). The whole thing runs in two phases.&lt;/p&gt;

&lt;p&gt;In the &lt;strong&gt;absorbing&lt;/strong&gt; phase, the message is chopped into pieces the size of the rate. Each piece is mixed into the rate portion of the state, and then the entire state is scrambled by a fixed permutation called Keccak-f. Absorb a block, permute. Absorb the next, permute. The capacity bits are never written by the message and never read out during this phase. They just sit there, stirred by the permutation, accumulating entropy the attacker cannot see or set.&lt;/p&gt;

&lt;p&gt;In the &lt;strong&gt;squeezing&lt;/strong&gt; phase, you read output from the rate portion, permute, read again, and repeat until you have as many output bits as you want. For SHA3-256 you only need one squeeze. For an extendable-output function you can keep squeezing forever.&lt;/p&gt;

&lt;p&gt;The security level of a sponge is roughly half its capacity. SHA3-256 uses a capacity of 512 bits, giving 256-bit security, and a rate of 1088 bits per absorbed block. SHA3-512 doubles the capacity to 1024, halves the rate, and runs slower as a result. The trade is explicit and easy to reason about, which is part of the design's appeal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inside Keccak-f: Five Steps That Repeat
&lt;/h2&gt;

&lt;p&gt;The permutation that stirs the state is where the actual mixing happens. Keccak-f arranges the 1600 bits as a three-dimensional 5 by 5 by 64 array of bits and runs 24 rounds. Each round applies five steps with Greek-letter names, and you do not need to memorize the bit math to understand their jobs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Theta&lt;/strong&gt; mixes each bit with the parity of nearby columns, spreading local changes across the state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rho&lt;/strong&gt; rotates bits within each lane by fixed offsets, so changes move along a different axis.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pi&lt;/strong&gt; permutes the positions of the lanes, shuffling where things live.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chi&lt;/strong&gt; is the only nonlinear step. It is what makes the function not solvable as a system of linear equations, and it is the heart of the cryptographic strength.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Iota&lt;/strong&gt; adds a round constant so that the rounds are not all identical, breaking symmetry that an attacker could otherwise exploit.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Diffusion (theta, rho, pi) and confusion (chi) alternate, which is the same Shannon principle that underlies block ciphers like AES. The difference is that here the permutation operates on a state far larger than any single message block, and the message only ever influences part of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Length-Extension Problem It Quietly Solves
&lt;/h2&gt;

&lt;p&gt;Here is the practical payoff that matters most in real systems. Merkle-Damgard hashes have a structural weakness called length extension. Because the digest is literally the final internal state, an attacker who knows &lt;code&gt;SHA256(secret || message)&lt;/code&gt; and the length of the input can compute &lt;code&gt;SHA256(secret || message || padding || extra)&lt;/code&gt; without ever knowing the secret. They just resume the hash from the published digest.&lt;/p&gt;

&lt;p&gt;This is not academic. It is exactly why you cannot build a secure message authentication code by simply prepending a key to your data and hashing it with SHA-256. The fix the industry adopted was &lt;a href="https://havenmessenger.com/blog/posts/hmac-message-authentication-explained/" rel="noopener noreferrer"&gt;HMAC&lt;/a&gt;, a nested construction specifically designed to neutralize length extension on Merkle-Damgard hashes. HMAC works, but it exists because the underlying hash had a sharp edge.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Because a sponge never reveals the capacity bits, the published digest is not the full internal state. An attacker cannot resume the computation, because they are missing the half of the state that was never output. Length extension simply does not apply.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That means with SHA-3 you can build a keyed MAC by prefixing the key and hashing, the naive thing that is dangerous with SHA-2. NIST standardized exactly this as KMAC in SP 800-185. The sharp edge is gone, not patched.&lt;/p&gt;

&lt;h2&gt;
  
  
  SHAKE and the Extendable-Output Trick
&lt;/h2&gt;

&lt;p&gt;The sponge has another property the old design could not offer cleanly. Since output comes from repeated squeezing, you can produce a digest of any length you like. NIST published these as SHAKE128 and SHAKE256, the extendable-output functions, or XOFs.&lt;/p&gt;

&lt;p&gt;This turns out to be quietly important for modern cryptography. Post-quantum schemes lean on it heavily. The lattice-based and &lt;a href="https://havenmessenger.com/blog/posts/hash-based-signatures-explained/" rel="noopener noreferrer"&gt;hash-based signature schemes&lt;/a&gt; now being standardized use SHAKE to expand seeds into large pseudorandom matrices and to derive arbitrary amounts of keying material from a fixed input. A single primitive that emits exactly as many bytes as you ask for removes a whole category of awkward truncation and re-hashing logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  So Should You Switch From SHA-2?
&lt;/h2&gt;

&lt;p&gt;No, and this is where honesty matters more than novelty. SHA-2 is not broken. It has held up to decades of cryptanalysis, it is faster in software on most CPUs without dedicated instructions, and it is the right default for the overwhelming majority of systems today. SHA-3 was never meant to replace SHA-2 because of a flaw, because there is no flaw to flee.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;SHA-2 (Merkle-Damgard)&lt;/th&gt;
&lt;th&gt;SHA-3 (Sponge)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Internal structure&lt;/td&gt;
&lt;td&gt;Chained compression function&lt;/td&gt;
&lt;td&gt;Sponge over a large permutation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Length-extension safe&lt;/td&gt;
&lt;td&gt;No (needs HMAC)&lt;/td&gt;
&lt;td&gt;Yes, by construction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Variable-length output&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes (SHAKE)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Software speed (no HW accel)&lt;/td&gt;
&lt;td&gt;Generally faster&lt;/td&gt;
&lt;td&gt;Generally slower&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Status&lt;/td&gt;
&lt;td&gt;Unbroken, recommended&lt;/td&gt;
&lt;td&gt;Unbroken, recommended&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The right way to think about SHA-3 is as &lt;a href="https://havenmessenger.com/blog/posts/cryptographic-agility-explained/" rel="noopener noreferrer"&gt;cryptographic agility&lt;/a&gt; realized: a fully vetted, structurally independent fallback that is ready the day SHA-2 ever shows weakness, plus a cleaner toolkit (no length-extension footgun, native XOFs) for the systems being designed now. It is the backup you build before you need it, which is the only time you can build it calmly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where This Touches Real Software
&lt;/h2&gt;

&lt;p&gt;Hash functions are load-bearing in places most people never see: they fingerprint the leaves of a &lt;a href="https://havenmessenger.com/blog/posts/merkle-trees-explained/" rel="noopener noreferrer"&gt;Merkle tree&lt;/a&gt;, they derive keys through functions like &lt;a href="https://havenmessenger.com/blog/posts/hkdf-key-derivation-explained/" rel="noopener noreferrer"&gt;HKDF&lt;/a&gt;, they authenticate messages, and they bind together the certificate chains your browser validates on every connection. Choosing the wrong construction for the wrong job, or assuming a bare hash is a safe MAC, is a recurring source of real vulnerabilities.&lt;/p&gt;

&lt;p&gt;At Haven, the hashing primitives underneath our encryption are vetted, standard, and chosen for the specific job rather than for marketing. We would rather use a boring, decades-tested function correctly than a fashionable one carelessly. The sponge is a genuinely elegant piece of engineering, and the most useful thing it teaches is that a hash is never just a black box that turns data into a fingerprint. The shape inside determines what it is safe to build on top.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/sha3-keccak-sponge-explained/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>encryption</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>The Cryptographic Doom Principle: Why Order Matters in Encrypt-and-MAC</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Wed, 24 Jun 2026 12:19:02 +0000</pubDate>
      <link>https://dev.to/havenmessenger/the-cryptographic-doom-principle-why-order-matters-in-encrypt-and-mac-3cnc</link>
      <guid>https://dev.to/havenmessenger/the-cryptographic-doom-principle-why-order-matters-in-encrypt-and-mac-3cnc</guid>
      <description>&lt;p&gt;A system that decrypts a message before it checks whether the message is authentic has handed the attacker a tool. The cryptographic doom principle is one sentence, but it explains a decade of TLS vulnerabilities, the reason padding oracles exist, and why modern protocols stopped letting engineers choose the order at all.&lt;/p&gt;

&lt;p&gt;Encryption keeps a message secret. A message authentication code (MAC) proves the message was not altered and came from someone holding the right key. Most secure channels need both, so they combine a cipher with a MAC. The surprising part is that the &lt;em&gt;order&lt;/em&gt; in which you apply those two operations is not a matter of taste. Get it wrong and you can build a channel that leaks the plaintext it was supposed to protect, even though every individual primitive is sound.&lt;/p&gt;

&lt;p&gt;Moxie Marlinspike named the rule in 2011, and the phrasing has stuck because it is blunt:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you have to perform any cryptographic operation before verifying the MAC on a message you have received, it will somehow inevitably lead to doom.&lt;br&gt;
— Moxie Marlinspike, "The Cryptographic Doom Principle," 2011&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The operative word is &lt;strong&gt;before&lt;/strong&gt;. Decryption is a cryptographic operation. If you decrypt first and verify second, you are processing attacker-controlled bytes with your secret key before you have any assurance those bytes are legitimate. Everything observable about that processing, including how long it takes and whether it throws an error, becomes a signal the attacker can read.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three ways to combine a cipher and a MAC
&lt;/h2&gt;

&lt;p&gt;There are three classical constructions, and they differ only in sequencing.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Construction&lt;/th&gt;
&lt;th&gt;What gets authenticated&lt;/th&gt;
&lt;th&gt;Used by&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Encrypt-and-MAC&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The plaintext. Ciphertext and MAC are sent side by side.&lt;/td&gt;
&lt;td&gt;SSH (transport layer, classic mode)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MAC-then-Encrypt&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The plaintext, then the whole thing is encrypted together.&lt;/td&gt;
&lt;td&gt;TLS 1.0 through 1.2 (CBC cipher suites)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Encrypt-then-MAC&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The ciphertext. The MAC covers exactly what travels on the wire.&lt;/td&gt;
&lt;td&gt;IPsec, and the TLS Encrypt-then-MAC extension (RFC 7366)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Only encrypt-then-MAC lets the receiver verify the MAC &lt;em&gt;without touching the cipher first&lt;/em&gt;. The MAC is computed over the ciphertext, so the receiver recomputes it over the ciphertext it just received, compares, and only decrypts if the comparison passes. Forged or tampered packets are rejected at the door, before the decryption key ever processes them. Hugo Krawczyk proved in 2001 that encrypt-then-MAC is secure for any secure cipher and any secure MAC, which is a much stronger guarantee than the other two orderings can offer.&lt;/p&gt;

&lt;h2&gt;
  
  
  How MAC-then-encrypt broke TLS
&lt;/h2&gt;

&lt;p&gt;MAC-then-encrypt feels natural. You authenticate the real message, then wrap the authenticated bundle in a cipher. The problem is what the receiver has to do to check it. The receiver gets ciphertext, and the MAC is hidden inside that ciphertext, so the receiver has no choice but to decrypt first. Decryption is the cryptographic operation that happens before verification. That is the doom condition exactly.&lt;/p&gt;

&lt;p&gt;With CBC-mode ciphers, decryption involves removing padding that was added to round the plaintext up to a block boundary. If the padding is malformed, the receiver behaves differently than if the padding is valid: a different error, or a different amount of work before the error. That difference is a padding oracle. Serge Vaudenay described the attack in 2002. An attacker who can submit modified ciphertexts and watch how the server reacts can recover the plaintext one byte at a time, without ever knowing the key.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why this is so dangerous:&lt;/strong&gt; A padding oracle does not break the cipher. AES is untouched. The attacker recovers plaintext purely from the receiver's observable reaction to decrypting forged data. The vulnerability lives in the ordering, not in any primitive.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The TLS designers tried to close the oracle by making the error responses identical. That moved the leak from the error message to the clock. The 2013 Lucky Thirteen attack measured tiny timing differences in how long the MAC check ran depending on how much padding was removed, and reconstructed plaintext from the timing alone. Years of patches followed, each one papering over a leak that existed only because verification happened after decryption instead of before it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two fixes the industry actually adopted
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Encrypt-then-MAC as a retrofit
&lt;/h3&gt;

&lt;p&gt;RFC 7366, published in 2014, added an encrypt-then-MAC extension to TLS so that existing CBC cipher suites could authenticate the ciphertext instead of the plaintext. With the MAC over the ciphertext, the server rejects tampered records before decrypting, and the padding oracle disappears because there is no decryption of attacker-controlled data to observe. It was a correct fix, but a retrofit onto a protocol that had shipped the wrong order for over a decade.&lt;/p&gt;

&lt;h3&gt;
  
  
  AEAD as the permanent answer
&lt;/h3&gt;

&lt;p&gt;The durable fix was to stop asking engineers to wire a cipher and a MAC together by hand. Authenticated encryption with associated data (AEAD) bundles confidentiality and integrity into a single primitive with one interface. AES-GCM and ChaCha20-Poly1305 are the two in common use. There is no separate MAC step to misorder, because the construction handles authentication internally and is designed so that verification gates decryption.&lt;/p&gt;

&lt;p&gt;TLS 1.3 took the strongest possible position: it removed CBC cipher suites entirely and permits only AEAD constructions. The protocol no longer offers a way to get the order wrong, because the order is no longer a choice the implementer makes. That is the cleanest expression of the lesson. When a class of bug comes from a decision, the most reliable fix is to remove the decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this means when you read a system's design
&lt;/h2&gt;

&lt;p&gt;The doom principle is a fast diagnostic for evaluating any protocol or library that handles encrypted messages. Two questions cover most of it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Is the MAC computed over the ciphertext or the plaintext?&lt;/strong&gt; Ciphertext is the answer you want. It means the receiver can reject forgeries before decrypting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Does the receiver verify before it decrypts, with no observable difference in behavior between a failed MAC and a malformed plaintext?&lt;/strong&gt; Any branch, error, or timing gap that depends on decrypting unverified data is a potential oracle.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In practice the cleanest answer to both is to not roll the combination yourself. Use a vetted AEAD construction through a library that has been reviewed, and let the single primitive enforce the ordering for you. The same reasoning runs through everything we build at Haven: AEAD ciphers for symmetric encryption, audited implementations rather than hand-assembled cipher-and-MAC pairs, and a strong default bias against any code path that processes data before it has been authenticated. The doom principle is old, but the failure it describes still ships in new systems whenever someone decides the order is just a detail.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/cryptographic-doom-principle-explained/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>encryption</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>Private Set Intersection: Finding What Two Parties Share Without Revealing the Rest</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Tue, 23 Jun 2026 12:18:59 +0000</pubDate>
      <link>https://dev.to/havenmessenger/private-set-intersection-finding-what-two-parties-share-without-revealing-the-rest-c83</link>
      <guid>https://dev.to/havenmessenger/private-set-intersection-finding-what-two-parties-share-without-revealing-the-rest-c83</guid>
      <description>&lt;p&gt;Private Set Intersection, usually shortened to PSI, is a protocol for two parties who each hold a set of items. They want to compute the items the two sets have in common. The requirement is strict: neither party should learn anything about the other party's items that are not in the intersection. If your contact list has 400 numbers and three of them are app users, you learn those three, and the server learns those three, and nothing about the other 397 leaves your device in usable form.&lt;/p&gt;

&lt;p&gt;That sounds like it should be impossible. How do you compare two lists without showing them to each other? The trick is that you never compare the plaintext items. You compare cryptographic transformations of them, chosen so that equal inputs collide and unequal inputs reveal nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the Naive Approaches Fail
&lt;/h2&gt;

&lt;p&gt;The first idea most people have is hashing. Both sides hash their items and compare the hashes. Equal items produce equal hashes, so the intersection falls out. The problem is that &lt;a href="https://havenmessenger.com/blog/posts/password-breach-checking-k-anonymity/" rel="noopener noreferrer"&gt;hashes of low-entropy data are reversible by brute force&lt;/a&gt;. Phone numbers live in a space of maybe ten billion possibilities. A server that receives the SHA-256 of a phone number can simply hash every possible number and build a lookup table. Hashing a phone number hides nothing from a motivated adversary.&lt;/p&gt;

&lt;p&gt;The second idea is to add a secret salt. But for two parties to get matching hashes, they would need to share the same salt, and once they share it the brute-force attack works again for whoever holds it. A salt that both parties know is not a secret. This is the wall that makes PSI a genuine cryptographic problem rather than a hashing exercise.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The defining property:&lt;/strong&gt; PSI is not "hash and compare." Hashing identifiers like phone numbers or emails leaks them to brute force because the input space is small. PSI uses keyed operations where neither party ever holds a value that lets them reverse the other party's non-matching items.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Diffie-Hellman Style Construction
&lt;/h2&gt;

&lt;p&gt;One of the cleanest PSI designs builds on the same hardness assumption as &lt;a href="https://havenmessenger.com/blog/posts/diffie-hellman-key-exchange-explained/" rel="noopener noreferrer"&gt;Diffie-Hellman key exchange&lt;/a&gt;. The idea is double encryption with two secret keys, where the order of application does not matter.&lt;/p&gt;

&lt;p&gt;Suppose the client has a secret exponent &lt;em&gt;a&lt;/em&gt; and the server has a secret exponent &lt;em&gt;b&lt;/em&gt;. Each item is first mapped onto a point in a group where the discrete logarithm problem is hard. The client raises each of its items to the power &lt;em&gt;a&lt;/em&gt; and sends them over. The server raises those to the power &lt;em&gt;b&lt;/em&gt;, producing items locked under both keys, and sends them back. Separately, the server raises its own items to the power &lt;em&gt;b&lt;/em&gt;, the client raises those to the power &lt;em&gt;a&lt;/em&gt;, and now both sets are locked under both &lt;em&gt;a&lt;/em&gt; and &lt;em&gt;b&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Because exponentiation commutes, an item that appears in both sets ends up at exactly the same doubly-locked value regardless of which side applied which key first. The client compares the two doubly-locked sets and reads off the matches. For any item the client did not have, it only ever saw a value locked under the server's secret &lt;em&gt;b&lt;/em&gt;, which it cannot strip off, so it learns nothing about those.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Faster Modern Family: OPRFs and OT
&lt;/h2&gt;

&lt;p&gt;The Diffie-Hellman construction is elegant but uses public-key operations on every item, which is slow at scale. Most high-performance PSI today is built from two other primitives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Oblivious Pseudorandom Functions (OPRF).&lt;/strong&gt; The server holds a secret key for a pseudorandom function. The client gets the function applied to its inputs without the server learning those inputs, and without the client learning the key. The client ends up with keyed, non-reversible tags it can match against a list of the server's tags.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Oblivious Transfer (OT).&lt;/strong&gt; A primitive where a receiver picks one of several values a sender holds, the receiver learns only the value it chose, and the sender never learns which one was chosen. Modern OT extension makes millions of these cheap, which is what lets OT-based PSI process large sets quickly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These constructions can intersect sets of millions of items in seconds, which is why PSI moved from a theoretical curiosity to something deployable in consumer apps over the last decade.&lt;/p&gt;

&lt;h2&gt;
  
  
  Variants That Matter in Practice
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Variant&lt;/th&gt;
&lt;th&gt;What each side learns&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Plain PSI&lt;/td&gt;
&lt;td&gt;The intersection itself, nothing else.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PSI cardinality&lt;/td&gt;
&lt;td&gt;Only the size of the intersection, not which items. Useful for analytics like "how many of my contacts use this."&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PSI sum / analytics&lt;/td&gt;
&lt;td&gt;An aggregate over matched items, such as a total spend, without revealing the matched identities. This underpinned conversion-measurement systems.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unbalanced PSI&lt;/td&gt;
&lt;td&gt;Optimized for the common case where one set is huge (server user base) and the other is small (your contacts), shifting work off the small client.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Where the Threat Model Gets Subtle
&lt;/h2&gt;

&lt;p&gt;PSI protects the inputs during the computation. It does not protect you from a party that simply lies about its set. A malicious server can run the protocol with a set crafted to probe for specific targets. If the server wants to know whether you have one particular number, it can run a PSI where its "set" is just that number, and the result tells it yes or no. PSI guarantees nobody learns your non-matching items; it does not guarantee the other side is asking an honest question.&lt;/p&gt;

&lt;p&gt;This is why &lt;a href="https://havenmessenger.com/blog/posts/contact-discovery-privacy/" rel="noopener noreferrer"&gt;private contact discovery&lt;/a&gt; in real systems pairs PSI-style cryptography with rate limiting, abuse detection, and sometimes trusted hardware enclaves. Some designs deliberately avoid server-side contact discovery altogether because even a perfect PSI still tells the server the size and rate of your queries. The cryptography is one layer; the deployment around it carries the rest of the weight.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Belongs in Your Mental Model
&lt;/h2&gt;

&lt;p&gt;PSI is a good example of a broader truth in privacy engineering: the question is rarely "is it encrypted." It is "who learns what, and under what assumptions." A feature can be cryptographically private in the narrow technical sense while still leaking metadata about how often you use it and how large your contact graph is. When you evaluate a tool that promises private matching, contact discovery, or breach checking, the useful questions are what exactly is computed, what each party walks away knowing, and whether a dishonest party can turn the protocol into a probe.&lt;/p&gt;

&lt;p&gt;For builders, PSI and its cousins, like &lt;a href="https://havenmessenger.com/blog/posts/private-information-retrieval-explained/" rel="noopener noreferrer"&gt;private information retrieval&lt;/a&gt; and &lt;a href="https://havenmessenger.com/blog/posts/secure-multiparty-computation-explained/" rel="noopener noreferrer"&gt;secure multiparty computation&lt;/a&gt;, are the toolkit for computing on data you are not allowed to see. They are slower and more constrained than plaintext, but the gap keeps closing, and the privacy they buy is real.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/private-set-intersection-explained/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>encryption</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>HMAC Explained: Why a Hash Alone Cannot Prove Who Sent a Message</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Mon, 22 Jun 2026 12:18:48 +0000</pubDate>
      <link>https://dev.to/havenmessenger/hmac-explained-why-a-hash-alone-cannot-prove-who-sent-a-message-6mp</link>
      <guid>https://dev.to/havenmessenger/hmac-explained-why-a-hash-alone-cannot-prove-who-sent-a-message-6mp</guid>
      <description>&lt;p&gt;A SHA-256 hash next to a download link tells you the bytes you downloaded are the bytes the checksum was computed over. If an attacker can change the file, they can also change the published checksum to match. A plain hash protects against accidental corruption, not against a deliberate adversary who controls the channel.&lt;/p&gt;

&lt;p&gt;The property you usually want is stronger: that the message came from someone who holds a particular secret, and that not a single bit has changed since they produced it. That property is called message authentication, and the standard tool for it with symmetric keys is the keyed-hash message authentication code, or HMAC.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrity versus authenticity
&lt;/h2&gt;

&lt;p&gt;These two words get used loosely, so it is worth pinning them down. Integrity means the data has not been altered. Authenticity means you know who it came from. A checksum gives you integrity against noise on the wire. It gives you nothing against an adversary, because the checksum function is public and unkeyed.&lt;/p&gt;

&lt;p&gt;A message authentication code gives you both at once, but only relative to a shared key. The sender computes a tag over the message using a key both parties know. The receiver recomputes the tag with the same key and checks that it matches. Because producing a valid tag requires the key, a matching tag tells the receiver two things: the message is unchanged, and it was produced by someone holding the key.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The boundary.&lt;/strong&gt; A MAC proves the sender holds the shared key. It does not prove which of the two parties sent the message, because both hold the same key. For non-repudiation, where you need to prove a specific individual signed something, you need a digital signature with a private key. A MAC is symmetric; a signature is asymmetric.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The tempting design that does not work
&lt;/h2&gt;

&lt;p&gt;The obvious way to turn a hash into a keyed function is to prepend the key to the message and hash the whole thing: &lt;code&gt;tag = H(key || message)&lt;/code&gt;. It looks fine. The key is secret, so an attacker who does not know it cannot compute the tag. Unfortunately, this construction is broken for the most common hash functions of the SHA-1 and SHA-2 families, and the reason is a property called length extension.&lt;/p&gt;

&lt;p&gt;Hashes like SHA-256 are built on the Merkle-Damgard construction. They process a message in fixed-size blocks, and the output is simply the function's internal state after the last block. That is the flaw an attacker exploits. If you know &lt;code&gt;H(key || message)&lt;/code&gt; and the length of the secret, you can set the hash function's internal state to the published digest and keep feeding it more data. You produce a valid tag for &lt;code&gt;key || message || padding || extra&lt;/code&gt; without ever knowing the key.&lt;/p&gt;

&lt;p&gt;This is not theoretical. The Flickr API was vulnerable to exactly this in 2009, allowing forged API calls against a signing scheme that prepended a secret to the request parameters. The lesson is that you cannot reason about cryptographic constructions from the outside. A scheme can look secure and fail to a structural property of the primitive underneath it.&lt;/p&gt;

&lt;h2&gt;
  
  
  How HMAC is actually built
&lt;/h2&gt;

&lt;p&gt;HMAC, defined in RFC 2104 and analyzed by Mihir Bellare, Ran Canetti, and Hugo Krawczyk, sidesteps length extension by hashing twice with two derived keys. The structure is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;HMAC(K, m) = H( (K' XOR opad) || H( (K' XOR ipad) || m ) )&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here &lt;code&gt;K'&lt;/code&gt; is the key adjusted to the hash's block size, &lt;code&gt;ipad&lt;/code&gt; is the byte 0x36 repeated, and &lt;code&gt;opad&lt;/code&gt; is 0x5c repeated. The inner hash binds the key to the message. The outer hash then hashes that result again with a different keyed prefix. Because the output of HMAC is the digest of a digest, an attacker cannot continue the computation from a published tag. The internal state they would need is the inner hash, which they never see.&lt;/p&gt;

&lt;p&gt;The deeper result is what makes HMAC trustworthy in practice: it is provably secure as long as the underlying hash's compression function behaves as a pseudorandom function. This is why HMAC-SHA-1 remained safe for authentication well after SHA-1 collisions became practical. A collision attack lets you find two messages with the same hash; it does not let you recover the HMAC key or forge a tag without it. Construction matters as much as the primitive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verifying tags without leaking timing
&lt;/h2&gt;

&lt;p&gt;There is a subtle trap in the verification step. The natural way to compare the received tag against the computed one is a byte-by-byte comparison that stops at the first mismatch. That early exit leaks information. An attacker measuring how long verification takes can learn how many leading bytes they guessed correctly, then forge a valid tag one byte at a time.&lt;/p&gt;

&lt;p&gt;The fix is a constant-time comparison that always examines every byte regardless of where the first difference is. Most cryptographic libraries ship one, such as &lt;code&gt;hmac.compare_digest&lt;/code&gt; in Python or &lt;code&gt;crypto.timingSafeEqual&lt;/code&gt; in Node. A correct algorithm with a careless comparison is still exploitable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where HMAC shows up
&lt;/h2&gt;

&lt;p&gt;Once you know the shape of it, HMAC is visible across the protocols you use daily.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Context&lt;/th&gt;
&lt;th&gt;What HMAC does there&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;TLS record layer&lt;/td&gt;
&lt;td&gt;Older cipher suites use HMAC to authenticate each record; modern AEAD suites fold this into the cipher itself.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Key derivation&lt;/td&gt;
&lt;td&gt;HKDF is built entirely on HMAC, using it to extract and expand key material from a shared secret.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JWT tokens&lt;/td&gt;
&lt;td&gt;The HS256 signing algorithm is HMAC-SHA-256 over the token header and payload.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TOTP codes&lt;/td&gt;
&lt;td&gt;The six-digit codes from authenticator apps are HMAC of a counter or timestamp, truncated to digits.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API request signing&lt;/td&gt;
&lt;td&gt;Cloud provider request signatures authenticate the request body and headers under your secret key.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  When not to reach for it
&lt;/h3&gt;

&lt;p&gt;HMAC authenticates; it does not encrypt. A message protected only by HMAC is fully readable, just tamper-evident. If you need both confidentiality and authenticity, the modern answer is an authenticated encryption (AEAD) mode like AES-GCM or ChaCha20-Poly1305, which integrates the authentication tag into the cipher and removes the chance of combining encryption and a MAC incorrectly. HMAC remains the right tool when there is nothing to hide and everything to verify, such as a download signature, a webhook payload, or a session cookie that must not be forged.&lt;/p&gt;

&lt;h2&gt;
  
  
  The takeaway
&lt;/h2&gt;

&lt;p&gt;A hash answers "did this change?" An HMAC answers "did this change, and was it produced by someone holding the key?" The gap between those two questions is where most real attacks live, and the design of HMAC, two nested hashes with two derived keys, exists because the simpler answer to that gap turned out to be forgeable. The next time you see a SHA-256 sum sitting next to a download with no key behind it, you know exactly what it does and does not promise.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/hmac-message-authentication-explained/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>encryption</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>Oblivious HTTP Explained: Separating Who You Are From What You Ask</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Sun, 21 Jun 2026 12:19:31 +0000</pubDate>
      <link>https://dev.to/havenmessenger/oblivious-http-explained-separating-who-you-are-from-what-you-ask-1g8d</link>
      <guid>https://dev.to/havenmessenger/oblivious-http-explained-separating-who-you-are-from-what-you-ask-1g8d</guid>
      <description>&lt;p&gt;Most privacy tools encrypt the contents of a request. Oblivious HTTP attacks a different problem: making sure the server that learns your IP address is never the same server that reads your request. Standardized as RFC 9458 in 2024, it is a small, sharp tool for a specific class of telemetry and lookup traffic.&lt;/p&gt;

&lt;p&gt;When your phone reports a crash, checks a URL against a safe-browsing list, or sends an anonymized usage metric, two facts travel together by default: the contents of that request, and the network address it came from. A single server on the receiving end sees both. Over millions of requests, that pairing is enough to build a profile keyed to you, even when each individual message looks innocuous.&lt;/p&gt;

&lt;p&gt;Oblivious HTTP, or OHTTP, exists to break that pairing. The design goal is narrow and worth stating precisely: ensure that no single party sees both the client's identity and the client's message. It does this not with heavy anonymity machinery but with two cooperating servers and one layer of public-key encryption.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Two-Server Split
&lt;/h2&gt;

&lt;p&gt;OHTTP introduces four roles. The &lt;strong&gt;client&lt;/strong&gt; wants to send a request. The &lt;strong&gt;oblivious relay&lt;/strong&gt; receives that request and forwards it. The &lt;strong&gt;oblivious gateway&lt;/strong&gt; decrypts the request and passes it to the &lt;strong&gt;target&lt;/strong&gt; resource that actually answers it. The relay and gateway are operated by different organizations that are trusted not to collude.&lt;/p&gt;

&lt;p&gt;The mechanism rests on a clean division of knowledge:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;relay&lt;/strong&gt; sees your IP address, because you connect to it directly. It does not see your request, because the request is encrypted to the gateway's public key, which the relay does not hold.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;gateway&lt;/strong&gt; sees your request, because it can decrypt it. It does not see your IP address, because the connection it receives comes from the relay, not from you.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Neither server alone can link a person to a query. The privacy property holds as long as the two operators do not combine their logs. That non-collusion assumption is the load-bearing trust in the whole design, and it is why deployments deliberately put the relay and gateway under separate administrative control.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The relay knows who you are but not what you said. The gateway knows what you said but not who you are. Privacy fails only if these two parties merge their records.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How the Encryption Actually Works
&lt;/h2&gt;

&lt;p&gt;OHTTP does not invent its own cryptography. The encapsulation is built on HPKE (Hybrid Public Key Encryption, RFC 9180), the same modern primitive used in TLS Encrypted Client Hello and the Message Layer Security protocol.&lt;/p&gt;

&lt;p&gt;The flow looks like this. The gateway publishes a &lt;strong&gt;key configuration&lt;/strong&gt;: an HPKE public key plus the identifiers for the key derivation function and the authenticated-encryption algorithm it expects. The client fetches this configuration, then uses HPKE to encapsulate its binary HTTP request into an encrypted blob carried with the media type &lt;code&gt;message/ohttp-req&lt;/code&gt;. The client sends that blob to the relay over an ordinary HTTPS connection.&lt;/p&gt;

&lt;p&gt;The relay forwards the blob to the gateway. The gateway decrypts it, recovers the inner request, and hands it to the target. The response travels back through the same path, encrypted with a key derived from the original exchange and tagged &lt;code&gt;message/ohttp-res&lt;/code&gt;. The relay shuttles bytes in both directions without ever holding a key that would let it read them.&lt;/p&gt;

&lt;p&gt;Because the inner payload is binary HTTP rather than a fresh connection, OHTTP suits single request-and-response interactions. There is no long-lived session, no cookies surviving across requests, and no opportunity for the target to set a tracking identifier that persists.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where OHTTP Is Not the Right Tool
&lt;/h2&gt;

&lt;p&gt;OHTTP is sometimes confused with Tor or with a VPN. It is neither, and the differences are the point.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;OHTTP&lt;/th&gt;
&lt;th&gt;Tor&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hops&lt;/td&gt;
&lt;td&gt;One relay, one gateway&lt;/td&gt;
&lt;td&gt;Three relays, rotating circuits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for&lt;/td&gt;
&lt;td&gt;Single request/response, telemetry, lookups&lt;/td&gt;
&lt;td&gt;Interactive browsing, full sessions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latency cost&lt;/td&gt;
&lt;td&gt;Low, one extra hop&lt;/td&gt;
&lt;td&gt;Higher, multiple hops&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trust model&lt;/td&gt;
&lt;td&gt;Two named parties, assumed non-colluding&lt;/td&gt;
&lt;td&gt;Distributed volunteers, no single trusted party&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Tor protects against a much broader adversary and provides stronger anonymity, at the cost of latency and a volunteer-operated network. OHTTP makes a smaller promise to a smaller threat model, and in exchange it is cheap enough to run on every metrics ping a large service sends. A VPN, by contrast, routes all your traffic through one operator who sees both your address and your destinations, which is exactly the pairing OHTTP refuses to allow.&lt;/p&gt;

&lt;p&gt;OHTTP also does not hide that you are using OHTTP. The relay still sees your IP connecting to it. And it does nothing about timing or volume correlation if the same two operators decide to misbehave together. It is a targeted decoupling, not a cloak.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where It Is Being Used
&lt;/h2&gt;

&lt;p&gt;The protocol moved from draft to RFC because real systems needed it. It underpins privacy-preserving telemetry designs and aggregation protocols where a server should be able to count events without learning who generated them. Infrastructure providers including Cloudflare and Fastly have offered relay services, and the model fits any case where a service wants useful aggregate data without building a per-user dossier as a side effect.&lt;/p&gt;

&lt;p&gt;The pattern generalizes well beyond HTTP requests. The same shape appears in Oblivious DoH, where DNS queries are split across a proxy and a resolver so that no one server sees both the client and the domain it is looking up. OHTTP is the more general statement of that idea.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The honest framing is that OHTTP narrows trust rather than removing it. You still trust that two organizations will not pool their logs. You have simply made the privacy-violating action require active collusion instead of passive default.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why This Design Matters
&lt;/h2&gt;

&lt;p&gt;Most surveillance is not the product of a single dramatic interception. It is the slow accumulation of metadata that nobody individually decided to weaponize. Request contents get paired with source addresses because that is what a normal server log looks like, and the profile assembles itself.&lt;/p&gt;

&lt;p&gt;OHTTP is interesting because it changes the default. It takes a piece of infrastructure that would otherwise collect a linkable record and restructures it so the linkable record never exists in one place. That is a more durable kind of protection than a policy promise not to look, because it removes the capability rather than asking for restraint. If you care about metadata surveillance, designs that make the harmful correlation structurally impossible are the ones worth paying attention to.&lt;/p&gt;

&lt;p&gt;It will not anonymize your browsing or replace Tor. But for the steady background hum of lookups and telemetry that modern apps generate, separating the who from the what is a meaningful improvement, and it is now a standardized, deployable one.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/oblivious-http-explained/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>encryption</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>SCRAM: How to Prove a Password Without Sending It</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Sat, 20 Jun 2026 12:19:07 +0000</pubDate>
      <link>https://dev.to/havenmessenger/scram-how-to-prove-a-password-without-sending-it-400e</link>
      <guid>https://dev.to/havenmessenger/scram-how-to-prove-a-password-without-sending-it-400e</guid>
      <description>&lt;p&gt;When you log in to PostgreSQL, MongoDB, or an XMPP server, your password usually never crosses the wire. Instead the two sides run a short challenge-response dance called SCRAM, and each proves something to the other without revealing what it knows. The design is older than most people realize and quietly correct in ways many login systems still are not.&lt;/p&gt;

&lt;p&gt;The obvious way to log in is to send your password to the server, which hashes it and compares it to a stored hash. This works, and a great deal of the internet still does exactly this over TLS. But it has a structural weakness: at the moment of login, the server holds your plaintext password in memory. A compromised server, a verbose log line, or a debugging proxy can capture it. And the server has to be trusted to hash it correctly rather than just store what it received.&lt;/p&gt;

&lt;p&gt;SCRAM, the Salted Challenge Response Authentication Mechanism defined in RFC 5802, takes a different route. The client proves it knows the password by performing a computation that only the password-holder could perform, and the server verifies that proof against stored values that are not the password and cannot be replayed. Neither side ever transmits the secret.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Server Actually Stores
&lt;/h2&gt;

&lt;p&gt;SCRAM never stores your password, and it does not even store a single hash of it. For each user, the server keeps four things: a random &lt;strong&gt;salt&lt;/strong&gt;, an &lt;strong&gt;iteration count&lt;/strong&gt;, a &lt;strong&gt;StoredKey&lt;/strong&gt;, and a &lt;strong&gt;ServerKey&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;These derive from the password through a chain. The password and salt feed a slow, iterated function (PBKDF2) to produce a SaltedPassword. From that, an HMAC produces a ClientKey, and a single hash of the ClientKey produces the StoredKey. A separate HMAC produces the ServerKey. The server keeps StoredKey and ServerKey; it discards ClientKey and the password.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The server stores enough to &lt;em&gt;verify&lt;/em&gt; a login but not enough to &lt;em&gt;perform&lt;/em&gt; one. Someone who steals the SCRAM database cannot turn around and authenticate as a user without first cracking the salted, iterated password. This is the same reason we hash passwords with slow functions instead of storing them, pushed one step further into the login protocol itself.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Four-Message Handshake
&lt;/h2&gt;

&lt;p&gt;A SCRAM exchange is four messages. Each carries a nonce, a random value that makes every session unique and kills replay attacks.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Client first:&lt;/strong&gt; the client sends its username and a client nonce.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server first:&lt;/strong&gt; the server replies with the salt, the iteration count, and a combined nonce (the client nonce with server randomness appended).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client final:&lt;/strong&gt; the client computes its proof and sends it, along with the combined nonce.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server final:&lt;/strong&gt; the server verifies the proof and returns a server signature, proving to the client that the server also knew the stored values.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The clever part is the third message. The client derives the ClientKey from the password, computes a ClientSignature by HMAC-ing the full transcript of the exchange under the StoredKey, and XORs the two together into a &lt;strong&gt;ClientProof&lt;/strong&gt;. It sends the proof, not the key.&lt;/p&gt;

&lt;p&gt;The server takes the proof, XORs it with its own recomputed ClientSignature to recover the candidate ClientKey, hashes that, and checks whether the result equals the StoredKey it has on file. If they match, the client proved it knew the password. The server never reconstructed the password, only confirmed the proof was consistent with its stored verifier.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mutual Authentication, For Free
&lt;/h2&gt;

&lt;p&gt;SCRAM is not just the client proving itself to the server. The fourth message runs the logic in reverse: the server computes a ServerSignature over the transcript using the ServerKey and sends it back. The client, which can derive the ServerKey from the password, checks it.&lt;/p&gt;

&lt;p&gt;This means a fake server cannot complete the handshake. An attacker who intercepts the exchange and tries to impersonate the server fails at the final step, because it does not hold the ServerKey and cannot produce a valid ServerSignature. The client learns it is talking to the real server, not just the other way around. Few password protocols give you that property without extra machinery.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the Transcript Is Signed
&lt;/h2&gt;

&lt;p&gt;Both signatures are computed over the entire message exchange so far, called the AuthMessage, not just over a single challenge. This binds the proof to this specific conversation. An attacker who records one login cannot replay the captured proof in a later session, because the nonces and therefore the transcript differ every time. It also means a man-in-the-middle cannot quietly alter the negotiated parameters without invalidating both signatures.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Threat&lt;/th&gt;
&lt;th&gt;Plain password-over-TLS&lt;/th&gt;
&lt;th&gt;SCRAM&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Server sees plaintext password&lt;/td&gt;
&lt;td&gt;Yes, at login&lt;/td&gt;
&lt;td&gt;Never&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stolen database lets attacker log in directly&lt;/td&gt;
&lt;td&gt;Depends on hashing&lt;/td&gt;
&lt;td&gt;No, must crack first&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Replay of a captured login&lt;/td&gt;
&lt;td&gt;Possible if TLS fails&lt;/td&gt;
&lt;td&gt;Blocked by nonces&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Client verifies the server&lt;/td&gt;
&lt;td&gt;Only via TLS cert&lt;/td&gt;
&lt;td&gt;Built into the handshake&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The Honest Limits
&lt;/h2&gt;

&lt;p&gt;SCRAM is a real improvement, but it is not a force field, and it pays to know its edges.&lt;/p&gt;

&lt;p&gt;First, it is not a substitute for a secure channel. SCRAM should run inside TLS. The channel-binding variants (SCRAM-SHA-256-PLUS) tie the SCRAM exchange to the underlying TLS connection, which defends against a relay attack where someone sits between client and server on separate TLS sessions. Without channel binding, a sufficiently positioned attacker can still relay the handshake. Use the PLUS variant when both sides support it.&lt;/p&gt;

&lt;p&gt;Second, the stored verifiers are offline-crackable. If an attacker steals StoredKey, ServerKey, and the salt, they can mount an offline guessing attack against the password, just as they could against any password hash. The iteration count is your defense, and the protocol lets the server choose it. Too low, and cracking is cheap. This is why a strong, high-entropy password still matters even with SCRAM in front of it. A long passphrase is what makes the offline attack hopeless.&lt;/p&gt;

&lt;p&gt;Third, SCRAM authenticates a password. It is not multi-factor authentication, and it does not protect against phishing of the password itself at a fake login page outside the protocol. For the strongest account security, password-based mechanisms like SCRAM are increasingly paired with, or replaced by, public-key methods such as passkeys that have no shared secret to steal at all.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;SCRAM belongs to the same family as SRP and the newer OPAQUE protocol: password authentication that keeps the secret off the wire and out of the server's hands. SCRAM is the pragmatic, widely deployed member of that family, which is why you find it under PostgreSQL, MongoDB, Kafka, and XMPP rather than in a research paper.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why This Pattern Matters
&lt;/h2&gt;

&lt;p&gt;The recurring theme across modern security design is the same: minimize what any single party has to be trusted with. SCRAM applies that to login. The server is trusted to verify you, not to hold your password. The wire carries a proof, not a secret. The stored data confirms a guess, it does not enable an impersonation.&lt;/p&gt;

&lt;p&gt;At Haven, the same instinct runs through the whole system. Your passphrase derives keys on your device and never reaches our servers, not even as a hash. We would rather hold as little of your secret as the math allows, because the safest thing to do with a secret is never to receive it. SCRAM is one small, well-worn example of that principle working in practice.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/scram-authentication-explained/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>encryption</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>PASETO vs JWT: A Token Format That Removes the Footguns</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Fri, 19 Jun 2026 12:17:42 +0000</pubDate>
      <link>https://dev.to/havenmessenger/paseto-vs-jwt-a-token-format-that-removes-the-footguns-3gl0</link>
      <guid>https://dev.to/havenmessenger/paseto-vs-jwt-a-token-format-that-removes-the-footguns-3gl0</guid>
      <description>&lt;p&gt;JSON Web Tokens are everywhere, and most of their famous vulnerabilities trace back to a single design choice: the token tells the verifier which algorithm to use. PASETO was built by people who got tired of cleaning up after that decision. It is worth understanding even if you never adopt it — because it shows what a token format looks like when security is the default, not a configuration option.&lt;/p&gt;

&lt;p&gt;A bearer token is a short string a client presents to prove it is allowed to do something. The server issued it, signed or encrypted it, and trusts it on sight because the cryptography says it has not been tampered with. JSON Web Tokens (JWT) are the dominant format for this, baked into OAuth, OpenID Connect, and countless session systems. PASETO — Platform-Agnostic Security Tokens — is a deliberate alternative, designed by Scott Arciszewski of the Paragon Initiative as a response to the recurring ways JWT implementations get broken.&lt;/p&gt;

&lt;p&gt;The two formats solve the same problem. The difference is philosophy: JWT gives you a flexible cryptographic toolbox and trusts you to wield it safely. PASETO hands you exactly one safe option per version and refuses to let you negotiate.&lt;/p&gt;

&lt;h2&gt;
  
  
  The header is where JWT goes wrong
&lt;/h2&gt;

&lt;p&gt;A JWT carries a header object that declares its own algorithm — &lt;code&gt;{"alg": "RS256"}&lt;/code&gt;, for example. The verifier reads that field and uses the named algorithm to check the signature. This is the root of JWT's two most infamous attack classes.&lt;/p&gt;

&lt;p&gt;The first is &lt;strong&gt;the "none" algorithm&lt;/strong&gt;. The JWT spec includes &lt;code&gt;alg: none&lt;/code&gt; for unsigned tokens. A naive verifier that honors the header will accept a token with no signature at all if an attacker sets &lt;code&gt;alg&lt;/code&gt; to &lt;code&gt;none&lt;/code&gt; and strips the signature. Whole authentication systems have been bypassed this way.&lt;/p&gt;

&lt;p&gt;The second is &lt;strong&gt;algorithm confusion&lt;/strong&gt;. Suppose a server verifies RS256 tokens using an RSA public key — which, being public, is not secret. An attacker changes the header to &lt;code&gt;HS256&lt;/code&gt; (HMAC) and signs the forged token using that public key as the HMAC secret. If the verifier sees &lt;code&gt;HS256&lt;/code&gt; and dutifully runs HMAC with its RSA public key as the key, the signature checks out. The public key was never meant to be a secret, but the token format let it become one.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The core lesson:&lt;/strong&gt; Both attacks exist because the verifier lets the attacker-supplied token choose the verification algorithm. The cryptographic primitives are fine. The protocol around them hands control to the wrong party.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  PASETO's answer: version and purpose, not negotiation
&lt;/h2&gt;

&lt;p&gt;A PASETO looks like &lt;code&gt;v4.public.&amp;lt;payload&amp;gt;.&amp;lt;optional-footer&amp;gt;&lt;/code&gt;. The two leading segments are not negotiable algorithm fields — they are a fixed &lt;strong&gt;version&lt;/strong&gt; and a fixed &lt;strong&gt;purpose&lt;/strong&gt;, and the cryptography for each is hard-coded into the library.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Version&lt;/strong&gt; pins the entire cryptographic suite. There is no menu. A v4 token uses exactly the v4 primitives.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Purpose&lt;/strong&gt; is either &lt;code&gt;local&lt;/code&gt; (symmetric authenticated encryption with a shared secret key) or &lt;code&gt;public&lt;/code&gt; (asymmetric digital signature, readable by anyone but forgeable by no one).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is no &lt;code&gt;none&lt;/code&gt;. There is no algorithm field for an attacker to rewrite. A v4 verifier configured to accept &lt;code&gt;v4.public&lt;/code&gt; tokens will only ever run Ed25519 signature verification; it cannot be tricked into running HMAC because the format gives it nowhere to express that request.&lt;/p&gt;

&lt;h3&gt;
  
  
  What the versions actually use
&lt;/h3&gt;

&lt;p&gt;PASETO defines paired versions so you can pick a NIST-friendly suite or a modern one:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;th&gt;local (encryption)&lt;/th&gt;
&lt;th&gt;public (signature)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;v3&lt;/strong&gt; (NIST)&lt;/td&gt;
&lt;td&gt;AES-256-CTR + HMAC-SHA-384&lt;/td&gt;
&lt;td&gt;ECDSA over P-384&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;v4&lt;/strong&gt; (modern)&lt;/td&gt;
&lt;td&gt;XChaCha20 + BLAKE2b keyed MAC&lt;/td&gt;
&lt;td&gt;Ed25519&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The modern v4 suite is the recommended default for new systems. The NIST-based v3 exists for environments with compliance requirements that mandate FIPS-style algorithms. Older v1/v2 versions are deprecated in favor of these two.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pre-authentication encoding closes the canonicalization gap
&lt;/h2&gt;

&lt;p&gt;Even with a fixed algorithm, signature schemes can be undermined by ambiguity in &lt;em&gt;what&lt;/em&gt; gets signed. If a token concatenates several fields before signing, an attacker who can shift a byte from one field into another may produce a different logical message with the same signed bytes — a canonicalization attack.&lt;/p&gt;

&lt;p&gt;PASETO addresses this with &lt;strong&gt;Pre-Authentication Encoding (PAE)&lt;/strong&gt;: before signing or encrypting, every piece (header, payload, footer, and in v3/v4 an optional implicit assertion) is length-prefixed and packed unambiguously. The signature commits to the exact structure, not just a concatenation, so fields cannot be smuggled across boundaries.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The footer is authenticated but &lt;em&gt;not&lt;/em&gt; encrypted — useful for data a verifier needs to read before decrypting, like a key identifier. Anything secret belongs in the payload, never the footer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  So should you switch?
&lt;/h2&gt;

&lt;p&gt;Not reflexively. JWT is not broken when implemented correctly: pin the expected algorithm server-side, reject &lt;code&gt;none&lt;/code&gt;, never let the token choose, and use a well-maintained library that does these things by default. Mature ecosystems — OAuth providers, identity platforms — speak JWT, and interoperability is a real constraint. PASETO has fewer libraries and less tooling around it.&lt;/p&gt;

&lt;p&gt;PASETO earns its place when you control both ends of the system and want the secure path to be the only path. For internal service-to-service tokens, session tokens in a first-party app, or any greenfield design where you are not bound to an existing JWT consumer, it removes an entire category of misconfiguration. The point is not that PASETO programmers are smarter — it is that the format gives them less rope.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Either way:&lt;/strong&gt; Tokens are bearer credentials: whoever holds one can use it. Keep lifetimes short, transmit only over TLS, store them where script injection cannot reach them, and have a revocation story. No token format fixes a stolen token.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/paseto-vs-jwt-tokens/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>encryption</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>Threshold Signatures and FROST: One Signature, No Single Signer</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Thu, 18 Jun 2026 12:18:17 +0000</pubDate>
      <link>https://dev.to/havenmessenger/threshold-signatures-and-frost-one-signature-no-single-signer-4djm</link>
      <guid>https://dev.to/havenmessenger/threshold-signatures-and-frost-one-signature-no-single-signer-4djm</guid>
      <description>&lt;p&gt;Splitting a key with Shamir's scheme protects a secret at rest, but to use it you have to reassemble the whole key in one place — and for one fatal moment, somebody holds all of it. Threshold signatures remove that moment entirely: a quorum jointly produces a valid signature while the complete private key never exists anywhere, not even briefly. FROST is the design that made this fast enough to deploy.&lt;/p&gt;

&lt;p&gt;Imagine three executives who must collectively authorize wire transfers, a custody service guarding crypto assets across geographically separate machines, or a certificate authority that does not want any single operator able to sign on its behalf. The shared requirement: an action that needs &lt;em&gt;multiple&lt;/em&gt; parties to agree, with no individual able to act alone, and ideally no single machine that — if compromised — hands an attacker the full signing power.&lt;/p&gt;

&lt;p&gt;There are several ways to approximate this, and they are not equally good. Understanding why threshold signatures win for many of these cases means understanding what the alternatives leak.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three Approaches, and Their Seams
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Secret sharing
&lt;/h3&gt;

&lt;p&gt;Shamir's Secret Sharing splits a key into &lt;em&gt;n&lt;/em&gt; shares such that any &lt;em&gt;t&lt;/em&gt; reconstruct it and fewer reveal nothing. It's elegant for protecting a key you rarely use. But the act of &lt;em&gt;using&lt;/em&gt; the key requires reassembling it — gathering &lt;em&gt;t&lt;/em&gt; shares onto one machine, which becomes a single point of total compromise at exactly the moment of highest value. The full key briefly exists. An attacker who owns that machine during signing owns everything.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multisignature (multisig)
&lt;/h3&gt;

&lt;p&gt;Multisig, familiar from Bitcoin, takes a different route: each party has a fully independent key, and the verifier checks that &lt;em&gt;t&lt;/em&gt; separate signatures are present. No key is ever combined — a real strength. The cost is on the verification side: the signatures are visible as multiple distinct signatures, the policy (who signed, how many are required) is exposed on-chain or on the wire, and the size and fees grow with the number of signers. It works, but it advertises its own structure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Threshold signatures
&lt;/h3&gt;

&lt;p&gt;A threshold signature scheme (TSS) gives you the best of both. Like multisig, no party holds the whole key. Unlike multisig, the parties run an interactive protocol that outputs &lt;strong&gt;one ordinary signature&lt;/strong&gt; — indistinguishable from a signature made by a single key. The verifier sees a normal signature against a single public key and has no idea, from the signature alone, that a quorum of five machines in four countries produced it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The key insight:&lt;/strong&gt; In a threshold scheme the full private key is never assembled — not during setup, not during signing, not ever. It exists only as a mathematical relationship distributed across the participants' individual key shares. There is no instant where stealing one machine's memory yields the whole secret.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Where FROST Comes In
&lt;/h2&gt;

&lt;p&gt;Threshold Schnorr signatures are appealing because Schnorr signatures are clean and linear, which makes them friendlier to "split across parties" math than ECDSA. But early threshold Schnorr constructions needed multiple interactive rounds of communication for every signature, and were fragile in the face of concurrent signing sessions — a serious problem for any real service handling parallel requests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FROST&lt;/strong&gt; — Flexible Round-Optimized Schnorr Threshold signatures, introduced by Komlo and Goldberg in 2020 and specified by the IETF in &lt;strong&gt;RFC 9591&lt;/strong&gt; (2024) — solved the practicality problem. Its headline properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Round efficiency.&lt;/strong&gt; Signing takes a single round of interaction when participants pre-process commitments in advance, or two rounds without pre-processing — a major improvement over earlier multi-round schemes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrency safety.&lt;/strong&gt; FROST is designed to remain secure even when many signing sessions run at once, avoiding the ROS-style attacks that broke naive parallel Schnorr signing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Standard output.&lt;/strong&gt; The result is a normal Schnorr signature, verifiable with the ordinary single-key verification algorithm. No special verifier is needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexible thresholds.&lt;/strong&gt; Any &lt;em&gt;t&lt;/em&gt;-of-&lt;em&gt;n&lt;/em&gt; policy, configurable at key-generation time.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How a FROST Signature Comes Together
&lt;/h2&gt;

&lt;p&gt;Without drowning in notation, the shape of the protocol is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Distributed key generation (DKG).&lt;/strong&gt; The &lt;em&gt;n&lt;/em&gt; participants jointly run a protocol that produces a shared public key and gives each participant a private &lt;em&gt;share&lt;/em&gt;. No party — and no coordinator — ever sees the corresponding full private key. (A trusted dealer can alternatively distribute shares, but DKG removes even that single point of trust.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Commitment.&lt;/strong&gt; Each of the &lt;em&gt;t&lt;/em&gt; signers picks fresh random nonces and publishes commitments to them. With pre-processing, this happens before the message to sign is even known.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Signing.&lt;/strong&gt; Given the message, each signer computes a partial signature using its share and its nonces, binding in the others' commitments to prevent manipulation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aggregation.&lt;/strong&gt; A coordinator (who needs no secret material) sums the partial signatures into one final Schnorr signature. The coordinator can verify each partial contribution, so a misbehaving signer can be identified rather than silently corrupting the result.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The randomness handling deserves emphasis. Schnorr signatures are catastrophically broken by nonce reuse — repeat a nonce and the private key falls out of the algebra. Distributing signing across parties multiplies the ways nonce handling can go wrong, which is exactly why FROST's careful, binding commitment structure (and its concurrency analysis) is the substance of the scheme, not a detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Threshold vs Multisig, Compared
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Multisig&lt;/th&gt;
&lt;th&gt;Threshold (FROST)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Full key ever assembled&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output signature&lt;/td&gt;
&lt;td&gt;Multiple, distinct&lt;/td&gt;
&lt;td&gt;One, ordinary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Policy visible to verifier&lt;/td&gt;
&lt;td&gt;Yes — exposes signers/threshold&lt;/td&gt;
&lt;td&gt;No — looks single-key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Size / cost scaling&lt;/td&gt;
&lt;td&gt;Grows with signers&lt;/td&gt;
&lt;td&gt;Constant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Needs interaction to sign&lt;/td&gt;
&lt;td&gt;No (signers act independently)&lt;/td&gt;
&lt;td&gt;Yes — signers coordinate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verifier complexity&lt;/td&gt;
&lt;td&gt;Must understand the policy&lt;/td&gt;
&lt;td&gt;Standard verification&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The trade-off is real: threshold signing requires the participants to be online and to interact during signing, whereas multisig signers can act fully independently. That interactivity, plus the subtlety of getting the protocol right, is the price of the privacy and uniformity benefits.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A threshold signature is the cryptographic version of a rule that says "this door needs three keys turned at once, but anyone watching it open just sees a door open." The structure of the authority is invisible from outside.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Where You'll Encounter It
&lt;/h2&gt;

&lt;p&gt;Threshold and multi-party signing now underpin institutional crypto custody, hot-wallet protection, distributed certificate authorities, and the signing infrastructure behind some software supply-chain and code-signing systems. The common thread is high-value signing authority that no single person or machine should be able to exercise alone — and that benefits from not advertising its own governance structure to everyone who checks a signature.&lt;/p&gt;

&lt;p&gt;It is not a tool for everyday application authentication; the interactivity and operational complexity only pay off when the signing key is genuinely catastrophic to lose. For most systems, simpler controls are the right answer. But where the stakes justify it, FROST is the current state of the art for doing it efficiently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Haven Fits
&lt;/h2&gt;

&lt;p&gt;Haven doesn't ask you to run a quorum to send a message — that would be the wrong tool for personal communication. But the underlying principle is exactly the one we build on: &lt;strong&gt;no single party should hold the power to read or impersonate you.&lt;/strong&gt; In Haven, your keys are derived on your device and never assembled on a server we could be compelled to hand over. Threshold cryptography is the institutional expression of the same idea we apply at the individual level — distribute trust so there is no one place an adversary can break to win everything.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/threshold-signatures-frost-explained/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>encryption</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>Blind Signatures Explained: Getting Something Signed Without Revealing It</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Wed, 17 Jun 2026 12:17:22 +0000</pubDate>
      <link>https://dev.to/havenmessenger/blind-signatures-explained-getting-something-signed-without-revealing-it-k78</link>
      <guid>https://dev.to/havenmessenger/blind-signatures-explained-getting-something-signed-without-revealing-it-k78</guid>
      <description>&lt;p&gt;Imagine handing a notary a sealed envelope with carbon paper inside, having them stamp the outside, and walking away with their signature pressed onto a document they never read. That is a blind signature — and it is the cryptographic foundation for anonymous tokens, untraceable digital cash, and credentials that prove you are authorized without revealing who you are.&lt;/p&gt;

&lt;p&gt;A blind signature, introduced by cryptographer David Chaum in 1982, is a form of digital signature where the signer does not see the content of the message being signed. The recipient later "unblinds" the result to obtain a valid signature on the original message — one that anyone can verify against the signer's public key, but that the signer cannot link back to the specific signing session. It sounds paradoxical: how can a signature be valid on something the signer never saw? The answer lies in the algebra of how some signature schemes work.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Sealed Envelope, Made Mathematical
&lt;/h2&gt;

&lt;p&gt;The carbon-paper envelope is the right intuition, and it maps cleanly onto the math. The protocol has three moves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Blind.&lt;/strong&gt; The user takes their message and multiplies in a secret random "blinding factor." The result looks like meaningless noise to anyone who doesn't know that factor. This is the sealed envelope.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sign.&lt;/strong&gt; The signer applies their private key to the blinded value, exactly as they would sign anything. They learn nothing about the underlying message. This is the stamp on the outside.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unblind.&lt;/strong&gt; The user divides out their blinding factor. Because of how the underlying scheme commutes, what remains is a valid signature on the &lt;em&gt;original&lt;/em&gt; message — as if the signer had signed it directly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the classic RSA construction, the blinding factor is raised to the public exponent and multiplied into the message before signing; the signer's private-key operation passes through that structure, and dividing by the blinding factor afterward leaves a clean signature. The signer's view during signing — the blinded value — is statistically independent of the final message, so even a signer who records every interaction cannot match a later-presented signature to the session that produced it. That unlinkability is the whole point.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Two distinct guarantees.&lt;/strong&gt; &lt;em&gt;Blindness&lt;/em&gt;: the signer cannot read the message or link a finished signature to a signing session. &lt;em&gt;Unforgeability&lt;/em&gt;: the user cannot produce more valid signatures than the number of signing operations the signer actually performed. A secure blind signature scheme must provide both — blindness without unforgeability would let users mint credentials at will.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why Anyone Wants This
&lt;/h2&gt;

&lt;p&gt;The killer application Chaum had in mind was digital cash. A bank can blind-sign a token representing one dollar. The user withdraws it (the bank debits their account), then spends it somewhere else entirely. When the token comes back to the bank for deposit, the signature is valid — the bank knows it issued exactly one dollar — but it cannot tell &lt;em&gt;which&lt;/em&gt; withdrawal produced &lt;em&gt;this&lt;/em&gt; coin. The money is verifiable but untraceable, decoupling "is this valid?" from "who spent it?"&lt;/p&gt;

&lt;p&gt;That same shape solves a surprisingly common modern problem: proving authorization without identity.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Use case&lt;/th&gt;
&lt;th&gt;What blind signatures enable&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Anonymous rate-limiting tokens&lt;/td&gt;
&lt;td&gt;A server signs tokens for verified humans; tokens are later redeemed without linking back to the verification event&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Private digital cash&lt;/td&gt;
&lt;td&gt;Verifiable value that cannot be traced to the withdrawal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unlinkable credentials&lt;/td&gt;
&lt;td&gt;Prove "I am a paying subscriber" without revealing which subscriber&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anonymous e-voting&lt;/td&gt;
&lt;td&gt;An authority blind-signs a ballot to confirm eligibility without seeing the vote&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The rate-limiting case is live infrastructure today. Privacy Pass — and the IETF's standardized Privacy Pass token architecture built on it — uses this style of cryptography so that a service can confirm you already passed a CAPTCHA without correlating that challenge to every later request. The result is fewer CAPTCHAs and better privacy at the same time, a rare combination.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Double-Spending Problem
&lt;/h2&gt;

&lt;p&gt;Blind digital cash has an obvious weakness: a digital token is just data, and data copies perfectly. What stops someone from spending the same blind-signed coin twice? Chaum's systems handled this two ways. The simple approach is &lt;strong&gt;online verification&lt;/strong&gt;: the recipient checks each token against the bank's spent-token database at the moment of payment, rejecting duplicates. The more elegant approach is &lt;strong&gt;cryptographic double-spend detection&lt;/strong&gt;, where spending a coin once reveals nothing, but spending it twice mathematically exposes the cheater's identity — privacy for the honest, accountability for the dishonest.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Blind signatures gave the world its first serious model for money that is private by default and traceable only on abuse — the inverse of today's payment rails, which are traceable by default and private only with effort.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Limitations and Modern Variants
&lt;/h2&gt;

&lt;p&gt;The basic Chaumian blind signature is powerful but blunt: the signer signs whatever it is given, sight unseen, which means it cannot enforce any structure on the message. Newer constructions address this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Partially blind signatures&lt;/strong&gt; let the signer embed common information (an expiry date, a denomination) that stays visible, while keeping the user-specific part blind.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blind signatures over elliptic curves&lt;/strong&gt; bring the technique to modern, efficient elliptic-curve cryptography rather than large RSA moduli.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anonymous credentials&lt;/strong&gt; (such as the BBS and related schemes) generalize the idea into selective disclosure — proving statements about attributes without revealing the attributes themselves, overlapping with zero-knowledge proofs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are also security subtleties: some blind signature schemes are vulnerable to parallel-session attacks (the ROS problem) if the signer allows too many concurrent signing operations, which is why production deployments bound concurrency and choose carefully studied parameters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why It Matters for Private Systems
&lt;/h2&gt;

&lt;p&gt;Blind signatures embody a principle that runs through all serious privacy engineering: collect and link only what you must. A system that needs to know "is this user authorized?" does not also need to know "which user is this, and what else have they done?" Most software conflates those two questions because it is easier to. Blind signatures prove they can be cleanly separated.&lt;/p&gt;

&lt;p&gt;Haven's design follows the same instinct in spirit, even where it uses different primitives. The goal is always to let the system verify what it legitimately needs — that a message is authentic, that a subscription is valid, that a session is authorized — without accumulating a linkable record of who did what and when. Blind signatures are one of the oldest and most elegant demonstrations that "verifiable" and "anonymous" are not opposites. They are a design choice, and for thirty years the math has been on the side of privacy.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/blind-signatures-explained/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>encryption</category>
      <category>cryptography</category>
    </item>
  </channel>
</rss>
