Skip to content

Groth16 setup gets stuck if invalid ptau file #622

@flipchan

Description

@flipchan

Hey,

Problem:

groth16 setup hangs indefinitely with corrupted/truncated ptau file (missing input validation)

Was trying to reuse a ptau file and it ended up running at 100% cpu at 12 hours, getting stuck in a loop when trying to reuse a ptau file.

12.5 h it was stuck at 100% cpu on one core:

ps waux | grep snarkjs                    
root     16466  100  0.5 11155740 92068 pts/161 Rl+ Apr15 741:48 node /usr/local/bin/snarkjs groth16 setup /tmp/erc20_output/withdraw_phase2_erc20.r1cs /tmp/erc20_output/pot19_final.ptau /tmp/erc20_output/withdraw_phase2_erc20_0000.zkey       

Description

Problem Statement

When running snarkjs groth16 setup with a corrupted or truncated .ptau (powers of tau) file, the command hangs indefinitely without producing any error output or timeout. This makes it impossible to distinguish between a legitimately slow operation and a failed one, causing automated pipelines and CI/CD workflows to stall.

Root Cause Analysis

The issue stems from missing input validation in the groth16 setup command when reading sections 12-15 of the ptau file. The code assumes the file is well-formed and attempts to read data without verifying that sufficient bytes remain in the file.

When the ptau file is truncated or corrupted:

  1. The code reads section headers that indicate how many bytes to read
  2. These values may be garbage or point beyond EOF
  3. The underlying stream operations wait indefinitely for data that will never arrive
  4. No timeout mechanism exists to recover from this state

Missing Validations

The following validations are absent in src/zkey_new.js:

  1. File size validation: No check that the ptau file size matches expected minimum for the circuit degree
  2. Section bounds checking: No verification that section data fits within file boundaries before reading
  3. Header integrity validation: Section headers are not validated against expected values
  4. Stream timeout handling: No timeout on read operations to detect stalled streams
  5. EOF detection: No proactive check for end-of-file before attempting reads

Comparison with FFLONK Setup

The FFLONK setup implementation (src/fflonk_setup.js) includes proper validation that catches this issue:

FFLONK (lines 115-120) - Proper validation:

// src/fflonk_setup.js:115-120
const sectionSize = await readUInt64(fd);
if (sectionSize > fileSize - currentPos) {
    throw new Error("Corrupted ptau file: section size exceeds file boundaries");
}
if (sectionSize === 0) {
    throw new Error("Corrupted ptau file: invalid section size (zero)");
}

Groth16 (lines 145-151) - Missing validation:

// src/zkey_new.js:145-151 - NO VALIDATION
const sectionSize = await readUInt64(fd);
// Proceeds to read sectionSize bytes without checking if they exist
const data = await read(fd, sectionSize);
// This will hang forever if sectionSize > remaining bytes

Expected Behavior

When provided with a corrupted or truncated ptau file, snarkjs groth16 setup should:

  1. Detect the corruption early in the setup process
  2. Throw a descriptive error message indicating the file is corrupted
  3. Exit with a non-zero status code
  4. Complete within a reasonable timeout (not hang indefinitely)

Reproduction Steps

# Create a valid ptau file
snarkjs powersoftau new bn128 19 pot19_0000.ptau -v
snarkjs powersoftau contribute pot19_0000.ptau pot19_0001.ptau --name="test" -v
snarkjs powersoftau prepare phase2 pot19_0001.ptau pot19_final.ptau -v

# Truncate it to simulate corruption
truncate -s 50% pot19_final.ptau

# Run setup - will hang forever with no output
snarkjs groth16 setup circuit.r1cs pot19_final.ptau output.zkey

Observed behavior: Command hangs indefinitely with no error output.

Expected behavior: Command should fail quickly with an error message about corrupted ptau file.

Proposed Fix

Add validation before reading sections 12-15 in src/zkey_new.js:

// src/zkey_new.js - Add before reading sections 12-15

async function validatePtauSection(fd, fileSize, expectedSection) {
    const pos = await fd.tell();
    const header = await readSectionHeader(fd);
    
    // Validate section number
    if (header.section !== expectedSection) {
        throw new Error(
            `Corrupted ptau file: expected section ${expectedSection}, got ${header.section}`
        );
    }
    
    // Validate section size doesn't exceed remaining file
    if (header.size > fileSize - await fd.tell()) {
        throw new Error(
            `Corrupted ptau file: section ${expectedSection} size (${header.size} bytes) ` +
            `exceeds remaining file size (${fileSize - await fd.tell()} bytes)`
        );
    }
    
    // Validate section size is non-zero
    if (header.size === 0) {
        throw new Error(
            `Corrupted ptau file: section ${expectedSection} has zero size`
        );
    }
    
    return header;
}

// Usage in setup function (around line 145):
const stats = await fd.stat();
const fileSize = stats.size;

// Validate each section before reading
for (const sectionNum of [12, 13, 14, 15]) {
    await validatePtauSection(fd, fileSize, sectionNum);
}

Additionally, add header validation using existing utilities from src/powersoftau_utils.js:

// src/powersoftau_utils.js:52-71 already provides header validation
// Import and use these functions in zkey_new.js:

const { validatePtauHeader, getExpectedPtauSize } = require('./powersoftau_utils');

// At the start of setup:
const header = await validatePtauHeader(fd);
const minExpectedSize = getExpectedPtauSize(header.power, header.curve);

if (fileSize < minExpectedSize) {
    throw new Error(
        `Corrupted ptau file: file size (${fileSize} bytes) is less than ` +
        `minimum expected size (${minExpectedSize} bytes) for power ${header.power}`
    );
}

Code References

File Lines Description
src/zkey_new.js 145-151 Missing bounds checking when reading ptau sections
src/fflonk_setup.js 115-120 Proper validation example that should be replicated
src/powersoftau_utils.js 52-71 Header validation utilities that should be used

Environment

  • snarkjs version: 0.7.5
  • OS: Linux Debian trixie

Impact

This bug affects:

  • CI/CD pipelines that use snarkjs for automated proving setup
  • Users who download ptau files from untrusted sources
  • Any workflow where ptau files may be interrupted during download
  • Development workflows testing with partial ptau files
    This also affetcts:
    SnarkJS stuck on Groth16 setup #614

Severity

High - Causes complete workflow blockage with no recovery mechanism.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions