Skip to content

Add accumulated log entry type - #172

Closed
Bren2010 wants to merge 1 commit into
ietf-plants-wg:mainfrom
Bren2010:brendan/accumulated
Closed

Add accumulated log entry type#172
Bren2010 wants to merge 1 commit into
ietf-plants-wg:mainfrom
Bren2010:brendan/accumulated

Conversation

@Bren2010

Copy link
Copy Markdown
Contributor

No description provided.

@Bren2010
Bren2010 requested a review from davidben as a code owner January 11, 2026 18:41
@davidben

Copy link
Copy Markdown
Collaborator

Hmm, so purely mechanically, we can't add a field to the overall entry struct like this without updating the certificate format with the accumulated count. Otherwise the verifier cannot reconstruct things.

Do you have an example of use that would need the count and two layers of extensibility? Naively I would have assumed one could just extend the top-level entry type when adding new kinds of entries, though that doesn't categorize things into accumulator and normal entries.

@Bren2010

Copy link
Copy Markdown
Contributor Author

Do you have an example of use that would need the count and two layers of extensibility?

The purpose of the count is to make it easy to find the n^th or the most recent accumulator log entry, through something like binary search.

To kind of summarize the argument:

  • MTC transparency logs have a very very robust gossip mechanism: clients talk to a lot of servers that make claims about the state of the transparency log, which they can verify against their own view. Servers also talk to a lot of clients, and the client accepting the server's signatureless certificate means the client agrees with the server's view of the log.
  • Servers want to be able to monitor for mis-issued certificates related to their domain names. Downloading the entirety of every log from every CA is expensive, so most servers will use something like a Verifiable Index. Because the Verifiable Index is a separate log, the server also needs some gossip mechanism here to ensure that it has the same view of the Verifiable Index as everyone else.
  • So let's put the root hash of the Verifiable Index(es) into a log entry of the MTC transparency log. This way the server, which has its highly gossiped view of the MTC transparency log, can look at this log entry and know that everyone else sees this root hash for the Verifiable Index as well.
  • Using the counter to find the most recent accumulator log entry carries the guarantee that anyone else with your view of the MTC transparency log will get the same Verifiable Index root hashes. If you didn't have/use the counter, then you'd have to download a huge chunk of the log to find it, or trust someone to tell you where it is.

I don't really want the second layer of extensibility, I just don't want to define the format for this object right now / in this document.

Hmm, so purely mechanically, we can't add a field to the overall entry struct like this without updating the certificate format with the accumulated count. Otherwise the verifier cannot reconstruct things.

I can add the counter to MTCProof -- would that fix this?

@bwesterb

Copy link
Copy Markdown
Collaborator

It'd be great to have a mechanism to bind important extensions such as verifiable indices. The present proposal is quite heavy handed though: the counter feels out of place on every MerkleTreeCertEntry and MTCProof.

Few scattershot remarks:

  • Accepting a signatureless certificate confirms the view of the particular CA that issued the certificate between RP and AP for that landmark. That's maybe once a week. More importantly, the AP would like to know about all CAs that could've issued a cert for it.
  • Your proposal seems to presume gossip of arbitrary tree heads, which would need to be curtailed for client privacy. Wouldn't verifiable indices naturally move on a slower cadence like landmarks. (Although let me know if you have something faster in mind.)
  • Gossiping tree heads of landmarks of all CAs is quite a bit of data; certainly if the number of CAs doesn't decrease.
  • The TLS library API boundary which makes it hard to pass gossiped data (although we need to improve that API anyway, so it could be solvable.)
  • A natural place to commit to verifiable index tree heads is in the landmark checkpoint. And for consistency we could add an entry type for them.

Probably just having the AP pull the landmark tree heads from multiple (mirrors of) root programs is simplest. It'd be nice though to have a distributed way to generate a log of all tree heads of all CAs (cf. CTNG broadcast protocol), so we'd have only one tree head to gossip, but it's not obvious at all how to make that work across root programs, and prevent bad behaviour if opening up completely. Perhaps the list is a better place than a PR to discuss this.

@Bren2010

Copy link
Copy Markdown
Contributor Author

Accepting a signatureless certificate confirms the view of the particular CA that issued the certificate between RP and AP for that landmark. That's maybe once a week. More importantly, the AP would like to know about all CAs that could've issued a cert for it.

What goes into an accumulated log entry is TBD

Your proposal seems to presume gossip of arbitrary tree heads, which would need to be curtailed for client privacy. Wouldn't verifiable indices naturally move on a slower cadence like landmarks. (Although let me know if you have something faster in mind.)

I'm only considering the gossip that happens when a server presents a signatureless certificate and the client accepts it. Arbitrary Verifiable Index tree heads may get put in the accumulated log entry, if that's what you mean.

  • Gossiping tree heads of landmarks of all CAs is quite a bit of data; certainly if the number of CAs doesn't decrease.
  • The TLS library API boundary which makes it hard to pass gossiped data (although we need to improve that API anyway, so it could be solvable.)

I'm not proposing that either of these be done

  • A natural place to commit to verifiable index tree heads is in the landmark checkpoint. And for consistency we could add an entry type for them.

I haven't looked into how landmarks are defined yet, but I expect it's just an arbitrary demarcation. Which goes back to "you need a trusted party to tell you what they are", which is a different (weaker) security model than what this provides. With this, there are no trusted third parties. That seems worth it for 8 bytes!

@davidben

Copy link
Copy Markdown
Collaborator

The references to a better security model, etc., here, are hard for me to follow. Ultimately this PR doesn't provide a security improvement in itself, rather some secondary extension points on an already extensible system, with the aim that something not yet defined will improve security.

I'm still quite unclear on this not-yet-defined thing. AIUI, the root issue is that you dismiss the cosigner-based threat model of the, currently orthogonal, vindex work that the transparency.dev community is working on? And so the claim is that this not-yet-defined will somehow provide something stronger, but we haven't written down what this not-yet-defined thing is, or what the other trade-offs will be.

Without any of those details to evaluate, I don't think we can usefully use that not-yet-defined thing to reason about whether this PR makes sense. I suspect there are likely more straightforward schemes here, but there isn't enough information here, and it's probably a much larger discussion than an extension point in a PR. For example:

  • Are you proposing that clients will see binary search and vindex proofs? If yes, this now much, much higher than 8 bytes
  • If no, how does the monitor believe that the append log and the vindex contain the same information? It seems one needs to trust that someone is tailing the log for consistency, at which point it seems much more straightforward schemes are possible. For example, you could just say that all accumulations must be accurate, and you must put one at least one every 1024 entries, or whatever.

Looking at this purely as an extension point, it seems more-or-less redundant with the extension points that already exist.

First, this introduces a second layer of extensibility, AccumulatedType, on top of an already extensible structure, MerkleTreeCertEntryType. If the goal was to make it possible to add new entry types, that wasn't needed.

Now, AccumulatedTypes are special in this PR, in that they contribute to a per-entry count. I am not quite following how you want to use the binary search (see above), or your overall system, but it seems like this wouldn't work? If a log uses multiple AccumulatedTypes, the count would cover all of them, so you'd still have to potentially do a lot of work to find the one that you want, no?

Then there's the problem how to do per-entry extensions. As noted, it needs to be echo'd back into the certificate. Putting it into the MTCProof would solve that mechanically, but it's redundant with a mechanism that already exists: non-critical X.509 extensions. Rather than all this, it seems you could instead just use one of those.

That is entry-type-dependent, so it's a little messy and maybe there's a discussion to be had about how best to structure an individual entry, but my feeling is we should start simple.

Finally keep in mind that, for all changes that involve adding to what a CA does when it constructs a log, there is already a natural extension point: the CA itself. If you change the responsibilities of a CA, you will likely need to spin up a new CA instance and do CA-level migration (e.g. trust anchor negotiation). At that point you can always key a v2 entry format, or a new set of entry types, new client behavior, etc., on that new CA. Indeed that's the very extension point that makes a MTCs, PQC, etc., viable.

