How it works

The technical version: what kysigned proves cryptographically, what it can’t, and how anyone can verify a signed document without trusting us, offline, forever. This page is the complete trust thesis; there is no separate write-up to chase down.

The trust model in one sentence

A kysigned signature is a real email your provider cryptographically signed on your behalf. kysigned just collects those signed emails, timestamps them, and packages them into one self-contained PDF, the signing record, that anyone can re-verify with public math and public archives. kysigned is not in the trust set: the trust comes from your email provider’s DKIM signature, the public DKIM-key archives, the timestamp authorities, and the maths.

The signing flow

  1. Sender uploads a PDF. kysigned computes its SHA-256, the original-document hash A that uniquely identifies the exact document, and for each signer prepends a one-page cover (consent language + that signer’s name) to produce the canonical PDF that signer will sign.
  2. Each signer receives an email with the document attached and a short routing token in the subject. To sign, the signer forwards that email back to the signing address and types I sign this document as the first line.
  3. The signer’s email provider (Gmail, Outlook, Apple, …) DKIM-signs the outgoing forward: an RSA signature, automatic on every major provider, that proves the message genuinely left that mailbox and that its headers and body weren’t altered in transit.
  4. kysigned verifies the forward classically (with mailauth, the mainstream open-source DKIM/SPF/DMARC library, never self-rolled crypto): the DKIM signature is valid over the full body, the forwarded PDF attachment is byte-identical to the canonical PDF we sent, and the first line is exactly the intent phrase. It then records the signed reply and timestamps the hash of the raw email twice (RFC 3161 TSA + an OpenTimestamps Bitcoin anchor: why two).
  5. When everyone has signed, kysigned assembles the signing record: one PDF holding the document, a signature page, every signer’s original DKIM-signed email, and the timestamp proofs, then emails it to every party. The working copy on our servers is then deleted.

That signing record is the signature. Anyone you show it to can re-verify every claim with no kysigned account, no API key, and no cooperation from us, even if kysigned no longer exists.

Anatomy of the signing record

The signing record is a single, ordinary PDF. It carries no digital-signature dictionary and no certificate, so it opens with no warning and no red-X in any viewer, and it embeds the complete machine-checkable evidence as attachments:

EmbeddedWhat it is
document-original.pdfThe original document D alone (the file the sender uploaded), embedded once. It is not cover-plus-document: each signer’s cover is the separate cover-<n>.pdf, and what a signer signed is the reconstruction cover-<n>.pdf followed by this file. Its SHA-256 is the original-document hash A the verifier reports.
cover-<n>.pdfEach signer’s own cover page (page 1 of the PDF that signer signed), embedded separately so the verifier can reconstruct exactly what each signer signed.
signer-<n>.emlEach signer’s original forwarded email, byte-complete: the DKIM-signed message itself, re-verifiable on its own.
proofs/signer-<n>.tsr + .otsThe RFC 3161 timestamp token and the OpenTimestamps Bitcoin proof over the SHA-256 of that .eml.
keys.jsonThe DKIM public keys the signatures verify against, with their provider, selector, and archive provenance.
VERIFY-README.txtPlain-language verification instructions and the exact trust set.

The rendered pages are a human-readable signature page (per-signer verdict block + a SHA-256 verification code computed over the whole embedded evidence set), followed by the cover and document. The code is printed on the page and recomputed by the verifier: an integrity check, never a trust anchor.

What is cryptographically proven

Each claim below is checkable using only public math and public archives. Zero trust in kysigned or the operator is required.

