Skip to content

Refactor benchmark command to use engine abstraction and add Metal engine support with validation - #22

Open
italoag wants to merge 13 commits into
mainfrom
claude/security-audit-five-vulnerabilities-04alh4
Open

Refactor benchmark command to use engine abstraction and add Metal engine support with validation#22
italoag wants to merge 13 commits into
mainfrom
claude/security-audit-five-vulnerabilities-04alh4

Conversation

@italoag

@italoag italoag commented Sep 1, 2026

Copy link
Copy Markdown
Owner

italoag and others added 12 commits May 14, 2026 21:46
…or" and add Metal engine support with GPU batch size configuration
…etrics table including pattern info, difficulty breakdown, and success rates
…keystore fixes

CPU (12.8x faster, ~3.36M addr/s):
- Replace big.Int ScalarBaseMult with decred secp256k1 plus Jacobian
  point-addition chaining over a per-batch seed, batched inversion,
  one-shot Keccak, byte-level nibble matching, and a reused hasher
- Move chain initialization out of the worker loop and double-buffer
  refills to hide batch costs

Metal (27x faster, ~243k addr/s with validation):
- Kernel now reports match indices so CPU validation only re-checks
  matches (validation cost drops from 24.8s to ~2ms per 1M keys)
- Add fixed-base 4-bit comb table with precomputed Jacobian points
  and pooled Metal buffers to avoid per-batch allocation
- Rewrite field arithmetic as 4x64 limbs to dodge an MSL compiler
  stack-corruption bug with large 32-bit limb arrays; fix the wrap
  correction in fe_add (2^32 term was added to the wrong limb), a
  lost carry in fe_mul's t[k+2] += c1, the p-2 exponent constant,
  and the fe_inv loop skipping bit 0 (returned +/- z^-1)
- Verified against geth: comb table, kernel pubkeys, addresses, and
  full chain intermediates

Default path: auto resolves to CPU until Metal is competitive.

Keystore V3:
- Use geth naming convention UTC--<timestamp>--<address>.json and
  locate files by directory scan
- Derive the real Ethereum address in EncryptPrivateKey (was a
  zero placeholder) and enforce IV/ciphertext/MAC/salt lengths in
  Validate()
- use go env for install paths, platform detection, and version metadata
 - include Metal-aware darwin/arm64 builds and install/uninstall targets
 - ignore generated release binaries with a wildcard pattern
Upgrade vulnerable crypto and transitive modules to patched releases.
This clears all 15 Dependabot ranges and removes the reachable x/text
issue found by govulncheck.
Auditoria manual do código Go, do empacotamento, dos workflows de CI e do
histórico Git, com as cinco categorias solicitadas mapeadas para o equivalente
estrutural de uma CLI local (sem banco, sem auth, sem frontend).

13 achados verificados (4 altas, 3 médias, 5 baixas, 1 informativa) e 10 pontos
fortes. Destaques:

- F1 (alta): a engine CPU entrega chaves privadas Ethereum encadeadas
  (k0, k0+1, ... k0+4095), então carteiras da mesma execução não são
  independentes. Confirmado empiricamente contra a API real.
- F2/F3 (altas): senha do keystore V3 e chave Solana gravadas em texto claro
  ao lado dos artefatos cifrados.
- F4 (alta): backup de Bitcoin salva mnemônica que não deriva a chave gerada.
- F5/F8/F10: controles declarados na CLI que nunca chegam à camada que executa.
- F9/F12: injeção de script no workflow de release, action não pinada e
  dependabot.yml inerte.

Entrega o relatório em PDF e Markdown, mais o gerador (venv isolado com
reportlab+matplotlib) para regerar ambos a partir de docs/security-audit/achados.py.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VS3G7uWtzTjo1Vx3iDqiK5
Copilot AI lite review requested due to automatic review settings September 1, 2026 04:49

@amazon-q-developer amazon-q-developer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Summary

I've identified 3 critical defects that must be fixed before merging:

Critical Issues

  1. internal/engine/metal_darwin_arm64.go - Resource leak: Metal command buffer lacks deferred cleanup, causing GPU memory accumulation
  2. internal/worker/pool.go - Race condition: Unsynchronized worker.status access creates data race potential
  3. internal/cli/benchmark.go - Division by zero risk: Missing validation for iterations parameter can crash the application

All issues have been commented with specific code suggestions that can be committed directly.


You can now have the agent implement changes and create commits directly on your pull request's source branch. Simply comment with /q followed by your request in natural language to ask the agent to make changes.


⚠️ This PR contains more than 30 files. Amazon Q is better at reviewing smaller PRs, and may miss issues in larger changesets.