@Bren2010

Bren2010 commented Jan 13, 2026

Copy link
Copy Markdown
Contributor Author

The references to a better security model, etc., here, are hard for me to follow. Ultimately this PR doesn't provide a security improvement in itself, rather some secondary extension points on an already extensible system, with the aim that something not yet defined will improve security.

Well, yes, but that's because you wanted monitoring to be a secondary deliverable. So it's not defined here. I'm happy to talk more about the security model I described in my first comment offline if you'd like?

AIUI, the root issue is that you dismiss the cosigner-based threat model of the, currently orthogonal, vindex work that the transparency.dev community is working on?

I'm not dismissing it, but I think it's worth considering the security model of monitoring. What you seem to have in mind is a Verifiable Index system where the cosigners are unrelated / orthogonal to CAs. I'm loath to add more trusted parties to the webPKI when it's so easy to avoid here.

Are you proposing that clients will see binary search and vindex proofs? If yes, this now much, much higher than 8 bytes

It's servers that do the binary search. They would do it as part of monitoring, so it would be offline. Browsers only see the extra 8 bytes.

If no, how does the monitor believe that the append log and the vindex contain the same information? It seems one needs to trust that someone is tailing the log for consistency, at which point it seems much more straightforward schemes are possible. For example, you could just say that all accumulations must be accurate, and you must put one at least one every 1024 entries, or whatever.

Yes, the assumption is already that some anonymous person is/will tail the log and check the vindex for correctness.

The core issue with doing it the way you say is authenticating negative results, i.e. when there are no accumulators. Because this is going in an extension point regardless, the CA can't be assumed to support it! So if you can just tell me "there are no accumulators in this CA, fall back to the collusion-secure system" and I have to trust you or download the whole log to prove you wrong -- that would seem to defeat the point. With a counter approach, if the counter is zero, then you know there are no accumulator log entries.

I think it's also worth pointing out that what you're proposing is just a lot more operationally complicated. Like I mentioned, we'd need some way to convey to servers whether a CA supports this extension or not. But also, you have to commit upfront to this parameter of "every 1024 entries" or something, and accept edge cases where that may be way too frequent or infrequent. The counter approach adjusts nicely to changes in demand.

That is entry-type-dependent, so it's a little messy and maybe there's a discussion to be had about how best to structure an individual entry, but my feeling is we should start simple.

My goal here was of course to keep it very simple. CAs can hardcode the counter to be 0 until they actually support any accumulator types.

I hope this helps the PR make more sense. I think a call with either of you would actually be better than going to the mailing list but let me know :)

@davidben

Copy link
Copy Markdown
Collaborator

