Skip to content

Instantly share code, notes, and snippets.

@jeffro256
Last active August 25, 2025 19:35
Show Gist options
  • Save jeffro256/12f4fcc001058dd1f3fd7e81d6476deb to your computer and use it in GitHub Desktop.
Save jeffro256/12f4fcc001058dd1f3fd7e81d6476deb to your computer and use it in GitHub Desktop.
Carrot follow-up audit proposal

Carrot follow-up audit

Background

Cyperstack finished their audit of Carrot in November of 2024. Since then, a handful of tweaks were made to Carrot that may be worth reviewing. There were also a couple misunderstadings by Cypherstack on the protocol shown in the review because the lack of spec clarity. It makes the most sense to ask Cypherstack to do the follow-up audit since they are already so familiar with Carrot.

Scope

In a nutshell, the scope is the set of changes in the Carrot specification repository since commit dbb04d91d40b68b2a8b82b895acf762c864b4cbc and revisiting some previous assumptions in the first audit.

Protocol tweaks

  • Change the assignment of the amount commitment blinding factor ka = ScalarDerive("Carrot commitment mask" || ssrctx || enote_type) to ka = ScalarDerive("Carrot commitment mask" || ssrctx || a || Ksj || enote_type) code src
  • Remove the cofactor (8) clearing multiply for the initial X25519 ECDH key exchange ssr. We rely on the fact that we recompute De during the Janus check to mitigate small subgroup attacks. code src
  • Change the assignment of the special Janus anchor anchorsp = SecretDerive("Carrot janus anchor special" || De || input_context || Ko || kv || Ks)[:16] to anchorsp = SecretDerive("Carrot janus anchor special" || De || input_context || Ko || kv)[:16] code src
  • Change the assignment of the ephemeral private key de = ScalarDerive("Carrot sending key normal" || anchornorm || input_context || Ksj || Kvj || pid) to de = ScalarDerive("Carrot sending key normal" || anchornorm || input_context || Ksj || pid) code src
  • Addressing of previous audit comments (commits fe5c8667f7439340798c86fe52a87e7cd6c461fa-aeb450bd1446333d1a8276b8798717f5b1207074)

First audit comments

I also wanted to re-visit some things in Cypherstack's previous audit:

  • There was a misunderstaning about the size of the Carrot view tag. In section "1.3.2 Janus attack" of the audit: "Additionally, the view tag vt has the input context baked into it, so that a third party cannot simply copy values into a new enote, as then the view tag will only match if a hash collision has been found, which we assume occurs with negligible probability due to collision resistance". This is not true because the view tag is only a few bytes; hash collisions should be considered trivially easy. In my view, Janus protection shouldn't rely on the view tag's collision resistance, but since it is listed falesly as a reason for the security of Janus protection, this needs to be rectified.
  • This same bad premise (vt is big enough to have high security against hash collisions) is used in the security argument for burning bug protection.

Deliverable

A new audit document either confirming or rejecting the same security properties hold under A) the protocol changes listed above, and B) the recognition that the computation of the view tag is not secure against hash collisions.

Quote

TBD

I believe that the protocol changes do not affect the security analysis of the existing security arguments, so the existing audit's arguments should more or less apply the same way, it would just be a matter of getting Cypherstack to re-affirm. The view tag assumption has the potential to challenge some of the provided security arguments. So while I don't think that Cypherstack will have an issue writing new arguments after throwing that assumption out, it may take a bit longer to remove those.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment