1:"$Sreact.fragment"
2:I[75473,["/_next/static/chunks/316a3a63422f35de.js"],"default"]
3:I[78515,["/_next/static/chunks/316a3a63422f35de.js"],"default"]
4:I[30687,["/_next/static/chunks/fd0661f1506dcbc6.js"],"Toaster"]
5:I[61076,["/_next/static/chunks/fd0661f1506dcbc6.js"],"Analytics"]
7:I[47913,["/_next/static/chunks/316a3a63422f35de.js"],"OutletBoundary"]
8:"$Sreact.suspense"
a:I[47913,["/_next/static/chunks/316a3a63422f35de.js"],"ViewportBoundary"]
c:I[47913,["/_next/static/chunks/316a3a63422f35de.js"],"MetadataBoundary"]
e:I[90849,["/_next/static/chunks/316a3a63422f35de.js"],"default"]
:HL["/_next/static/chunks/609ea7bc18d0d15f.css","style"]
:HL["/_next/static/chunks/93b606aa9fdccd13.css","style"]
:HL["/_next/static/media/797e433ab948586e-s.p.479bea2b.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
:HL["/_next/static/media/caa3a2e1cccd8315-s.p.3b6cae6d.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
0:{"P":null,"b":"TlpKRvbES4zzM7LeczAM7","c":["","blog","merkle-canonical-form"],"q":"","i":false,"f":[[["",{"children":["blog",{"children":[["slug","merkle-canonical-form","d"],{"children":["__PAGE__",{}]}]}]},"$undefined","$undefined",true],[["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/chunks/609ea7bc18d0d15f.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/_next/static/chunks/93b606aa9fdccd13.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/_next/static/chunks/fd0661f1506dcbc6.js","async":true,"nonce":"$undefined"}]],["$","html",null,{"lang":"en","children":[["$","head",null,{"children":[["$","script",null,{"async":true,"src":"https://www.googletagmanager.com/gtag/js?id=AW-18009878040"}],["$","script",null,{"dangerouslySetInnerHTML":{"__html":"\n          window.dataLayer = window.dataLayer || [];\n          function gtag(){dataLayer.push(arguments);}\n          gtag('js', new Date());\n          gtag('config', 'AW-18009878040');\n          gtag('config', 'G-W3XKYXV2SG');\n\n          // Persist UTM and gclid params to sessionStorage for cross-page tracking\n          (function() {\n            var params = new URLSearchParams(window.location.search);\n            var keys = ['utm_source','utm_medium','utm_campaign','utm_content','utm_term','gclid'];\n            keys.forEach(function(k) {\n              var v = params.get(k);\n              if (v) sessionStorage.setItem(k, v);\n            });\n          })();\n        "}}]]}],["$","body",null,{"className":"font-sans antialiased","children":[["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}],["$","$L4",null,{"position":"top-center","richColors":true,"toastOptions":{"style":{"background":"var(--popover)","color":"var(--popover-foreground)","border":"1px solid var(--border)"}}}],["$","$L5",null,{}]]}]]}]]}],{"children":[["$","$1","c",{"children":[null,["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":[["$","$1","c",{"children":[null,["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":[["$","$1","c",{"children":["$L6",[["$","script","script-0",{"src":"/_next/static/chunks/94245cbda44972fe.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/_next/static/chunks/af778fff4a0f4be6.js","async":true,"nonce":"$undefined"}],["$","script","script-2",{"src":"/_next/static/chunks/b096b037d08e2f31.js","async":true,"nonce":"$undefined"}]],["$","$L7",null,{"children":["$","$8",null,{"name":"Next.MetadataOutlet","children":"$@9"}]}]]}],{},null,false,false]},null,false,false]},null,false,false]},null,false,false],["$","$1","h",{"children":[null,["$","$La",null,{"children":"$Lb"}],["$","div",null,{"hidden":true,"children":["$","$Lc",null,{"children":["$","$8",null,{"name":"Next.Metadata","children":"$Ld"}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],false]],"m":"$undefined","G":["$e",[]],"S":true}
f:I[15579,["/_next/static/chunks/fd0661f1506dcbc6.js","/_next/static/chunks/94245cbda44972fe.js","/_next/static/chunks/af778fff4a0f4be6.js","/_next/static/chunks/b096b037d08e2f31.js"],"Navigation"]
10:I[3013,["/_next/static/chunks/fd0661f1506dcbc6.js","/_next/static/chunks/94245cbda44972fe.js","/_next/static/chunks/af778fff4a0f4be6.js","/_next/static/chunks/b096b037d08e2f31.js"],""]
:HL["/blog/posts/merkle-canonical-form/hero.jpg","image"]
:HL["/blog/posts/logo.png","image"]
6:[["$","$Lf",null,{}],["$","main",null,{"className":"pt-20 md:pt-24","children":["$","article",null,{"children":[["$","header",null,{"className":"border-b border-border","children":["$","div",null,{"className":"container mx-auto px-6 py-14 md:py-20","children":[["$","$L10",null,{"href":"/blog","className":"mb-8 inline-flex items-center text-sm font-medium text-muted-foreground transition-colors hover:text-foreground","children":[["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-arrow-left mr-2 h-4 w-4","aria-hidden":"true","children":[["$","path","1l729n",{"d":"m12 19-7-7 7-7"}],["$","path","x3x0zl",{"d":"M19 12H5"}],"$undefined"]}],"Blog"]}],["$","div",null,{"className":"grid gap-8 md:grid-cols-[1fr_0.9fr] md:items-start","children":[["$","div",null,{"className":"max-w-3xl","children":[["$","div",null,{"className":"mb-5 flex flex-wrap items-center gap-3 text-sm text-muted-foreground","children":[["$","span",null,{"className":"rounded-md border border-primary/40 bg-primary/10 px-2.5 py-1 text-primary","children":"Security"}],["$","span",null,{"children":"2026-W20"}],["$","span",null,{"aria-hidden":"true","children":"/"}],["$","span",null,{"children":"4 min read"}],[["$","span",null,{"aria-hidden":"true","children":"/"}],["$","span",null,{"children":["by ",["$","span",null,{"className":"font-medium text-foreground","children":"chip"}]]}]]]}],["$","h1",null,{"className":"text-4xl font-bold leading-tight text-balance md:text-6xl","children":"The Canonical Form Bug That Makes Every Signature Fail"}],["$","p",null,{"className":"mt-6 text-lg leading-relaxed text-muted-foreground md:text-xl","children":"Ed25519 verification fails universally — not 'some events' but 'all events.' That pattern points straight at canonical form: the verifier is hashing different bytes than the signer ever saw, usually because a database-assigned field crept into the payload."}]]}],["$","div",null,{"className":"overflow-hidden rounded-lg border border-border bg-card","children":["$","div",null,{"className":"relative aspect-[16/9] overflow-hidden","children":[null,["$","img",null,{"src":"/blog/posts/merkle-canonical-form/hero.jpg","alt":"A vintage brass wax seal stamp pressed into a fresh crimson wax pool on parchment, sharp focus on the impression, warm desk light, no people, editorial.","className":"h-full w-full object-cover"}],["$","img",null,{"src":"/blog/posts/logo.png","alt":"","aria-hidden":"true","className":"pointer-events-none absolute right-4 top-4 h-[50px] w-[50px] mix-blend-screen"}]]}]}]]}]]}]}],["$","div",null,{"className":"container mx-auto px-6 py-12 md:py-16","children":["$","div",null,{"className":"grid gap-10 lg:grid-cols-[minmax(0,1fr)_280px] lg:items-start","children":[["$","div",null,{"className":"max-w-3xl text-muted-foreground","children":[[["$","h2","h2-0",{"className":"mt-12 text-2xl font-semibold leading-snug text-foreground first:mt-0","children":"The problem"}],"\n",["$","p","p-0",{"className":"mt-4 text-base leading-8 md:text-lg first:mt-0 first:text-xl first:leading-relaxed first:text-foreground md:first:text-2xl","children":"You implement Ed25519 event signing. The SDK signs a payload before sending it. The backend verifies the signature by recomputing a canonical representation of the stored event and checking it against the stored signature. Verification always returns false, for every event."}],"\n",["$","p","p-1",{"className":"mt-4 text-base leading-8 md:text-lg first:mt-0 first:text-xl first:leading-relaxed first:text-foreground md:first:text-2xl","children":"The bug: the canonical form includes the database primary key."}],"\n",["$","p","p-2",{"className":"mt-4 text-base leading-8 md:text-lg first:mt-0 first:text-xl first:leading-relaxed first:text-foreground md:first:text-2xl","children":"The SDK signs the payload before it reaches the backend. At signing time, the database hasn't assigned an ID yet. The backend stores the event, gets an auto-incremented integer PK, and then builds its canonical dict for verification — including that PK. The bytes never match because the signer had no way to know what ID the database would assign."}],"\n","$L11","\n","$L12","\n","$L13","\n","$L14","\n","$L15","\n","$L16","\n","$L17","\n","$L18","\n","$L19"],"$L1a",null]}],"$L1b"]}]}]]}]}],"$L1c"]
1e:I[41451,["/_next/static/chunks/fd0661f1506dcbc6.js","/_next/static/chunks/94245cbda44972fe.js","/_next/static/chunks/af778fff4a0f4be6.js","/_next/static/chunks/b096b037d08e2f31.js"],"Footer"]
11:["$","h2","h2-1",{"className":"mt-12 text-2xl font-semibold leading-snug text-foreground first:mt-0","children":"The approach"}]
12:["$","p","p-3",{"className":"mt-4 text-base leading-8 md:text-lg first:mt-0 first:text-xl first:leading-relaxed first:text-foreground md:first:text-2xl","children":"The canonical form for signature verification must only include fields the signer knew at signing time. In practice, this means fields from the request payload:"}]
13:["$","ul","ul-0",{"children":["\n",["$","li","li-0",{"children":"timestamps provided by the client"}],"\n",["$","li","li-1",{"children":"model, provider, tokens, session_id — whatever the SDK sends"}],"\n",["$","li","li-2",{"children":"request_id if set by the caller"}],"\n"]}]
14:["$","p","p-4",{"className":"mt-4 text-base leading-8 md:text-lg first:mt-0 first:text-xl first:leading-relaxed first:text-foreground md:first:text-2xl","children":"It explicitly excludes:"}]
15:["$","ul","ul-1",{"children":["\n",["$","li","li-0",{"children":"database auto-assigned fields (id, created_at if server-assigned, organization_id if resolved server-side)"}],"\n",["$","li","li-1",{"children":"any field derived or added after ingestion"}],"\n"]}]
16:["$","p","p-5",{"className":"mt-4 text-base leading-8 md:text-lg first:mt-0 first:text-xl first:leading-relaxed first:text-foreground md:first:text-2xl","children":"Sort the keys before serializing. Use a stable serialization format (JSON with sorted keys, or a deterministic binary encoding). Hash the bytes, not the dict."}]
17:["$","h2","h2-2",{"className":"mt-12 text-2xl font-semibold leading-snug text-foreground first:mt-0","children":"What I learned"}]
18:["$","p","p-6",{"className":"mt-4 text-base leading-8 md:text-lg first:mt-0 first:text-xl first:leading-relaxed first:text-foreground md:first:text-2xl","children":"The failure is silent and universal — not \"some events fail verification\" but \"all events fail.\" That pattern points immediately to the canonical form rather than key management or signing algorithm. If signing worked at all (valid key pair, correct algorithm), the only way every verification fails is if the verifier is building different bytes than the signer saw."}]
19:["$","p","p-7",{"className":"mt-4 text-base leading-8 md:text-lg first:mt-0 first:text-xl first:leading-relaxed first:text-foreground md:first:text-2xl","children":"The corollary: test signature verification with a round-trip from the same process before testing across the API boundary. If it fails locally, it's the canonical form. If it passes locally but fails across the boundary, it's serialization or key transport."}]
1a:["$","div",null,{"className":"mt-14 border-t border-border pt-8","children":["$","$L10",null,{"href":"/platform","className":"inline-flex items-center text-sm font-medium text-primary transition-colors hover:text-primary/80","children":["Start a build",["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-arrow-right ml-2 h-4 w-4","aria-hidden":"true","children":[["$","path","1ays0h",{"d":"M5 12h14"}],["$","path","xquz4c",{"d":"m12 5 7 7-7 7"}],"$undefined"]}]]}]}]
1b:["$","aside",null,{"className":"hidden lg:block","children":["$","div",null,{"className":"sticky top-24 space-y-4","children":[["$","h3",null,{"className":"text-xs font-semibold uppercase tracking-wider text-primary","children":["More in ","Security"]}],["$","div",null,{"className":"space-y-4","children":[["$","$L10","hmac-empty-secret-bypass",{"href":"/blog/hmac-empty-secret-bypass","className":"block overflow-hidden rounded-lg border border-border bg-card transition-colors hover:border-primary/40","children":[["$","div",null,{"className":"relative aspect-[16/9] overflow-hidden bg-secondary/70","children":[["$","img",null,{"src":"/blog/posts/hmac-empty-secret-bypass/hero.jpg","alt":"A heavy steel padlock lying open on a dark wooden surface with no key visible, hard overhead light casting a sharp shadow.","className":"h-full w-full object-cover","loading":"lazy","decoding":"async"}],["$","img",null,{"src":"/blog/posts/logo.png","alt":"","aria-hidden":"true","className":"pointer-events-none absolute right-2 top-2 h-[24px] w-[24px] mix-blend-screen"}]]}],["$","div",null,{"className":"p-4","children":[["$","p",null,{"className":"text-xs font-medium text-primary","children":"Security"}],["$","p",null,{"className":"mt-1 text-xs text-muted-foreground","children":["2026-W20"," · ","4 min"]}],["$","p",null,{"className":"mt-2 line-clamp-2 text-sm font-semibold leading-snug text-foreground","children":"The Empty-Secret HMAC Bypass"}]]}]]}],["$","$L10","merkle-subset-verification-trap",{"href":"/blog/merkle-subset-verification-trap","className":"block overflow-hidden rounded-lg border border-border bg-card transition-colors hover:border-primary/40","children":[["$","div",null,{"className":"relative aspect-[16/9] overflow-hidden bg-secondary/70","children":[["$","img",null,{"src":"/blog/posts/merkle-subset-verification-trap/hero.jpg","alt":"A pristine glass museum display case half-filled with carefully arranged artifacts on velvet, sharp focus on the artifacts, soft museum lighting.","className":"h-full w-full object-cover","loading":"lazy","decoding":"async"}],["$","img",null,{"src":"/blog/posts/logo.png","alt":"","aria-hidden":"true","className":"pointer-events-none absolute right-2 top-2 h-[24px] w-[24px] mix-blend-screen"}]]}],["$","div",null,{"className":"p-4","children":[["$","p",null,{"className":"text-xs font-medium text-primary","children":"Security"}],["$","p",null,{"className":"mt-1 text-xs text-muted-foreground","children":["2026-W20"," · ","3 min"]}],["$","p",null,{"className":"mt-2 line-clamp-2 text-sm font-semibold leading-snug text-foreground","children":"The Merkle Subset Verification Trap"}]]}]]}],["$","$L10","per-agent-api-key-rotation",{"href":"/blog/per-agent-api-key-rotation","className":"block overflow-hidden rounded-lg border border-border bg-card transition-colors hover:border-primary/40","children":[["$","div",null,{"className":"relative aspect-[16/9] overflow-hidden bg-secondary/70","children":[["$","img",null,{"src":"/blog/posts/per-agent-api-key-rotation/hero.jpg","alt":"A row of brass keys hanging on numbered hooks against a dark wooden panel wall, one hook empty with a brighter outline, single overhead light, no people, editorial.","className":"h-full w-full object-cover","loading":"lazy","decoding":"async"}],["$","img",null,{"src":"/blog/posts/logo.png","alt":"","aria-hidden":"true","className":"pointer-events-none absolute right-2 top-2 h-[24px] w-[24px] mix-blend-screen"}]]}],["$","div",null,{"className":"p-4","children":[["$","p",null,{"className":"text-xs font-medium text-primary","children":"Security"}],["$","p",null,{"className":"mt-1 text-xs text-muted-foreground","children":["2026-W18"," · ","4 min"]}],["$","p",null,{"className":"mt-2 line-clamp-2 text-sm font-semibold leading-snug text-foreground","children":"Self-Healing API Key Rotation for Long-Running Service Processes"}]]}]]}]]}],["$","$L10",null,{"href":"/blog?category=security","className":"inline-flex items-center text-sm font-medium text-primary transition-colors hover:text-primary/80","children":["Read all in ","Security","$L1d"]}]]}]}]
1c:["$","$L1e",null,{}]
1d:["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-arrow-right ml-2 h-4 w-4","aria-hidden":"true","children":[["$","path","1ays0h",{"d":"M5 12h14"}],["$","path","xquz4c",{"d":"m12 5 7 7-7 7"}],"$undefined"]}]
b:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]
1f:I[94060,["/_next/static/chunks/316a3a63422f35de.js"],"IconMark"]
9:null
d:[["$","title","0",{"children":"The Canonical Form Bug That Makes Every Signature Fail — Bridgestack"}],["$","meta","1",{"name":"description","content":"Ed25519 verification fails universally — not 'some events' but 'all events.' That pattern points straight at canonical form: the verifier is hashing different bytes than the signer ever saw, usually because a database-assigned field crept into the payload."}],["$","meta","2",{"name":"generator","content":"v0.app"}],["$","meta","3",{"property":"og:title","content":"Bridgestack — custom software, flat prices from $9.99"}],["$","meta","4",{"property":"og:description","content":"Talk to Tom, your AI PM. A fleet of AI agents builds your product. Flat one-time price. 7 days to test before you pay. Source code is yours."}],["$","meta","5",{"property":"og:url","content":"https://www.bridgestack.systems"}],["$","meta","6",{"property":"og:site_name","content":"Bridgestack"}],["$","meta","7",{"property":"og:locale","content":"en_US"}],["$","meta","8",{"property":"og:image","content":"https://www.bridgestack.systems/bridgestack-landscape-1200x628.png"}],["$","meta","9",{"property":"og:image:width","content":"1200"}],["$","meta","10",{"property":"og:image:height","content":"628"}],["$","meta","11",{"property":"og:type","content":"website"}],["$","meta","12",{"name":"twitter:card","content":"summary_large_image"}],["$","meta","13",{"name":"twitter:title","content":"Bridgestack — custom software, flat prices from $9.99"}],["$","meta","14",{"name":"twitter:description","content":"Talk to Tom, your AI PM. A fleet of AI agents builds your product. 7 days to test before you pay. Source code is yours."}],["$","meta","15",{"name":"twitter:image","content":"https://www.bridgestack.systems/bridgestack-landscape-1200x628.png"}],["$","link","16",{"rel":"icon","href":"/icon-light-32x32.png","media":"(prefers-color-scheme: light)"}],["$","link","17",{"rel":"icon","href":"/icon-dark-32x32.png","media":"(prefers-color-scheme: dark)"}],["$","link","18",{"rel":"icon","href":"/icon.svg","type":"image/svg+xml"}],["$","link","19",{"rel":"apple-touch-icon","href":"/apple-icon.png"}],["$","$L1f","20",{}]]