Am somewhat swamped right now (there's a reason we said to do these kinds of addons separately :-P), but real quick...

The core issue with doing it the way you say is authenticating negative results, i.e. when there are no accumulators. Because this is going in an extension point regardless, the CA can't be assumed to support it! So if you can just tell me "there are no accumulators in this CA, fall back to the collusion-secure system" and I have to trust you or download the whole log to prove you wrong -- that would seem to defeat the point. With a counter approach, if the counter is zero, then you know there are no accumulator log entries.

I'm confused. Is that the only reason for this? Surely the verifier, as part of configuring all the known CAs and their keys, can simply configure whether the CA has promised to implement this extension or not.

@Bren2010

Copy link
Copy Markdown
Contributor Author

I think this is only true from a client perspective, servers just use whatever gets pushed down from ACME. So a server wouldn't necessarily trust all the CAs that it uses / have trustworthy sources of information about them. A server generally also wouldn't have a list of "all" CAs.

It's not relevant to this PR but building on the above point, I see monitoring working by either having all CAs aggregated into individual vindexes, or there being some kind of verifiable discovery step for all the CAs trusted by a particular client. You wouldn't want it to be the case that the server has to have it's own view of what CAs it thinks Samsung TV accepts, where an inaccurate/out-of-date view causes monitoring misses.

@Bren2010
Bren2010 force-pushed the brendan/accumulated branch from 473bfa2 to 1e5968a Compare April 22, 2026 20:44
@lukevalenta

lukevalenta commented Apr 23, 2026

Copy link
Copy Markdown
Collaborator

A natural place to commit to verifiable index tree heads is in the landmark checkpoint. And for consistency we could add an entry type for them.

Going back to this idea, why doesn't this work? Landmarks are allocated on a strict cadence (one per landmark interval, Section 6.3.2). Every time it allocates a landmark, the CA could insert a landmark log entry (say, just before generating the checkpoint) that commits to vindex tree heads and anything else it likes.

For a server doing monitoring, it can either fetch the landmark sequence from the CA (which requires trusting a third party, as you mention) or it can get the location of a relatively fresh landmark (and corresponding landmark log entry) by inspecting any landmark-relative certificates it holds 1. Then the server can use the gossip mechanism you described to bootstrap trust in the landmark log entries from RPs by presenting the landmark-relative certs in a TLS handshake.

On the negative-results question: the landmark sequence is append-only and monotonically increasing, and any landmark-relative cert the server holds gives a lower bound on landmark freshness (the cert is unexpired, so the landmark it's relative to is within max_cert_lifetime). For vindex monitoring, that's sufficient — the server doesn't need to prove "there is no newer landmark," only that the entry it's looking at is recent enough. A CA that stopped issuing landmark entries or rolled back its landmark sequence would be detectable the same way any other log misbehavior is: by monitors observing the log structure against cosigned checkpoints.

Footnotes

  1. This would require a format change in MTCProof: instead of encoding the start and end indices of a landmark subtree, we'd need to encode the start and end landmark tree sizes (and from those and the leaf index it's easy to go back to the corresponding landmark subtree with find_subtrees, Section 4.5).

@Bren2010

Copy link
Copy Markdown
Contributor Author

There are a few immediate reservations I'd have about that approach:

  • With this PR, if you're able to connect to your website at all, and you're confident for whatever reason that there's no MitM, then you get the bootstrap property. With what you're describing, the connection needs to specifically be authenticated by a landmark-relative cert, which isn't guaranteed. It's a lot more ergonomic to care about "the website is online" vs "the website is serving this specific sub-type of certificate".

  • The security of that approach would seem to come from third-party auditors verifying that a landmark log entry is present at every point where a landmark head is issued. But it's not clear to me that auditors have visibility into which landmark heads have been issued. My understanding so far has been that landmarks are (for the most part) just arbitrary subtrees that browser vendors choose to push down.

  • Like you say, it limits monitoring frequency to be no greater than issuance frequency. But realistically speaking, you would want to know about mis-issuance much faster than you would want to re-issue a valid certificate.

@lukevalenta

Copy link
Copy Markdown
Collaborator

With what you're describing, the connection needs to specifically be authenticated by a landmark-relative cert, which isn't guaranteed.

Oops, yes, I forgot to mention that point. Not sure how serious that limitation would be but good to note. (As a more heavyweight approach, you could insert a "checkpoint log entry" every time the log issues a checkpoint if you want this to work for standalone certs. I'm not advocating for this but just mentioning it as another possible tradeoff.)

One correction on my original post: The server doesn't really need to trust the CA to use a CA-served landmark sequence as an index into the log. If the landmark sequence points to valid landmark log entries, great! Otherwise, the server has to do more work to find a recent landmark log entry.

But it's not clear to me that auditors have visibility into which landmark heads have been issued. My understanding so far has been that landmarks are (for the most part) just arbitrary subtrees that browser vendors choose to push down.

Both those issuing landmark-relative certs and RPs need to agree on the landmark tree sizes. (See section 6.3.1: "Landmarks are agreed-upon tree sizes across the ecosystem for optimizing certificates.") To issue landmark-relative certificates, the CA has to get cosignatures on the landmark subtrees (via /sign-subtree, currently described in Appendix C.2). That would be a fine place to plug in the vindex validation, I think, assuming the log cosigners are the ones doing the vindex auditing.

But realistically speaking, you would want to know about mis-issuance much faster than you would want to re-issue a valid certificate.

Isn't this PR doing the same thing? The server only learns about fresh accumulated_counts (and corresponding vindexes) when it gets a fresh certificate?

@Bren2010

Copy link
Copy Markdown
Contributor Author

If the landmark sequence points to valid landmark log entries, great! Otherwise, the server has to do more work to find a recent landmark log entry.

If by "the server has to do more work", you mean that the server has to process a linear number of certificates, that's not really ideal. The CA is an untrusted party here, it shouldn't be able to force the server to do a prohibitive amount of work to remain secure.

To issue landmark-relative certificates, the CA has to get cosignatures on the landmark subtrees (via /sign-subtree, currently described in Appendix C.2).

In 7.4 the document says "It is not necessary that the cosigners have generated signatures over the specific subtrees, only that they are consistent." So that would need to change to require 1.) cosignatures that indicate an intent to make a landmark, over the specific subtrees, and 2.) have cosigners verify existence of a landmark log entry before signing. And you'd still have the other downsides we've discussed, so this wouldn't be my preference.