ClaimHow it’s provenCan the operator fake it?
“I sign this document” came from the signer The provider’s DKIM signature covers the email body. Changing one character invalidates it. No, needs the email provider’s private key.
The signer’s email address The From header is covered by the DKIM signature. No, same DKIM constraint.
The exact document being signed The forwarded attachment is SHA-256 byte-identical to the reconstruction cover-<n>.pdf ++ document-original.pdf, and because every signer reconstructs against the same document-original.pdf, all signed the same document A. No, a different document is a different hash.
When it was signed An RFC 3161 TSA token and an OpenTimestamps Bitcoin anchor, both over the hash of the raw email. No, you can’t backdate a Bitcoin block.
The DKIM public key was the provider’s real key The signature verifies mathematically against the embedded key, and that exact key matches the provider’s key in a public archive that fetched it from the provider’s own DNS. No: a self-minted key produces math that checks out against itself, but it will not match the provider’s real key in the public archive, so the verdict is FAILED, never confirmed.

The intent grammar

A signature is recognised only when the first non-empty line of the forwarded email is exactly:

I sign this document

Matching is case-insensitive and whitespace-normalised (so I SIGN THIS DOCUMENT and a leading-space variant both count), but nothing else qualifies: a reply without that line, or with other words ahead of it, is not a signature and is bounced back with instructions. This keeps the act of signing deliberate and unambiguous, and it is the same line a verifier reads back out of the embedded .eml.

Because the phrase is singular and binds to exactly one canonical PDF, each signing request carries exactly one document. A provider could DKIM-sign several attachments at once, but kysigned deliberately accepts only one, so there is never any doubt about which document the intent line refers to. If you have several documents, combine them into a single PDF (within the size limit) or send each one separately.

How to verify a signature independently

You don’t need to trust kysigned.com, the operator, or anyone. Drop the signing record PDF onto the verify page: the check runs entirely in your browser (the file never uploads) and works with no internet and even if kysigned is gone. For each signer the verifier:

  1. Extracts the embedded files from the PDF.
  2. Verifies the signer’s .eml DKIM signature against the embedded keys.json (no live DNS needed).
  3. Reconstructs that signer’s canonical PDF (cover-<n>.pdf ++ document-original.pdf) and confirms the forwarded attachment is SHA-256 byte-identical to it, which also proves every signer signed the same document A.
  4. Confirms the first line is the intent phrase.
  5. Confirms the timestamp proof commits to the SHA-256 of that .eml.
  6. Confirms the DKIM public key is present in the public archive (key authenticity, below).
  7. Recomputes the verification code and matches the value printed on the signature page.
Every offline check passing means a signer authenticated by their provider sent exactly this document, with the intent line, at the timestamped time. That is the INTEGRITY VERIFIED tier below; going online then confirms the provider’s key and the Bitcoin anchor, raising a genuine record to its highest tier. Any tampered byte, in the document, an .eml, or a proof, fails the relevant check and changes the verification code.

The verdict is an assurance tier, not a yes/no

kysigned does not return a single green “PROVEN”. It returns one of four assurance tiers, because “the signature math is internally consistent” and “the signing key was genuinely the provider’s” are different facts, proven by different evidence. Showing which one you actually hold is the honest thing to do, and it is what stops a forgery from borrowing a real signature’s credibility.

TierWhat it means
FAILEDA required check did not hold: an invalid DKIM signature, an attachment that is not byte-identical to the document, a missing intent line, no timestamp, or a public archive that publishes a different key than the one embedded (a forgery signal).
INTEGRITY VERIFIEDEvery offline check holds: valid DKIM signature, matching document, intent line, and a timestamp token present. Anyone can reach this with no network. It proves the record is internally consistent and unaltered, but not, on its own, that the key was the provider’s genuine key.
PROVIDER KEY CONFIRMEDPlus: the public DKIM-key archive confirms the exact key that signed was the provider’s real published key, which is what an offline check cannot establish alone.
PROVEN (DURABLE)Plus: the time is durable, the OpenTimestamps proof is confirmed in a Bitcoin block and agrees with the RFC 3161 token, and the signing time falls within the window the archive observed that key live. Authentic key, un-back-datable time, re-verifiable by anyone forever.

