Tessera

privacy-preserving identity & reputation · a .NET SDK

Prove facts,
not data.

Let your users prove they're KYC'd, accredited, in-jurisdiction — or simply human — without handing your app a single byte of their data. You stay compliant; they stay private. One SDK, anchored to Solana, EVM, or Cardano through the same interface.

dotnet add package Sagynbaev.Tessera.Sdk

Package IDs ship under the Sagynbaev. prefix on nuget.org — namespaces stay Tessera.*.

activate a leaf — the other attestations stay sealed

Built and hashed live in your browser: leaves SHA-256(0x00 ‖ fact), nodes SHA-256(0x01 ‖ L ‖ R) — the same scheme as Tessera.Attestations.MerkleTree. Recompute it: run tessera.verifyRoot() in the console. Facts are sample data; the tree is real.

use cases · where it fits

One identity layer.
RWA, DeFi, Bitcoin, and more.

Three moves — disclose one fact, prove a predicate without revealing the value, anchor a root on-chain — compose into products across very different domains. A map, by domain, of what teams build on it.

▣ runnable example in the repo○ application pattern

RWA & regulated assets

Tokenized securities & RWA

Gate every transfer on identity — holders prove kyc_verified + a permitted jurisdiction — while the registry stays off-chain and no PII ever touches the chain.

selective disclosure + allowlist · PermissionedToken (ERC-3643 / T-REX)

Private placements & accredited sales

Let only accredited buyers in: the holder proves income ≥ $X with a Bulletproof bound to the issuer's commitment, and the value itself is never disclosed.

bound predicate proof · CardanoCreditLine

Transfer-agent compliance

Revoke a holder's attestation and the on-chain allowlist drops them at the next revocation epoch — pending transfers simply stop, with the decision made off-chain.

allowlist gateway + revocation epoch

DeFi

Reputation & undercollateralized lending

Extend a credit line against income ≥ X or reputation ≥ N without doxxing the figure; your contract reads only approved.

range proof · CardanoCreditLine

Compliant pools & perps

Restrict LPing or trading to verified, in-jurisdiction wallets, with eligibility enforced at the contract via the same allowlist gateway that drives permissioned tokens.

verification policy + allowlist

Confidential transfers

Move value without publishing the amount: a Pedersen-committed amount carries two range proofs — amount ≥ 0 and balance − amount ≥ 0.

Pedersen + Bulletproofs · ConfidentialTransfer

Governance, DAOs & airdrops

Sybil-resistant voting

One human, one DID. Each ballot is a commitment to 0 or 1 with a validity proof, so individual votes stay private while the tally stays sound.

commitment + validity proof · PrivateVoting

Proof-of-humanity airdrops

Filter bots from a drop using a human_verified attestation — without ever linking the claiming wallet to a real-world identity.

human_verified + selective disclosure

Reusable KYC / soulbound credentials

KYC once through a source plugin, then present the result anywhere — no document re-upload, and the verifier learns only the predicate it asked for.

Sources.Sumsub / Sources.XRoad

Markets & AI agents

Sealed-bid auctions

Bids commit inside [min, max] and reveal only after close, so no one can read or front-run a bid — and no one can change theirs once committed.

range proof + commitment · SealedBidAuction

Eligibility-gated prediction markets

Admit only eligible participants — by jurisdiction or age — proven as a predicate, so a location or birthdate is never shared with the market.

jurisdiction predicate

AI-agent identity & delegation

Issue agent_identity attestations so a dapp can tell an authorized, accountable agent from an anonymous bot — and bound proofs scope what each agent may do.

agent_identity + bound proofs

Bitcoin & proof of reserves

Proof of Bitcoin reserves

Prove control of Bitcoin addresses with a BIP-137 signed challenge and that the balance clears a threshold — without revealing the amount or the addresses, each bound to a point-in-time chain snapshot.

Sources.Bitcoin · BitcoinCreditLine

BTC-backed credit lines

A holder proves BTC balance ≥ 1 — a Pedersen commitment bound to a block height — and the lender anchors the decision on Cardano. The amount is never disclosed.

committed btc_balance · BitcoinCreditLine

Aggregate reserves, many addresses

Sum per-address commitments with CombineCommitments to prove total reserves ≥ X across a whole wallet set, each bound to a point-in-time height and hash.

CombineCommitments + ChainSnapshot

under the hood — three primitives

One human, one DID.
Many facts, disclosed one at a time.

DIDs & signed attestations did:tessera:base58(sha256(pubkey ‖ "v1"))
Identifiers are derived from the controller key, never chosen — squatting is impossible and identity is tied to provable key control. Issuers sign typed, expiring attestation envelopes against the DID: humanity, phone, wallet control, KYC, jurisdiction, reputation.
Selective disclosure — Merkle bundles leaf = SHA-256(0x00 ‖ data)  ·  node = SHA-256(0x01 ‖ L ‖ R)
A holder's attestations form a domain-separated SHA-256 Merkle tree; only the 32-byte root is anchored on-chain. A presentation reveals one leaf plus its inclusion path, bound to {verifier, session_nonce, as_of_epoch, chain} — the verifier checks it against the anchored root and learns nothing about the other leaves.
Predicate proofs — Bulletproofs over Pedersen commitments C = v·G + r·H  ·  proof commitment V = C − threshold·G
The issuer commits to a value inside the attestation; the holder proves v ≥ threshold without revealing v. The proof is bound to that exact commitment so it cannot be replayed against a different value — and ranges are two-sided: C − min·G and max·G − C are both proved non-negative. Pure C# secp256k1, no external dependencies.

try it — the credit-gating flow

What the verifier learns

This is the CardanoCreditLine example, simulated in your browser. Set an income as the holder; set the approval threshold as the lender. The committed value never crosses the wire — only the verdict does.

holder

85,000

what leaves the holder — a Pedersen commitment

02 ····

fresh blinding r per commitment — bytes are non-reproducible by design; verification is deterministic.

verifier

verifier receives

commitment C + Bulletproof for C − threshold·G ≥ 0

the verifier recomputes C − threshold·G and checks the proof — it never sees the value.

press verify proof — the lender checks the bound proof against the commitment

Visual demo — the bytes above are simulated. Real proofs run via Tessera.Attestations.CredentialProof.ProveBoundMinimum / VerifyBound, with the Bulletproofs math in Tessera.Cryptography — see the SDK on GitHub.

how it works

Three parties. The chain is a notary.

  1. Issuer. Holds a signing key, registered in the on-chain issuer registry; signs a typed, expiring attestation for the subject DID.
  2. Holder. Collects attestations into a Merkle bundle, anchors the 32-byte root on-chain, and builds a presentation — one leaf + inclusion path + predicate proofs, bound to {verifier, session_nonce, as_of_epoch, chain}.
  3. Verifier. Checks the issuer signature, the inclusion path against the anchored root, the predicate proofs against their commitments, and the revocation epoch — all off-chain, in C#.
  4. On-chain notary (IdentityRegistry). Stores only the attestation root (32 B), the revocation epoch (u64), owner, and issuer records. It verifies no proofs and holds no identity data.

“Hard rule: the chain is for audit, not for storage.” — docs/architecture.md

security — hardened at the trust boundary

Built to fail closed

Release 3.3.0 hardens every step where trust is established. The guarantees a verifier actually relies on:

Signed presentations

Every presentation carries the holder's controller key and a signature over a canonical challenge — verifier, nonce, epoch, chain, freshness, disclosed leaves. The verifier re-derives the DID and checks the signature; audience and nonce aren't just plaintext fields.

Holder.BuildSignedPresentation

Revocation & freshness

A presentation bound to a stale epoch is rejected unconditionally when an anchor is reachable, and a freshness window — authenticated via the signed CreatedAt — bounds replay.

RequireCurrentRevocationEpoch · MaxPresentationAge

Address-bound wallet binding

Binding proves the address is controlled by the wallet key; binding nonces are single-use, and DID resolution enforces revocation on every read.

IWalletControlVerifier · INonceStore

Authenticated anchors

EVM registerDid requires a controller signature bound to (didHash, root, chainId, contract); Solana issuer registration is admin-gated; Cardano reads authenticate the controller.

EVM · Solana · Cardano

Honest caveat: Tessera.Cryptography is still not constant-time — constant-time Point.ScalarMul is deferred to the planned external crypto audit, whose dossier is already public in docs/security-audit-readiness.md.

start building

One package. The code lives on GitHub.

The SDK exposes Holder, Issuer, and Verifier — the three roles in any attestation flow. Install it, then lift a runnable scenario straight from examples/; the full API and the modular package layout are in the repo.

dotnet add package Sagynbaev.Tessera.Sdk

chains — honest statuses

Three live backends. Verify in C#.

The on-chain layer stores only Merkle attestation roots and revocation epochs — DID documents, attestations, and proofs are never written on-chain. Three adapters are complete — Solana, EVM, Cardano — behind one IChainAnchor interface, with Stellar and Midnight scaffolds; plug in any network by implementing it.

didHash = SHA-256(utf8(did)) — the same identity keys the same record on every backend.

roadmap — planned, not shipped

What comes next