Skip to content

Personal

nostr-linkr

A trustless bridge between a Nostr identity and an Ethereum address, with full BIP-340 Schnorr verification performed on-chain: no DNS, no platform post, no third party to believe.

Mar 2026NostrWeb3Cryptography

nostr-linkr lets someone prove that a Nostr public key and an Ethereum address belong to the same person, and lets anyone else check that proof without asking a server. It is a smart contract, a TypeScript SDK, and a specification proposed to the Nostr protocol.

Parts
Contract · SDK · example client · NIP proposal
Proposal
NIP-XX, On-Chain EVM Identity Linking (open)
Role
Author
Repository
VincenzoImp/nostr-linkr
VincenzoImp/nostr-linkrOn-chain Ethereum↔Nostr identity bridge with BIP-340 Schnorr verification: smart contract, TypeScript SDK, and example client.TypeScript

The problem

Nostr already has two ways to say “this account is also me somewhere else”, and the specification proposal states the objection to both. NIP-05 verification depends on a DNS-controlled server: whoever runs the domain can change or withdraw the claim. NIP-39 depends on a post on GitHub or Twitter, which the platform can delete and the platform’s owner can decide about.

Both work. Both are mutable, censorable, and require trusting a service that is not a party to the identity being claimed.

What I built

The link is written to a smart contract, and it requires both private keys, which is what makes it a claim neither side can fake.

The Nostr key signs an event containing the Ethereum address. The Ethereum key sends the transaction that submits it. The contract then does the part that would ordinarily be taken on trust: it recomputes the NIP-01 event id from the event’s fields, checks it matches the id presented, and verifies the Schnorr signature against the Nostr public key. Only then is the link recorded, and it can be looked up in either direction. A pullLinkr call removes it, so the link is revocable by the address that made it.

Around the contract sit a TypeScript SDK, an example client, and a proposal written up as a NIP and submitted to the specification repository, where it is open.

Hard parts

The EVM cannot verify a Nostr signature. Ethereum’s precompiled ecrecover handles ECDSA; Nostr signs with BIP-340 Schnorr. Same curve, different scheme, and no precompile for it, so the verification is implemented in Solidity: lifting the x-only public key back to a curve point, which works because secp256k1’s field prime is congruent to 3 mod 4 and the square root is therefore a single modular exponentiation, then checking that s·G == R + e·P. It runs entirely on-chain, which is the whole point; verification that happens off-chain is a claim about a claim. The hand-written verifier has not received a security audit, and the deployed contract is limited to Base Sepolia. It demonstrates the proof path rather than establishing production security.

Recomputing the event id rather than accepting it. A signature is over the event id, so a contract that trusts a submitted id verifies nothing about the event’s contents. The contract serialises the fields per NIP-01 and derives the id itself, and only compares afterwards.