A genuine record verified online reaches PROVIDER KEY CONFIRMED at once and PROVEN (DURABLE) once its Bitcoin anchor settles (a few hours after signing). Offline, or while the archive and chain are still settling, that same genuine record sits honestly at INTEGRITY VERIFIED, pending and never failed.

Two of these checks reach past the offline record when the network is available: the key-archive gate and the Bitcoin timestamp. The verify page runs both automatically the moment you open a record. The Bitcoin confirmation shows grey (“pending”) until the OpenTimestamps proof is provably committed to a Bitcoin block, then green (“confirmed”, with the block height and time), which for a freshly-signed record typically happens within a few hours. It is the only part that contacts the Bitcoin network, and it sends just the timestamp’s hash, so your document still never leaves your device. The key-archive gate shows grey (“pending”) while the archive is unreachable or has not yet recorded the key, which never fails the result; turns green (“key in public archive”, with the date it was registered) when it finds the exact key; and fails the verdict in one specific case, when the archive publishes a different key for that domain and selector than the one embedded, which is the fingerprint of a forged, self-minted key. So a record that passes the offline checks is already INTEGRITY VERIFIED the instant you open it; going online then raises a genuine record toward PROVEN (DURABLE) and exposes a forged key as FAILED.

Why each check is there

Each check closes a specific gap. Drop any one and a particular forgery becomes possible, which is why the verifier insists on all of them.

CheckWhat it confirmsWhy it is needed
Email signature (DKIM)The signer’s provider authenticated this exact email.The provider’s DKIM signature is the signature; without it there is nothing to trust and anyone could forge a message in your name.
Document matchesThe forwarded attachment reconstructs to that signer’s cover plus the shared document A.Stops the operator showing one signer a different document behind a matching cover, and proves every signer signed the same A.
Intent lineThe signer typed the exact phrase as the first line.Makes signing a deliberate act, so an ordinary forward is never mistaken for a signature.
TimestampThe signed email existed by a proven time (RFC 3161 token + Bitcoin anchor).Freezes the evidence in time, so a forgery made later with a leaked, retired key cannot be back-dated into the signing window.
Key authenticityThe exact signing key matches the provider’s key recorded in the public DKIM archive.Proves the key was the provider’s genuine published key, not one an operator minted and merely claimed was the provider’s. A mismatch fails the verdict; a match raises it above INTEGRITY VERIFIED.
Verification codeThe whole embedded evidence set is intact.Catches any byte edited after assembly, even bytes outside an individual .eml.

Three ways to run the verification

The same documented algorithm runs from three independent surfaces, so our verifier is never the only word on what “verified” means:

Separately, the hash-check tool answers a related question for whoever sent a document: it confirms your original file is the one carried inside a signing record (a byte-exact match) or a sign-request (a content match), also entirely in your browser.

Sample files for both tools ship in the repository under docs/test-assets: a genuine signed record (which verifies to the top tier, PROVEN (DURABLE), once online), tampered bundles that each fail one named check, and original + sign-request pairs for the hash-check tool. The folder README lists the expected verdict for every file, and the toolkit’s self-test reproduces them all offline.

Why two timestamp anchors

Each signature is timestamped twice, over the SHA-256 of the raw signed email: once with an RFC 3161 token from a timestamping authority, and once with an OpenTimestamps proof anchored in the Bitcoin blockchain. This is deliberate. The two anchors prove the same fact through two independent trust roots, and each one covers the other’s single weakness.

A timestamp proves one narrow thing: that a specific hash existed no later than a given moment. That matters because the whole signature rests on the provider’s DKIM key, and DKIM keys are eventually retired. Freezing the signed email in time is what defeats the “publish a retired private key later and forge a back-dated signature” attack: a forgery minted after a key is retired cannot also carry a timestamp from before it was. The timestamp is therefore a clock, and the only real question is how much you must trust that clock.

