MetamorphicLog.Coniks (metamorphic_log v0.2.0)

Copy Markdown View Source

CONIKS key-transparency lookup and absence verification (Layer 3).

CONIKS lets a relying party verify what value a log binds to an identity — or that it binds none — without the operator being able to equivocate, and without revealing other identities. Lookups are privacy-preserving: the identity is blinded through a VRF (RFC 9381 ECVRF over edwards25519 by default, suite 0x03).

These functions are the verifier side and need no directory state — only the operator's published vrf_public key, the directory root (a 64-byte SHA3-512 prefix-tree root), the queried identity, and the proof the operator returned.

All binary arguments are base64-encoded; namespace is a UTF-8 label such as "mosslet.app".

Summary

Types

An opaque, stateful CONIKS directory resource owned by the runtime.

Functions

The server-side oblivious evaluation (RFC 9497 BlindEvaluate): evaluate a client's blinded element under this directory's POPRF key.

Derive the deployment POPRF keypair from a 32-byte seed and a public key-info string (RFC 9497 §3.2.1 DeriveKeyPair).

Open a per-namespace directory from an existing VRF secret key, returning an opaque, empty directory/0 resource.

Open a per-namespace POPRF-backed directory from the deployment POPRF secret key, returning an opaque, empty directory/0 resource.

Generate a fresh classical VRF keypair (RFC 9381 ECVRF over edwards25519, suite 0x03) for a namespace directory.

Insert (or replace) identity's value in the directory, committing to it at the identity's VRF-derived index. Serialized against other appends.

Look up identity, producing a presence or absence proof against the current root.

Look up a 32-byte derived tree index, producing an index-bound presence or absence proof against the current root — the POPRF serving path. No identity, no cleartext label: the caller derived the index obliviously and verifies with verify_indexed_lookup/6 / verify_indexed_absence/6.

The public POPRF info metadata (base64) binding this directory's evaluations, for a POPRF-backed directory. Returns {:ok, info_b64} or {:error, reason}.

The POPRF public key (base64) clients blind under, for a POPRF-backed directory. Returns {:ok, poprf_public_b64} or {:error, reason}.

The current directory root: the 64-byte SHA3-512 prefix-tree root over all commitments, base64-encoded. Returns {:ok, root_b64}.

This directory's index-derivation suite identifier — an RFC 9381 octet for a VRF directory (0x03 classical ECVRF), 0x80 for a POPRF one — bound into every leaf hash. Clients need it to verify index-bound proofs. Returns {:ok, suite_id}.

Verify an absence proof: that identity is not bound in the directory committed by root.

Verify an index-bound absence proof: the index provably holds the empty leaf under root. Returns :ok or {:error, reason}.

Verify an index-bound presence proof (the POPRF oblivious-lookup path): the caller's self-derived 32-byte index plus the canonical IndexedLookupProof bytes against root. No identity or scheme key is needed — the index itself is the caller's evidence.

Verify a presence (lookup) proof: that identity maps to a value in the directory committed by root.

The VRF public key (base64) relying parties use to verify this directory's proofs. Returns {:ok, vrf_public_b64}.

Types

directory()

@opaque directory()

An opaque, stateful CONIKS directory resource owned by the runtime.

Held as a reference to a Rust-side RwLock<ConiksDirectory>: reads (root/1, lookup/2, vrf_public/1) run concurrently, appends (insert/3) are serialized. It is derived from a namespace's append-only log — built once with directory_open/2 and updated incrementally with insert/3, rather than rebuilt per request. Not serializable; do not persist it. Persist the VRF secret (see generate_vrf_key/0) and replay entries to rebuild.

Functions

blind_evaluate(directory, blinded_element_b64)

@spec blind_evaluate(directory(), blinded_element_b64 :: String.t()) ::
  {:ok, {String.t(), String.t()}} | {:error, String.t()}

The server-side oblivious evaluation (RFC 9497 BlindEvaluate): evaluate a client's blinded element under this directory's POPRF key.

Returns {:ok, {evaluated_element_b64, dleq_proof_b64}} or {:error, reason}. The directory learns nothing about the identity behind the blinded element. POPRF-backed directories only.

derive_poprf_key_pair(seed_b64, key_info_b64)

@spec derive_poprf_key_pair(seed_b64 :: String.t(), key_info_b64 :: String.t()) ::
  {:ok, {String.t(), String.t()}} | {:error, String.t()}

Derive the deployment POPRF keypair from a 32-byte seed and a public key-info string (RFC 9497 §3.2.1 DeriveKeyPair).

Returns {:ok, {secret_b64, public_b64}}. The secret_b64 is deployment operator infrastructure — persist it securely and pass it to directory_open_poprf/3; it is not user key material and not a signing key. The public_b64 is published so clients can blind under it and verify DLEQ proofs.

directory_open(namespace, vrf_secret_b64)

@spec directory_open(namespace :: String.t(), vrf_secret_b64 :: String.t()) ::
  {:ok, directory()} | {:error, String.t()}

Open a per-namespace directory from an existing VRF secret key, returning an opaque, empty directory/0 resource.

Replay the namespace's entries into it with insert/3 to reconstruct the current directory. Returns {:ok, directory} or {:error, reason} (a malformed namespace or structurally invalid secret key).

directory_open_poprf(namespace, info_b64, poprf_secret_b64)

@spec directory_open_poprf(
  namespace :: String.t(),
  info_b64 :: String.t(),
  poprf_secret_b64 :: String.t()
) :: {:ok, directory()} | {:error, String.t()}

Open a per-namespace POPRF-backed directory from the deployment POPRF secret key, returning an opaque, empty directory/0 resource.

info_b64 is the base64 public POPRF metadata binding this namespace's evaluations (e.g. "mosskeys/directory/v1:<namespace_id>"); it is threaded through both construction and serving, and clients must use the identical info to recover the same index. Replay the namespace's entries with insert/3 to reconstruct the current directory (insert-time index derivation is the non-oblivious RFC 9497 Evaluate, matching what clients derive obliviously). Returns {:ok, directory} or {:error, reason}.

generate_vrf_key()

@spec generate_vrf_key() :: {:ok, {String.t(), String.t()}} | {:error, String.t()}

Generate a fresh classical VRF keypair (RFC 9381 ECVRF over edwards25519, suite 0x03) for a namespace directory.

Returns {:ok, {secret_b64, public_b64}}. The secret_b64 is per-namespace operator infrastructure — persist it securely and pass it to directory_open/2; it is not user key material and not a signing key. The public_b64 is published so relying parties can verify lookups.

insert(directory, identity_b64, value_b64)

@spec insert(directory(), identity_b64 :: String.t(), value_b64 :: String.t()) ::
  :ok | {:error, String.t()}

Insert (or replace) identity's value in the directory, committing to it at the identity's VRF-derived index. Serialized against other appends.

Returns :ok or {:error, reason}.

lookup(directory, identity_b64)

@spec lookup(directory(), identity_b64 :: String.t()) ::
  {:ok, {:present, String.t(), String.t()}}
  | {:ok, {:absent, String.t()}}
  | {:error, String.t()}

Look up identity, producing a presence or absence proof against the current root.

Returns {:ok, {:present, value_b64, proof_b64}} when the identity is bound, {:ok, {:absent, proof_b64}} when it is not, or {:error, reason}. The returned proof_b64 verifies via verify_lookup/5 (presence) or verify_absence/5 (absence) against the published vrf_public/1 key and root/1.

lookup_by_index(directory, index_b64)

@spec lookup_by_index(directory(), index_b64 :: String.t()) ::
  {:ok, {:present, String.t(), String.t()}}
  | {:ok, {:absent, String.t()}}
  | {:error, String.t()}

Look up a 32-byte derived tree index, producing an index-bound presence or absence proof against the current root — the POPRF serving path. No identity, no cleartext label: the caller derived the index obliviously and verifies with verify_indexed_lookup/6 / verify_indexed_absence/6.

