-
Notifications
You must be signed in to change notification settings - Fork 0
Add ZK documentation: nullifiers, compressed accounts, and Groth16 guides #10
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: main
Are you sure you want to change the base?
Conversation
WalkthroughAdds a new ZK section and reorganizes Compressed PDAs under Light Token Program; introduces ZK docs, circuits, Solana program snippets (nullifier, merkle-proof), Rust test clients, helper scripts, AI prompt snippets, and updates multiple site navigation targets and vocabulary. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Client
participant Program
participant LightProtocol
User->>Client: provide secret + verification_id
Client->>Client: compute nullifier = Poseidon(vid, secret)
Client->>Client: generate Groth16 proof (nullifier inputs)
Client->>Program: submit create_nullifier(proof, vid, nullifier)
Program->>Program: decompress & verify Groth16 proof
Program->>Program: derive nullifier address from (vid, nullifier)
Program->>LightProtocol: request create_account(derived_address, metadata)
LightProtocol-->>Program: success / failure
Program-->>Client: transaction result
Client-->>User: confirmation / error
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
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.
Actionable comments posted: 16
🤖 Fix all issues with AI agents
In @snippets/ai-prompts/v1-to-v2-migration.md:
- Around line 8-11: The docs have inconsistent dependency versions:
v1-to-v2-migration.md lists light-sdk, light-sdk-types, light-program-test, and
light-client as "0.17" while zk-app.md uses "0.17.1"; update the version strings
so both files use the same exact version (either upgrade the four entries in
v1-to-v2-migration.md to "0.17.1" or downgrade the entries in zk-app.md to
"0.17") and ensure the four dependency names (light-sdk, light-sdk-types,
light-program-test, light-client) are identical across both prompts.
In @snippets/ai-prompts/zk-app.md:
- Around line 66-69: Replace the hardcoded path
"/home/tilo/Workspace/program-examples/zk/" used in the grep commands with a
portable path (e.g., use a repository-relative path like
"./program-examples/zk/" or an environment variable such as
"$REPO_ROOT/program-examples/zk/"); update each grep invocation that searches
for "LightAccountPoseidon", "Groth16Verifier", "derive_address.*nullifier", and
"read_state_merkle_tree_root" to reference the new variable or relative path so
the commands work on other machines and CI.
In @zk/nullifiers.mdx:
- Line 24: Fix the grammatical error in the sentence by adding the missing word:
change "Nullifier accounts cannot be closed without to reclaim rent to ensure
the same amount is not spent twice." to "Nullifier accounts cannot be closed
without reclaiming rent to ensure the same amount is not spent twice." Update
the sentence in the nullifier documentation so it uses "reclaiming" instead of
"to reclaim."
- Around line 14-15: Fix the grammar and clarity of the two bullet points: add a
comma to the first sentence so it reads "The same secret always produces the
same nullifier, and only the owner can compute the correct nullifier." and
rewrite the second sentence to "When you spend or update your state, you derive
a unique nullifier as a 'receipt' from your secret." Update the two bullet
strings accordingly to preserve meaning and readability.
In @zk/overview.mdx:
- Around line 18-27: The Events section contains outdated dates (e.g., the Card
with text "January 12 - February 1, 2025" and the Card titled "Workshop: ZK with
Light Protocol" showing "Wednesday Jan 15 · 12:00pm ET / 5:00pm UTC") and must
be updated or removed; either update those Card components' date strings and
hrefs to reflect current/upcoming events, or remove the entire Events/Card block
if there are no scheduled events, ensuring you edit the Card elements and the
title strings mentioned so the page no longer shows past 2025 dates.
- Line 4: The CI is failing because cspell flags the term "hackathon" as a
spelling error in zk/overview.mdx; open your cspell configuration (e.g., the
project-level cspell.json or package.json cspell.words) and add "hackathon" to
the "words" array so the word is treated as valid, then commit the updated
cspell config.
- Line 84: Correct the typo in the sentence "For you application you must build
a custom circuit, define your constraints, and compile it to generate the
verification key." by changing the first "you" to "your" so it reads "For your
application you must build a custom circuit, define your constraints, and
compile it to generate the verification key."; locate the string in the
zk/overview.mdx content and update that word only to preserve the rest of the
sentence.
- Around line 66-68: Fix the spelling mistakes in the overview text: change
"commited" to "committed" and "cccompanied" to "accompanied" in the bullet list
(the lines describing Merkle tree commitments and zk proof generation). Edit the
sentences in the same paragraph so the corrected words replace the misspelled
ones and run the docs pipeline/linter to confirm CI passes.
- Around line 116-122: The fragment contains a leftover draft block inside the
Step element ("add" followed by bullet items: confidential transfers, shielded
pool, mixer, zk vote, private airdrop claim) that must be removed or replaced
with finished documentation; locate the Step element containing that draft list
and either delete the entire "add" + bullet list or replace it with a completed
paragraph or properly formatted list explaining each feature, ensuring there are
no stray draft markers and the Step tag remains well-formed.
In @zk/toolkits/groth16-solana.mdx:
- Line 4: CI is failing because cspell flags technical terms used in the docs;
open your cspell config (cspell.json or .cspell.json) and add the terms "altbn",
"circom", and "snarkjs" to the top-level "words" array so they are recognized as
valid spellings and the pipeline stops reporting them as errors.
- Around line 36-44: The struct literal for VERIFYINGKEY uses a misspelled field
name vk_gamme_g2; change that field to the correct vk_gamma_g2 to match the
Groth16Verifyingkey definition and other usages (e.g., the field referenced on
line 139). Update the field name in the Groth16Verifyingkey literal
(VERIFYINGKEY) so the key sequence includes vk_gamma_g2 with the same value
currently assigned to vk_gamme_g2.
In @zk/zk-compressed-accounts.mdx:
- Line 14: The anchor link "Find a [full program example at the
end](#full-program-example)" is broken because the actual section heading is
"Full Code Example" (generates #full-code-example); fix it by either updating
the link to point to "#full-code-example" or renaming the heading "Full Code
Example" to "Full Program Example" so the anchor matches, and ensure the link
text and the heading remain consistent (refer to the link string
"full-program-example" and the heading text "Full Code Example").
- Around line 26-34: Update the pinned dependency versions in the TOML block:
change anchor-lang from "0.31.1" to "0.32.0" and replace the git-pinned
groth16-solana with the released crate version "0.2.0" so the dependencies read
anchor-lang = "0.32.0" and groth16-solana = "0.2.0" while leaving light-sdk,
light-hasher, and light-sdk-types unchanged.
In @zk/zk-with-light.mdx:
- Line 1: The file zk/zk-with-light.mdx currently contains the placeholder
header "ADD AFTER WORKSHOP." which must not be merged; either replace that
placeholder with the completed workshop content (fill out the body, headings,
and any TODO sections) or remove the file from the PR/commit so it isn’t
published incomplete—locate the file named zk/zk-with-light.mdx and either
commit the finished markdown content or delete/unstage the file from the branch
before merging.
- Around line 14-18: Two list items are both numbered "3." in the ordered list;
change the second item that starts "3. To spend private state, users..." to "4."
so the sequence reads 1., 2., 3., 4.; update the numbering in zk-with-light.mdx
for the line containing "To spend private state..." and ensure any following
list items (if present) have correct incremental numbering.
🧹 Nitpick comments (5)
zk/zk-compressed-accounts.mdx (5)
9-9: Minor grammar: hyphenate compound adjective."PDA like" should be "PDA-like" when used as a compound adjective before a noun.
Suggested fix
-* For Solana PDA like behavior your compressed account has an address as persistent identifier. +* For Solana PDA-like behavior your compressed account has an address as persistent identifier.
132-141: Code ordering inconsistency:light_cpi_accountsused before definition.Step 5 uses
light_cpi_accounts(line 134), but it's not defined until Step 8 (lines 186-190). Consider either:
- Reordering steps so the CPI accounts setup comes before address derivation
- Adding a note that the full code ordering differs from the step presentation
472-480: Consider replacing.unwrap()with proper error handling in on-chain code.Multiple
.unwrap()calls on cryptographic operations could panic. While panics in Solana programs are treated as errors, explicit error handling with?provides clearer error messages and is more idiomatic.Suggested fix
let merkle_tree_hashed = hashv_to_bn254_field_size_be_const_array::<2>(&[&merkle_tree_pubkey.to_bytes()]) - .unwrap(); + .map_err(|_| ProgramError::InvalidArgument)?; let mut discriminator = [0u8; 32]; discriminator[24..].copy_from_slice(CredentialAccount::LIGHT_DISCRIMINATOR_SLICE); - let issuer_hashed = hashv_to_bn254_field_size_be_const_array::<2>(&[&issuer]).unwrap(); + let issuer_hashed = hashv_to_bn254_field_size_be_const_array::<2>(&[&issuer]) + .map_err(|_| ProgramError::InvalidArgument)?; let account_owner_hashed = - hashv_to_bn254_field_size_be_const_array::<2>(&[&crate::ID.to_bytes()]).unwrap(); + hashv_to_bn254_field_size_be_const_array::<2>(&[&crate::ID.to_bytes()]) + .map_err(|_| ProgramError::InvalidArgument)?;
469-469: Simplify redundant closure.
|e| ProgramError::from(e)can be replaced withProgramError::from.Suggested fix
- .map_err(|e| ProgramError::from(e))?; + .map_err(ProgramError::from)?;
648-671: Clarify bit-width comment for accuracy.The comment states "248 bits" but the implementation stores 31 bytes (248 bits) in a 32-byte array with a leading zero byte. Consider clarifying this in the comment to help readers understand the BN254 field compatibility requirement.
Suggested clarification
#[derive(Debug, Clone)] struct CredentialKeypair { - pub private_key: [u8; 32], // 248 bits + pub private_key: [u8; 32], // 31 bytes (248 bits) with leading zero for BN254 field pub public_key: [u8; 32], // Poseidon hash of private key }
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (18)
compressed-pdas/overview.mdxdocs.jsonhome.mdxlearn/core-concepts/considerations.mdxreferences/migration-v1-to-v2.mdxresources/addresses-and-urls.mdxresources/cli-installation.mdxsnippets/ai-prompts/v1-to-v2-migration.mdsnippets/ai-prompts/zk-app.mdsnippets/overview-tables/zk-examples-table.mdxwelcome.mdxzk/examples.mdxzk/nullifiers.mdxzk/overview.mdxzk/toolkits/groth16-solana.mdxzk/toolkits/overview.mdxzk/zk-compressed-accounts.mdxzk/zk-with-light.mdx
🧰 Additional context used
🪛 GitHub Actions: CI
zk/toolkits/groth16-solana.mdx
[error] 4-4: CSpell: Unknown word 'altbn'.
[error] 12-12: CSpell: Unknown word 'circom'.
[error] 12-12: CSpell: Unknown word 'snarkjs'.
zk/overview.mdx
[error] 4-4: CSpell: Unknown word 'hackathon'.
[error] 66-66: CSpell: Unknown word 'commited' (suggested fix: 'committed').
[error] 68-68: CSpell: Unknown word 'ccompanied'.
🪛 Gitleaks (8.30.0)
zk/toolkits/groth16-solana.mdx
[high] 36-36: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
[high] 135-135: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
🪛 LanguageTool
zk/overview.mdx
[grammar] ~68-~68: Ensure spelling is correct
Context: ... proof to prove knowledge of the secret ccompanied by a unique nullifier. * RPCs index sta...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
zk/zk-compressed-accounts.mdx
[grammar] ~9-~9: Use a hyphen to join words.
Context: ... the state Merkle tree. * For Solana PDA like behavior your compressed account ha...
(QB_NEW_EN_HYPHEN)
🔇 Additional comments (12)
snippets/ai-prompts/v1-to-v2-migration.md (1)
21-21: Clarify the hardcodedSome(0)parameter in the migration guide.The migration replaces
into_new_address_params_packed(seed)withinto_new_address_params_assigned_packed(seed, Some(0)), whereSome(0)appears to be hardcoded. Verify thatSome(0)is the appropriate default for all migration scenarios, or provide guidance on when users should use different values.welcome.mdx (1)
25-31: LGTM!The navigation update to
/compressed-pdas/overviewis consistent with the PR-wide restructuring of Compressed PDAs documentation.resources/cli-installation.mdx (1)
252-258: LGTM!Navigation update aligns with the consolidated Compressed PDAs overview structure.
learn/core-concepts/considerations.mdx (1)
80-86: LGTM!Consistent navigation update to the Compressed PDAs overview page.
resources/addresses-and-urls.mdx (1)
185-191: LGTM!Navigation update is consistent with the other documentation changes in this PR.
home.mdx (1)
189-195: LGTM! Navigation update to/compressed-pdas/overviewis consistent across all documentation files. The target path is properly defined in docs.json and the corresponding overview.mdx file exists.snippets/overview-tables/zk-examples-table.mdx (1)
1-3: LGTM!The table snippet is well-structured with proper Markdown formatting and a clear link to the ZK-ID example.
references/migration-v1-to-v2.mdx (1)
1-21: LGTM!The migration guide is well-structured with clear before/after code examples and the AI migration prompt integration is a useful addition.
zk/nullifiers.mdx (1)
140-503: LGTM!The full code example is comprehensive, well-highlighted, and demonstrates the complete nullifier flow including Groth16 verification, address derivation, and compressed account handling.
docs.json (1)
102-130: LGTM!The navigation structure is well-organized with the new ZK group logically placed under "ZK Compression" tab. All referenced pages exist:
zk/overview.mdx,zk/nullifiers.mdx,zk/zk-compressed-accounts.mdx, andzk/examples.mdx.zk/zk-compressed-accounts.mdx (2)
691-787: LGTM!The test function
test_create_issuer_and_add_credentialis well-structured with clear step-by-step flow and proper assertions validating the issuer creation, credential addition, and ZK verification.
1256-1264: LGTM!Clean navigation card linking to the related nullifier guide.
| light-sdk = { version = "0.17", features = ["anchor", "v2"] } | ||
| light-sdk-types = { version = "0.17", features = ["v2"] } | ||
| light-program-test = { version = "0.17", features = ["v2"] } | ||
| light-client = { version = "0.17", features = ["v2"] } |
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.
🧩 Analysis chain
🏁 Script executed:
# List files in the snippets/ai-prompts directory
find snippets/ai-prompts -type f -name "*.md" 2>/dev/null | head -20Repository: Lightprotocol/docs-v2
Length of output: 136
🏁 Script executed:
# Check the first file - v1-to-v2-migration.md at lines 8-11
if [ -f "snippets/ai-prompts/v1-to-v2-migration.md" ]; then
echo "=== v1-to-v2-migration.md (lines 1-20) ==="
head -20 snippets/ai-prompts/v1-to-v2-migration.md | cat -n
fiRepository: Lightprotocol/docs-v2
Length of output: 1059
🏁 Script executed:
# Check the second file - zk-app.md around lines 108-116
if [ -f "snippets/ai-prompts/zk-app.md" ]; then
echo "=== zk-app.md (lines 100-120) ==="
sed -n '100,120p' snippets/ai-prompts/zk-app.md | cat -n -v
fiRepository: Lightprotocol/docs-v2
Length of output: 1061
Resolve version inconsistency across migration and new project documentation.
The dependencies in v1-to-v2-migration.md specify version 0.17, but in zk-app.md (lines 108-116), the same dependencies use version 0.17.1:
- light-sdk
- light-sdk-types
- light-program-test
- light-client
Update one or both files to use consistent versions across all documentation prompts.
🤖 Prompt for AI Agents
In @snippets/ai-prompts/v1-to-v2-migration.md around lines 8 - 11, The docs have
inconsistent dependency versions: v1-to-v2-migration.md lists light-sdk,
light-sdk-types, light-program-test, and light-client as "0.17" while zk-app.md
uses "0.17.1"; update the version strings so both files use the same exact
version (either upgrade the four entries in v1-to-v2-migration.md to "0.17.1" or
downgrade the entries in zk-app.md to "0.17") and ensure the four dependency
names (light-sdk, light-sdk-types, light-program-test, light-client) are
identical across both prompts.
zk/nullifiers.mdx
Outdated
| * The same secret always produces the same nullifier and only the owner can compute the correct nullifier. | ||
| * When you spend update your state, you derive a unique nullifier as a "receipt" from your secret. |
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.
Fix grammatical error in description.
The sentence structure is unclear.
Proposed fix
- * When you spend update your state, you derive a unique nullifier as a "receipt" from your secret.
+ * When you spend or update your state, you derive a unique nullifier as a "receipt" from your secret. 📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| * The same secret always produces the same nullifier and only the owner can compute the correct nullifier. | |
| * When you spend update your state, you derive a unique nullifier as a "receipt" from your secret. | |
| * The same secret always produces the same nullifier and only the owner can compute the correct nullifier. | |
| * When you spend or update your state, you derive a unique nullifier as a "receipt" from your secret. |
🤖 Prompt for AI Agents
In @zk/nullifiers.mdx around lines 14 - 15, Fix the grammar and clarity of the
two bullet points: add a comma to the first sentence so it reads "The same
secret always produces the same nullifier, and only the owner can compute the
correct nullifier." and rewrite the second sentence to "When you spend or update
your state, you derive a unique nullifier as a 'receipt' from your secret."
Update the two bullet strings accordingly to preserve meaning and readability.
zk/nullifiers.mdx
Outdated
|
|
||
| For nullifiers on Solana, you typically would create a PDA account. | ||
|
|
||
| Nullifier accounts cannot be closed without to reclaim rent to ensure the same amount is not spent twice. |
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.
Fix grammatical error.
Missing word in the sentence.
Proposed fix
-Nullifier accounts cannot be closed without to reclaim rent to ensure the same amount is not spent twice.
+Nullifier accounts cannot be closed to reclaim rent, ensuring the same amount is not spent twice.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| Nullifier accounts cannot be closed without to reclaim rent to ensure the same amount is not spent twice. | |
| Nullifier accounts cannot be closed to reclaim rent, ensuring the same amount is not spent twice. |
🤖 Prompt for AI Agents
In @zk/nullifiers.mdx at line 24, Fix the grammatical error in the sentence by
adding the missing word: change "Nullifier accounts cannot be closed without to
reclaim rent to ensure the same amount is not spent twice." to "Nullifier
accounts cannot be closed without reclaiming rent to ensure the same amount is
not spent twice." Update the sentence in the nullifier documentation so it uses
"reclaiming" instead of "to reclaim."
zk/toolkits/groth16-solana.mdx
Outdated
| pub const VERIFYINGKEY: Groth16Verifyingkey = Groth16Verifyingkey { | ||
| nr_pubinputs: 10, | ||
| vk_alpha_g1: [...], | ||
| vk_beta_g2: [...], | ||
| vk_gamme_g2: [...], | ||
| vk_delta_g2: [...], | ||
| vk_ic: &[...], | ||
| }; | ||
| ``` |
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.
Fix typo: vk_gamme_g2 should be vk_gamma_g2.
Line 40 has a typo that doesn't match the correct field name shown on line 139.
Proposed fix
- vk_gamme_g2: [...],
+ vk_gamma_g2: [...],🧰 Tools
🪛 Gitleaks (8.30.0)
[high] 36-36: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
🤖 Prompt for AI Agents
In @zk/toolkits/groth16-solana.mdx around lines 36 - 44, The struct literal for
VERIFYINGKEY uses a misspelled field name vk_gamme_g2; change that field to the
correct vk_gamma_g2 to match the Groth16Verifyingkey definition and other usages
(e.g., the field referenced on line 139). Update the field name in the
Groth16Verifyingkey literal (VERIFYINGKEY) so the key sequence includes
vk_gamma_g2 with the same value currently assigned to vk_gamme_g2.
zk/compressed-account-zk.mdx
Outdated
| * Nullifiers prevent double-spending by recording spent commitments in an address tree. | ||
|
|
||
| <Info> | ||
| Find a [full program example at the end](#full-program-example) with Rust test, a zk-id implementation with issuer/credential flow. |
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.
Broken anchor link: section heading mismatch.
The anchor #full-program-example won't resolve because the section heading at line 253 is "Full Code Example" (generates #full-code-example).
Suggested fix
-Find a [full program example at the end](#full-program-example) with Rust test, a zk-id implementation with issuer/credential flow.
+Find a [full code example at the end](#full-code-example) with Rust test, a zk-id implementation with issuer/credential flow.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| Find a [full program example at the end](#full-program-example) with Rust test, a zk-id implementation with issuer/credential flow. | |
| Find a [full code example at the end](#full-code-example) with Rust test, a zk-id implementation with issuer/credential flow. |
🤖 Prompt for AI Agents
In @zk/zk-compressed-accounts.mdx at line 14, The anchor link "Find a [full
program example at the end](#full-program-example)" is broken because the actual
section heading is "Full Code Example" (generates #full-code-example); fix it by
either updating the link to point to "#full-code-example" or renaming the
heading "Full Code Example" to "Full Program Example" so the anchor matches, and
ensure the link text and the heading remain consistent (refer to the link string
"full-program-example" and the heading text "Full Code Example").
| ```toml | ||
| [dependencies] | ||
| anchor-lang = "0.31.1" | ||
| borsh = "0.10.4" | ||
| light-sdk = { version = "0.17.1", features = ["anchor", "poseidon", "merkle-tree", "v2"] } | ||
| light-hasher = "5.0.0" | ||
| light-sdk-types = { version = "0.17.1", features = ["v2"] } | ||
| groth16-solana = { git = "https://github.com/Lightprotocol/groth16-solana", rev = "66c0dc87" } | ||
| ``` |
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.
🧩 Analysis chain
🌐 Web query:
latest light-sdk crate version Solana Rust
💡 Result:
The latest light-sdk crate version is 0.17.1 (as of January 12, 2026). [1][2]
Sources:
[1] docs.rs — light-sdk 0.17.1.
[2] lib.rs — light-sdk crate listing.
🌐 Web query:
anchor-lang latest version 2024 2025
💡 Result:
The latest released anchor-lang is v0.32.0 (released Oct 8, 2025). [1][2]
For reference: v0.31.1 was published Apr 20, 2025. [3]
Sources:
- Anchor changelog (v0.32.0 release notes). [1]
- anchor-lang docs.rs page for v0.32.0. [2]
- anchor-lang release listing (v0.31.1). [3]
🌐 Web query:
light-hasher light-sdk-types latest versions Solana
💡 Result:
- light-hasher: 5.0.0. [1]
- light-sdk-types: 0.16.0. [2]
Sources:
[1] docs.rs — light-hasher (latest).
[2] docs.rs — light-sdk-types v0.16.0.
🌐 Web query:
groth16-solana latest version Lightprotocol
💡 Result:
Latest release: groth16-solana v0.2.0 — released June 14, 2025. [1][2]
Sources:
- GitHub releases for Lightprotocol/groth16-solana. [1]
- crate documentation on docs.rs (groth16-solana 0.2.0). [2]
Update anchor-lang to v0.32.0 and groth16-solana to use released version 0.2.0.
The documentation pins anchor-lang = "0.31.1", but v0.32.0 was released on October 8, 2025 and is now the latest version. Update to the current release.
Additionally, groth16-solana is pinned to a git revision instead of the released version. Use groth16-solana = "0.2.0" (released June 14, 2025) instead of the git dependency for better stability and maintainability. The remaining dependencies are current: light-sdk = "0.17.1", light-hasher = "5.0.0", and light-sdk-types = "0.17.1" are all up-to-date.
🤖 Prompt for AI Agents
In @zk/zk-compressed-accounts.mdx around lines 26 - 34, Update the pinned
dependency versions in the TOML block: change anchor-lang from "0.31.1" to
"0.32.0" and replace the git-pinned groth16-solana with the released crate
version "0.2.0" so the dependencies read anchor-lang = "0.32.0" and
groth16-solana = "0.2.0" while leaving light-sdk, light-hasher, and
light-sdk-types unchanged.
zk/nullifiers.mdx
Outdated
| 2. **Prove ownership** -> Show you own state without revealing it (ZK proof) | ||
| 3. **Prevent Double Spending** -> Ensure the same state can't be used twice (nullifier) | ||
| * The same secret always produces the same nullifier and only the owner can compute the correct nullifier. | ||
| * When you spend update your state, you derive a unique nullifier as a "receipt" from your secret. |
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.
| * When you spend update your state, you derive a unique nullifier as a "receipt" from your secret. | |
| * When you use your state, you derive a unique nullifier as a "receipt" from your secret. |
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.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In @zk/compressed-account-zk.mdx:
- Line 11: Update the sentence containing "PDA like behavior" to use the
compound adjective form "PDA-like behavior" so it reads: "For Solana PDA-like
behavior your compressed account has an address as persistent identifier."
Locate the exact phrase "PDA like behavior" in the document and replace it with
"PDA-like behavior" to comply with the style guideline for hyphenation of
compound adjectives.
In @zk/overview.mdx:
- Around line 13-28: The CardGroup contains two static Card entries with
hard-coded past dates/times ("Solana Privacy Hack" and "Workshop: ZK with Light
Protocol"); remove or update these outdated Card components (Card title="Solana
Privacy Hack" and Card title="Workshop: ZK with Light Protocol") so the page
only shows current/upcoming events or switch to a dynamic source; either delete
the two Card nodes, replace their date strings with current event dates/times,
or refactor to fetch and render events programmatically instead of hard-coding
past dates.
- Line 86: Fix the typo in the sentence "For you application you must build a
custom circuit, define your constraints, and compile it to generate the
verification key." by changing "you" to "your" so it reads "For your application
you must build a custom circuit, define your constraints, and compile it to
generate the verification key."
- Around line 117-122: Remove the draft placeholder bullet list ("confidential
transfers", "shielded pool", "mixer", "zk vote", "private airdrop claim") from
the document or replace it with a proper "Coming Soon" section; specifically
locate the bulleted lines added in the diff and either delete them or replace
them with a short heading like "Coming Soon" and a one-sentence explanation
indicating these topics will be added later.
🧹 Nitpick comments (2)
zk/compressed-account-zk.mdx (2)
86-86: Typo: "Derive" should be lowercase or phrased as instruction.Minor wording inconsistency - consider rephrasing for clarity.
Suggested fix
-* Derive `LightHasher` for Poseidon hashing (instead of default SHA-256). +* Use `LightHasher` derive macro for Poseidon hashing (instead of default SHA-256).
484-486: Consider using?instead of.unwrap()for consistency.The surrounding code uses proper error handling with
map_err, but line 486 uses.unwrap()which could panic. For consistency with the error handling pattern used elsewhere in the function, consider propagating the error.Suggested fix
let merkle_tree_hashed = hashv_to_bn254_field_size_be_const_array::<2>(&[&merkle_tree_pubkey.to_bytes()]) - .unwrap(); + .map_err(|_| ProgramError::InvalidAccountData)?;
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (17)
compressed-pdas/overview.mdxcspell.jsondocs.jsonhome.mdxlearn/core-concepts/considerations.mdxreferences/migration-v1-to-v2.mdxresources/addresses-and-urls.mdxresources/cli-installation.mdxsnippets/ai-prompts/v1-to-v2-migration.mdxsnippets/ai-prompts/zk-app.mdxsnippets/overview-tables/zk-examples-table.mdxwelcome.mdxzk/compressed-account-zk.mdxzk/examples.mdxzk/nullifiers.mdxzk/overview.mdxzk/zk-with-light.mdx
✅ Files skipped from review due to trivial changes (5)
- snippets/overview-tables/zk-examples-table.mdx
- snippets/ai-prompts/zk-app.mdx
- cspell.json
- snippets/ai-prompts/v1-to-v2-migration.mdx
- zk/zk-with-light.mdx
🚧 Files skipped from review as they are similar to previous changes (6)
- resources/cli-installation.mdx
- learn/core-concepts/considerations.mdx
- resources/addresses-and-urls.mdx
- zk/examples.mdx
- zk/nullifiers.mdx
- references/migration-v1-to-v2.mdx
🧰 Additional context used
🪛 LanguageTool
zk/compressed-account-zk.mdx
[grammar] ~11-~11: Use a hyphen to join words.
Context: ... the state Merkle tree. * For Solana PDA like behavior your compressed account ha...
(QB_NEW_EN_HYPHEN)
🔇 Additional comments (6)
home.mdx (1)
192-192: LGTM!The link update to
/compressed-pdas/overviewis consistent with the navigation restructuring indocs.json.welcome.mdx (1)
27-27: LGTM!Link update is consistent with the navigation restructuring across the documentation.
docs.json (2)
102-130: LGTM!The new ZK and Compressed PDAs navigation groups are well-structured. The nested Program Guides under Compressed PDAs provides good organization for the how-to documentation.
252-252: LGTM!The migration reference page addition is appropriate for the References section.
zk/compressed-account-zk.mdx (1)
274-630: Comprehensive example code - well documented.The full program example demonstrates the complete flow including issuer management, credential issuance, and ZK verification. The code is well-structured with clear separation of concerns.
zk/overview.mdx (1)
30-106: Infrastructure section is well-structured.The tabbed approach with Overview and AI assistance is user-friendly. The step-by-step breakdown of nullifiers, state trees, and Groth16 verification provides a clear learning path.
zk/overview.mdx
Outdated
| <CardGroup cols={2}> | ||
| <Card | ||
| title="Solana Privacy Hack" | ||
| icon="arrow-up-right-from-square" | ||
| href="https://solana.com/privacyhack" | ||
| > | ||
| January 12 - February 1, 2025 | ||
| </Card> | ||
| <Card | ||
| title="Workshop: ZK with Light Protocol" | ||
| icon="x-twitter" | ||
| href="https://x.com/solana_devs" | ||
| > | ||
| Wednesday Jan 15 · 12:00pm ET / 5:00pm UTC | ||
| </Card> | ||
| </CardGroup> |
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.
Outdated event dates - these events have passed.
The "Solana Privacy Hack" (January 12 - February 1, 2025) and the workshop (Wednesday Jan 15) are from 2025 and have already occurred. Consider removing these outdated events or replacing with current/upcoming events.
🤖 Prompt for AI Agents
In @zk/overview.mdx around lines 13 - 28, The CardGroup contains two static Card
entries with hard-coded past dates/times ("Solana Privacy Hack" and "Workshop:
ZK with Light Protocol"); remove or update these outdated Card components (Card
title="Solana Privacy Hack" and Card title="Workshop: ZK with Light Protocol")
so the page only shows current/upcoming events or switch to a dynamic source;
either delete the two Card nodes, replace their date strings with current event
dates/times, or refactor to fetch and render events programmatically instead of
hard-coding past dates.
zk/overview.mdx
Outdated
| add | ||
| * confidential transfers | ||
| * shielded pool | ||
| * mixer | ||
| * zk vote | ||
| * private airdrop claim |
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.
Draft content appears to be left in the document.
This section appears to be placeholder/TODO content that shouldn't be published. Either remove it or convert to a proper "Coming Soon" format.
Suggested fix - either remove or format properly
Option 1 - Remove entirely:
<ZkExamplesTable />
-
-add
-* confidential transfers
-* shielded pool
-* mixer
-* zk vote
-* private airdrop claim
-
## Reach outOption 2 - Format as "Coming Soon":
<ZkExamplesTable />
-add
-* confidential transfers
-* shielded pool
-* mixer
-* zk vote
-* private airdrop claim
+### Coming Soon
+
+- Confidential transfers
+- Shielded pool
+- Mixer
+- ZK vote
+- Private airdrop claim
## Reach out📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| add | |
| * confidential transfers | |
| * shielded pool | |
| * mixer | |
| * zk vote | |
| * private airdrop claim | |
| <ZkExamplesTable /> | |
| ## Reach out |
| add | |
| * confidential transfers | |
| * shielded pool | |
| * mixer | |
| * zk vote | |
| * private airdrop claim | |
| <ZkExamplesTable /> | |
| ### Coming Soon | |
| - Confidential transfers | |
| - Shielded pool | |
| - Mixer | |
| - ZK vote | |
| - Private airdrop claim | |
| ## Reach out |
🤖 Prompt for AI Agents
In @zk/overview.mdx around lines 117 - 122, Remove the draft placeholder bullet
list ("confidential transfers", "shielded pool", "mixer", "zk vote", "private
airdrop claim") from the document or replace it with a proper "Coming Soon"
section; specifically locate the bulleted lines added in the diff and either
delete them or replace them with a short heading like "Coming Soon" and a
one-sentence explanation indicating these topics will be added later.
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.
Actionable comments posted: 6
🤖 Fix all issues with AI agents
In @docs.json:
- Around line 111-130: The "Compressed PDAs" group in docs.json currently
references "client-library/client-guide" which breaks the group's
"compressed-pdas/" prefix convention; either move/rename the source file to
compressed-pdas/client-guide.mdx and update the entry in docs.json to
"compressed-pdas/client-guide", or if the file must remain under client-library,
explicitly document the exception and replace the docs.json entry with a brief
comment or an alternate group that explains why "client-library/client-guide" is
shared; locate the docs.json entry for the "Compressed PDAs" group and update
the referenced string accordingly and/or move the file and adjust any
imports/metadata to match the new path.
In @zk/overview.mdx:
- Around line 33-35: Add the proper-cased term "Zcash" to the project's
spellcheck dictionary (in addition to the existing "zcash") so CSpell no longer
flags instances like the "Zcash" token in the Accordion title and the "Zcash
stores private state..." sentence; update the spelling config (e.g., cspell.json
or the repository's custom dictionary file) by adding "Zcash" as an allowed word
and commit the change.
- Line 100: Update the typo in the sentence containing "you application" in
zk/overview.mdx by replacing "you application" with "your application" so the
sentence reads "For your application you must build a custom circuit, define
your constraints, and compile it to generate the verification key."; locate the
sentence by searching for the exact phrase "you application" or the surrounding
text "build a custom circuit, define your constraints" and make the
substitution.
- Line 5: CI is failing because "zcash" isn't recognized by CSpell; either add
"zcash" and "Zcash" to the project's cspell word list (e.g., add them to
cspell.json / .cspell.json "words" array) or add an inline CSpell ignore comment
in zk/overview.mdx on the keywords line to suppress the spellcheck error; update
the repository's cspell configuration for a permanent fix or use the inline
ignore for a local exception.
In @zk/zk-with-light.mdx:
- Line 1: Remove the placeholder text "ADD AFTER WORKSHOP." at the top of the
document: either delete it if no follow-up content is needed or replace it with
the intended workshop content or a clear TODO comment that includes owner and
ETA; ensure the final file contains no unresolved internal notes before merging.
- Around line 14-17: The ordered list in zk-with-light.mdx has duplicate "3."
entries; update the second "3." ("To spend private state...") to "4." (or
convert the list to automatic Markdown numbering) so the list numbers are
sequential and unique.
🧹 Nitpick comments (5)
snippets/ai-prompts/v1-to-v2-migration.mdx (1)
77-99: Consider adding a retry limit to prevent infinite loops.The "NEVER GIVE UP" directive with unlimited debugger spawning could cause AI agents to enter infinite retry loops on genuinely unfixable issues (e.g., incompatible dependencies, missing features). Consider adding a maximum retry count or escalation path.
💡 Suggested improvement
**Loop rules:** 1. Each debugger gets fresh context + previous debug reports 2. Each attempt tries something DIFFERENT -3. **NEVER GIVE UP** - keep spawning until fixed +3. Retry up to 5 times with different approaches +4. If still failing after 5 attempts, summarize blockers and ask user for guidance Do NOT proceed until all tests pass.zk/compressed-account-zk.mdx (2)
11-11: Add hyphen to compound adjective.Per static analysis hint, "PDA like behavior" should use a hyphen for the compound adjective.
Suggested fix
-* For Solana PDA like behavior your compressed account has an address as persistent identifier. +* For Solana PDA-like behavior, your compressed account has an address as persistent identifier.
212-212: Fix subject-verb agreement.The sentence has a grammatical issue with "and verifies" - should be parallel structure.
Suggested fix
-A minimal Solana program to create compressed accounts and verifies with Groth16 proofs. +A minimal Solana program that creates compressed accounts and verifies Groth16 proofs.zk/nullifiers.mdx (1)
8-10: Remove redundant separator and fix style.The horizontal rule on line 8 appears redundant after the frontmatter. Also, per static analysis, "can not" should be "cannot" for standard usage.
Suggested fix
--- ---- - -1. The required property for nullifiers is that they can not be created twice. +1. The required property for nullifiers is that they cannot be created twice.zk/overview.mdx (1)
55-55: Use "cannot" instead of "can not".Per static analysis and standard usage, "cannot" is preferred over "can not" unless emphasis is intended.
Suggested fix
-The required property for nullifiers is that they can not be created twice. +The required property for nullifiers is that they cannot be created twice.
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (17)
compressed-pdas/overview.mdxcspell.jsondocs.jsonhome.mdxlearn/core-concepts/considerations.mdxreferences/migration-v1-to-v2.mdxresources/addresses-and-urls.mdxresources/cli-installation.mdxsnippets/ai-prompts/v1-to-v2-migration.mdxsnippets/ai-prompts/zk-app.mdxsnippets/overview-tables/zk-examples-table.mdxwelcome.mdxzk/compressed-account-zk.mdxzk/examples.mdxzk/nullifiers.mdxzk/overview.mdxzk/zk-with-light.mdx
✅ Files skipped from review due to trivial changes (2)
- snippets/overview-tables/zk-examples-table.mdx
- home.mdx
🚧 Files skipped from review as they are similar to previous changes (5)
- cspell.json
- learn/core-concepts/considerations.mdx
- welcome.mdx
- zk/examples.mdx
- snippets/ai-prompts/zk-app.mdx
🧰 Additional context used
🪛 GitHub Actions: CI
zk/overview.mdx
[error] 5-5: Spellcheck failed: Unknown word 'zcash' (CSpell)
[error] 33-33: Spellcheck failed: Unknown word 'Zcash' (CSpell)
[error] 35-35: Spellcheck failed: Unknown word 'Zcash' (CSpell)
🪛 LanguageTool
zk/nullifiers.mdx
[style] ~10-~10: Unless you want to emphasize “not”, use “cannot” which is more common.
Context: ...ed property for nullifiers is that they can not be created twice. 2. On Solana, you ty...
(CAN_NOT_PREMIUM)
zk/overview.mdx
[style] ~55-~55: Unless you want to emphasize “not”, use “cannot” which is more common.
Context: ...ed property for nullifiers is that they can not be created twice. Light uses rent-free...
(CAN_NOT_PREMIUM)
zk/compressed-account-zk.mdx
[grammar] ~11-~11: Use a hyphen to join words.
Context: ... the state Merkle tree. * For Solana PDA like behavior your compressed account ha...
(QB_NEW_EN_HYPHEN)
🔇 Additional comments (14)
resources/cli-installation.mdx (1)
252-258: LGTM!The navigation link update to
/compressed-pdas/overviewis consistent with the broader navigation restructuring in this PR, aligning with the new Compressed PDAs group structure defined indocs.json.resources/addresses-and-urls.mdx (1)
185-191: LGTM!Navigation link update is consistent with other files in this PR.
docs.json (2)
102-110: LGTM!The new ZK navigation group is well-structured with a logical progression from overview to specific topics (nullifiers, compressed accounts) and examples.
248-255: LGTM!The
migration-v1-to-v2page is correctly added to the References group, complementing the new AI prompt snippet and updated migration guide content.snippets/ai-prompts/v1-to-v2-migration.mdx (2)
1-5: LGTM!The frontmatter properly defines the prompt's purpose and available tools for AI agents.
20-23: Verify the documentation URL matches the deployed path.The migration guide URL
https://zkcompression.com/references/migration-v1-to-v2should match the path defined indocs.json(references/migration-v1-to-v2). Ensure the deployed docs site uses this exact path structure.references/migration-v1-to-v2.mdx (2)
7-7: LGTM!The import statement correctly references the new AI prompt snippet using the absolute path convention for Mintlify docs.
254-259: LGTM!The AI Prompt tab is well-integrated alongside the existing SDK tabs, providing users with an automated migration workflow option. The component usage follows the established pattern in this file.
zk/compressed-account-zk.mdx (2)
219-390: LGTM!The program example is well-structured with proper Anchor account definitions, Groth16 verification flow, and Light SDK integration for compressed accounts.
392-716: LGTM!The client test code provides a comprehensive example of the full workflow including witness generation, proof creation, local verification, and on-chain verification setup.
zk/nullifiers.mdx (3)
24-126: LGTM!The implementation guide provides a clear step-by-step flow with appropriate code snippets demonstrating nullifier computation, ZK circuit constraints, on-chain address derivation, and the complete nullifier lifecycle.
137-369: LGTM!The program correctly implements both single and batch nullifier creation with proper Groth16 verification, address tree validation, and compressed account creation via Light SDK.
371-845: LGTM!The test examples comprehensively demonstrate both single and batch nullifier workflows, including duplicate detection verification. The CU simulation output is helpful for understanding on-chain costs.
zk/overview.mdx (1)
131-144: Event dates appear to be in the past.The "Solana Privacy Hack" is listed as "January 12 - February 1, 2025" and the workshop as "Wednesday Jan 15". Since the current date is January 2026, these events have already occurred. Consider updating with current events or removing this section.
| { | ||
| "group": "Compressed PDAs", | ||
| "pages": [ | ||
| "compressed-pdas/overview", | ||
| { | ||
| "group": "Program Guides", | ||
| "pages": [ | ||
| "compressed-pdas/guides", | ||
| "compressed-pdas/guides/how-to-create-compressed-accounts", | ||
| "compressed-pdas/guides/how-to-update-compressed-accounts", | ||
| "compressed-pdas/guides/how-to-close-compressed-accounts", | ||
| "compressed-pdas/guides/how-to-reinitialize-compressed-accounts", | ||
| "compressed-pdas/guides/how-to-burn-compressed-accounts" | ||
| ] | ||
| }, | ||
| "compressed-pdas/program-examples", | ||
| "client-library/client-guide", | ||
| "compressed-pdas/solana-attestation-service" | ||
| ] | ||
| }, |
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.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify the client-library/client-guide path exists
fd -t f "client-guide" --extension mdx --extension md
# Check if there's also a compressed-pdas version
fd -t f -p "compressed-pdas.*client" --extension mdx --extension md
# Also check the overall structure
find . -type d -name "client-library" 2>/dev/null
find . -type d -name "compressed-pdas" 2>/dev/null | head -20Repository: Lightprotocol/docs-v2
Length of output: 131
🏁 Script executed:
#!/bin/bash
# Check the full docs.json structure around the Compressed PDAs section
cat -n docs.json | sed -n '100,150p'
# Search for all occurrences of client-library in docs.json
rg "client-library" docs.json -n
# Also check the overall structure to see if client-library appears in other groups
rg '"group"' docs.json -A 15 | head -100Repository: Lightprotocol/docs-v2
Length of output: 5712
🏁 Script executed:
#!/bin/bash
# Check if client-library directory contains content and what it covers
ls -la client-library/ 2>/dev/null || echo "Directory listing failed"
# Check the content of client-guide to understand its scope
head -50 client-library/client-guide.mdx 2>/dev/null || echo "File read failed"
# Check if there are any references in the codebase to justify this placement
rg "client-guide" . --type md --type mdx -B 2 -A 2 | head -50Repository: Lightprotocol/docs-v2
Length of output: 2695
Move or rename the client guide to match the Compressed PDAs path pattern.
The file client-library/client-guide is documented as a Compressed PDAs client guide (based on its metadata and content describing "compressed pda client"), but it breaks the consistent compressed-pdas/ prefix pattern used throughout the group. Either move the file to compressed-pdas/client-guide.mdx and update the reference in docs.json, or clarify if this shared content should remain in client-library/ with explicit documentation of why it's an exception to the group's naming convention.
🤖 Prompt for AI Agents
In @docs.json around lines 111 - 130, The "Compressed PDAs" group in docs.json
currently references "client-library/client-guide" which breaks the group's
"compressed-pdas/" prefix convention; either move/rename the source file to
compressed-pdas/client-guide.mdx and update the entry in docs.json to
"compressed-pdas/client-guide", or if the file must remain under client-library,
explicitly document the exception and replace the docs.json entry with a brief
comment or an alternate group that explains why "client-library/client-guide" is
shared; locate the docs.json entry for the "Compressed PDAs" group and update
the referenced string accordingly and/or move the file and adjust any
imports/metadata to match the new path.
zk/overview.mdx
Outdated
| <Accordion title="Example: Zcash UTXO's (Unspent Transaction Outputs)"> | ||
|
|
||
| Zcash stores private state as "notes", which are UTXOs (Unspent Transaction Outputs). |
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.
Add "Zcash" to spellcheck dictionary.
Lines 33 and 35 use "Zcash" which is also flagged by CSpell. This should be added to the dictionary alongside "zcash".
🧰 Tools
🪛 GitHub Actions: CI
[error] 33-33: Spellcheck failed: Unknown word 'Zcash' (CSpell)
[error] 35-35: Spellcheck failed: Unknown word 'Zcash' (CSpell)
🤖 Prompt for AI Agents
In @zk/overview.mdx around lines 33 - 35, Add the proper-cased term "Zcash" to
the project's spellcheck dictionary (in addition to the existing "zcash") so
CSpell no longer flags instances like the "Zcash" token in the Accordion title
and the "Zcash stores private state..." sentence; update the spelling config
(e.g., cspell.json or the repository's custom dictionary file) by adding "Zcash"
as an allowed word and commit the change.
zk/overview.mdx
Outdated
|
|
||
| ## Groth16 for on-chain ZK proof verification | ||
|
|
||
| For you application you must build a custom circuit, define your constraints, and compile it to generate the verification key. |
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.
Fix typo: "you application" → "your application".
Suggested fix
-For you application you must build a custom circuit, define your constraints, and compile it to generate the verification key.
+For your application you must build a custom circuit, define your constraints, and compile it to generate the verification key.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| For you application you must build a custom circuit, define your constraints, and compile it to generate the verification key. | |
| For your application you must build a custom circuit, define your constraints, and compile it to generate the verification key. |
🤖 Prompt for AI Agents
In @zk/overview.mdx at line 100, Update the typo in the sentence containing "you
application" in zk/overview.mdx by replacing "you application" with "your
application" so the sentence reads "For your application you must build a custom
circuit, define your constraints, and compile it to generate the verification
key."; locate the sentence by searching for the exact phrase "you application"
or the surrounding text "build a custom circuit, define your constraints" and
make the substitution.
| @@ -0,0 +1,26 @@ | |||
| ADD AFTER WORKSHOP. | |||
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.
Remove or address TODO placeholder.
The file begins with "ADD AFTER WORKSHOP." which appears to be an internal note that should be removed before merging, or the content should be added as indicated.
🤖 Prompt for AI Agents
In @zk/zk-with-light.mdx at line 1, Remove the placeholder text "ADD AFTER
WORKSHOP." at the top of the document: either delete it if no follow-up content
is needed or replace it with the intended workshop content or a clear TODO
comment that includes owner and ETA; ensure the final file contains no
unresolved internal notes before merging.
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.
Actionable comments posted: 13
🤖 Fix all issues with AI agents
In @scripts/copy-zk-merkle-proof.sh:
- Around line 6-7: Replace the hardcoded absolute paths stored in
PROGRAM_EXAMPLES and SNIPPETS_DIR with values derived from either environment
variables (e.g., respect PROGRAM_EXAMPLES and SNIPPETS_DIR if provided) or
computed relative paths based on the script location (use the script directory
via dirname "$0" to build defaults); then add validation checks that both
PROGRAM_EXAMPLES and SNIPPETS_DIR exist as directories and, if not, print an
error to stderr and exit with a non-zero status. Ensure you update the
assignments for PROGRAM_EXAMPLES and SNIPPETS_DIR and add the
directory-existence checks immediately after those assignments so failures are
detected early.
In @scripts/copy-zk-nullifier.sh:
- Around line 5-6: Replace the hardcoded absolute paths assigned to
PROGRAM_EXAMPLES and SNIPPETS_DIR with portable alternatives: read their values
from environment variables (e.g., use PROGRAM_EXAMPLES and SNIPPETS_DIR if set)
and otherwise construct sensible relative defaults based on the script location
(using the script directory as the base) so contributors can run the script from
different workspaces; update the assignments for PROGRAM_EXAMPLES and
SNIPPETS_DIR accordingly and ensure downstream uses of those variables remain
unchanged.
In @snippets/ai-prompts/zk-app.mdx:
- Line 109: Replace the git dependency pin for groth16-solana that currently
uses a specific commit rev ("66c0dc87") with a tagged release reference; locate
the dependency entry named groth16-solana and change its rev field to the
appropriate tag (e.g., v0.2.0) or switch to using a tag-based git ref so the
project depends on a released version rather than a single commit for better
stability and reproducibility.
In @snippets/code-snippets/zk/merkle-proof/circuit.mdx:
- Around line 81-83: The main component instantiation references
CompressedAccountMerkleProof(26) but the template is actually named
CompressedCompressedAccountMerkleProof; update either the template name or the
component instantiation so they match (e.g., rename the template to
CompressedAccountMerkleProof or change the component to use
CompressedCompressedAccountMerkleProof) to resolve the Circom compilation error,
ensuring references to main, CompressedAccountMerkleProof, and
CompressedCompressedAccountMerkleProof are consistent.
In @zk/compressed-account-zk.mdx:
- Around line 128-136: The code calls
address_tree_info.get_tree_pubkey(&light_cpi_accounts) and derive_address(...)
before light_cpi_accounts is constructed (CpiAccounts::new), causing an ordering
dependency; move the CpiAccounts::new(...) that creates light_cpi_accounts (Step
8) to occur before the call to address_tree_info.get_tree_pubkey and
derive_address (so address_tree_pubkey, address, and address_seed are derived
after light_cpi_accounts exists), or explicitly document the dependency in the
steps if you intentionally keep the current order.
- Line 14: Change the compound adjective "PDA like behavior" to the hyphenated
form "PDA-like behavior" in the sentence that begins "For Solana PDA like
behavior your compressed account..." so the phrase reads "For Solana PDA-like
behavior your compressed account has an address as persistent identifier."
In @zk/nullifiers.mdx:
- Line 14: Fix the grammar in the sentence by replacing "can not" with the
correct single-word form "cannot" in the nullifiers description (update the text
that currently reads "can not be created twice" to "cannot be created twice").
In @zk/overview.mdx:
- Line 5: CI is failing due to unknown words "zcash" and "Zcash" in
zk/overview.mdx; add both spellings to the project's cspell dictionary (e.g.,
add "zcash" and "Zcash" to .cspell.json words array) or add an inline cspell
ignore directive around the keywords line (the keywords: [...] entry in
overview.mdx) so the spell checker accepts these terms.
- Line 18: Replace the incorrect plural "RPC's" with the correct plural "RPCs"
in the sentence referencing Merkle trees maintained by Light Protocol; update
the text in the overview content (the sentence that currently reads "The Merkle
trees referenced are maintained by Light Protocol and are indexed by RPC's.") to
"RPCs" to remove the apostrophe used incorrectly for a plural.
- Line 14: The bullet "use nullifiers on Solana prevent double spending," is
missing the word "to"; update the sentence to "use nullifiers on Solana to
prevent double spending" (and remove the trailing comma if not needed) so the
grammar reads correctly.
- Around line 94-109: The event cards in the CardGroup currently show outdated
January 2025 events; update or remove them by editing the CardGroup/ Card
components (titles "Solana Privacy Hack" and "Workshop: ZK with Light Protocol")
to either replace dates/details with current events or remove those Card nodes
entirely; if replacing, ensure href, title, icon, and child content reflect the
new event metadata and timing, and if removing, delete the corresponding <Card
...>...</Card> blocks so the section no longer displays past events.
In @zk/zk-with-light.mdx:
- Around line 1-2: The file contains a leftover placeholder "ADD AFTER
WORKSHOP."—remove that placeholder or replace it with the finalized workshop
content in zk-with-light.mdx; ensure the placeholder line is deleted or
substituted with the completed text, update any related links/TOC if needed, and
commit the change before merging.
- Around line 14-17: The ordered list has a duplicate "3." numbering; update the
second occurrence (the list item starting "To spend private state, users
generate a zero-knowledge proof to prove knowledge of the secret") to "4." so
the sequence becomes 1., 2., 3., 4., ensuring the list numbering is correct.
🧹 Nitpick comments (7)
scripts/copy-zk-merkle-proof.sh (1)
21-34: Consider adding feedback when source files are missing.The conditional checks silently skip missing files. Consider adding else clauses to warn when expected source files are not found, which aids debugging.
💡 Optional: Add warnings for missing files
# Circuit if [ -f "$PROGRAM_EXAMPLES/circuits/merkle_proof.circom" ]; then wrap_code "$PROGRAM_EXAMPLES/circuits/merkle_proof.circom" "$SNIPPETS_DIR/circuit.mdx" "circom expandable" +else + echo "Warning: Circuit file not found: $PROGRAM_EXAMPLES/circuits/merkle_proof.circom" fi # Program if [ -f "$PROGRAM_EXAMPLES/src/lib.rs" ]; then wrap_code "$PROGRAM_EXAMPLES/src/lib.rs" "$SNIPPETS_DIR/program.mdx" "rust expandable" +else + echo "Warning: Program file not found: $PROGRAM_EXAMPLES/src/lib.rs" fi # Rust client if [ -f "$PROGRAM_EXAMPLES/tests/test.rs" ]; then wrap_code "$PROGRAM_EXAMPLES/tests/test.rs" "$SNIPPETS_DIR/rust-client.mdx" "rust expandable" +else + echo "Warning: Test file not found: $PROGRAM_EXAMPLES/tests/test.rs" fisnippets/code-snippets/zk/nullifier/rust-client-batch.mdx (1)
36-48: Consider: Hardcoded array initialization tightly couples to BATCH_SIZE.The secrets and nullifiers arrays are manually initialized with 4 elements rather than deriving from
BATCH_SIZE. While acceptable for documentation examples, note that changingBATCH_SIZEwould require manual updates here:// Currently hardcoded to 4 elements let secrets: [[u8; 32]; BATCH_SIZE] = [ generate_random_secret(), generate_random_secret(), generate_random_secret(), generate_random_secret(), ];For production code, consider using
std::array::from_fnor similar patterns for flexibility.snippets/code-snippets/zk/merkle-proof/circuit.mdx (2)
49-49: Document the magic number for domain separation.The value
36893488147419103232(which equals2^65) is used for domain separation but lacks explanation. Consider adding a comment explaining its purpose for future maintainers.📝 Suggested comment
- poseidon.inputs[4] <== discriminator + 36893488147419103232; + // Domain separator: 2^65 added to discriminator for collision resistance + poseidon.inputs[4] <== discriminator + 36893488147419103232;
54-54: Consider renaming the stuttering template name.
CompressedCompressedAccountMerkleProofappears to have an unintentional repetition of "Compressed".snippets/code-snippets/zk/merkle-proof/rust-client.mdx (2)
195-195: Hardcoded zkey path may limit portability.The path
./build/merkle_proof_final.zkeyassumes a specific build directory structure. For documentation snippets, consider adding a comment noting this path should be adjusted based on the project setup.📝 Suggested comment
+ // Adjust this path to match your project's build output directory let zkey_path = "./build/merkle_proof_final.zkey".to_string();
308-317: Proof conversion performed twice.
convert_proofis called at line 292-293 and again at lines 308-309. Consider reusing the first conversion result for efficiency.♻️ Suggested optimization
- let (proof_a_uncompressed, proof_b_uncompressed, proof_c_uncompressed) = - convert_proof(&proof.proof).expect("Failed to convert proof"); - use groth16_solana::proof_parser::circom_prover::convert_proof_to_compressed; let (proof_a, proof_b, proof_c) = convert_proof_to_compressed( - &proof_a_uncompressed, - &proof_b_uncompressed, - &proof_c_uncompressed, + &proof_a, + &proof_b, + &proof_c, ) .expect("Failed to compress proof");This reuses
proof_a,proof_b,proof_cfrom the verification block above.snippets/code-snippets/zk/merkle-proof/program.mdx (1)
89-95: Unwrap calls on hash functions could panic on-chain.While
hashv_to_bn254_field_size_be_const_arraywith constant inputs is likely safe, using.unwrap()in on-chain code is generally discouraged. Consider propagating the error.♻️ Suggested error handling
let owner_hashed = - hashv_to_bn254_field_size_be_const_array::<2>(&[&crate::ID.to_bytes()]).unwrap(); + hashv_to_bn254_field_size_be_const_array::<2>(&[&crate::ID.to_bytes()]) + .map_err(|_| ProgramError::InvalidArgument)?; let merkle_tree_pubkey = ctx.accounts.state_merkle_tree.key(); let merkle_tree_hashed = - hashv_to_bn254_field_size_be_const_array::<2>(&[&merkle_tree_pubkey.to_bytes()]) - .unwrap(); + hashv_to_bn254_field_size_be_const_array::<2>(&[&merkle_tree_pubkey.to_bytes()]) + .map_err(|_| ProgramError::InvalidArgument)?;
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (27)
compressed-pdas/overview.mdxcspell.jsondocs.jsonhome.mdxlearn/core-concepts/considerations.mdxreferences/migration-v1-to-v2.mdxresources/addresses-and-urls.mdxresources/cli-installation.mdxscripts/copy-zk-merkle-proof.shscripts/copy-zk-nullifier.shsnippets/ai-prompts/v1-to-v2-migration.mdxsnippets/ai-prompts/zk-app.mdxsnippets/code-snippets/zk/merkle-proof/circuit.mdxsnippets/code-snippets/zk/merkle-proof/program.mdxsnippets/code-snippets/zk/merkle-proof/rust-client.mdxsnippets/code-snippets/zk/nullifier/circuit.mdxsnippets/code-snippets/zk/nullifier/program.mdxsnippets/code-snippets/zk/nullifier/rust-client-batch.mdxsnippets/code-snippets/zk/nullifier/rust-client-single.mdxsnippets/mermaid/nullifier-flow.mdxsnippets/overview-tables/zk-examples-table.mdxwelcome.mdxzk/compressed-account-zk.mdxzk/examples.mdxzk/nullifiers.mdxzk/overview.mdxzk/zk-with-light.mdx
✅ Files skipped from review due to trivial changes (1)
- snippets/mermaid/nullifier-flow.mdx
🚧 Files skipped from review as they are similar to previous changes (4)
- resources/addresses-and-urls.mdx
- snippets/ai-prompts/v1-to-v2-migration.mdx
- resources/cli-installation.mdx
- learn/core-concepts/considerations.mdx
🧰 Additional context used
🧬 Code graph analysis (2)
scripts/copy-zk-nullifier.sh (1)
scripts/copy-zk-merkle-proof.sh (1)
wrap_code(11-19)
scripts/copy-zk-merkle-proof.sh (1)
scripts/copy-zk-nullifier.sh (1)
wrap_code(10-18)
🪛 GitHub Actions: CI
zk/overview.mdx
[error] 5-5: CSpell: Unknown word 'zcash' in zk/overview.mdx. Spellcheck failed with exit code 1.
[error] 29-29: CSpell: Unknown word 'Zcash' in zk/overview.mdx. Spellcheck failed with exit code 1.
🪛 LanguageTool
zk/compressed-account-zk.mdx
[grammar] ~14-~14: Use a hyphen to join words.
Context: ... the state Merkle tree. * For Solana PDA like behavior your compressed account ha...
(QB_NEW_EN_HYPHEN)
zk/nullifiers.mdx
[style] ~14-~14: Unless you want to emphasize “not”, use “cannot” which is more common.
Context: ...ed property for nullifiers is that they can not be created twice. 2. On Solana, you ty...
(CAN_NOT_PREMIUM)
🔇 Additional comments (28)
welcome.mdx (1)
25-31: LGTM!The updated href to
/compressed-pdas/overviewaligns with the navigation restructuring described in the PR objectives.home.mdx (1)
189-195: LGTM!Consistent with the link update in
welcome.mdx, aligning the Compressed PDAs card with the restructured navigation.cspell.json (1)
178-182: LGTM!The new dictionary entries appropriately support the ZK documentation terminology introduced in this PR (Circom circuits, SnarkJS tooling, alt_bn128 curve references).
references/migration-v1-to-v2.mdx (3)
9-16: LGTM!The V2 improvements table provides a clear, scannable comparison of v1 vs v2 characteristics.
254-259: LGTM!Adding an AI Prompt tab provides a helpful migration assistant option, consistent with the pattern of including AI prompts in documentation.
7-7: Import path is correct. The snippet filesnippets/ai-prompts/v1-to-v2-migration.mdxexists in the repository and is properly imported.scripts/copy-zk-merkle-proof.sh (1)
11-19: LGTM!The
wrap_codefunction is consistent with the implementation incopy-zk-nullifier.sh.zk/compressed-account-zk.mdx (2)
1-20: LGTM!The frontmatter, imports, and introductory bullet points provide a clear overview of ZK compressed accounts functionality. The info callout directing users to the full example is helpful.
202-232: LGTM!The full code example section with tabs for Program/Rust client, the circuit inclusion, and the navigation card to the nullifier guide are well-structured and provide a complete reference for developers.
snippets/ai-prompts/zk-app.mdx (1)
1-149: LGTM!The AI prompt template is comprehensive and well-structured:
- Clear phases from design through cleanup
- Strict enforcement of
build-sbf/test-sbfcommands- Reference patterns from existing examples
- Useful DeepWiki fallback mechanism
The workflow guidance and dependency specifications will help AI agents produce consistent, working ZK applications.
snippets/code-snippets/zk/nullifier/circuit.mdx (1)
1-32: LGTM!The Circom circuit templates are well-designed:
Nullifier()correctly constrains the nullifier to equalPoseidon(verification_id, secret)BatchNullifier(n)efficiently reuses the single nullifier template for batch proving- The Poseidon(2) hasher is appropriate for the 2-input case
zk/examples.mdx (1)
1-17: LGTM!Clean examples page with appropriate frontmatter and component composition. The structure effectively reuses the shared snippets for the examples table and AI prompt.
snippets/overview-tables/zk-examples-table.mdx (1)
1-12: LGTM!The examples table provides a clear overview of available ZK examples with links to the program-examples repository. The descriptions are concise and help developers understand each example's purpose.
docs.json (1)
102-130: LGTM!The new ZK navigation group and reorganized Compressed PDAs structure are well-organized and follow the existing navigation patterns. The nesting and page references align with the PR objectives.
snippets/code-snippets/zk/nullifier/rust-client-single.mdx (2)
94-99: Note: Reduced entropy in secret generation.The secret generation deliberately zeros
secret[0]and only copies 31 bytes. This is likely intentional to ensure the value fits within the BN254 scalar field (< 2^254), but it reduces entropy by 8 bits. For production use, consider documenting this constraint or using proper field-aware random generation.
1-224: LGTM!The single-nullifier test implementation is well-structured with clear separation of concerns: secret generation, nullifier computation, address derivation, instruction building, and proof generation. The duplicate-submission test (lines 75-91) correctly validates that the same nullifier cannot be created twice.
zk/nullifiers.mdx (1)
1-171: LGTM!The nullifier guide is comprehensive and well-structured. The implementation flow diagram (lines 35-47) clearly illustrates the architecture, the step-by-step guide with code examples is thorough, and the full code example section properly references the snippets. The cost comparison table (lines 19-22) effectively highlights the rent savings.
scripts/copy-zk-nullifier.sh (1)
10-18: LGTM!The
wrap_codefunction is well-implemented and matches the pattern used in the relatedcopy-zk-merkle-proof.shscript.snippets/code-snippets/zk/nullifier/rust-client-batch.mdx (1)
1-251: LGTM!The batch nullifier test implementation correctly exercises the batch workflow, including proper handling of multiple addresses, batch proof generation with array inputs (lines 197-213), and duplicate-batch rejection testing (lines 90-106). The CU logging (lines 76-78) is helpful for understanding per-nullifier costs.
snippets/code-snippets/zk/merkle-proof/rust-client.mdx (2)
27-65: LGTM!The test function properly demonstrates the end-to-end workflow: creating a compressed account with a data hash, retrieving it, and verifying it with a ZK proof.
287-306: Redundant verification is acceptable for documentation.The proof is verified twice: once via
CircomProver::verify(line 283) and again viaGroth16Verifier(lines 296-305). While redundant for production, this serves well as documentation showing both verification approaches.snippets/code-snippets/zk/merkle-proof/program.mdx (3)
38-75: LGTM!The
create_accountfunction correctly derives the address from seeds, initializes a compressed account, and invokes the Light CPI. The address derivation includes both theZK_ACCOUNTprefix anddata_hashfor deterministic addressing.
150-156: LGTM!The
VerifyAccountAccountsstruct correctly usesUncheckedAccountfor the state merkle tree with a safety comment indicating validation happens inread_state_merkle_tree_root.
158-171: LGTM!The
ZkAccountandDataHashstructures are well-defined with appropriate derives and theToByteArrayimplementation correctly returns the inner 32-byte array.snippets/code-snippets/zk/nullifier/program.mdx (4)
39-118: LGTM!The single nullifier creation flow correctly validates the proof, checks the address tree, derives the nullifier address deterministically, and creates the account via Light CPI.
185-213: LGTM!The batch nullifier creation loop correctly:
- Derives unique addresses for each nullifier using the same verification_id
- Creates separate accounts with the same output state tree index
- Collects all new address params before invoking the CPI
The builder pattern usage is idiomatic.
225-226: LGTM!An empty
NullifierAccountstruct is appropriate here - its on-chain existence serves as proof that the nullifier has been consumed, preventing double-spending without storing redundant data.
136-142: Only the first address tree is validated in batch mode.The code validates
address_tree_infos[0]againstADDRESS_TREE_V2, butaddress_tree_infos[1..3]are used in the loop without validation. If all addresses must use the v2 tree, consider validating all of them or documenting that the caller is responsible for ensuring consistency.
| PROGRAM_EXAMPLES="/home/tilo/Workspace/program-examples/zk/zk-merkle-proof" | ||
| SNIPPETS_DIR="/home/tilo/Workspace/docs/snippets/code-snippets/zk/merkle-proof" |
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.
Hardcoded absolute paths break portability.
These paths are specific to your local development environment and will fail for any other contributor. Consider using relative paths or environment variables.
🔧 Suggested fix using relative paths or environment variables
-PROGRAM_EXAMPLES="/home/tilo/Workspace/program-examples/zk/zk-merkle-proof"
-SNIPPETS_DIR="/home/tilo/Workspace/docs/snippets/code-snippets/zk/merkle-proof"
+# Set source directory via environment variable or use default relative path
+PROGRAM_EXAMPLES="${PROGRAM_EXAMPLES:-../program-examples/zk/zk-merkle-proof}"
+# Resolve script directory for relative output path
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+SNIPPETS_DIR="${SCRIPT_DIR}/../snippets/code-snippets/zk/merkle-proof"You may also want to add validation that the source directory exists:
if [ ! -d "$PROGRAM_EXAMPLES" ]; then
echo "Error: Source directory not found: $PROGRAM_EXAMPLES" >&2
exit 1
fi🤖 Prompt for AI Agents
In @scripts/copy-zk-merkle-proof.sh around lines 6 - 7, Replace the hardcoded
absolute paths stored in PROGRAM_EXAMPLES and SNIPPETS_DIR with values derived
from either environment variables (e.g., respect PROGRAM_EXAMPLES and
SNIPPETS_DIR if provided) or computed relative paths based on the script
location (use the script directory via dirname "$0" to build defaults); then add
validation checks that both PROGRAM_EXAMPLES and SNIPPETS_DIR exist as
directories and, if not, print an error to stderr and exit with a non-zero
status. Ensure you update the assignments for PROGRAM_EXAMPLES and SNIPPETS_DIR
and add the directory-existence checks immediately after those assignments so
failures are detected early.
| PROGRAM_EXAMPLES="/home/tilo/Workspace/program-examples/zk/zk-nullifier" | ||
| SNIPPETS_DIR="/home/tilo/Workspace/docs/snippets/code-snippets/zk/nullifier" |
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.
Replace hardcoded absolute paths with portable alternatives.
The script uses hardcoded absolute paths specific to a local development environment (/home/tilo/Workspace/...), making it unusable for other contributors. Use relative paths or environment variables instead:
Proposed fix
-PROGRAM_EXAMPLES="/home/tilo/Workspace/program-examples/zk/zk-nullifier"
-SNIPPETS_DIR="/home/tilo/Workspace/docs/snippets/code-snippets/zk/nullifier"
+# Configure these paths or set via environment variables
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
+
+PROGRAM_EXAMPLES="${PROGRAM_EXAMPLES:-../program-examples/zk/zk-nullifier}"
+SNIPPETS_DIR="${SNIPPETS_DIR:-$REPO_ROOT/snippets/code-snippets/zk/nullifier}"🤖 Prompt for AI Agents
In @scripts/copy-zk-nullifier.sh around lines 5 - 6, Replace the hardcoded
absolute paths assigned to PROGRAM_EXAMPLES and SNIPPETS_DIR with portable
alternatives: read their values from environment variables (e.g., use
PROGRAM_EXAMPLES and SNIPPETS_DIR if set) and otherwise construct sensible
relative defaults based on the script location (using the script directory as
the base) so contributors can run the script from different workspaces; update
the assignments for PROGRAM_EXAMPLES and SNIPPETS_DIR accordingly and ensure
downstream uses of those variables remain unchanged.
| light-sdk = { version = "0.17.1", features = ["anchor", "poseidon", "merkle-tree", "v2"] } | ||
| light-hasher = "5.0.0" | ||
| light-sdk-types = { version = "0.17.1", features = ["v2"] } | ||
| groth16-solana = { git = "https://github.com/Lightprotocol/groth16-solana", rev = "66c0dc87" } |
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.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify the git commit exists in the groth16-solana repository
# Using GitHub API to check the commit
curl -s "https://api.github.com/repos/Lightprotocol/groth16-solana/commits/66c0dc87" | jq -r '.sha, .commit.message, .html_url' 2>/dev/null
# Also check if this commit is tagged
echo "---"
git ls-remote --tags https://github.com/Lightprotocol/groth16-solana.git | grep -i "66c0dc87" || echo "No exact tag match found"
# Get recent commits to see context
echo "---"
curl -s "https://api.github.com/repos/Lightprotocol/groth16-solana/commits?per_page=20" | jq -r '.[] | "\(.sha | .[0:8]) - \(.commit.message | split("\n")[0])"' 2>/dev/nullRepository: Lightprotocol/docs-v2
Length of output: 1345
Use a tagged release for the groth16-solana dependency instead of a specific commit.
The revision 66c0dc87 (full hash: 66c0dc87d0808c4d2aadb53c61435b6edb8ddfd9, message: "feat: add error conversion") is a valid commit in the repository, but it is not a tagged release. For production dependencies, prefer using a tagged release version (such as v0.2.0) for better stability and reproducibility across environments.
🤖 Prompt for AI Agents
In @snippets/ai-prompts/zk-app.mdx at line 109, Replace the git dependency pin
for groth16-solana that currently uses a specific commit rev ("66c0dc87") with a
tagged release reference; locate the dependency entry named groth16-solana and
change its rev field to the appropriate tag (e.g., v0.2.0) or switch to using a
tag-based git ref so the project depends on a released version rather than a
single commit for better stability and reproducibility.
| component main { | ||
| public [owner_hashed, merkle_tree_hashed, discriminator, data_hash, expectedRoot] | ||
| } = CompressedAccountMerkleProof(26); |
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.
Template name mismatch will cause compilation error.
The main component references CompressedAccountMerkleProof(26) but the template is defined as CompressedCompressedAccountMerkleProof on line 54. This will fail during Circom compilation.
🐛 Proposed fix
component main {
public [owner_hashed, merkle_tree_hashed, discriminator, data_hash, expectedRoot]
-} = CompressedAccountMerkleProof(26);
+} = CompressedCompressedAccountMerkleProof(26);Alternatively, rename the template to remove the stuttering:
-template CompressedCompressedAccountMerkleProof(levels) {
+template CompressedAccountMerkleProof(levels) {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| component main { | |
| public [owner_hashed, merkle_tree_hashed, discriminator, data_hash, expectedRoot] | |
| } = CompressedAccountMerkleProof(26); | |
| component main { | |
| public [owner_hashed, merkle_tree_hashed, discriminator, data_hash, expectedRoot] | |
| } = CompressedCompressedAccountMerkleProof(26); |
🤖 Prompt for AI Agents
In @snippets/code-snippets/zk/merkle-proof/circuit.mdx around lines 81 - 83, The
main component instantiation references CompressedAccountMerkleProof(26) but the
template is actually named CompressedCompressedAccountMerkleProof; update either
the template name or the component instantiation so they match (e.g., rename the
template to CompressedAccountMerkleProof or change the component to use
CompressedCompressedAccountMerkleProof) to resolve the Circom compilation error,
ensuring references to main, CompressedAccountMerkleProof, and
CompressedCompressedAccountMerkleProof are consistent.
|
|
||
| * Compressed and regular Solana accounts share the same functionality and are fully composable. | ||
| * The account state is hashed with Poseidon and stored as a commitment in the state Merkle tree. | ||
| * For Solana PDA like behavior your compressed account has an address as persistent 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.
Grammar: Hyphenate compound adjective.
Per the static analysis hint, "PDA like behavior" should be "PDA-like behavior" when used as a compound adjective.
Suggested fix
-* For Solana PDA like behavior your compressed account has an address as persistent identifier.
+* For Solana PDA-like behavior, your compressed account has an address as persistent identifier.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| * For Solana PDA like behavior your compressed account has an address as persistent identifier. | |
| * For Solana PDA-like behavior, your compressed account has an address as persistent identifier. |
🧰 Tools
🪛 LanguageTool
[grammar] ~14-~14: Use a hyphen to join words.
Context: ... the state Merkle tree. * For Solana PDA like behavior your compressed account ha...
(QB_NEW_EN_HYPHEN)
🤖 Prompt for AI Agents
In @zk/compressed-account-zk.mdx at line 14, Change the compound adjective "PDA
like behavior" to the hyphenated form "PDA-like behavior" in the sentence that
begins "For Solana PDA like behavior your compressed account..." so the phrase
reads "For Solana PDA-like behavior your compressed account has an address as
persistent identifier."
| <CardGroup cols={2}> | ||
| <Card | ||
| title="Solana Privacy Hack" | ||
| icon="arrow-up-right-from-square" | ||
| href="https://solana.com/privacyhack" | ||
| > | ||
| January 12 - February 1, 2025 | ||
| </Card> | ||
| <Card | ||
| title="Workshop: ZK with Light Protocol" | ||
| icon="x-twitter" | ||
| href="https://x.com/solana_devs" | ||
| > | ||
| Wednesday Jan 15 · 12:00pm ET / 5:00pm UTC | ||
| </Card> | ||
| </CardGroup> |
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.
🧩 Analysis chain
🏁 Script executed:
fd -t f "overview.mdx" | head -20Repository: Lightprotocol/docs-v2
Length of output: 270
🏁 Script executed:
sed -n '90,115p' zk/overview.mdxRepository: Lightprotocol/docs-v2
Length of output: 566
Update or remove outdated event information.
The events displayed are from January 2025 ("Solana Privacy Hack: January 12 - February 1, 2025" and "Workshop: ZK with Light Protocol: Wednesday Jan 15"). These have concluded and should be updated with current events or removed from the section.
🤖 Prompt for AI Agents
In @zk/overview.mdx around lines 94 - 109, The event cards in the CardGroup
currently show outdated January 2025 events; update or remove them by editing
the CardGroup/ Card components (titles "Solana Privacy Hack" and "Workshop: ZK
with Light Protocol") to either replace dates/details with current events or
remove those Card nodes entirely; if replacing, ensure href, title, icon, and
child content reflect the new event metadata and timing, and if removing, delete
the corresponding <Card ...>...</Card> blocks so the section no longer displays
past events.
| ADD AFTER WORKSHOP. | ||
|
|
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.
Remove or address the placeholder note before merging.
Line 1 contains "ADD AFTER WORKSHOP." which appears to be a TODO/reminder note. This should be removed or the content should be completed before merging.
🤖 Prompt for AI Agents
In @zk/zk-with-light.mdx around lines 1 - 2, The file contains a leftover
placeholder "ADD AFTER WORKSHOP."—remove that placeholder or replace it with the
finalized workshop content in zk-with-light.mdx; ensure the placeholder line is
deleted or substituted with the completed text, update any related links/TOC if
needed, and commit the change before merging.
| 3. These commitments are created during deposits, transfers, and | ||
| other interactions, and are subsequently spent (nullified) | ||
| when the UTXO is consumed. | ||
| 3. To spend private state, users generate a zero-knowledge proof to prove knowledge of the secret |
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.
Fix duplicate list numbering.
There are two items numbered "3." (lines 14-16 and line 17). The second "3." on line 17 should be "4.":
Proposed fix
3. These commitments are created during deposits, transfers, and
other interactions, and are subsequently spent (nullified)
when the UTXO is consumed.
-3. To spend private state, users generate a zero-knowledge proof to prove knowledge of the secret
+4. To spend private state, users generate a zero-knowledge proof to prove knowledge of the secret
associated with a commitment in the Merkle tree, accompanied by a unique nullifier. 📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| 3. These commitments are created during deposits, transfers, and | |
| other interactions, and are subsequently spent (nullified) | |
| when the UTXO is consumed. | |
| 3. To spend private state, users generate a zero-knowledge proof to prove knowledge of the secret | |
| 3. These commitments are created during deposits, transfers, and | |
| other interactions, and are subsequently spent (nullified) | |
| when the UTXO is consumed. | |
| 4. To spend private state, users generate a zero-knowledge proof to prove knowledge of the secret |
🤖 Prompt for AI Agents
In @zk/zk-with-light.mdx around lines 14 - 17, The ordered list has a duplicate
"3." numbering; update the second occurrence (the list item starting "To spend
private state, users generate a zero-knowledge proof to prove knowledge of the
secret") to "4." so the sequence becomes 1., 2., 3., 4., ensuring the list
numbering is correct.
…ides - Add nullifier guide with implementation steps and full code examples - Add compressed accounts for ZK applications guide - Create snippet-based code examples from program-examples repo - Add shell scripts to sync code snippets from source - Reorganize tabs: Program, Client, Circuit Example, Get started with AI Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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.
Actionable comments posted: 16
🤖 Fix all issues with AI agents
In @scripts/copy-zk-merkle-proof.sh:
- Around line 11-19: The wrap_code function silently produces partial outputs
and uses echo for backticks; update wrap_code to validate its inputs and use
printf and safe cat usage: in wrap_code (function wrap_code) check that both
input_file and output_file exist and are non-empty and print a warning to stderr
and return non-zero if the source is missing, replace echo "\`\`\`$lang" with
printf '```%s\n' "$lang" > "$output_file", use cat -- "$input_file" to append,
and replace the closing echo '```' with printf '```\n' >> "$output_file"; also
add existence warnings (to stderr) for the three other snippet-generation blocks
referenced (the blocks around lines 22-34 and 36-38) so they print a WARN with
the missing source path when files are absent.
- Around line 6-9: The script currently hardcodes PROGRAM_EXAMPLES and
SNIPPETS_DIR which breaks portability; change it to accept PROGRAM_EXAMPLES and
SNIPPETS_DIR from environment or command-line args and fall back to
repo-relative defaults computed from the script directory (e.g., a SCRIPT_DIR
derived from the script location) before calling mkdir -p; update the variable
assignments so $PROGRAM_EXAMPLES and $SNIPPETS_DIR are set from provided
args/env or from the computed repo-relative paths and ensure the rest of the
script uses those variables.
In @snippets/ai-prompts/v1-to-v2-migration.mdx:
- Around line 74-75: The listed functions are Rust SDK items wrongly placed
under the TypeScript SDK section; remove get_address_tree_v1(),
get_address_tree_v2(), get_random_state_tree_info_v1(), and
get_random_state_tree_info() from the TypeScript mappings and add them to Phase
3 (Rust SDK replacements) where Rust examples live, updating the table rows and
any surrounding prose so those four symbols appear under the Rust SDK
replacement list instead of the TypeScript SDK section.
In @snippets/ai-prompts/zk-app.mdx:
- Around line 144-149: The DeepWiki fallback uses an environment-specific
tooling call mcp__deepwiki__ask_question which may not exist for all readers;
update the "DeepWiki fallback" section to include a plain‑English fallback
alongside the tooling example by adding a human-readable instruction or template
(e.g., a sentence users can copy/paste) that explains how to ask the question
without the tool and shows the same example in natural language; keep the
existing mcp__deepwiki__ask_question line but add a short explanatory sentence
or example immediately before or after it so readers know how to proceed if the
tool is unavailable.
In @snippets/code-snippets/zk/merkle-proof/circuit.mdx:
- Around line 35-52: The constant addition "discriminator +
36893488147419103232" in template CompressedAccountHash is magic-numbery and
must be documented and centralized; update the template to replace or accompany
that literal with a named constant (e.g., ACCOUNT_DISCRIMINATOR_OFFSET = 2^65)
and add a comment explaining the purpose (domain separation/avoid collisions and
why 2^65 is chosen), and ensure any other code computing discriminators uses the
same named constant for consistency.
- Around line 54-84: The template is declared as
CompressedCompressedAccountMerkleProof but instantiated as
CompressedAccountMerkleProof, causing a name mismatch; fix by making the names
consistent—either rename the template to CompressedAccountMerkleProof or change
the instantiation component main to use CompressedCompressedAccountMerkleProof,
and ensure any references to the template (e.g.,
CompressedCompressedAccountMerkleProof, CompressedAccountMerkleProof) throughout
the file are updated accordingly so the template declaration and its
instantiation match exactly.
In @snippets/code-snippets/zk/merkle-proof/rust-client.mdx:
- Around line 146-147: Replace the magic literal "% 2400" used to derive
root_index with a named constant or configuration value that reflects the tree's
actual root-history size (e.g., ROOT_HISTORY_LEN or a field on
MerkleTree/MerkleProof), and use that constant in the modulo and type cast so
the calculation is explicit and correct; update the derivation in the root_index
assignment (currently using merkle_proof.root_seq and merkle_proof.merkle_tree)
and any other occurrences around lines 162-166 to read from the constant/config
or the tree's API instead of hardcoding 2400.
- Around line 93-106: packed_address_tree_accounts[0] can panic if the RPC
response lacks address trees; change to safely obtain the first element (e.g.,
use packed_address_tree_accounts.first().ok_or(...) or equivalent) and propagate
a descriptive error instead of indexing. Replace the direct indexing when
building instruction_data (zk_merkle_proof::instruction::CreateAccount) to use
the safely-unwrapped value and include a clear error message referencing the RPC
result (rpc_result) so the function returns an Err on missing address trees
rather than panicking.
In @zk/compressed-account-zk.mdx:
- Around line 215-216: The sentence currently reads "A minimal Solana program to
create compressed accounts and verifies with Groth16 proofs"; change the verb to
match the plural infinitive form so it reads "A minimal Solana program to create
compressed accounts and verify with Groth16 proofs." Locate the sentence in the
zk/compressed-account-zk.mdx content and replace the word "verifies" with
"verify" to correct the grammar.
- Around line 195-199: The empty Client Tab shown as <Tab title="Client"> is
either removed or populated; either delete the entire <Tab
title="Client">...</Tab> block to avoid an empty tab, or add meaningful content
(brief description, usage, or links) inside the <Tab title="Client"> element so
the tab is not blank—update the compressed-account-zk.mdx file by editing the
<Tab title="Client"> block accordingly.
- Around line 12-16: Tighten the phrasing in the third bullet: change "For
Solana PDA like behavior your compressed account has an address as persistent
identifier." to a clearer form such as "For Solana PDA-like behavior, your
compressed account uses an address as a persistent identifier." — add the hyphen
in "PDA-like", insert the comma after "behavior", and replace "has" with "uses"
to improve clarity and grammar.
In @zk/nullifiers.mdx:
- Around line 14-18: Fix minor grammar and punctuation issues: change "can not"
to "cannot", ensure each sentence ends with proper punctuation and has correct
spacing after commas and periods, remove any stray spaces before punctuation
(e.g., around the tilde in "~0.001 SOL"), and normalize terms like "rent-free
PDAs" (keep hyphen) and "address Merkle tree" capitalization/spacing consistent
with the document style.
In @zk/zk-with-light.mdx:
- Around line 1-3: Remove the placeholder text "ADD AFTER WORKSHOP." from the
document and replace it with the intended final content (or delete it if no
content is ready) so the draft does not ship with the placeholder; locate the
string "ADD AFTER WORKSHOP." in the zk-with-light.mdx content and either remove
it or substitute the completed section before merging.
- Around line 4-26: Add a clear section heading (e.g., "Compressed Accounts &
Private Spending") above the paragraph, fix the ordered list numbering so it
reads 1–4 (remove the duplicate "3."), and tighten terminology: use "commitment"
consistently instead of "hash" where appropriate, call the on-chain value
"Merkle root (32 bytes)" and the per-account item "commitment in the Merkle
tree." Also clarify the nullifier derivation line to read "nullifier =
Poseidon(context, secret)" and explicitly say the nullifier is then recorded in
an indexed address Merkle tree to prevent double-spends.
🧹 Nitpick comments (8)
snippets/ai-prompts/zk-app.mdx (1)
102-114: Pinned dependency versions in documentation prompts will become stale—add guidance to check current versions in the actual repository.This AI prompt should direct users to verify compatibility rather than rely on these fixed versions. Suggest revising the Dependencies section to include a note like:
These are example versions. Always check the Light Protocol repository for current compatible releases and update accordingly.
Or directly reference the repo's
Cargo.tomlfor authoritative versions.snippets/code-snippets/zk/nullifier/rust-client-batch.mdx (2)
109-114: Clarify intent of zeroingsecret[0].The secret generation leaves
secret[0]as zero while copying 31 bytes into positions 1-31. This appears intentional to ensure the value fits within the BN254 scalar field (< 2^254), but a brief comment would help readers understand this constraint.📝 Suggested documentation
fn generate_random_secret() -> [u8; 32] { + // First byte is zeroed to ensure the secret fits within BN254 field let random_keypair = Keypair::new(); let mut secret = [0u8; 32]; secret[1..32].copy_from_slice(&random_keypair.to_bytes()[0..31]); secret }
159-164: Hardcoded array indexing assumesBATCH_SIZE = 4.If
BATCH_SIZEchanges in thezk_nullifiercrate, this code will panic or produce incorrect results. Consider usingtry_into()for a more defensive approach.♻️ Suggested improvement
- let address_tree_infos: [_; BATCH_SIZE] = [ - packed_address_tree_accounts[0], - packed_address_tree_accounts[1], - packed_address_tree_accounts[2], - packed_address_tree_accounts[3], - ]; + let address_tree_infos: [_; BATCH_SIZE] = packed_address_tree_accounts + .try_into() + .expect("packed_address_tree_accounts length must match BATCH_SIZE");snippets/code-snippets/zk/nullifier/rust-client-single.mdx (1)
94-99: Same clarification applies for secret generation.Same observation as the batch variant:
secret[0]is intentionally zeroed for BN254 field compatibility. A comment would improve readability.snippets/code-snippets/zk/merkle-proof/program.mdx (1)
2-3: Consider documenting reason for#![allow(deprecated)].Suppressing deprecated warnings globally may hide important migration notices from dependencies. Consider either documenting which specific deprecated API is being used and why, or applying
#[allow(deprecated)]more narrowly to specific items.snippets/code-snippets/zk/merkle-proof/rust-client.mdx (2)
142-157: Fix (or assert)leaf_indexconsistency to avoid generating a proof for a different leaf than the one hashed.
Right now,leaf_indexis passed in (Line 149-156) and used as a private input (Line 253), but the recreatedcomputed_hashusesaccount.leaf_index(Line 211-213). If those ever diverge, this becomes very hard to debug (and can silently “validate” the wrong assumption until the final assert trips).Proposed diff
fn generate_merkle_proof( account: &light_client::indexer::CompressedAccount, merkle_tree_pubkey: &Pubkey, leaf_index: u32, @@ ) -> light_compressed_account::instruction_data::compressed_proof::CompressedProof { @@ let address = account.address.expect("Account must have an address"); // Verify hash can be recreated + let account_leaf_index_u32 = account.leaf_index as u32; + assert_eq!( + account_leaf_index_u32, leaf_index, + "Leaf index mismatch between proof metadata and account" + ); let mut leaf_index_bytes = [0u8; 32]; - leaf_index_bytes[28..32].copy_from_slice(&(account.leaf_index as u32).to_le_bytes()); + leaf_index_bytes[28..32].copy_from_slice(&leaf_index.to_le_bytes()); @@ // Private inputs proof_inputs.insert("leaf_index".to_string(), vec![leaf_index.to_string()]); let mut account_leaf_index_bytes = [0u8; 32]; - account_leaf_index_bytes[28..32].copy_from_slice(&(account.leaf_index as u32).to_le_bytes()); + account_leaf_index_bytes[28..32].copy_from_slice(&leaf_index.to_le_bytes()); proof_inputs.insert( "account_leaf_index".to_string(), vec![BigUint::from_bytes_be(&account_leaf_index_bytes).to_string()], );Also applies to: 208-229, 252-266
195-196: Make the.zkeypath configurable (or document the expected working directory).
"./build/merkle_proof_final.zkey"will frequently fail when the snippet is copied into a different crate/workspace layout.Proposed diff
- let zkey_path = "./build/merkle_proof_final.zkey".to_string(); + let zkey_path = std::env::var("MERKLE_PROOF_ZKEY_PATH") + .unwrap_or_else(|_| "./build/merkle_proof_final.zkey".to_string());zk/nullifiers.mdx (1)
15-23: Call out that the SOL cost numbers are approximate and may change with rent/fees.
Otherwise the doc will become “wrong” over time.Proposed diff
-2. On Solana, you typically would create a PDA account. Nullifier accounts must remain active, hence lock ~0.001 SOL in rent per nullifier PDA permanently. +2. On Solana, you typically would create a PDA account. Nullifier accounts must remain active, which (at current rent rates) can lock ~0.001 SOL in rent per nullifier PDA. @@ -| PDA | ~0.001 SOL | -| Compressed PDA | ~0.000005 SOL | +| PDA | ~0.001 SOL (approx.) | +| Compressed PDA | ~0.000005 SOL (approx.) |
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (27)
compressed-pdas/overview.mdxcspell.jsondocs.jsonhome.mdxlearn/core-concepts/considerations.mdxreferences/migration-v1-to-v2.mdxresources/addresses-and-urls.mdxresources/cli-installation.mdxscripts/copy-zk-merkle-proof.shscripts/copy-zk-nullifier.shsnippets/ai-prompts/v1-to-v2-migration.mdxsnippets/ai-prompts/zk-app.mdxsnippets/code-snippets/zk/merkle-proof/circuit.mdxsnippets/code-snippets/zk/merkle-proof/program.mdxsnippets/code-snippets/zk/merkle-proof/rust-client.mdxsnippets/code-snippets/zk/nullifier/circuit.mdxsnippets/code-snippets/zk/nullifier/program.mdxsnippets/code-snippets/zk/nullifier/rust-client-batch.mdxsnippets/code-snippets/zk/nullifier/rust-client-single.mdxsnippets/mermaid/nullifier-flow.mdxsnippets/overview-tables/zk-examples-table.mdxwelcome.mdxzk/compressed-account-zk.mdxzk/examples.mdxzk/nullifiers.mdxzk/overview.mdxzk/zk-with-light.mdx
🚧 Files skipped from review as they are similar to previous changes (12)
- learn/core-concepts/considerations.mdx
- zk/examples.mdx
- resources/addresses-and-urls.mdx
- zk/overview.mdx
- welcome.mdx
- cspell.json
- resources/cli-installation.mdx
- snippets/overview-tables/zk-examples-table.mdx
- home.mdx
- references/migration-v1-to-v2.mdx
- snippets/code-snippets/zk/nullifier/program.mdx
- snippets/mermaid/nullifier-flow.mdx
🧰 Additional context used
🧬 Code graph analysis (2)
scripts/copy-zk-merkle-proof.sh (1)
scripts/copy-zk-nullifier.sh (1)
wrap_code(10-18)
scripts/copy-zk-nullifier.sh (1)
scripts/copy-zk-merkle-proof.sh (1)
wrap_code(11-19)
🪛 LanguageTool
zk/compressed-account-zk.mdx
[grammar] ~14-~14: Use a hyphen to join words.
Context: ... the state Merkle tree. * For Solana PDA like behavior your compressed account ha...
(QB_NEW_EN_HYPHEN)
zk/nullifiers.mdx
[style] ~14-~14: Unless you want to emphasize “not”, use “cannot” which is more common.
Context: ...ed property for nullifiers is that they can not be created twice. 2. On Solana, you ty...
(CAN_NOT_PREMIUM)
🔇 Additional comments (17)
snippets/ai-prompts/v1-to-v2-migration.mdx (5)
25-30: LGTM!The reference repository structure is clear and provides helpful context for locating v2 patterns.
55-64: LGTM!The Rust SDK replacement patterns are well-organized and follow Rust naming conventions consistently.
77-99: LGTM!The build/test loop guidance is clear, with appropriate emphasis on using proper SBF tooling and avoiding shortcuts. The iterative debugging approach with fresh context is a sensible pattern for AI-assisted development.
101-105: LGTM!The DeepWiki fallback provides a sensible escape hatch for patterns not covered by the reference repositories.
20-23: Documentation links are accessible.Both URLs in the documentation section are reachable: the migration guide (returns 307 redirect) and the reference PR commit (returns 200 OK).
snippets/ai-prompts/zk-app.mdx (1)
1-7: No changes needed. The YAML header inside the fenced code block is intentional—it's part of the prompt template structure, not page metadata, and will be correctly treated as plain text content.snippets/code-snippets/zk/nullifier/rust-client-batch.mdx (1)
28-107: LGTM!The test correctly validates the batch nullifier creation flow: it creates 4 nullifiers in a single transaction, verifies the expected account count, and confirms that duplicate submission fails. The CU simulation output is helpful for performance analysis.
snippets/code-snippets/zk/nullifier/rust-client-single.mdx (1)
28-92: LGTM!The single nullifier test is well-structured, following the same pattern as the batch variant. It properly demonstrates creation, verification, and idempotency (duplicate rejection).
snippets/code-snippets/zk/nullifier/circuit.mdx (2)
7-16: LGTM!The Nullifier template correctly constrains
nullifier = Poseidon(verification_id, secret). The signal flow is clean and the constraint is properly enforced.
19-31: LGTM!The BatchNullifier template elegantly reuses the single Nullifier template via composition. Each iteration shares the same
verification_idwhile using indexednullifier[i]andsecret[i], which matches the Rust client's batch proof generation logic.snippets/code-snippets/zk/merkle-proof/program.mdx (4)
97-98: Discriminator padding is intentional.The 8-byte discriminator is right-aligned in a 32-byte array for consistency with BN254 field element representation. This is the correct approach for circuit compatibility.
77-141: LGTM!The
verify_accountfunction correctly implements on-chain Groth16 proof verification:
- Reads the expected Merkle root from state
- Hashes program ID and merkle tree pubkey to BN254 field elements
- Constructs public inputs array in the correct order
- Decompresses the proof and runs verification
The error handling pattern consistently converts errors to custom program errors.
38-75: LGTM!The
create_accountfunction demonstrates proper Light SDK usage:
- Derives a deterministic address from
[ZK_ACCOUNT, data_hash]seeds- Initializes a
LightAccountPoseidonwith the derived address- Invokes the Light System Program CPI with proper signer authorization
158-171: LGTM!The
ZkAccountstruct andDataHashnewtype are cleanly defined. TheToByteArrayimplementation correctly returns the inner 32-byte array, enabling Poseidon hashing for compressed account state.docs.json (1)
102-130: Navigation structure is well-organized and all page references exist.The new "ZK" and "Compressed PDAs" groups provide clear logical organization. The ZK section groups overview, nullifiers, compressed accounts, and examples cohesively. The nested "Program Guides" structure under Compressed PDAs improves discoverability for how-to content. All referenced page paths resolve correctly to their corresponding
.mdxfiles.zk/nullifiers.mdx (1)
12-16: The mid-file---on line 12 is a valid Markdown thematic break and does not cause parsing issues. MDX frontmatter parsing only recognizes the initial YAML block (lines 1–4); subsequent---sequences are parsed as normal Markdown content. No change required.Likely an incorrect or invalid review comment.
zk/compressed-account-zk.mdx (1)
32-39: The pinned dependency versions in this snippet are currently aligned with Light Protocol docs-v2 recommendations (anchor-lang 0.31.1, light-sdk 0.17.1 with v2 features, light-sdk-types 0.17.1 with v2 features, and light-hasher 5.0.0). However, since these are documentation examples without a canonical Cargo.lock to reference, establish a process to periodically verify these versions remain current with Light Protocol's recommended releases—particularly anchor-lang and light-sdk, which may release updates independent of this repository.
| PROGRAM_EXAMPLES="/home/tilo/Workspace/program-examples/zk/zk-merkle-proof" | ||
| SNIPPETS_DIR="/home/tilo/Workspace/docs/snippets/code-snippets/zk/merkle-proof" | ||
|
|
||
| mkdir -p "$SNIPPETS_DIR" |
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.
Hard-coded absolute paths make this script effectively non-portable.
Use repo-relative paths (based on the script’s directory) and/or accept PROGRAM_EXAMPLES + SNIPPETS_DIR as args/env vars so others (and CI) can run it.
Proposed fix
-#!/bin/bash
+#!/usr/bin/env bash
+set -euo pipefail
-PROGRAM_EXAMPLES="/home/tilo/Workspace/program-examples/zk/zk-merkle-proof"
-SNIPPETS_DIR="/home/tilo/Workspace/docs/snippets/code-snippets/zk/merkle-proof"
+SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
+REPO_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)"
+
+# Allow overrides: ./copy-zk-merkle-proof.sh [program_examples_dir] [snippets_dir]
+PROGRAM_EXAMPLES="${1:-${PROGRAM_EXAMPLES:-${REPO_ROOT}/program-examples/zk/zk-merkle-proof}}"
+SNIPPETS_DIR="${2:-${SNIPPETS_DIR:-${REPO_ROOT}/snippets/code-snippets/zk/merkle-proof}}"
mkdir -p "$SNIPPETS_DIR"🤖 Prompt for AI Agents
In @scripts/copy-zk-merkle-proof.sh around lines 6 - 9, The script currently
hardcodes PROGRAM_EXAMPLES and SNIPPETS_DIR which breaks portability; change it
to accept PROGRAM_EXAMPLES and SNIPPETS_DIR from environment or command-line
args and fall back to repo-relative defaults computed from the script directory
(e.g., a SCRIPT_DIR derived from the script location) before calling mkdir -p;
update the variable assignments so $PROGRAM_EXAMPLES and $SNIPPETS_DIR are set
from provided args/env or from the computed repo-relative paths and ensure the
rest of the script uses those variables.
| wrap_code() { | ||
| local input_file="$1" | ||
| local output_file="$2" | ||
| local lang="$3" | ||
| echo "\`\`\`$lang" > "$output_file" | ||
| cat "$input_file" >> "$output_file" | ||
| echo '```' >> "$output_file" | ||
| echo "Created: $output_file" | ||
| } |
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.
Prefer printf + warn on missing inputs (current behavior silently produces partial snippet sets).
Proposed fix
wrap_code() {
local input_file="$1"
local output_file="$2"
local lang="$3"
- echo "\`\`\`$lang" > "$output_file"
- cat "$input_file" >> "$output_file"
- echo '```' >> "$output_file"
+ printf '```%s\n' "$lang" > "$output_file"
+ cat -- "$input_file" >> "$output_file"
+ printf '```\n' >> "$output_file"
echo "Created: $output_file"
}
# Circuit
if [ -f "$PROGRAM_EXAMPLES/circuits/merkle_proof.circom" ]; then
wrap_code "$PROGRAM_EXAMPLES/circuits/merkle_proof.circom" "$SNIPPETS_DIR/circuit.mdx" "circom expandable"
+else
+ echo "WARN: Missing $PROGRAM_EXAMPLES/circuits/merkle_proof.circom" >&2
fiAlso applies to: 22-34, 36-38
🤖 Prompt for AI Agents
In @scripts/copy-zk-merkle-proof.sh around lines 11 - 19, The wrap_code function
silently produces partial outputs and uses echo for backticks; update wrap_code
to validate its inputs and use printf and safe cat usage: in wrap_code (function
wrap_code) check that both input_file and output_file exist and are non-empty
and print a warning to stderr and return non-zero if the source is missing,
replace echo "\`\`\`$lang" with printf '```%s\n' "$lang" > "$output_file", use
cat -- "$input_file" to append, and replace the closing echo '```' with printf
'```\n' >> "$output_file"; also add existence warnings (to stderr) for the three
other snippet-generation blocks referenced (the blocks around lines 22-34 and
36-38) so they print a WARN with the missing source path when files are absent.
| PROGRAM_EXAMPLES="/home/tilo/Workspace/program-examples/zk/zk-nullifier" | ||
| SNIPPETS_DIR="/home/tilo/Workspace/docs/snippets/code-snippets/zk/nullifier" | ||
|
|
||
| mkdir -p "$SNIPPETS_DIR" |
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.
Hard-coded absolute paths make this script non-portable (same issue as merkle-proof script).
Proposed fix (same pattern)
-#!/bin/bash
+#!/usr/bin/env bash
+set -euo pipefail
+
+# Allow overrides: ./copy-zk-nullifier.sh [program_examples_dir] [snippets_dir]
+# (derive defaults relative to repo root)| wrap_code() { | ||
| local input_file="$1" | ||
| local output_file="$2" | ||
| local lang="$3" | ||
| echo "\`\`\`$lang" > "$output_file" | ||
| cat "$input_file" >> "$output_file" | ||
| echo '```' >> "$output_file" | ||
| echo "Created: $output_file" | ||
| } |
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.
Use printf and consider warnings on missing inputs to avoid silent partial outputs.
| | get_address_tree_v1() | get_address_tree_v2() | | ||
| | get_random_state_tree_info_v1() | get_random_state_tree_info() | |
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.
🧩 Analysis chain
🏁 Script executed:
head -n 80 snippets/ai-prompts/v1-to-v2-migration.mdx | tail -n 15Repository: Lightprotocol/docs-v2
Length of output: 567
🏁 Script executed:
cat -n snippets/ai-prompts/v1-to-v2-migration.mdx | sed -n '60,80p'Repository: Lightprotocol/docs-v2
Length of output: 1064
🏁 Script executed:
rg "get_address_tree_v1|get_address_tree_v2|get_random_state_tree_info" --type ts --type tsx --type js --type jsxRepository: Lightprotocol/docs-v2
Length of output: 92
🏁 Script executed:
rg "get_address_tree_v1|get_address_tree_v2|get_random_state_tree_info" --type rsRepository: Lightprotocol/docs-v2
Length of output: 91
🏁 Script executed:
rg "get_address_tree_v1|get_address_tree_v2|get_random_state_tree_info"Repository: Lightprotocol/docs-v2
Length of output: 4092
🏁 Script executed:
git ls-files | grep -E "\.(ts|js|rs)$" | head -20Repository: Lightprotocol/docs-v2
Length of output: 124
Rust functions incorrectly placed in TypeScript SDK section.
get_address_tree_v1(), get_address_tree_v2(), get_random_state_tree_info_v1(), and get_random_state_tree_info() are Rust SDK functions, not TypeScript. They should be moved to Phase 3 (Rust SDK replacements) to match their actual usage across Rust code snippets in the documentation.
🤖 Prompt for AI Agents
In @snippets/ai-prompts/v1-to-v2-migration.mdx around lines 74 - 75, The listed
functions are Rust SDK items wrongly placed under the TypeScript SDK section;
remove get_address_tree_v1(), get_address_tree_v2(),
get_random_state_tree_info_v1(), and get_random_state_tree_info() from the
TypeScript mappings and add them to Phase 3 (Rust SDK replacements) where Rust
examples live, updating the table rows and any surrounding prose so those four
symbols appear under the Rust SDK replacement list instead of the TypeScript SDK
section.
| <Tab title="Client"> | ||
|
|
||
|
|
||
| </Tab> | ||
|
|
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.
Remove or populate the empty “Client” tab.
An empty tab looks like a broken page section.
Proposed diff (remove the empty tab)
-<Tab title="Client">
-
-
-</Tab>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <Tab title="Client"> | |
| </Tab> |
🤖 Prompt for AI Agents
In @zk/compressed-account-zk.mdx around lines 195 - 199, The empty Client Tab
shown as <Tab title="Client"> is either removed or populated; either delete the
entire <Tab title="Client">...</Tab> block to avoid an empty tab, or add
meaningful content (brief description, usage, or links) inside the <Tab
title="Client"> element so the tab is not blank—update the
compressed-account-zk.mdx file by editing the <Tab title="Client"> block
accordingly.
| A minimal Solana program to create compressed accounts and verifies with Groth16 proofs. | ||
|
|
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.
Grammar: “create … and verify”.
Proposed diff
-A minimal Solana program to create compressed accounts and verifies with Groth16 proofs.
+A minimal Solana program to create compressed accounts and verify with Groth16 proofs.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| A minimal Solana program to create compressed accounts and verifies with Groth16 proofs. | |
| A minimal Solana program to create compressed accounts and verify with Groth16 proofs. |
🤖 Prompt for AI Agents
In @zk/compressed-account-zk.mdx around lines 215 - 216, The sentence currently
reads "A minimal Solana program to create compressed accounts and verifies with
Groth16 proofs"; change the verb to match the plural infinitive form so it reads
"A minimal Solana program to create compressed accounts and verify with Groth16
proofs." Locate the sentence in the zk/compressed-account-zk.mdx content and
replace the word "verifies" with "verify" to correct the grammar.
| 1. The required property for nullifiers is that they can not be created twice. | ||
| 2. On Solana, you typically would create a PDA account. Nullifier accounts must remain active, hence lock ~0.001 SOL in rent per nullifier PDA permanently. | ||
| 3. Light uses rent-free PDAs to track nullifiers in an address Merkle tree. | ||
| 4. The address tree is the nullifier set and indexed by Helius. You don’t need to index your own Merkle tree. | ||
|
|
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.
Fix small grammar/style nits (“cannot”, punctuation spacing).
Proposed diff
-1. The required property for nullifiers is that they can not be created twice.
+1. The required property for nullifiers is that they cannot be created twice.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| 1. The required property for nullifiers is that they can not be created twice. | |
| 2. On Solana, you typically would create a PDA account. Nullifier accounts must remain active, hence lock ~0.001 SOL in rent per nullifier PDA permanently. | |
| 3. Light uses rent-free PDAs to track nullifiers in an address Merkle tree. | |
| 4. The address tree is the nullifier set and indexed by Helius. You don’t need to index your own Merkle tree. | |
| 1. The required property for nullifiers is that they cannot be created twice. | |
| 2. On Solana, you typically would create a PDA account. Nullifier accounts must remain active, hence lock ~0.001 SOL in rent per nullifier PDA permanently. | |
| 3. Light uses rent-free PDAs to track nullifiers in an address Merkle tree. | |
| 4. The address tree is the nullifier set and indexed by Helius. You don't need to index your own Merkle tree. |
🧰 Tools
🪛 LanguageTool
[style] ~14-~14: Unless you want to emphasize “not”, use “cannot” which is more common.
Context: ...ed property for nullifiers is that they can not be created twice. 2. On Solana, you ty...
(CAN_NOT_PREMIUM)
🤖 Prompt for AI Agents
In @zk/nullifiers.mdx around lines 14 - 18, Fix minor grammar and punctuation
issues: change "can not" to "cannot", ensure each sentence ends with proper
punctuation and has correct spacing after commas and periods, remove any stray
spaces before punctuation (e.g., around the tilde in "~0.001 SOL"), and
normalize terms like "rent-free PDAs" (keep hyphen) and "address Merkle tree"
capitalization/spacing consistent with the document style.
| ADD AFTER WORKSHOP. | ||
|
|
||
|
|
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.
Remove the “ADD AFTER WORKSHOP.” placeholder before merging.
🤖 Prompt for AI Agents
In @zk/zk-with-light.mdx around lines 1 - 3, Remove the placeholder text "ADD
AFTER WORKSHOP." from the document and replace it with the intended final
content (or delete it if no content is ready) so the draft does not ship with
the placeholder; locate the string "ADD AFTER WORKSHOP." in the
zk-with-light.mdx content and either remove it or substitute the completed
section before merging.
| Privacy-preserving applications can use compressed accounts to store state rent-free. | ||
|
|
||
| Each compressed account contains: | ||
|
|
||
| - **owner**: The program that controls the account | ||
| - **data**: Application-specific state (credential, note, vote) | ||
| - **address**: A deterministic identifier derived from seeds | ||
|
|
||
| 1. For each compressed account, a cryptographic hash is computed and inserted into an on-chain Merkle tree. | ||
| 2. This hash commits to the account's state. The Merkle root—a single 32-byte value on-chain—secures all compressed state in the tree. | ||
| 3. These commitments are created during deposits, transfers, and | ||
| other interactions, and are subsequently spent (nullified) | ||
| when the UTXO is consumed. | ||
| 3. To spend private state, users generate a zero-knowledge proof to prove knowledge of the secret | ||
| associated with a commitment in the Merkle tree, accompanied by a unique nullifier. | ||
|
|
||
| The nullifier is derived deterministically: | ||
|
|
||
| nullifier = Poseidon(context, secret) | ||
|
|
||
| Once verified, the nullifier is recorded as an address in | ||
| an indexed address Merkle tree that prevents the same state from being spent twice. | ||
|
|
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.
Doc structure/readability: add a real heading + fix numbering (duplicate “3.”) and tighten terminology.
🤖 Prompt for AI Agents
In @zk/zk-with-light.mdx around lines 4 - 26, Add a clear section heading (e.g.,
"Compressed Accounts & Private Spending") above the paragraph, fix the ordered
list numbering so it reads 1–4 (remove the duplicate "3."), and tighten
terminology: use "commitment" consistently instead of "hash" where appropriate,
call the on-chain value "Merkle root (32 bytes)" and the per-account item
"commitment in the Merkle tree." Also clarify the nullifier derivation line to
read "nullifier = Poseidon(context, secret)" and explicitly say the nullifier is
then recorded in an indexed address Merkle tree to prevent double-spends.
Summary
Changes
zk/nullifiers.mdx- complete nullifier implementation guidezk/zk-compressed-accounts.mdx- ZK-friendly state storagezk/toolkits/groth16-solana.mdx- on-chain proof verificationzk/overview.mdx- ZK infrastructure overview with AI promptdocs.jsonSummary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.