Isn't this PR doing the same thing? The server only learns about fresh accumulated_counts (and corresponding vindexes) when it gets a fresh certificate?

No, the server is able to go to the CA (or a mirror) at any time and find a newer accumulated log entry (if one exists). The server uses its certificate to gossip the tree head with browsers, so gossip here is limited to issuance frequency. But if the server is stateful, then any fork will be detected eventually. So while the landmark log entry idea is best-case as fast as re-issuance, the accumulated log entry idea is worst-case (= your chosen CA is malicious) as fast as re-issuance and best-case as fast as your CA will allow (allowing you to detect mis-issuances by other CAs sooner).

@lukevalenta

lukevalenta commented Apr 23, 2026 via email

Copy link
Copy Markdown
Collaborator

@lukevalenta

lukevalenta commented Apr 26, 2026

Copy link
Copy Markdown
Collaborator

One more question: why accumulated_count instead of an accumulated_index? Basically, instead of making the per-entry field be a count that requires binary search to find some entry, it could be an index in the tree pointing directly to the latest entry of interest at the time the log entry is created.

@Bren2010

Bren2010 commented Apr 27, 2026

Copy link
Copy Markdown
Contributor Author

That assumes third-party auditors verify each log entry. The counter approach is secure without assuming third-party auditors. Yes, verifiable indexes require assuming that third-party auditors exist, but that assumption is specific to that application. You can think of other applications where being able to authenticate "most recent" is valuable and where pulling in that assumption isn't otherwise necessary. The prime example being revocation.

Edit: Thinking about it some more, another cool point is secure pruning. In a pruned part of the log, I can keep only the accumulated log entries and the log(n)-sized search path that leads to them. That lets you verify that those were in fact all of the accumulated log entries that were created, even though everything else is deleted.

@lukevalenta

lukevalenta commented Apr 28, 2026

Copy link
Copy Markdown
Collaborator

That assumes third-party auditors verify each log entry. The counter approach is secure without assuming third-party auditors.

Isn't there an attack where the CA writes non-monotonic counter values to the log(n) entries that would be returned to the verifier to trick them into accepting an old accumulated log entry? This would be caught with either a global auditor, like mentioned in Section 5, or might be caught if the verifier keeps state across checks or has other peers doing similar checks, but I don't think the binary search for a verifier in isolation gives security guarantees (or at least, more work is needed to demonstrate that).

@lukevalenta

Copy link
Copy Markdown
Collaborator

One other idea I wanted to explore (not fully thought out yet): put the index of the most recent 'accumulated log entry' in each checkpoint. Mirror cosigners only sign the checkpoint if that pointer is correct (so they take on additional responsibilities). The server can still learn the set of RP-trusted cosigners by serving its standalone certificate in a TLS handshake, and can then request a recent checkpoint cosigned by the same set of cosigners to get an up-to-date vindex root. This probably has different security guarantees than your proposal, but also doesn't require any per-entry state.

@Bren2010

Bren2010 commented Apr 30, 2026

