Implementation Architectures

A) Hybrid: Off-chain Secrets + On-chain Commitments

Current implementation on Stacks blockhain

Storage:

  • Off-chain: encrypted payload (or encrypted “envelope”) stored on a controlled service (DB/object storage).

  • On-chain: commitment = H(payload_bytes) (or H(ciphertext)), plus optional metadata (algo/version/mime/size).

Access / Reveal

  • Client signs a request (wallet signature).

  • Gateway verifies current NFT ownership on-chain, rate-limits, then returns the encrypted bytes (or a short-lived URL).

  • Client verifies: H(received_payload) == on-chain commitment.

Answer verification (example: Seed Phrase Hunt)

  • Canonical answer stored encrypted (or as H(answer||salt)).

  • User submits answer → server checks correctness without publicly revealing plaintext (e.g., compare hashes/HMACs; or compare deterministic transforms).

Pros

  • Fast UX, low cost, chain-agnostic.

  • Strong integrity guarantee: server can’t “swap the secret” after mint without being caught.

Trade-offs

  • Availability and access control depend on the service (not fully trustless).

  • Privacy is off-chain (keys + delivery must be protected).


B) On-chain Commitments + On-chain “Claim” + Off-chain Key Release

Idea: keep payload encrypted off-chain (or even on-chain), but move the “right to reveal” and the audit trail on-chain. The secret is only unlocked when an on-chain condition is met (ownership + event + optional payment/proof).

Storage

  • Option 1: ciphertext stored off-chain; commitment on-chain.

  • Option 2: ciphertext stored on-chain (if small enough); commitment still on-chain.

Unlock flow

  1. Owner calls an on-chain function: claim-reveal(token-id) (or start-reveal), emitting an event.

  2. Backend watches chain events and releases the decryption key (or envelope) to the owner only after seeing the on-chain claim.

  3. Client decrypts locally and verifies commitment.

Pros

  • More “protocol-like”: reveal attempts are publicly auditable.

  • Stronger fairness for games: unlocks can be conditioned on on-chain actions (fees, deadlines, proofs-of-participation).

  • Still much simpler than ZK reencryption proofs.

Trade-offs

  • Still relies on a key release service (or MPC network) for confidentiality.

  • Requires indexer/event listener reliability.

C) Fully On-Chain (ciphertext + proofs on-chain)

Storage:

  • Ciphertext stored directly in contract storage

  • Master encryption key encrypted under owner's pubkey

  • All data verifiable on-chain

Transfer flow:

  1. Seller re-encrypts master key under buyer's pubkey

  2. Seller generates ElGamal re-encryption consistency proof (ZK proof)

  3. Seller submits new ciphertext + proof on-chain

  4. Contract verifies proof: "new ciphertext contains same master key"

  5. If proof valid → transfer proceeds, payment released

  6. Buyer decrypts master key with private key → decrypts secret

Proof verification: verify_reencryption_proof( old_ciphertext, new_ciphertext, old_pubkey, new_pubkey, zk_proof ) -> bool Pros:

  • Trustless (cryptographic guarantees, no escrow needed)

  • Maximum auditability (everything on-chain)

  • Prevents seller cheating (can't provide fake secret)

Cons:

  • Higher gas (proof verification + storage)

  • Requires chains with EC operations + ZK precompiles

  • More complex implementation

Last updated