Two related holes in Issuance Step One.
C' is used before definition. Step one says only "It computes a commitment." It never says of what, or how. You only learn the commitment is Pedersen from step two's check: "The client then checks Cprime = aprime G + bprime H". This crate assumes C' = a'G + b'H on that basis.
The generator H is undefined. That H is a group element — and it collides notationally with H the hash function from the same paragraph of the draft. Nothing says where it comes from. This matters: if $\log_G H$ is knowable, the commitment is not binding and the opening in finalize proves nothing.
What this crate chose: H = hash_to_group("pedersen-H") under DST OR13_EXP_MOLE/h2g/pedersen-H/v1 — nothing-up-my-sleeve, so no party knows the discrete log.
Why this is filed as help wanted rather than settled: the choice is defensible but it is a guess about intent, not a reading of text. A specification could equally derive H from the Anchor's key, fix it as a named constant, or restructure the commitment entirely. I do not know which the authors mean, and the notational collision suggests the draft text itself needs an editorial pass here.
Draft text: https://github.com/Moderation-of-unLinkable-Endorsements/internet-drafts/blob/main/draft-authors-mole-crypto.md
Update — upstream PR #39 (open, unmerged): the generator half is RESOLVED
PR #39 adds:
We use two generators. G is the generator of the group. H is Hash2Curve("IHAT second generator").
That is the same nothing-up-my-sleeve construction this crate guessed, arrived at independently — only the label differs (ours hashes "pedersen-H" under OR13_EXP_MOLE/h2g/pedersen-H/v1). The concern that motivated the help wanted tag — that log_G H might be knowable and the commitment therefore not binding — is answered.
Once PR #39 merges, aligning the profile is a one-line change to the hash input.
What remains open, and why this issue stays open:
-
C' is still never defined. Issuance Step One still says only "It computes a commitment." PR #39 does not touch that sentence. The reader still has to infer C' = a'G + b'H from Step Two's check. Now that both generators are defined two paragraphs earlier, writing the equation is nearly free.
-
The H collision got worse. H is now simultaneously: the hash in e = H(Y, Zhat, T1, T2, C), the second group generator, and adjacent to a SHAKE128 sponge introduced in the same PR. Three things, overlapping notation, one document.
Retitled to reflect that the generator question is settled and only the missing definition remains.
Update — the generator is now the draft's, verbatim
The profile derives the Pedersen second generator as
Hash2Curve("IHAT second generator"), which is the literal definition PR #39 adds.
Previously it hashed our own "pedersen-H" label; the message is now the draft's
string, under our DST (#2), so this half of the issue is closed in the code as well
as upstream.
Still open, and the reason this issue remains: C' is never defined. Issuance
Step One still says only "It computes a commitment", and PR #39 does not touch that
sentence. The profile continues to assume C' = a'G + b'H, inferred from Step Two's
check. With both generators now defined two paragraphs earlier, writing the equation
is nearly free.
Update — resolved, and PR #39 contradicts the reference implementation
ihat-rs defines the Pedersen generator, but not the way PR #39 does.
|
|
| PR #39 |
H = Hash2Curve("IHAT second generator") — one global generator |
ihat-rs |
H = H(endorsement_context) — derived per context |
ihat-rs's own comment on why:
Deriving H from the context (rather than fixing one global H) binds the context
into C structurally, so it acts as public metadata every party commits under.
It is load-bearing, and its wire-format doc says so: "a mismatch makes the Client's
Pedersen check fail at finalize, because H would differ." crypto::exp_ihat now
derives H from the context, and
tests/exp_ihat_profile.rs::context_mismatch_fails_the_pedersen_check asserts the
failure.
A consequence worth noting: the Anchor must therefore receive the
endorsement_context (it appears in SignatureRequest), because it needs it to
compute C'. That is a deliberate, benign disclosure — the context is public epoch
metadata — but it means "the Anchor learns nothing" is not quite the right framing.
The nullifier remains hidden behind Y' = vY, which is the property that matters.
Still open: C' is still never defined in Issuance Step One ("It computes a
commitment"), and PR #39 does not touch that sentence. Keeping this issue open for
that, and for the contradiction above, which upstream should resolve one way or the
other.
Two related holes in Issuance Step One.
C' is used before definition. Step one says only "It computes a commitment." It never says of what, or how. You only learn the commitment is Pedersen from step two's check: "The client then checks Cprime = aprime G + bprime H". This crate assumes
C' = a'G + b'Hon that basis.The generator H is undefined. That$\log_G H$ is knowable, the commitment is not binding and the opening in
His a group element — and it collides notationally withHthe hash function from the same paragraph of the draft. Nothing says where it comes from. This matters: iffinalizeproves nothing.What this crate chose:
H = hash_to_group("pedersen-H")under DSTOR13_EXP_MOLE/h2g/pedersen-H/v1— nothing-up-my-sleeve, so no party knows the discrete log.Why this is filed as
help wantedrather than settled: the choice is defensible but it is a guess about intent, not a reading of text. A specification could equally deriveHfrom the Anchor's key, fix it as a named constant, or restructure the commitment entirely. I do not know which the authors mean, and the notational collision suggests the draft text itself needs an editorial pass here.Draft text: https://github.com/Moderation-of-unLinkable-Endorsements/internet-drafts/blob/main/draft-authors-mole-crypto.md
Update — upstream PR #39 (open, unmerged): the generator half is RESOLVED
PR #39 adds:
That is the same nothing-up-my-sleeve construction this crate guessed, arrived at independently — only the label differs (ours hashes
"pedersen-H"underOR13_EXP_MOLE/h2g/pedersen-H/v1). The concern that motivated thehelp wantedtag — thatlog_G Hmight be knowable and the commitment therefore not binding — is answered.Once PR #39 merges, aligning the profile is a one-line change to the hash input.
What remains open, and why this issue stays open:
C'is still never defined. Issuance Step One still says only "It computes a commitment." PR #39 does not touch that sentence. The reader still has to inferC' = a'G + b'Hfrom Step Two's check. Now that both generators are defined two paragraphs earlier, writing the equation is nearly free.The
Hcollision got worse.His now simultaneously: the hash ine = H(Y, Zhat, T1, T2, C), the second group generator, and adjacent to a SHAKE128 sponge introduced in the same PR. Three things, overlapping notation, one document.Retitled to reflect that the generator question is settled and only the missing definition remains.
Update — the generator is now the draft's, verbatim
The profile derives the Pedersen second generator as
Hash2Curve("IHAT second generator"), which is the literal definition PR #39 adds.Previously it hashed our own
"pedersen-H"label; the message is now the draft'sstring, under our DST (#2), so this half of the issue is closed in the code as well
as upstream.
Still open, and the reason this issue remains:
C'is never defined. IssuanceStep One still says only "It computes a commitment", and PR #39 does not touch that
sentence. The profile continues to assume
C' = a'G + b'H, inferred from Step Two'scheck. With both generators now defined two paragraphs earlier, writing the equation
is nearly free.
Update — resolved, and PR #39 contradicts the reference implementation
ihat-rsdefines the Pedersen generator, but not the way PR #39 does.H = Hash2Curve("IHAT second generator")— one global generatorihat-rsH = H(endorsement_context)— derived per contextihat-rs's own comment on why:It is load-bearing, and its wire-format doc says so: "a mismatch makes the Client's
Pedersen check fail at finalize, because
Hwould differ."crypto::exp_ihatnowderives
Hfrom the context, andtests/exp_ihat_profile.rs::context_mismatch_fails_the_pedersen_checkasserts thefailure.
A consequence worth noting: the Anchor must therefore receive the
endorsement_context(it appears inSignatureRequest), because it needs it tocompute
C'. That is a deliberate, benign disclosure — the context is public epochmetadata — but it means "the Anchor learns nothing" is not quite the right framing.
The nullifier remains hidden behind
Y' = vY, which is the property that matters.Still open:
C'is still never defined in Issuance Step One ("It computes acommitment"), and PR #39 does not touch that sentence. Keeping this issue open for
that, and for the contradiction above, which upstream should resolve one way or the
other.