Understanding ECMH in commits

Floating the question here, with some context.

From the last dev diary post:

The ECMH for a permissioned repo is authenticated using a randomly generated and transient HMAC key, which is in turn signed by the user’s atproto signing key.

The commit is composed of the ECMH hash, the computed HMAC, the HMAC key, and the signature.

Each commit is authenticated for only one party and is not intended to be rebroadcast. HMACs are used to provide deniability in the event a signature is exposed. Every reader who reads a permissioned repo from a PDS will receive a different HMAC key.

This effectively means that the ECMH can be adjusted incrementally and then with each request for the space commit is built like this:

let ecmh = set_hash.to_bytes();
let hmac_key: [u8; 32] = rand::random();
let hmac = hmac_sha256(&hmac_key, &ecmh);
let sig = sign(signing_key, &hmac_key)

And then only the hmac, hmac_key, and signature should be returned. The client would build their own ecmh input, then validate that the hmac_key comes from the identity using its verification method, and then uses it to create an hmac of the ecmh and the validated hmac_key.

This specifically is the source of contention.

The commit is composed of the ECMH hash, the computed HMAC, the HMAC key, and the signature.


The attack here is that someone in the past had a list of the values in the ECMH hash plus a commit and could demonstrated that at some point in time, a list of values along with a commit and it’s transmitted signed hmac key could demonstrate membership.

1 Like

Just noting that I want to come back to this when I have a moment and really understand what you’re saying here, thanks for sharing. :eyes:

1 Like

The attack here is that someone in the past had a list of the values in the ECMH hash plus a commit and could demonstrated that at some point in time, a list of values along with a commit and it’s transmitted signed hmac key could demonstrate membership.

I understood that ECMH commit is used as a checksum to verify and authenticate already synced records. That is to protect clients from being fed counterfeit records during sync by rogue PDS or intermediary.

The space credential is used to authorize the client to be allowed to sync those records in the first place. So, once membership is revoked, outcasts are not allowed to sync anymore past the last issued valid space credential expires.

What I didn’t get however, was how exactly “HMACs are used to provide deniability in the event a signature is exposed“. My understanding of HMACs was the opposite - to provide non-repudiation, not deniability :man_shrugging:

I think the ECMH hash can still be a part of the commit.

There’s not a problem with an ECMH hash leaking because it doesn’t prove anything. The problem is an asymmetrically signed ECMH hash leaking because that’s a proof that a user published some set of records within a space that can then be distributed around outside the space boundary.

HMACs can only be verified by if you have the key, but having the key also lets you compute an HMAC. So that prevents redistribution of proofs of space contents outside of the space boundary. I belive Signal uses a similar-ish scheme that allows for deniability if messages leak. Signing the HMAC key is a way to do this unidirectionally & non-interactively.

Separately, given recent developments in quantum computing ( A Cryptography Engineer’s Perspective on Quantum Computing Timelines ), I expect we’ll be using something other than an ECMH hash (which is not PQ-safe). But whatever we use will have roughly the same semantics of a multiset hash.

1 Like