Copy link
Copy Markdown
Contributor Author

This would be caught with either a global auditor, like mentioned in Section 5, or might be caught if the verifier keeps state across checks or has other peers doing similar checks, but I don't think the binary search for a verifier in isolation gives security guarantees (or at least, more work is needed to demonstrate that).

Yes, the expectation is that the verifier retains state. Retaining state will generally just be necessary to detect forks, though it also helps here. The expectation is also that all users are doing the search in a way that maximizes their ability to detect conflicts with each other. The general idea for the algorithm is Section 4 here

One other idea I wanted to explore (not fully thought out yet): put the index of the most recent 'accumulated log entry' in each checkpoint. Mirror cosigners only sign the checkpoint if that pointer is correct (so they take on additional responsibilities).

This would be interesting to consider, but muddles the layers of abstraction between MTC (defining a log entry format) and tlog-mirror (agnostic to log entry contents). You think that muddling is worth avoiding 8 (or 4) bytes?

@mhutchinson

Copy link
Copy Markdown

I wanted to comment on this from the perspective of a log implementer (specifically thinking of horizontally scaled designs like Tessera).

This proposal introduces a strict data dependency between individual leaf contents. Currently, log sequencers can treat leaves as opaque, immutable blobs once they are hashed. There is no ordering or data dependency between leaves; they can be considered completely independently from all other leaves in the log. With this PR, the accumulated_count means a leaf's final hash is dependent on its sequencing order, and the content/type of previous leaves.

In a batched, distributed environment:

  1. Batch Rewriting: If a batch contains one or more accumulator leaves, the sequencer must 'rewrite' the count field for every subsequent leaf in that batch before calculating the Merkle tree. This adds a significant complexity to the critical path
  2. Sequencer Bottlenecks: It effectively forces a 'stop-the-world' or strongly consistent global counter for every single entry, which is difficult to reconcile with high-throughput, horizontally scaled architectures

@Bren2010

Copy link
Copy Markdown
Contributor Author

To put it differently, log operators have 3 options:

  • They can use a sequencer that's aware of the counter and sets it correctly. Yes, this requires a hook for application logic in the sequencer's critical path. But the sequencer is already enforcing a global order so it's not inherently less scalable, it maybe just doesn't align with current design decisions made in Tessera.
  • If the above isn't an option: a log operator can pause new submissions, wait for everything to flush through, increase the counter and sequence an accumulated log entry, then resume submissions. This is less good, but accumulated log entries will likely only be sequenced once per day or less often. So I still wouldn't expect this to affect the overall scalability of the system.
  • Log operators can just not support this extension, which is a valid and secure thing to do, and results in the counter always being 0.

cjpatton added a commit to cjpatton/merkle-tree-certs that referenced this pull request May 18, 2026
Define an extensions field for the MerkleTreeCertEntry structure.
Repeated extensions are disallowed, but unrecognized extensions are
ignored. The extensions are duplicated in the MTCProof.

This change accommodates two previously requested features for MTC:

1. ietf-plants-wg#172: The
   accumulated count for the accumulated log entry type

2. ietf-plants-wg#226: The log
   entry randomizer
cjpatton added a commit to cjpatton/merkle-tree-certs that referenced this pull request May 22, 2026
Define an extensions field for the MerkleTreeCertEntry structure.
Unrecognized extensions are ignored. The extensions are duplicated in
the MTCProof.

This change accommodates two previously requested features for MTC:

1. ietf-plants-wg#172: The
   accumulated count for the accumulated log entry type

2. ietf-plants-wg#226: The log
   entry randomizer
cjpatton added a commit to cjpatton/merkle-tree-certs that referenced this pull request May 22, 2026
Define an extensions field for the MerkleTreeCertEntry structure.
Unrecognized extensions are ignored. The extensions are duplicated in
the MTCProof.

This change accommodates two previously requested features for MTC:

1. ietf-plants-wg#172: The
   accumulated count for the accumulated log entry type

2. ietf-plants-wg#226: The log
   entry randomizer
@Bren2010 Bren2010 closed this May 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants