-
Notifications
You must be signed in to change notification settings - Fork 29
Add domain to secretToScalar #818
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: release/v0.3.0-alpha.1-rc.0
Are you sure you want to change the base?
Changes from all commits
d761131
54a99e4
089f8df
7544633
a9eedb4
ebbed40
c7a24a0
79b11f1
d3fbecf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,6 +34,13 @@ pragma language_version >= 0.23.0; | |
| * scalar. Feeding a raw `persistentHash` output into `ecMulGenerator` would | ||
| * occasionally exceed the Jubjub scalar field order and fault at runtime. | ||
| * | ||
| * @dev Domain separation. `persistentHash<Vector<N, Bytes<32>>>` is NOT | ||
| * domain-separating on its own. Two circuits hashing the same arity and | ||
| * element type share one hash domain, and the hash cannot tell which slot was | ||
| * "meant" as a tag. `secretToScalar` therefore prefixes a fixed constant, and | ||
| * that constant is placed FIRST so no call to `expandRandomness` (whose two | ||
| * slots are both caller-supplied) can reproduce the tuple by ordinary use. | ||
| * | ||
| * @dev TRUST ASSUMPTION — subgroup membership. This is the module's most | ||
| * load-bearing assumption. Every `JubjubPoint` reaching a curve operation is | ||
| * assumed to be in the Jubjub prime-order subgroup, including points supplied by | ||
|
|
@@ -102,11 +109,34 @@ module ElGamal { | |
| * @description Maps a 32-byte secret to a valid Jubjub scalar. See the | ||
| * module-level hash-to-scalar note for why `degradeToTransient` is required. | ||
| * | ||
| * @dev Domain separation here is load-bearing, not cosmetic. This output is | ||
| * the private key protecting every ciphertext held under an account. Public | ||
| * account identifiers elsewhere in the library are derived as | ||
| * `persistentHash([secretKey])` (`Utils.computeAccountId`), and that | ||
|
Comment on lines
+113
to
+115
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: "account identifiers elsewhere in the library" reads library-wide, but only added by claude (dev3-midnight-basic-review) |
||
| * identifier is stored in the clear as a ledger map key. Untagged, this | ||
| * circuit would compute that same hash, so a secret used in both roles would | ||
| * have its encryption key recoverable from a published identifier by applying | ||
| * `degradeToTransient`. The tag makes the two derivations unrelated, so a | ||
| * wallet MAY safely derive its account secret and its encryption secret from | ||
| * common key material. | ||
| * | ||
| * @dev The tag is FIRST, deliberately. `expandRandomness` hashes | ||
| * `[seed, tag]` with both slots caller-supplied, so tagging this circuit as | ||
| * `[secret, tag]` would make `secretToScalar(x)` identical to | ||
| * `expandRandomness(x, <this tag>)` reachable by passing this domain string | ||
| * to the parameter that exists to receive domain strings. Leading with the | ||
| * tag means reproducing this output through `expandRandomness` would require | ||
| * passing the domain constant as the *seed*. Do not normalise the orderings. | ||
| * | ||
| * @param secret - The 32-byte secret to map. | ||
| * @return A Field guaranteed to be a valid Jubjub scalar. | ||
| */ | ||
| export pure circuit secretToScalar(secret: Bytes<32>): Field { | ||
| return degradeToTransient(persistentHash<Vector<1, Bytes<32>>>([secret])); | ||
| return degradeToTransient( | ||
| persistentHash<Vector<2, Bytes<32>>>( | ||
| [pad(32, "ElGamal:secretToScalar"), secret] | ||
|
0xisk marked this conversation as resolved.
|
||
| ) | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -150,6 +150,16 @@ module Utils { | |
| * ## ID Derivation | ||
| * `accountId = persistentHash(secretKey)` | ||
| * | ||
| * @dev The absence of a domain-separation tag is DELIBERATE. This identifier | ||
| * is global by design: the same key material yields the same identity in | ||
| * every module deriving one, so a user who wishes to carry one identity | ||
| * across modules can. Modules wanting a per-deployment, unlinkable identity | ||
| * should not use this circuit. | ||
| * | ||
| * @dev NOT FOR PRIVATE DERIVATION. This returns an identifier, not a secret, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 2. Untagged
|
||
| * and the construction is untagged. A circuit deriving a PRIVATE value from a | ||
| * secret MUST use its own domain-separation tag. | ||
| * | ||
| * @param {Bytes<32>} secretKey - A 32-byte cryptographically secure random value. | ||
| * | ||
| * @returns {Bytes<32>} accountId - The computed account identifier. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
3. Tag position now differs across the library
🔵 followup: this mandates tag-first, while
ShieldedAccessControl.compact:744hashes[value, pad(32, "ShieldedAccessControl:nullifier")]tag-last.Write the rule down once (Utils or a crypto-conventions note) so a module copying SAC's shape for a private derivation does not recreate H-01.
added by claude (dev3-midnight-basic-review)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@andrew-fleming will that be covered here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Out of scope, let's keep the PR focused on addressing the fix. The rule for this implementation is already documented
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, out of scope. Filed as #854.
added by claude (dev3-midnight-basic-review)