Comment thread internal/worker/pool.go
@@ -154,6 +154,26 @@ func (p *Pool) GetStatsCollector() *StatsCollector {
return p.statsCollector
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛑 Race Condition: Protect worker.status access with the mutex. The status field is accessed without holding the lock, creating a data race that can cause incorrect status reads or memory corruption in concurrent scenarios.

Suggested change
worker.mu.Lock()
defer worker.mu.Unlock()
if worker.status != StatusIdle {

Comment thread internal/cli/benchmark.go
metalValidation, err = resolveMetalValidationConfig(cmd, selection.Resolved, metalValidation)
if err != nil {
return benchmarkOptions{}, err
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛑 Crash Risk: Add validation to prevent division by zero. If iterations is zero, this will cause a panic that crashes the application.

Suggested change
}
if iterations == 0 {
return fmt.Errorf("iterations must be greater than zero")
}
avgTime := totalTime / time.Duration(iterations)

"constant uchar KECCAKF_ROTC[25] = {\n"
" 0, 1, 62, 28, 27,\n"
" 36, 44, 6, 55, 20,\n"
" 3, 10, 43, 25, 39,\n"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛑 Resource Leak: Add deferred cleanup for the Metal command buffer to prevent resource leaks when errors occur during encoding or commit operations. Without proper cleanup, GPU resources will accumulate and eventually cause memory pressure or crashes.

Suggested change
" 3, 10, 43, 25, 39,\n"
cmdBuffer := e.commandQueue.MakeCommandBuffer()
defer cmdBuffer.Release()

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Add engine abstraction, validated Metal support, and faster key generation

✨ Enhancement 🐞 Bug fix 🧪 Tests 📝 Documentation ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Adds selectable CPU and Metal engines for generation, benchmarking, and comparison.
• Accelerates Ethereum search while validating GPU results and clearing sensitive buffers.
• Improves benchmark outputs, TUI diagnostics, keystore compatibility, releases, and security
 documentation.
Diagram

graph TD
  CLI["CLI Commands"] --> RESOLVE["Engine Resolver"]
  RESOLVE --> CPU["CPU Engine"] --> MATCH["Vanity Matcher"]
  RESOLVE --> METAL["Metal Engine"] --> MATCH
  CPU --> CHAIN["Key Chain"]
  MATCH --> RESULT["Wallet Results"] --> UI["TUI and Files"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Independent random CPU keys
  • ➕ Preserves cryptographic independence between delivered wallets
  • ➕ Prevents one compromised key from exposing its batch
  • ➖ Loses much of the point-chaining throughput gain
  • ➖ Requires further optimization to recover performance
2. Precompiled Metal library
  • ➕ Avoids runtime shader compilation
  • ➕ Separates Metal source from Go and Objective-C glue
  • ➖ Complicates architecture-specific packaging
  • ➖ Requires reliable offline Metal toolchains
3. Benchmark-only Metal backend
  • ➕ Limits exposure while kernel correctness matures
  • ➕ Keeps production generation on the faster CPU path
  • ➖ Delays opt-in GPU wallet generation
  • ➖ Maintains separate benchmark and generation capabilities

Recommendation: The engine abstraction and full CPU verification of Metal candidates are sound. However, production CPU generation should not return sequential private scalars from a reused batch; use independently sampled keys or redesign the optimization before merge. Keeping Metal opt-in and publishing a separate validated artifact is appropriate until comparison data supports changing defaults.

Files changed (46) +11196 / -1005

Enhancement (14) +4674 / -756
benchmark.goImplement engine-based benchmarks and comparison matrices +1160/-0

Implement engine-based benchmarks and comparison matrices

• Adds validated option parsing, CPU/Auto/Metal execution, detailed metrics, stability recommendations, TUI updates, cancellation, and protected text or JSON output.

internal/cli/benchmark.go

commands.goWire engine selection into generation, stats, and TUI flows +364/-485

Wire engine selection into generation, stats, and TUI flows

• Adds engine and GPU flags, Metal workers, diagnostics, default TUI behavior, richer stats, and comparison commands. Removes the placeholder benchmark loop.

internal/cli/commands.go

chain.goAdd batched secp256k1 point-chaining generation +498/-0

Add batched secp256k1 point-chaining generation

• Introduces prefetched Jacobian point chains, batched affine conversion, specialized Keccak, and nibble matching. Consecutive private scalars within each reused batch are returned to callers.

internal/crypto/chain.go

cpu.goAdd the CPU benchmark engine +402/-0

Add the CPU benchmark engine

• Implements concurrent real-key benchmarking with attempt limits, sampling, stage timings, nibble matching, and buffer clearing.

internal/engine/cpu.go

metal_darwin_arm64.goImplement the Apple Silicon Metal engine +1301/-0

Implement the Apple Silicon Metal engine

• Adds Metal setup, secp256k1 comb arithmetic, Keccak and matching kernels, pooled buffers, generation and benchmarks, plus CPU verification of GPU matches.

internal/engine/metal_darwin_arm64.go

metal_unavailable.goProvide a portable Metal-unavailable implementation +21/-0

Provide a portable Metal-unavailable implementation

• Adds build-tagged capability reporting and clear errors for unsupported builds.

internal/engine/metal_unavailable.go

types.goDefine engine contracts and resolution rules +197/-0

Define engine contracts and resolution rules

• Introduces engine interfaces, options, samples, factories, fallback metadata, and mandatory full Metal verification. Auto generation currently prefers CPU.

internal/engine/types.go

benchmark_compare.goAdd an interactive benchmark comparison TUI +260/-0

Add an interactive benchmark comparison TUI

• Displays CPU, Auto, and Metal throughput, speedups, stability, errors, recommendations, and cancellable progress.

internal/tui/benchmark_compare.go

manager.goAdd engine-aware TUI model factories +22/-0

Add engine-aware TUI model factories

• Adds constructors for progress, benchmark, comparison, and stats models populated with engine diagnostics.

internal/tui/manager.go

progress.goShow engine diagnostics in generation progress +106/-3

Show engine diagnostics in generation progress

• Defines reusable engine metadata and renders engine, fallback, device, batch, validation, thread, and network details.

internal/tui/progress.go

stats.goAdd engine context to the stats TUI +39/-12

Add engine context to the stats TUI

• Initializes statistics synchronously, enables table focus, and renders engine diagnostics above the metrics.

internal/tui/stats.go

metal_pool.goAdapt Metal generation to the worker-pool contract +163/-0

Adapt Metal generation to the worker-pool contract

• Wraps Metal generation with secure logging, statistics, cancellation translation, cleanup, and WorkerPool compatibility.

internal/worker/metal_pool.go

pool.goUse chained CPU keys and shared vanity matching +95/-237

Use chained CPU keys and shared vanity matching

• Replaces per-attempt scalar multiplication with persistent per-worker point chains and byte-level Ethereum matching.

internal/worker/pool.go

types.goExpand wallet and benchmark engine metadata +46/-19

Expand wallet and benchmark engine metadata

• Adds engine selection, device, batch, validation, match, throughput, and stage-timing result fields.

pkg/wallet/types.go

Bug fix (2) +135 / -42
keystore.goFix Ethereum keystore address and geth compatibility +61/-8

Fix Ethereum keystore address and geth compatibility

• Derives the stored address from the private key, validates cryptographic field sizes, and adopts geth-style UTC filenames with legacy lookup fallback.

internal/crypto/keystore.go

benchmark.goImprove benchmark progress, completion, and engine display +74/-34

Improve benchmark progress, completion, and engine display

• Renders diagnostics and real progress, removes debug output, exposes cancellation state, and shows results immediately.

internal/tui/benchmark.go

Refactor (2) +185 / -7
logo.goRemove the obsolete commented logo +0/-7

Remove the obsolete commented logo

• Deletes an unused legacy ASCII logo block.

internal/tui/logo.go

matching.goCentralize vanity and EIP-55 matching +185/-0

Centralize vanity and EIP-55 matching

• Extracts shared prefix, suffix, case-sensitivity, checksum formatting, and validation logic.

internal/vanity/matching.go

Tests (10) +2059 / -50
commands_test.goTest CLI engine, benchmark, stats, and TUI behavior +639/-0

Test CLI engine, benchmark, stats, and TUI behavior

• Covers environment precedence, validation, comparison decisions, real CPU attempts, progress, address derivation, and diagnostics.

internal/cli/commands_test.go

chain_bench_test.goBenchmark chained keys and specialized Keccak +52/-0

Benchmark chained keys and specialized Keccak

• Measures custom 64-byte Keccak, reference SHA3, chain consumption, and batch refill costs.

internal/crypto/chain_bench_test.go

chain_test.goValidate chained key and hashing correctness +250/-0

Validate chained key and hashing correctness

• Cross-checks Keccak, private/public keys, Ethereum addresses, batch boundaries, and nibble matching against references.

internal/crypto/chain_test.go

keystore_geth_compat_test.goVerify keystores with the official geth decoder +89/-0

Verify keystores with the official geth decoder

• Tests existing artifacts and fresh round trips against go-ethereum decryption and address derivation.

internal/crypto/keystore_geth_compat_test.go

keystore_test.goUpdate keystore tests for strict sizes and UTC names +136/-50

Update keystore tests for strict sizes and UTC names

• Uses valid cryptographic fixtures and verifies geth-compatible filenames, lookup, permissions, and end-to-end workflows.

internal/crypto/keystore_test.go

comb_kernel_test.goCross-check Metal comb kernel public keys +70/-0

Cross-check Metal comb kernel public keys

• Compares GPU-derived public keys for known scalars with Decred secp256k1.

internal/engine/comb_kernel_test.go

comb_table_test.goValidate Metal comb tables and accumulation +152/-0

Validate Metal comb tables and accumulation

• Checks every precomputed table entry and representative kernel multiplication against CPU references.

internal/engine/comb_table_test.go

engine_test.goTest engine resolution and benchmark safety +354/-0

Test engine resolution and benchmark safety

• Covers fallback, Metal constraints, validation modes, CPU and Metal execution, key ranges, zeroization, and matching.

internal/engine/engine_test.go

metal_darwin_arm64_test.goTest Metal generation and input validation +174/-0

Test Metal generation and input validation

• Validates GPU derivation, batch bounds, scalar ranges, timings, metadata, and wallet generation on supported Macs.

internal/engine/metal_darwin_arm64_test.go

progress_test.goTest TUI engine metadata rendering +143/-0

Test TUI engine metadata rendering

• Covers empty metadata, CPU and Metal rows, and progress and benchmark engine blocks.

internal/tui/progress_test.go

Documentation (11) +3729 / -6
DockerfileRename the container description to Vanity Generator +1/-1

Rename the container description to Vanity Generator

• Updates the OCI image description to reflect the product's vanity-generation purpose.

Dockerfile

contracts.mdUpdate the documented CLI product name +1/-1

Update the documented CLI product name

• Changes the expected version output from Bloco-ETH to Bloco Vanity Generator.

_reversa_sdd/internal/cli/contracts.md

questions.mdAlign product-name decision records +2/-2

Align product-name decision records

• Replaces remaining Bloco-ETH references in CLI naming questions and recommendations.

_reversa_sdd/internal/cli/questions.md

CODE_ANALYSIS.mdRename the project in code analysis documentation +2/-2

Rename the project in code analysis documentation

• Uses Bloco Vanity Generator in the report overview and conclusion.

docs/CODE_ANALYSIS.md

README.mdDocument security audit artifacts and regeneration +58/-0

Document security audit artifacts and regeneration

• Explains the audit files, isolated Python setup, report generation, visual checks, and severity palette.

docs/security-audit/README.md

achados.pyAdd the structured security audit findings database +1197/-0

Add the structured security audit findings database

• Records 13 findings, verified strengths, prioritized recommendations, and ready-to-file issues covering cryptography, storage, CLI, and CI risks.

docs/security-audit/achados.py

gerar_relatorio.pyGenerate Markdown, PDF, and audit charts +1229/-0

Generate Markdown, PDF, and audit charts

• Adds a ReportLab and Matplotlib generator for formatted reports, severity summaries, category charts, and GitHub issue text.

docs/security-audit/gerar_relatorio.py

categoria-barras.pngAdd the audit findings category chart +0/-0

Add the audit findings category chart

• Adds the generated bar chart grouping findings by category and highest severity.

docs/security-audit/graficos/categoria-barras.png

severidade-rosca.pngAdd the audit severity distribution chart +0/-0

Add the audit severity distribution chart

• Adds the generated donut chart summarizing findings by severity.

docs/security-audit/graficos/severidade-rosca.png

relatorio-auditoria-seguranca.mdAdd the complete Markdown security audit +1239/-0

Add the complete Markdown security audit

• Publishes audit scope, stack mapping, 13 detailed findings, strengths, remediation priorities, and seven issue templates.

docs/security-audit/relatorio-auditoria-seguranca.md

relatorio-auditoria-seguranca.pdfAdd the rendered security audit PDF +0/-0

Add the rendered security audit PDF

• Provides the generated, formatted PDF edition of the security audit.

docs/security-audit/relatorio-auditoria-seguranca.pdf

Other (7) +414 / -144
release.yamlPublish an optional Metal-enabled macOS ARM64 release +58/-2

Publish an optional Metal-enabled macOS ARM64 release

• Adds a native macOS job that validates the Metal toolchain, builds with CGO, and conditionally uploads a separate archive.

.github/workflows/release.yaml

.gitignoreIgnore local and cross-platform binaries +2/-0

Ignore local and cross-platform binaries

• Excludes the default bloco-vgen binary and platform-suffixed build artifacts.

.gitignore

MakefileModernize builds and add native Metal targets +160/-94

Modernize builds and add native Metal targets

• Reworks toolchain, version, install, cross-build, and release handling. Native darwin/arm64 builds can include Metal while portable artifacts remain CPU-only.

Makefile

.gitignoreIgnore security-report Python environments +2/-0

Ignore security-report Python environments

• Excludes the local virtual environment and Python bytecode cache used by report generation.

docs/security-audit/.gitignore

go.modPromote secp256k1 and refresh cryptographic dependencies +16/-9

Promote secp256k1 and refresh cryptographic dependencies

• Makes Decred secp256k1 direct and upgrades x/crypto, x/term, and related transitive modules.

go.mod

go.sumRefresh checksums for upgraded dependencies +63/-39

Refresh checksums for upgraded dependencies

• Updates module checksums for the new secp256k1 and go-ethereum dependency graph.

go.sum

synthetic.goAdd deterministic matching helpers +113/-0

Add deterministic matching helpers

• Provides synthetic addresses and byte-level pattern helpers used to validate prefix and suffix behavior.

internal/engine/synthetic.go

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

This report is out of date. Scroll down for Devin Review's latest report on this PR.

Devin Review found 3 potential issues.

3 flags not posted on this PR by your GitHub settings — view them in Devin Review. (Configure)

Devin Review

Comment thread internal/worker/pool.go
Comment on lines +163 to +164
if workerID < len(p.chains) && p.chains[workerID] != nil {
return p.chains[workerID], nil

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Repeated generation corrupts shared key chains

For multiple wallets, unfinished workers reuse each PrivateKeyChain without synchronization. Concurrent NextKey calls can pair an address with the wrong private key.

Prompt for agents
Fix shared PrivateKeyChain concurrency in internal/worker/pool.go. GenerateWalletWithContext returns after one worker sends a result but does not cancel or join the other workers. The next call for multi-wallet generation retrieves the same chain by worker ID, so old and new workers call NextKey concurrently. Ensure each generation call stops and joins all workers before returning, and ensure a chain cannot be consumed concurrently. Preserve chain reuse only after the previous consumer has fully stopped.
Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread internal/crypto/chain.go
Comment on lines +348 to +353
chain := &PrivateKeyChain{
batches: make(chan *chainBatch, 1),
current: first,
}
go chain.filler()
return chain, nil

@devin-ai-integration devin-ai-integration Bot Sep 1, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 CPU benchmarks leak background workers

Each RunBenchmark worker leaves its key chain open after completion. Repeated benchmarks retain goroutines and large precomputed batches until process exit.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +1163 to +1167
stageStart = time.Now()
if !addressMatches(address[:], prefix, suffix) {
return stages, fmt.Errorf("metal match validation failed: gpu index %d is not a match", index)
}
stages.Match += time.Since(stageStart)

@devin-ai-integration devin-ai-integration Bot Sep 1, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Checksum benchmarks count invalid matches

With case-sensitive checksum criteria, validateMetalBatch checks only raw hexadecimal digits. Metal counts wrong-case addresses, making its totals incomparable with CPU results.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@qodo-code-review

qodo-code-review Bot commented Sep 1, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (6) 📘 Rule violations (2) 📜 Skill insights (0)

Grey Divider


Action required

1. Metal batch size unbounded 🐞 Bug ☼ Reliability
Description
The new Metal paths accept any positive CLI batch size and multiply it for Go and Metal allocations
without an upper-bound or overflow check. A very large --gpu-batch-size or benchmark
--batch-size can therefore panic on integer overflow/allocation or terminate the process through
memory exhaustion instead of returning validation error.
Code

internal/engine/metal_darwin_arm64.go[R849-852]

+	batchSize := options.BatchSize
+	if batchSize <= 0 {
+		batchSize = DefaultMetalBatchSize
+	}
Evidence
Generation preserves every positive batch size, then allocates attempts*32 bytes and passes the
resulting count into Metal buffer allocations. Both CLI entry points validate only > 0, despite
the existing worker configuration defining a 10,000 maximum batch size.

internal/engine/metal_darwin_arm64.go[849-872]
internal/engine/metal_darwin_arm64.go[1088-1095]
internal/engine/metal_darwin_arm64.go[473-486]
internal/cli/commands.go[1599-1605]
internal/cli/benchmark.go[161-168]
internal/config/config.go[79-89]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
User-controlled Metal batch sizes are only checked for positivity before being used in multiplied allocations.

## Issue Context
Define a safe maximum, reject values above it in both generation and benchmark option parsing, and use checked multiplication before all byte/buffer size calculations.

## Fix Focus Areas
- internal/engine/metal_darwin_arm64.go[849-872]
- internal/engine/metal_darwin_arm64.go[1088-1095]
- internal/cli/benchmark.go[161-168]
- internal/cli/commands.go[1599-1605]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Chain fillers never terminate ✓ Resolved 🐞 Bug ☼ Reliability
Description
Every NewPrivateKeyChain starts a filler that has no cancellation path and eventually blocks on
its one-slot channel forever. CPU benchmarks create one chain per worker per run, so completed
benchmarks leak goroutines plus their prefetched multi-array batches, causing memory usage to grow
across repeated runs.
Code

internal/crypto/chain.go[R348-352]

+	chain := &PrivateKeyChain{
+		batches: make(chan *chainBatch, 1),
+		current: first,
+	}
+	go chain.filler()
Evidence
Chain construction always launches filler; that function loops forever and its only send target is
a capacity-one channel. CPU benchmark workers create fresh chains, but no benchmark teardown closes
them, so after consumption stops each filler remains blocked while retaining its chain and batch
storage.

internal/crypto/chain.go[329-371]
internal/crypto/chain.go[381-389]
internal/engine/cpu.go[67-86]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Private-key chains start permanent filler goroutines, so completed benchmarks retain goroutines and large prefetched batches.

## Issue Context
Give `PrivateKeyChain` an idempotent close/cancel lifecycle, make the filler send select on cancellation, and ensure every owner closes chains when it is finished. Preserve cached pool chains until pool shutdown.

## Fix Focus Areas
- internal/crypto/chain.go[342-371]
- internal/engine/cpu.go[67-86]
- internal/worker/pool.go[131-149]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Security audit exceeds scope 📘 Rule violation ⚙ Maintainability
Description
The PR adds a 1,197-line security-audit data module plus a generator and generated reports, which is
unrelated to the stated benchmark-engine refactor and Metal support. This sweeping documentation
artifact tree has no rationale in the PR description and should be moved to a separately scoped
change.
Code

docs/security-audit/achados.py[R3-6]

+Base de dados da auditoria de segurança do bloco-vanity-generator.
+
+Este módulo concentra TODO o conteúdo do relatório (achados, pontos fortes,
+recomendações e issues do GitHub). Os geradores (`gerar_relatorio.py`) apenas
Evidence
Compliance rule 1772932 requires touched files to remain within the current change scope and calls
out large sweeping unrelated changes without documented rationale. The added module identifies
itself as the complete database for a security-audit report, while the PR is scoped to benchmark
engine abstraction and Metal support.

Rule 1772932: Do not remove or alter files outside the current change scope
docs/security-audit/achados.py[1-16]
docs/security-audit/README.md[3-13]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The large `docs/security-audit` artifact tree is outside this PR's benchmark and Metal-engine scope.

## Issue Context
The PR description provides no rationale for adding the audit database, report generator, generated Markdown/PDF reports, or graphs. Move these artifacts to a separately scoped PR.

## Fix Focus Areas
- docs/security-audit/achados.py[1-1197]
- docs/security-audit/gerar_relatorio.py[1-1229]
- docs/security-audit/README.md[1-58]
- docs/security-audit/relatorio-auditoria-seguranca.md[1-1239]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Stats overview no longer renders 🐞 Bug ≡ Correctness
Description
StatsModel.View replaces the pattern-overview rendering call with the new optional engine block
and never invokes renderPatternOverview elsewhere. Interactive stats output consequently loses its
pattern, difficulty, probability, and expected-attempt overview even when no engine information is
provided.
Code

internal/tui/stats.go[R177-180]

+	if block := m.renderEngineInfoBlock(pad); block != "" {
+		content.WriteString(block)
+		content.WriteString("\n")
+	}
Evidence
The changed View now renders the title, optional engine block, and table with no call to the
still-defined overview renderer. The stats CLI routes interactive output through this model.

internal/tui/stats.go[171-183]
internal/tui/stats.go[226-255]
internal/cli/commands.go[840-850]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Adding engine diagnostics accidentally removed the existing pattern overview from the stats view.

## Issue Context
Render the engine block in addition to, not instead of, `renderPatternOverview`, preserving appropriate spacing in both zero and nonzero engine-info cases.

## Fix Focus Areas
- internal/tui/stats.go[171-183]
- internal/tui/stats.go[226-255]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Keystore cleanup leaves duplicates 🐞 Bug ⛨ Security
Description
Timestamped naming now permits multiple keystore files for the same address, but lookup returns only
the first matching entry and RemoveKeystoreFiles deletes only that one. Re-saving an address and
then removing it can therefore leave other encrypted private-key files behind after the shared
password file is deleted.
Code

internal/crypto/keystore.go[R1950-1952]

+		name := entry.Name()
+		if strings.HasPrefix(name, "UTC--") && strings.HasSuffix(name, suffix) {
+			return filepath.Join(ks.config.OutputDirectory, name), nil
Evidence
Each save uses a fresh nanosecond timestamp, so repeated saves of the same address create distinct
filenames. Lookup stops at the first matching directory entry, while removal invokes lookup once and
removes only that path before deleting the one shared password file.

internal/crypto/keystore.go[1489-1495]
internal/crypto/keystore.go[1934-1956]
internal/crypto/keystore.go[1987-2017]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Address lookup selects one timestamped keystore although multiple files for the address can exist, making cleanup incomplete.

## Issue Context
For removal, enumerate and safely delete every regular file matching the exact geth address suffix (plus the legacy file). Keep single-file lookup deterministic if it remains needed for other callers.

## Fix Focus Areas
- internal/crypto/keystore.go[1492-1495]
- internal/crypto/keystore.go[1934-1956]
- internal/crypto/keystore.go[1987-2014]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View medium (3)
6. Comparison failures exit successfully 🐞 Bug ≡ Correctness
Description
runBenchmarkComparisonCase converts invalid criteria and CPU benchmark failures—including context
cancellation—into resultCase.Error, and the outer comparison always returns a nil error. As a
result, an interrupted or failed comparison can emit an error-bearing report while the CLI exits
with status 0, preventing automation from detecting that no valid comparison completed.
Code

internal/cli/benchmark.go[R344-347]

+	cpuResult, err := app.runBenchmarkEngine(ctx, cpuOptions, sampleInterval, nil)
+	if err != nil {
+		resultCase.Error = err.Error()
+		return resultCase
Evidence
Case validation and CPU errors return only a value with Error populated. The outer loop appends
that value and unconditionally returns (comparison, nil), and the command passes that nil error
back to Cobra.

internal/cli/benchmark.go[289-310]
internal/cli/benchmark.go[332-347]
internal/cli/benchmark.go[818-822]
internal/cli/commands.go[1039-1045]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Fatal comparison failures are stored as report text and never affect the command error or exit status.

## Issue Context
Keep expected Metal-unavailable results reportable, but propagate context cancellation, invalid criteria, and CPU/baseline failures from the comparison loop.

## Fix Focus Areas
- internal/cli/benchmark.go[289-310]
- internal/cli/benchmark.go[313-347]
- internal/cli/benchmark.go[818-822]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. Metal release metadata unset 🐞 Bug ≡ Correctness
Description
The new Metal release build sets lowercase linker symbols main.version, main.commit, and
main.date, while the executable reads main.Version, main.GitCommit, and main.BuildTime. The
published Metal artifact therefore retains dev/unknown metadata instead of its release version,
commit, and build time.
Code

.github/workflows/release.yaml[R183-185]

+        if CGO_ENABLED=1 GOOS=darwin GOARCH=arm64 go build \
+          -ldflags="-w -s -X main.version=${{ needs.create-release.outputs.version }} -X main.commit=${{ github.sha }} -X main.date=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
+          -o dist/bloco-vgen \
Evidence
The workflow's lowercase -X targets do not match the uppercase package variables passed to
cli.NewApplication, so the new artifact cannot receive the intended values.

.github/workflows/release.yaml[183-186]
cmd/bloco-vgen/main.go[17-21]
cmd/bloco-vgen/main.go[39-40]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The Metal release job injects linker values into symbol names that do not match the variables used by the executable.

## Issue Context
Go linker symbol names are case-sensitive. Align this job with the uppercase variables and use `BuildTime` rather than `date`.

## Fix Focus Areas
- .github/workflows/release.yaml[183-186]
- cmd/bloco-vgen/main.go[17-21]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. Protected Dockerfile was edited 📘 Rule violation § Compliance
Description
The PR changes the pre-existing Dockerfile, although repository policy protects every pre-existing
legacy-project file from modification and the PR description documents no approved exception.
Implement the metadata change without editing the protected file, or document the required exception
process.
Code

Dockerfile[94]

+    org.opencontainers.image.description="An Ethereum like Vanity Generator" \
Evidence
Compliance rule 627532 prohibits content edits to declared protected legacy files. Repository policy
declares all pre-existing legacy-project files protected at AGENTS.md[16-19], while the diff
changes the existing image-description line in Dockerfile.

Rule 627532: Protect legacy project files from modification or deletion
AGENTS.md[16-19]
Dockerfile[94-94]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The PR edits the pre-existing `Dockerfile`, which is protected by the repository's non-negotiable legacy-file policy.

## Issue Context
`AGENTS.md` states that pre-existing legacy-project files must never be deleted, modified, or overwritten. The PR description contains no documented approved exception.

## Fix Focus Areas
- Dockerfile[94-94]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

9. Generated chart links are broken 🐞 Bug ≡ Correctness
Description
The report generator writes chart references under gráficos/ with an accented character, while it
creates both images under graficos/. Every regenerated Markdown report therefore points to paths
that do not exist in the repository.
Code

docs/security-audit/gerar_relatorio.py[1037]

+    a("Gráficos: `gráficos/severidade-rosca.png` e `gráficos/categoria-barras.png`.")
Evidence
The script defines its output directory as graficos, saves both PNGs there, and the README
documents that same directory; only the generated Markdown reference uses gráficos.

docs/security-audit/gerar_relatorio.py[47-49]
docs/security-audit/gerar_relatorio.py[135-136]
docs/security-audit/gerar_relatorio.py[186-187]
docs/security-audit/gerar_relatorio.py[1037-1037]
docs/security-audit/README.md[10-13]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Generated Markdown references a differently spelled directory from the one receiving generated chart files.

## Issue Context
Use the unaccented `graficos/` path consistently in generated report text.

## Fix Focus Areas
- docs/security-audit/gerar_relatorio.py[1037-1037]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
✅ Compliance rules (platform): 3 rules
Review mode: ⚖️ Balanced

Grey Divider

Tip of the day
💡 Did you know, you can add REVIEW.md to your repo root and Qodo follows it on every PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread Dockerfile
# Add labels
LABEL org.opencontainers.image.title="bloco-vgen" \
org.opencontainers.image.description="An Ethereum like Wallet Generator" \
org.opencontainers.image.description="An Ethereum like Vanity Generator" \

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

1. Protected dockerfile was edited 📘 Rule violation § Compliance

The PR changes the pre-existing Dockerfile, although repository policy protects every pre-existing
legacy-project file from modification and the PR description documents no approved exception.
Implement the metadata change without editing the protected file, or document the required exception
process.
Agent Prompt
## Issue description
The PR edits the pre-existing `Dockerfile`, which is protected by the repository's non-negotiable legacy-file policy.

## Issue Context
`AGENTS.md` states that pre-existing legacy-project files must never be deleted, modified, or overwritten. The PR description contains no documented approved exception.

## Fix Focus Areas
- Dockerfile[94-94]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +3 to +6
Base de dados da auditoria de segurança do bloco-vanity-generator.

Este módulo concentra TODO o conteúdo do relatório (achados, pontos fortes,
recomendações e issues do GitHub). Os geradores (`gerar_relatorio.py`) apenas

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

2. Security audit exceeds scope 📘 Rule violation ⚙ Maintainability

The PR adds a 1,197-line security-audit data module plus a generator and generated reports, which is
unrelated to the stated benchmark-engine refactor and Metal support. This sweeping documentation
artifact tree has no rationale in the PR description and should be moved to a separately scoped
change.
Agent Prompt
## Issue description
The large `docs/security-audit` artifact tree is outside this PR's benchmark and Metal-engine scope.

## Issue Context
The PR description provides no rationale for adding the audit database, report generator, generated Markdown/PDF reports, or graphs. Move these artifacts to a separately scoped PR.

## Fix Focus Areas
- docs/security-audit/achados.py[1-1197]
- docs/security-audit/gerar_relatorio.py[1-1229]
- docs/security-audit/README.md[1-58]
- docs/security-audit/relatorio-auditoria-seguranca.md[1-1239]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread internal/crypto/chain.go
Comment on lines +849 to +852
batchSize := options.BatchSize
if batchSize <= 0 {
batchSize = DefaultMetalBatchSize
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

4. Metal batch size unbounded 🐞 Bug ☼ Reliability

The new Metal paths accept any positive CLI batch size and multiply it for Go and Metal allocations
without an upper-bound or overflow check. A very large --gpu-batch-size or benchmark
--batch-size can therefore panic on integer overflow/allocation or terminate the process through
memory exhaustion instead of returning validation error.
Agent Prompt
## Issue description
User-controlled Metal batch sizes are only checked for positivity before being used in multiplied allocations.

## Issue Context
Define a safe maximum, reject values above it in both generation and benchmark option parsing, and use checked multiplication before all byte/buffer size calculations.

## Fix Focus Areas
- internal/engine/metal_darwin_arm64.go[849-872]
- internal/engine/metal_darwin_arm64.go[1088-1095]
- internal/cli/benchmark.go[161-168]
- internal/cli/commands.go[1599-1605]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +183 to +185
if CGO_ENABLED=1 GOOS=darwin GOARCH=arm64 go build \
-ldflags="-w -s -X main.version=${{ needs.create-release.outputs.version }} -X main.commit=${{ github.sha }} -X main.date=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
-o dist/bloco-vgen \

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

5. Metal release metadata unset 🐞 Bug ≡ Correctness

The new Metal release build sets lowercase linker symbols main.version, main.commit, and
main.date, while the executable reads main.Version, main.GitCommit, and main.BuildTime. The
published Metal artifact therefore retains dev/unknown metadata instead of its release version,
commit, and build time.
Agent Prompt
## Issue description
The Metal release job injects linker values into symbol names that do not match the variables used by the executable.

## Issue Context
Go linker symbol names are case-sensitive. Align this job with the uppercase variables and use `BuildTime` rather than `date`.

## Fix Focus Areas
- .github/workflows/release.yaml[183-186]
- cmd/bloco-vgen/main.go[17-21]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread internal/cli/benchmark.go
Comment on lines +344 to +347
cpuResult, err := app.runBenchmarkEngine(ctx, cpuOptions, sampleInterval, nil)
if err != nil {
resultCase.Error = err.Error()
return resultCase

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

6. Comparison failures exit successfully 🐞 Bug ≡ Correctness

runBenchmarkComparisonCase converts invalid criteria and CPU benchmark failures—including context
cancellation—into resultCase.Error, and the outer comparison always returns a nil error. As a
result, an interrupted or failed comparison can emit an error-bearing report while the CLI exits
with status 0, preventing automation from detecting that no valid comparison completed.
Agent Prompt
## Issue description
Fatal comparison failures are stored as report text and never affect the command error or exit status.

## Issue Context
Keep expected Metal-unavailable results reportable, but propagate context cancellation, invalid criteria, and CPU/baseline failures from the comparison loop.

## Fix Focus Areas
- internal/cli/benchmark.go[289-310]
- internal/cli/benchmark.go[313-347]
- internal/cli/benchmark.go[818-822]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +1950 to +1952
name := entry.Name()
if strings.HasPrefix(name, "UTC--") && strings.HasSuffix(name, suffix) {
return filepath.Join(ks.config.OutputDirectory, name), nil

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

7. Keystore cleanup leaves duplicates 🐞 Bug ⛨ Security

Timestamped naming now permits multiple keystore files for the same address, but lookup returns only
the first matching entry and RemoveKeystoreFiles deletes only that one. Re-saving an address and
then removing it can therefore leave other encrypted private-key files behind after the shared
password file is deleted.
Agent Prompt
## Issue description
Address lookup selects one timestamped keystore although multiple files for the address can exist, making cleanup incomplete.

## Issue Context
For removal, enumerate and safely delete every regular file matching the exact geth address suffix (plus the legacy file). Keep single-file lookup deterministic if it remains needed for other callers.

## Fix Focus Areas
- internal/crypto/keystore.go[1492-1495]
- internal/crypto/keystore.go[1934-1956]
- internal/crypto/keystore.go[1987-2014]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread internal/tui/stats.go
Comment on lines +177 to +180
if block := m.renderEngineInfoBlock(pad); block != "" {
content.WriteString(block)
content.WriteString("\n")
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

8. Stats overview no longer renders 🐞 Bug ≡ Correctness

StatsModel.View replaces the pattern-overview rendering call with the new optional engine block
and never invokes renderPatternOverview elsewhere. Interactive stats output consequently loses its
pattern, difficulty, probability, and expected-attempt overview even when no engine information is
provided.
Agent Prompt
## Issue description
Adding engine diagnostics accidentally removed the existing pattern overview from the stats view.

## Issue Context
Render the engine block in addition to, not instead of, `renderPatternOverview`, preserving appropriate spacing in both zero and nonzero engine-info cases.

## Fix Focus Areas
- internal/tui/stats.go[171-183]
- internal/tui/stats.go[226-255]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

for cat, qtd in por_cat.items():
a("| %s | %d | %s |" % (cat, qtd, A.ROTULO_SEVERIDADE[pior_severidade(cat)].title()))
a("")
a("Gráficos: `gráficos/severidade-rosca.png` e `gráficos/categoria-barras.png`.")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Informational

9. Generated chart links are broken 🐞 Bug ≡ Correctness

The report generator writes chart references under gráficos/ with an accented character, while it
creates both images under graficos/. Every regenerated Markdown report therefore points to paths
that do not exist in the repository.
Agent Prompt
## Issue description
Generated Markdown references a differently spelled directory from the one receiving generated chart files.

## Issue Context
Use the unaccented `graficos/` path consistently in generated report text.

## Fix Focus Areas
- docs/security-audit/gerar_relatorio.py[1037-1037]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

There are build/release and runtime recovery issues (incorrect ldflags injection, GOPATH-derived install path edge case, and non-recovering chain failure handling) that should be fixed before approval.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR introduces an engine abstraction for generation/benchmarking, adds Metal engine plumbing and diagnostics, and refactors hot-path vanity matching/crypto to support higher-throughput execution and richer benchmark reporting.

Changes:

  • Added internal/engine abstraction (CPU + Metal availability scaffolding) and expanded result types with engine/device/batch diagnostics.
  • Refactored worker generation to use a chained private-key generator and centralized vanity matching helpers.
  • Enhanced TUI to display engine diagnostics and added benchmark comparison UI + expanded tests; updated keystore naming/validation for geth compatibility.
File summaries
File Description
pkg/wallet/types.go Extends generation/benchmark result structs with engine + validation diagnostics.
Makefile Reworked build/install targets with ldflags metadata and CGO policy for Metal.
internal/worker/pool.go Uses chained key generation and vanity matcher helpers in CPU worker pool.
internal/worker/metal_pool.go Adds a WorkerPool implementation backed by the engine abstraction for Metal generation.
internal/vanity/matching.go Centralizes address matching + checksum helpers for reuse.
internal/tui/stats.go Adds engine info rendering and adjusts table update flow.
internal/tui/progress.go Introduces EngineInfo and renders engine diagnostics in the progress TUI.
internal/tui/progress_test.go Tests engine info rows and rendering in TUI models.
internal/tui/manager.go Adds constructors that preload engine diagnostics into TUI models.
internal/tui/logo.go Removes unused old logo comments.
internal/tui/benchmark.go Adds engine diagnostics rendering; changes benchmark state/view behavior.
internal/tui/benchmark_compare.go New TUI for CPU vs Auto vs Metal benchmark comparison.
internal/engine/types.go Defines engine names/options, selection/validation logic, and factories.
internal/engine/synthetic.go Adds synthetic address generation + hex pattern nibble utilities.
internal/engine/metal_unavailable.go Non-darwin/arm64/cgo stub for Metal availability + constructor error.
internal/engine/metal_darwin_arm64_test.go Metal kernel and generation validation tests gated by build tags.
internal/engine/engine_test.go Tests engine resolution/validation and CPU/Metal benchmark behavior.
internal/engine/cpu.go Implements CPU benchmark engine using chained key generation + stage timings.
internal/engine/comb_table_test.go Validates Metal comb table correctness against reference implementations.
internal/engine/comb_kernel_test.go Validates Metal comb kernel-derived pubkeys against CPU references.
internal/crypto/keystore.go Strengthens keystore validation and switches to geth-compatible UTC filename format.
internal/crypto/keystore_test.go Updates tests for new keystore validation + filename lookup behavior.
internal/crypto/keystore_geth_compat_test.go Adds interop tests proving geth can decrypt generated keystores.
internal/crypto/chain.go Adds chained private-key generator, fast Keccak(64) impl, and nibble matcher utilities.
internal/crypto/chain_test.go Tests chained key derivation correctness and matcher consistency.
internal/crypto/chain_bench_test.go Benchmarks keccak and chain refill/NextKey performance.
internal/cli/commands_test.go Expands CLI tests for benchmark engine options, validation, and TUI engine info.
go.sum Updates dependency checksums for new/updated modules.
go.mod Adds secp256k1 dependency and bumps several golang.org/x/* / indirect deps.
docs/security-audit/README.md Documents how to regenerate the security audit report artifacts.
docs/security-audit/.gitignore Ignores venv and pycache for the audit tooling.
docs/CODE_ANALYSIS.md Updates product naming in analysis doc.
Dockerfile Updates OCI description string to “Vanity Generator”.
.gitignore Ignores built binaries (bloco-vgen, bloco-vgen-*).
.github/workflows/release.yaml Adds Metal-enabled macOS arm64 release job and notes in release text.
_reversa_sdd/internal/cli/questions.md Updates Q-CLI-011 content (product naming).
_reversa_sdd/internal/cli/contracts.md Updates version command contract output naming.
Review details
  • Files reviewed: 41/46 changed files
  • Comments generated: 4
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +183 to +186
if CGO_ENABLED=1 GOOS=darwin GOARCH=arm64 go build \
-ldflags="-w -s -X main.version=${{ needs.create-release.outputs.version }} -X main.commit=${{ github.sha }} -X main.date=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
-o dist/bloco-vgen \
./cmd/bloco-vgen; then
Comment thread Makefile
Comment on lines +28 to +34
# Binary install directory. `go env GOBIN` is empty unless explicitly set, so
# fall back to the computed GOPATH/bin. This matches `go install` semantics.
GOBIN := $(shell $(GOCMD) env GOBIN)
GOPATH := $(shell $(GOCMD) env GOPATH)
ifeq ($(strip $(GOBIN)),)
GOBIN := $(GOPATH)/bin
endif
Comment thread internal/worker/pool.go
Comment on lines +372 to 386
var keyBytes [32]byte
var pub [64]byte
keyBytes, pub, err = chain.NextKey()
if err != nil {
p.poolManager.GetCryptoPool().PutPrivateKeyBuffer(privateKeyBytes)
if p.logger != nil {
context := map[string]interface{}{
"worker_id": workerID,
"attempts": attempts,
}
if logErr := p.logger.LogError("address_generation", err, context); logErr != nil {
if logErr := p.logger.LogError("crypto_key_generation", err, context); logErr != nil {
_ = logErr
}
}
continue
}
Comment thread internal/tui/benchmark.go
Comment on lines 186 to 193
switch m.state {
case BenchmarkStateProgress:
return m.renderProgressView()
case BenchmarkStateTransitioning:
return m.renderTransitionView()
return m.renderProgressView()
case BenchmarkStateResults:
return m.renderResultsView()
return m.renderProgressView()
default:

@llamapreview llamapreview Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LlamaPReview — Blocking issues found

Default CPU generation emits sequential, correlated private keys within each 4096-key chain

Exact-head CI remains unresolved (4 failed); no CI-dependent merge-safety claim is made.

Owner action: Draw a fresh random seed for every emitted wallet or restore independent crypto/rand key generation on the CPU path; remove cross-call chain reuse in Pool.getChain. Add a test asserting two wallets from count=2 are not k, k+1. Reconcile the audit finding the cited evidence with the implementation.

4 further items in details.

Risk path

Tracks the flow from CLI invocation to escaped wallet keys, highlighting where the CPU chain correlation defect and the unverified Metal validation step sit.

sequenceDiagram
participant CLI as bloco-vgen generate
participant ENG as engine dispatch
participant CPU as CPU pool
participant MET as Metal pool
participant OUT as returned wallet
CLI->>ENG: getGenerationEngineOptions (auto/cpu/metal)
ENG->>CPU: ResolveGeneration auto → CPU (default)
ENG->>MET: ResolveGeneration metal (only if forced/available)
CPU->>CPU: Pool.getChain → seed k0
note over CPU: PR change — chain reused per worker across calls<br/>keys k0, k0+1, ..., k0+4095
critical CPU unsafe path
CPU->>OUT: wallet with k0+i key (correlated)
end
MET->>MET: GPU runMetalMatch + findValidatedMetalGenerationCandidate
note over MET: PR change — candidate validation bodies unseen
critical Metal uncertainty
MET->>OUT: wallet if candidate validated (unverified)
end
Loading
Review details and evidence
Priority File Finding Evidence
P1 internal/worker/pool.go Default CPU generation emits sequential, correlated private keys within each 4096-key chain confirmed
P1 internal/engine/cpu.go Lint fails with 13 unused/staticcheck issues, all in PR-created or modified files confirmed

Finding details

P1 · Lint fails with 13 unused/staticcheck issues, all in PR-created or modified files

internal/engine/cpu.go

The exact-head golangci-lint run exits 1 with 13 issues: unused transitionTime, renderTransitionView, renderResultsView (internal/tui/benchmark.go); unused StatsModel.renderPatternOverview (internal/tui/stats.go); unused resolveCommandEngine (internal/cli/benchmark.go); unused runEthereumAddressAttempt, runEthereumPublicKeyAttempt, generateEthereumPrivateKeyAttempt, throughputForDuration (internal/engine/cpu.go); staticcheck QF1008 in engine_test.go and commands_test.go; staticcheck S1000 (select with single channel case) in internal/crypto/chain.go. All flagged files are new or modified in this PR, so the lint regression blocks merge under the repository's lint gate.

Verification boundary: confirmed; scope: bounded reviewed context.

Material unknowns

  • The bodies of findValidatedMetalGenerationCandidate, NormalizeMetalValidationMode, and ValidateMetalGenerationCriteria could not be retrieved; whether Metal candidates are actually CPU-verified and key-range-checked before being returned is unestablished. If these helpers do not perform full CPU re-verification, the PR's 'Metal with validation' claim is not met; this decides whether the Metal objective closure is satisfied.
    • Check: Retrieve and read the three helper definitions in the exact-head source and confirm they validate candidates on CPU before returning.
  • The bodies of generateSingleWallet and generateMultipleWallets were not retrieved, so it is unknown whether persistence/keystore behavior beyond the chain swap changed on the CPU path. If these helpers changed keystore naming or persistence logic, there could be additional regressions not covered by the CPU key-source finding.
    • Check: Inspect generateSingleWallet/generateMultipleWallets in the exact-head source to confirm only the key-source change was made.
  • Callers of GetKeystoreFilePath were not observable; the new logic scans for UTC--...--.json and falls back to legacy only if not found, whereas the old behavior returned the legacy path unconditionally. If callers load keystores from directories containing only legacy files, the import/export/load flows may regress.
    • Check: Verify all callers of GetKeystoreFilePath handle legacy-only directories correctly and add a regression test if needed.

LlamaPReview checks

  • Reviewed changed regions in internal/worker/pool.go.
  • Reviewed changed regions in internal/crypto/chain.go.
  • Reviewed changed regions in internal/crypto/chain_test.go.
  • Reviewed changed regions in docs/security-audit/relatorio-auditoria-seguranca.md.
  • Reviewed changed regions in internal/engine/cpu.go.
  • Reviewed changed regions in internal/cli/benchmark.go.

LlamaPReview is an open-source pull request reviewer. See how a review is built, from signed webhook to publication.

Comment thread internal/worker/pool.go
// getChain returns the chained key generator for a worker, creating it on
// first use. Chains are reused across GenerateWalletWithContext calls so
// batch generation does not rebuild the (expensive) point chain per wallet.
func (p *Pool) getChain(workerID int) (*crypto.PrivateKeyChain, error) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 | Confidence: High

Pool.getChain persists one PrivateKeyChain per worker and reuses it across GenerateWalletWithContext calls. The chain emits k0, k0+1,..., k0+4095 and is refilled with a new seed after 4096 keys. Multiple wallets from one invocation (or repeated calls on the same pool) therefore have private keys separated by exactly 1, not independent randomness. Recovering any two keys from the same chain reveals the seed and all other keys in that chain. The PR's own audit report rates this as high severity. chain_test.go verifies the sequential invariant (expected key = k0 + i) and cross-checks derivation against go-ethereum, but no test asserts non-correlation across outputs.

Evidence: changed region in internal/worker/pool.go; changed region in internal/crypto/chain.go; changed region in internal/crypto/chain_test.go; changed region in docs/security-audit/relatorio-auditoria-seguranca.md.

Fecha #15, #16, #17, #18, #19, #20 e #21.

#15 Chaves privadas Ethereum entregues não eram independentes
A engine CPU varre candidatos em lotes encadeados (k0, k0+1, ...) e entregava
essas chaves como carteiras, então duas carteiras da mesma execução ficavam a
poucas unidades de distância. A cadeia agora é aposentada assim que entrega uma
chave (Pool.retireChain), de modo que cada chave entregue vem de um seed
próprio. PrivateKeyChain.Close encerra o filler, evitando vazar goroutine e
memória do lote a cada descarte.

#16 Segredos em texto claro ao lado dos artefatos cifrados
O arquivo <endereço>.pwd e o <endereço>.key do Solana passam a ser opt-in
(--write-password-file / --write-plaintext-key). A senha é exibida uma vez ao
fim da execução, ou vai para o arquivo de --output.

Ao corrigir isso apareceu um defeito maior que o relatado: a geração de
keystore para Solana falhava por completo (ToECDSA sobre chave Ed25519 de 64
bytes), então nada era gravado e a chave só existia no stdout. O endereço agora
é derivado apenas para secp256k1, a validação do ciphertext aceita 32 ou 64
bytes, e o .json do Solana guarda um KeyStore V3 realmente cifrado — em vez do
placeholder cujo campo "note" afirmava falsamente que a chave estava cifrada.

#17 Backup de Bitcoin não restaurava a carteira
A mnemônica era sorteada sem relação com a chave e era o único artefato salvo.
O caminho padrão agora persiste um KeyStore V3 cifrado (alternativa prevista na
issue) e não anexa mais mnemônica falsa. --with-mnemonic passa a funcionar para
Bitcoin derivando a chave de verdade em m/44'/0'/0'/0/0, espelhando o que o
Ethereum já fazia.

#18 Controles de KDF e de permissão nunca aplicados
Primeiro o piso de segurança do scrypt (n >= 16384 e 128*n*r >= 16 MiB,
espelhando o preset "low" como o piso do PBKDF2 já fazia), depois a ligação dos
parâmetros: EncryptPrivateKeyWithKDF passa a usar config.KDFParams, com cópia
do mapa para o salt não ser reaproveitado entre keystores. O piso é reaplicado
antes de cifrar. KeyStore.FileMode agora afeta as escritas e a validação recusa
qualquer bit fora de owner-rw.

#19 Permissões frouxas
Logs passam de 0644 para 0600 (na criação e na rotação, com chmod explícito
para arquivos pré-existentes) e o diretório de keystores de 0755 para 0700.
CheckDirectoryPermissions passa a inspecionar o modo: recusa diretório
world-writable e alerta sobre bits de grupo/outros.

#20 Cadeia de CI
github.event.inputs.tag sai do corpo do run: e passa por env, com validação por
regex de semver; as demais interpolações do release seguem o mesmo padrão.
trivy-action fixada em @0.28.0. dependabot.yml preenchido com gomod e
github-actions.

#21 Flags inertes e --network sem validação
--output e --format implementados (text/json/csv), gravando com 0600 e sem
imprimir a chave privada no terminal. Network validado por lista fechada em
GenerationCriteria.Validate, falhando antes de gerar qualquer chave.

Testes: 30 novos casos de regressão, incluindo um que reproduz o achado #15
(sem a correção, acusa carteiras a distância 1, 2, 3...). go test ./... e
go vet limpos; suíte completa também sob -race.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VS3G7uWtzTjo1Vx3iDqiK5

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

3 flags not posted on this PR by your GitHub settings — view them in Devin Review. (Configure)

Devin Review

Comment thread internal/cli/benchmark.go
resultCase.MetalSpeedupVsAuto = metalResult.AverageSpeed / resultCase.Auto.AverageSpeed
}
resultCase.MetalCoefficientOfVariation = benchmarkCoefficientOfVariation(metalResult.SpeedSamples)
resultCase.MetalStable = len(metalResult.SpeedSamples) > 1 && resultCase.MetalCoefficientOfVariation <= phase6StabilityCVThreshold

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Metal comparisons always report instability

Comparison runs omit the callback that collects SpeedSamples, then synthesize one sample. The two-sample stability gate can never accept Metal.

Prompt for agents
Decouple Metal speed-sample collection from the presence of an external callback. internal/engine/metal_darwin_arm64.go should collect interval samples whenever sampleInterval is positive, while invoking onSample only when non-nil. Then the comparison stability gate in internal/cli/benchmark.go can evaluate multiple real samples.
Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants