Skip to content

Personhood & Web of Trust — proving you're a unique human

A wallet signature proves you control a key. It does not prove you’re a unique person — anyone can spin up ten wallets in ten minutes. That gap is the Sybil attack: flood a system with fake identities to capture a vote, drain an airdrop, or game a “one-human-one-share” mechanism. Any DAO that counts wallets gets captured the moment it holds real money.

Smart Engines’ answer is personhood verification: a pluggable subsystem that issues short-lived signed certificates attesting “this wallet has been verified, by this method, as a single human.”


Smart Engines does not prescribe how you verify personhood. It defines the shape of the question and the shape of the answer, and lets a hub plug in whatever trust model fits — vouching, biometrics, an external proof-of-personhood protocol.

A verifier takes a wallet address and an opaque proof (each method defines its own payload) and returns either a signed certificate or a clean rejection: no thrown exception, no leaked reason. Each verifier has an issuer ID and a certificate lifetime. Which verifier to run is the hub’s policy, not the platform’s, so the platform ships no default: with no verifier configured, the endpoint returns 503. That is explicit opt-in, never a silent fallback.


A PersonhoodCert (exported by @hsuite/smart-engines-sdk) is a small signed record — a portable, time-limited badge:

type PersonhoodCert = {
address: string;
issuerId: string; // who issued it (e.g. the hub's identity)
attestationMethod: 'web-of-trust' | 'biometric' | 'pop-protocol';
issuedAt: number; // unix seconds
expiresAt: number; // unix seconds — authoritative lifetime
signature: string; // signed by the issuer
};

Once issued, the holder can present it to any relying party that knows the issuer’s public key. The cert carries its own lifetime, so revocation is implicit: when it expires, you simply request a new one. (expiresAt is the authoritative gate — it’s inside the signed payload, so tampering breaks the signature.)


The reference implementation is a Web of Trust verifier. Its rule is simple:

A wallet is verified as a person when at least k people from an allow-list vouch for it, recently enough, with valid signatures.

A hub configures it with the list of addresses allowed to vouch, the threshold k, and the maximum age of a vouch.

The proof is a list of signed vouches; the verifier discards stale or non-allow-listed vouches, checks each signature, counts distinct vouchers, and issues a cert if the count meets k (otherwise it rejects).

%%{init: {'sequence':{'showSequenceNumbers':false}}}%%
sequenceDiagram
    autonumber
    participant User as New user
    participant Vouchers as k allow-listed vouchers
    participant App as App / SDK
    participant V as Verifier (Web of Trust)
    participant Relying as Relying app / DAO

    User->>Vouchers: ask for vouches
    loop k vouches
        Vouchers->>User: sign(address ‖ now)
    end
    User->>App: hand over vouches
    App->>V: verify(address, proof)
    V->>V: drop stale / non-allow-listed, check sigs, count unique
    alt enough valid vouches
        V-->>App: signed PersonhoodCert
        App->>Relying: present cert
        Relying->>Relying: verify signature vs issuer pubkey
        Relying-->>User: allow protected action
    else not enough
        V-->>App: rejected
        App-->>User: gather more vouches
    end

No identity company in the loop

You don’t depend on a KYC provider, biometric vendor, or government registry being online or honest.

Bootstrappable

Seed the allow-list with the founding team; they vouch for early members; the graph grows organically.

Composable

A well-vouched community can itself become a voucher for another community.

Transparent failure mode

When it fails, the reason is “not enough vouches” — clearly fixable. Not “the KYC server is down.”

The honest trade-off: early in a network’s life the allow-list is small, so the verifier is only as plural as its seed set. A hub can plug in a different trust model (biometric, an external proof-of-personhood protocol) through the same contract.


Web of Trust polices membership socially. Some communities need a harder, document-backed guarantee — but still without handing an identity company the keys. The second reference verifier is zkPassport. It checks a zero-knowledge proof over a real e-passport: the holder’s phone reads the passport’s NFC chip, and a ZK circuit proves “this is a genuine, unexpired passport held by a unique adult” — without revealing the passport.

What makes it decentralized in the Smart Engines sense: the validator is its own issuer — there is no identity-company call in the path. The proof is verified locally, against the public registry of certificates that certify real passport-issuing authorities.

Property What the verifier does
Discloses almost nothing The verifier builds the proof request itself and never takes it from the client; the issuing state (e.g. DE) is the only document fact it reads.
One human, one document Sybil resistance rides on a single per-document nullifier; a salted nullifier is rejected.
Purpose-bound Each purpose binds exactly what it should — membership binds the candidate address; a campaign proof binds no address and pins the jurisdiction; re-attestation binds the ceremony.
Fails closed If the passport-authority registry can’t be read, verification stops with an error and the caller answers 503 — never a pass.
Records only facts A positive verdict records the nullifier, issuing state and registry roots — never any passport data.

It is the same opt-in model as everything else here: zkPassport is a pluggable verifier, not an always-on one — a hub wires it exactly as it would Web of Trust (and, as with every verifier, nothing wired means the endpoint stays 503).


A certificate is just a signed blob — using it is the relying party’s choice. Possible uses, all planned:

DAO governance

Require a fresh personhood cert for “one human, one vote” proposals; or combine with token weight for hybrid systems.

Subscription tiers

A cheaper rate for verified humans (it reduces the incentive to abuse).

Rules Engine

A rule check that denies operations lacking a fresh cert. See Rules Engine.

Faucet / airdrop control

Issue once per verified human, not per wallet.

Because verification logic lives in one place behind a single contract, every feature benefits from any verifier you add.


Personhood is orthogonal to wallet authentication, by design. Wallet auth proves control of a key; the personhood verifier proves uniqueness of a human. Sybil-resistant smart-apps (voting, airdrops, UBI) need both. They’re kept as separate primitives precisely so you can mix and match — wallet auth on every request, personhood only where Sybil resistance matters.


  • A wallet proves key control, not uniqueness — leaving the Sybil gap.
  • A pluggable verifier contract decides personhood; two reference verifiers are built — social Web of Trust and document-backed zkPassport. Neither is enabled yet.
  • A PersonhoodCert is a short-lived, portable, signed badge any relying party can verify against the issuer’s pubkey. Expiry = implicit revocation.
  • Web of Trust needs no identity company — the community vouches for itself.
  • Personhood is opt-in at every layer (no verifier wired → 503) and orthogonal to wallet auth.