<?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: Chlora Tempra</title>
    <description>The latest articles on DEV Community by Chlora Tempra (@chl_e57e1033918e3898).</description>
    <link>https://dev.to/chl_e57e1033918e3898</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3890529%2Fa01ddacd-5717-406b-b54e-31ec71b213f6.png</url>
      <title>DEV Community: Chlora Tempra</title>
      <link>https://dev.to/chl_e57e1033918e3898</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chl_e57e1033918e3898"/>
    <language>en</language>
    <item>
      <title>[Boost]</title>
      <dc:creator>Chlora Tempra</dc:creator>
      <pubDate>Tue, 21 Apr 2026 10:39:46 +0000</pubDate>
      <link>https://dev.to/chl_e57e1033918e3898/-59ke</link>
      <guid>https://dev.to/chl_e57e1033918e3898/-59ke</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/chl_e57e1033918e3898/how-we-use-ed25519-signatures-to-give-users-cryptographic-proof-before-they-send-crypto-mik" class="crayons-story__hidden-navigation-link"&gt;How We Use Ed25519 Signatures to Give Users Cryptographic Proof Before They Send Crypto&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/chl_e57e1033918e3898" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3890529%2Fa01ddacd-5717-406b-b54e-31ec71b213f6.png" alt="chl_e57e1033918e3898 profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/chl_e57e1033918e3898" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Chlora Tempra
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Chlora Tempra
                
              
              &lt;div id="story-author-preview-content-3531352" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/chl_e57e1033918e3898" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3890529%2Fa01ddacd-5717-406b-b54e-31ec71b213f6.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Chlora Tempra&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/chl_e57e1033918e3898/how-we-use-ed25519-signatures-to-give-users-cryptographic-proof-before-they-send-crypto-mik" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Apr 21&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/chl_e57e1033918e3898/how-we-use-ed25519-signatures-to-give-users-cryptographic-proof-before-they-send-crypto-mik" id="article-link-3531352"&gt;
          How We Use Ed25519 Signatures to Give Users Cryptographic Proof Before They Send Crypto
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/cryptography"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;cryptography&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/security"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;security&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/privacy"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;privacy&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/blockchain"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;blockchain&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/chl_e57e1033918e3898/how-we-use-ed25519-signatures-to-give-users-cryptographic-proof-before-they-send-crypto-mik" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;1&lt;span class="hidden s:inline"&gt; reaction&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/chl_e57e1033918e3898/how-we-use-ed25519-signatures-to-give-users-cryptographic-proof-before-they-send-crypto-mik#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            5 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>How We Use Ed25519 Signatures to Give Users Cryptographic Proof Before They Send Crypto</title>
      <dc:creator>Chlora Tempra</dc:creator>
      <pubDate>Tue, 21 Apr 2026 10:19:50 +0000</pubDate>
      <link>https://dev.to/chl_e57e1033918e3898/how-we-use-ed25519-signatures-to-give-users-cryptographic-proof-before-they-send-crypto-mik</link>
      <guid>https://dev.to/chl_e57e1033918e3898/how-we-use-ed25519-signatures-to-give-users-cryptographic-proof-before-they-send-crypto-mik</guid>
      <description>&lt;p&gt;Most instant crypto swap services work on pure trust.&lt;/p&gt;

&lt;p&gt;You visit the site, get a deposit address, send funds, and hope the service sends back what it quoted. There's no cryptographic commitment before you transact. If something goes wrong — wrong rate applied, address substituted, service disputes the terms — you have nothing verifiable to stand on.&lt;/p&gt;

&lt;p&gt;We wanted to fix that. Here's how we built a pre-payment signature system for &lt;a href="https://0trace.io/" rel="noopener noreferrer"&gt;0trace&lt;/a&gt; using Ed25519, and why it matters for users doing private crypto swaps without accounts or identity disclosure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Problem: Trust Without Verification&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In a standard instant swap flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User requests a quote&lt;/li&gt;
&lt;li&gt;Service returns a deposit address and quoted amounts&lt;/li&gt;
&lt;li&gt;User sends funds&lt;/li&gt;
&lt;li&gt;Service executes the swap and sends payout&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Step 3 is the trust cliff. At the moment the user sends funds, they have no binding commitment from the service. The rate could change, the deposit address could theoretically be substituted, or a dispute could arise about what terms were actually agreed.&lt;/p&gt;