Returns {:ok, {:present, value_b64, proof_b64}} when a leaf is bound at the index, {:ok, {:absent, proof_b64}} when it holds the empty leaf, or {:error, reason}.

poprf_info(directory)

@spec poprf_info(directory()) :: {:ok, String.t()} | {:error, String.t()}

The public POPRF info metadata (base64) binding this directory's evaluations, for a POPRF-backed directory. Returns {:ok, info_b64} or {:error, reason}.

poprf_public(directory)

@spec poprf_public(directory()) :: {:ok, String.t()} | {:error, String.t()}

The POPRF public key (base64) clients blind under, for a POPRF-backed directory. Returns {:ok, poprf_public_b64} or {:error, reason}.

root(directory)

@spec root(directory()) :: {:ok, String.t()} | {:error, String.t()}

The current directory root: the 64-byte SHA3-512 prefix-tree root over all commitments, base64-encoded. Returns {:ok, root_b64}.

suite_id(directory)

@spec suite_id(directory()) :: {:ok, non_neg_integer()} | {:error, String.t()}

This directory's index-derivation suite identifier — an RFC 9381 octet for a VRF directory (0x03 classical ECVRF), 0x80 for a POPRF one — bound into every leaf hash. Clients need it to verify index-bound proofs. Returns {:ok, suite_id}.

verify_absence(namespace, vrf_public_b64, root_b64, identity_b64, proof_b64)

@spec verify_absence(
  namespace :: String.t(),
  vrf_public_b64 :: String.t(),
  root_b64 :: String.t(),
  identity_b64 :: String.t(),
  proof_b64 :: String.t()
) :: :ok | {:error, String.t()}

Verify an absence proof: that identity is not bound in the directory committed by root.

Returns :ok or {:error, reason}.

Example

:ok = MetamorphicLog.Coniks.verify_absence(namespace, vrf_public, root, identity, proof)

verify_indexed_absence(namespace, suite_id, root_b64, index_b64, proof_b64)

@spec verify_indexed_absence(
  namespace :: String.t(),
  suite_id :: non_neg_integer(),
  root_b64 :: String.t(),
  index_b64 :: String.t(),
  proof_b64 :: String.t()
) :: :ok | {:error, String.t()}

Verify an index-bound absence proof: the index provably holds the empty leaf under root. Returns :ok or {:error, reason}.

verify_indexed_lookup(namespace, suite_id, root_b64, index_b64, proof_b64)

@spec verify_indexed_lookup(
  namespace :: String.t(),
  suite_id :: non_neg_integer(),
  root_b64 :: String.t(),
  index_b64 :: String.t(),
  proof_b64 :: String.t()
) :: {:ok, String.t()} | {:error, String.t()}

Verify an index-bound presence proof (the POPRF oblivious-lookup path): the caller's self-derived 32-byte index plus the canonical IndexedLookupProof bytes against root. No identity or scheme key is needed — the index itself is the caller's evidence.

Returns {:ok, value_b64} with the bound value on success, or {:error, reason}.

verify_lookup(namespace, vrf_public_b64, root_b64, identity_b64, proof_b64)

@spec verify_lookup(
  namespace :: String.t(),
  vrf_public_b64 :: String.t(),
  root_b64 :: String.t(),
  identity_b64 :: String.t(),
  proof_b64 :: String.t()
) :: {:ok, String.t()} | {:error, String.t()}

Verify a presence (lookup) proof: that identity maps to a value in the directory committed by root.

Returns {:ok, value_b64} with the bound value on success, or {:error, reason}.

Example

{:ok, value} =
  MetamorphicLog.Coniks.verify_lookup(namespace, vrf_public, root, identity, proof)

vrf_public(directory)

@spec vrf_public(directory()) :: {:ok, String.t()} | {:error, String.t()}

The VRF public key (base64) relying parties use to verify this directory's proofs. Returns {:ok, vrf_public_b64}.