The two anchors answer that question in opposite ways, with opposite blind spots:

PropertyRFC 3161 (TSA token)OpenTimestamps (Bitcoin)
Trust modelA trusted timestamping authority and its CA.Trustless: Bitcoin proof-of-work and public math, with no authority to trust.
AvailabilityInstant: a complete, verifiable token in one round trip.Pending for a few hours, until a Bitcoin block confirms the proof.
Can the time be back-dated?Yes, if the authority is compromised, colludes, or is coerced.No: placing a hash into a past block would mean rewriting Bitcoin’s history.
Time precisionExact, signed wall-clock time.Coarser block time, but unforgeable in the “no later than” direction.
RecognitionThe conventional format that courts and eIDAS already recognise.Technically airtight, anchored in a public chain anyone can re-check.
CostFree (public TSA).Free (public calendars and chain).

Read down either column and the trade is plain: wherever one anchor is strong, the other is weak, and they alternate row by row. That alternation is the whole reason to carry both rather than pick one.

The deeper point is that the two anchors are complementary, not interchangeable. They reach the same conclusion from two unrelated foundations, one institutional (an authority backed by a CA) and one physical (the energy cost of Bitcoin’s proof-of-work), but they enter the verdict at different strengths. The RFC 3161 token gives an instant time, but one you must trust the authority not to have back-dated, so on its own it supports the INTEGRITY VERIFIED tier. The PROVEN (DURABLE) tier additionally requires the Bitcoin anchor to have confirmed in a block and to agree with the token, because a Bitcoin block cannot be back-dated: that is what makes the signing time truly un-back-datable. Until the block settles, a fresh record rests on the token at the lower tier rather than being falsely elevated; and if the two times ever contradict each other, the timestamp is graded inconclusive instead of durable. Both anchors are free to obtain, so the signing record simply carries both proofs (proofs/signer-<n>.tsr and proofs/signer-<n>.ots) for every signer.

One honest caveat: Bitcoin block times are not precise to the second, so OpenTimestamps establishes “existed by about this block”, not an exact instant. The direction kysigned relies on is the unforgeable one, proving a signature existed no later than a confirmed block, while the RFC 3161 token supplies the precise wall-clock instant alongside it. Pairing a coarse but trustless anchor with a precise but trusted one is exactly what makes the two anchors complementary rather than redundant.

Key authenticity: the public archives

DKIM keys rotate, and a provider only publishes the current key in DNS. To prove the key that signed was the provider’s real key at the time of signing, not one fabricated later, kysigned anchors it in two independent public records:

The archive independently fetches the provider’s DNS itself and timestamps the key it sees, so its record does not depend on anything kysigned says (we also submit the domain and selector so a rarely-seen key gets recorded, but the archive still fetches and verifies it on its own). Verification is a gate on the exact key, not a loose “is the domain in there” check: the verifier confirms the precise embedded key is the one the archive recorded for that domain and selector, and shows the date it was registered. If the archive instead holds a different key for that domain and selector, the embedded key was never the provider’s, and the verdict is FAILED. This is the check that catches an operator who minted its own key. If the archive is simply unreachable or has not yet recorded the key, the check shows “pending” and never fails the result, so an honest record is not punished for the archive being slow. There is no key registry that kysigned controls.

The archive’s timestamps also bound the key’s life. It records when a key was last seen live in DNS, and a signature reaches PROVEN (DURABLE) only if its anchored time is at or before that last-seen point (plus a grace margin). A key resurrected long after the provider stopped publishing it, the rotate-and-publish forgery, therefore cannot reach the top tier. The bound is one-sided on purpose: signing before the archive first noticed the key is fine, so we never require a lower bound.

One practical note on the web check: a browser cannot read the public archive directly, because the archive does not send the cross-origin headers browsers require. So the verify page asks our server to forward the lookup, passing only the public domain and selector, never your file. The command-line verifier queries the archive directly, with our server out of the path, so a fully independent check is always available to anyone who wants one. Either way the verdict is the offline maths running in your browser, not our word.