&lt;p&gt;For a service that stores no user accounts, no email addresses, and no transaction history — there's no customer service ticket to open. The anonymity that protects users also removes the standard dispute resolution fallback.&lt;/p&gt;

&lt;p&gt;We needed a different trust mechanism. One that doesn't require identity, accounts, or trusting our own servers after the fact.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Solution: Signed Order Documents&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before a user sends funds, we generate a Guarantee document — a JSON object signed with our Ed25519 private key. After the swap completes, we generate a Receipt with the settled transaction details, also signed.&lt;/p&gt;

&lt;p&gt;Both documents can be verified by anyone, at any time, offline, against our published public key. No API call. No server contact. Just the document, the signature, and the public key.&lt;/p&gt;

&lt;p&gt;Here's what a Guarantee contains:&lt;/p&gt;

&lt;p&gt;{&lt;br&gt;
  "orderId": "abc123...",&lt;br&gt;
  "createdAt": "2026-04-01T12:00:00Z",&lt;br&gt;
  "fromAsset": "btc",&lt;br&gt;
  "toAsset": "xmr",&lt;br&gt;
  "depositAddress": "bc1q...",&lt;br&gt;
  "payoutAddress": "4...",&lt;br&gt;
  "fromAmount": "0.01",&lt;br&gt;
  "toAmount": "1.842",&lt;br&gt;
  "rateType": "FIXED",&lt;br&gt;
  "expiresAt": "2026-04-01T12:10:00Z"&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;The signature covers the entire payload. If any field is altered after signing — deposit address, quoted amounts, payout address — the signature verification fails.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Ed25519&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We chose Ed25519 (Edwards-curve Digital Signature Algorithm over Curve25519) for several reasons.&lt;/p&gt;

&lt;p&gt;Small signature size. Ed25519 signatures are 64 bytes. RSA-2048 signatures are 256 bytes. For documents that users might store or transmit, this matters.&lt;/p&gt;

&lt;p&gt;Fast verification. Ed25519 verification is extremely fast — we run it client-side in the browser using the standard Web Crypto API with zero perceptible latency.&lt;/p&gt;

&lt;p&gt;Strong security properties. Ed25519 is not vulnerable to timing side-channel attacks by design. It also doesn't require a random nonce during signing, which eliminates an entire class of implementation bugs that have compromised ECDSA deployments (see: the PS3 key extraction, the Bitcoin Blockchain.info vulnerability).&lt;/p&gt;

&lt;p&gt;Wide browser support. SubtleCrypto in modern browsers natively supports Ed25519 key import and signature verification. No external crypto libraries needed for the verification page.&lt;/p&gt;

&lt;p&gt;Deterministic. The same private key + message always produces the same signature. This makes testing and auditability straightforward.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation: Signing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The signing happens inside our signer service, which is physically isolated from the main application server. The private key never touches the web-facing application layer.&lt;/p&gt;

&lt;p&gt;import { createPrivateKey, sign } from "crypto";&lt;/p&gt;

&lt;p&gt;function signOrderDocument(payload: object, privateKeyHex: string): string {&lt;br&gt;
  const privateKey = createPrivateKey({&lt;br&gt;
    key: Buffer.from(privateKeyHex, "hex"),&lt;br&gt;
    format: "der",&lt;br&gt;
    type: "pkcs8",&lt;br&gt;
  });&lt;/p&gt;

&lt;p&gt;const message = Buffer.from(JSON.stringify(payload));&lt;br&gt;
  const signature = sign(null, message, privateKey);&lt;/p&gt;

&lt;p&gt;return signature.toString("base64url");&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;The payload is serialized to JSON with deterministic key ordering before signing, so the verification side always produces the same byte sequence.&lt;/p&gt;

&lt;p&gt;The signed document returned to the user is the payload plus the base64url-encoded signature:&lt;/p&gt;

&lt;p&gt;{&lt;br&gt;
  "payload": { "...order fields..." },&lt;br&gt;
  "signature": "base64url-encoded-signature"&lt;br&gt;
}&lt;/p&gt;

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

&lt;p&gt;Verification runs entirely in the browser. The user downloads the document (or pastes it), and the page verifies the signature against the hardcoded public key using SubtleCrypto:&lt;/p&gt;

&lt;p&gt;async function verifyDocument(document) {&lt;br&gt;
  const { payload, signature } = document;&lt;/p&gt;

&lt;p&gt;const publicKeyBytes = hexToBytes(PUBLIC_KEY_HEX);&lt;/p&gt;

&lt;p&gt;const cryptoKey = await crypto.subtle.importKey(&lt;br&gt;
    "raw",&lt;br&gt;
    publicKeyBytes,&lt;br&gt;
    { name: "Ed25519" },&lt;br&gt;
    false,&lt;br&gt;
    ["verify"]&lt;br&gt;
  );&lt;/p&gt;

&lt;p&gt;const message = new TextEncoder().encode(JSON.stringify(payload));&lt;br&gt;
  const sigBytes = base64urlToBytes(signature);&lt;/p&gt;

&lt;p&gt;const valid = await crypto.subtle.verify(&lt;br&gt;
    { name: "Ed25519" },&lt;br&gt;
    cryptoKey,&lt;br&gt;
    sigBytes,&lt;br&gt;
    message&lt;br&gt;
  );&lt;/p&gt;

&lt;p&gt;return valid;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;No network requests. No server involvement. The public key is published on our website and hardcoded in the verification page — users can check it independently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What This Gives Users&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before sending funds, a user can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Download the Guarantee document&lt;/li&gt;
&lt;li&gt;Open the /verify page (or run verification locally)&lt;/li&gt;
&lt;li&gt;Confirm the signature is valid against the published public key&lt;/li&gt;
&lt;li&gt;Confirm the deposit address in the document matches what the UI shows&lt;/li&gt;
&lt;li&gt;Confirm the quoted amounts and payout address are exactly what they agreed to&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If any of those checks fail — document was tampered with, address was substituted, amounts were altered — the signature verification fails. The user has a clear signal before committing funds.&lt;/p&gt;

&lt;p&gt;After the swap completes, the Receipt provides the same cryptographic proof for the settled transaction, including the payout transaction hash when available.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why This Matters for Privacy-Focused Swaps&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;0trace is built for users who want to swap crypto without accounts, without KYC, and without leaving a data trail. The absence of an account system — which protects users — also removes the standard dispute resolution path that account-based services offer.&lt;/p&gt;

&lt;p&gt;Signed documents are the alternative trust mechanism that works without identity. A valid Ed25519 signature on a Guarantee is proof that is independent of our servers. It doesn't require us to look anything up. It doesn't require the user to identify themselves. The math either checks out or it doesn't.&lt;/p&gt;

&lt;p&gt;This is what "trustless" should mean in practice — not "trust that we're honest," but "verify that the commitment is real before you send."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Key Management Side&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The signing private key lives exclusively in the signer service, isolated on a separate physical machine. The main application server requests signed documents via an internal API — it never has access to the signing key itself.&lt;/p&gt;

&lt;p&gt;Key rotation is supported: the published public key fingerprint is versioned, and historical documents remain verifiable against the key that was active at signing time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limitations and Trade-offs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Float rate Guarantees are necessarily indicative. For FLOAT rate orders, the Guarantee captures the quoted amount at order creation time — but the final amount is determined at deposit detection, when the live rate is applied. The Guarantee for a float order commits to the deposit address and payout address, but the amounts are preview-only until the deposit lands.&lt;/p&gt;

&lt;p&gt;Fixed rate Guarantees are binding for the lock window. Once the lock expires and falls back to float semantics, the amount commitment no longer holds.&lt;/p&gt;

&lt;p&gt;We document this distinction explicitly via the rateType field, so users can evaluate what exactly they're getting a commitment on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Open Questions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A few things we're still thinking about:&lt;/p&gt;

&lt;p&gt;Should Guarantees be publicly auditable? Right now, verification is private — only the user with the document can verify it. There's an argument for a transparency log where all issued Guarantees are published (like Certificate Transparency for TLS), allowing anyone to audit that we're not issuing duplicate guarantees for the same deposit address.&lt;/p&gt;

&lt;p&gt;Should the public key be on-chain? Publishing the signing public key to an immutable on-chain record would make it harder to silently rotate to a compromised key. Currently it's web-published, which means it's only as trustworthy as our web infrastructure.&lt;/p&gt;

&lt;p&gt;Both would increase auditability at the cost of complexity. Happy to hear thoughts in the comments.&lt;/p&gt;

&lt;p&gt;The verification page is live at &lt;a href="https://0trace.io/verify" rel="noopener noreferrer"&gt;0trace.io/verify&lt;/a&gt;. If you want to test the flow, create a small order, download the Guarantee, and run it through the page — or implement your own verifier against the published key.&lt;/p&gt;

&lt;p&gt;Reference: SubtleCrypto verify — MDN&lt;/p&gt;

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