What kysigned (the operator) can see

Being honest about exposure: to assemble a signing record, kysigned necessarily sees the document content and the signing metadata (who, what, when) while a signing is in progress. Three things bound that exposure:

What kysigned does NOT prove

Threat model

ConcernWhat stops it
The operator forges a signatureImpossible: a valid signature needs a DKIM signature from the signer’s provider, and the operator doesn’t have the provider’s private key.
The operator alters the document after signingImpossible: the signer’s forwarded attachment is byte-bound by SHA-256 to the reconstruction cover-<n>.pdf ++ document-original.pdf; any change to the document is a different hash and fails verification.
The operator claims someone signed when they didn’tImpossible: no forward from the signer’s mailbox means no DKIM signature, so there is nothing to put in the signing record.
The operator mints its own DKIM key and forges a signatureAn operator can generate a keypair, list the public half in keys.json, and sign with the private half, which is mathematically valid against that embedded key, so the signature math alone does not stop it. The key-provenance gate does: the archive holds the provider’s real published key, not the operator’s invention, so online the verdict is FAILED, and offline the record rises no higher than INTEGRITY VERIFIED and never claims the key was authentic. (A key genuinely compromised during its live window is the same residual risk as any PKI.)
The provider rotates its DKIM key before you verifyThe key is embedded in keys.json and confirmed against the archive’s historical record (which the archive built by fetching DNS itself), so the verifier never needs live DNS; a later rotation changes nothing.
A colluding or breached timestamp authorityTimestamps are dual: an RFC 3161 token and an OpenTimestamps Bitcoin anchor. The durable tier requires the chain anchor, which can’t be back-dated, so a back-dated token the chain contradicts is graded inconclusive rather than trusted; the TSA in turn gives an instant time for the few hours an OpenTimestamps proof is still pending. Why two anchors.
Replaying or backdating a signatureEach .eml is unique and its timestamp is anchored to a Bitcoin block; the signing time can’t be moved.
Tampering with the signing record PDF itselfThe verifier recomputes the evidence-set verification code; any edited byte diverges from the value printed on the signature page.
Spam or oversize abuseSending is credit-gated (spam is uneconomic), and a creation-time size guard rejects any record that would exceed the deliverability ceiling.
A stranger emails or probes the signing mailboxInbound is dropped unless it is a reply from a known participant on that document; bounces never leak signing state to non-participants.
A compromised signer mailboxOut of scope for any e-signature product: see “What kysigned does NOT prove”. The evidence still records exactly which mailbox signed and when.

Forked instances stay independent

kysigned is Apache-2.0-licensed and self-hostable. A forked instance shares no secret and no central registry with kysigned.com or any other deployment. Each operator runs under its own domain and infrastructure, and trust still flows only from the signer’s provider, the public archives, the timestamp authorities, and the math. A signing record produced by any instance verifies the same way, anywhere, offline, because the trust set never included the operator in the first place. Forking changes who runs the plumbing; it changes nothing about what a signature proves or how it is checked.

Open-source components and audit posture

Everything on this page is meant to be checked, not taken on faith. The whole stack is Apache-2.0 open source, and the parts that matter for trust are deliberately not things we invented:

Our audit posture is honesty about it: we rely on widely-used components that get many eyes from the broader ecosystem rather than commissioning private audits, and we keep all trust-boundary code (verification, crypto, key handling) on those reviewed libraries, never on self-rolled substitutes. Because a signing record is verifiable from public inputs alone, the ultimate audit is the one you can run yourself: re-verify any record and check our claims against the math directly. The full source lives in the Apache-2.0 public repository.

kysigned is not a substitute for legal advice. It is your responsibility to determine whether electronic signatures are legally valid for your use case, jurisdiction, and industry. See our Terms of Service.