TheAlgorithms/Go · critical

panic(err)

Error message

panic(err)

What it means

In dsaParameterGeneration (cipher/dsa), choosing the N-bit prime q uses crypto/rand.Prime. If the cryptographic RNG fails, the code panics with panic(err) instead of returning an error. This is a hard crash: the library treats RNG failure as unrecoverable rather than propagating it to the caller.

Source

Thrown at cipher/dsa/dsa.go:63

// 2. Choose a N-bit prime q
// 3. Choose a L-bit prime p such that p-1 is a multiple of q
// 4. Choose an integer h randomly from the range [2, p-2]
// 5. Compute g = h^((p-1)/q) mod p
// 6. Return (p, q, g)
func (dsa *dsa) dsaParameterGeneration() {
	var err error
	p, q, bigInt := new(big.Int), new(big.Int), new(big.Int)
	one, g, h := big.NewInt(1), big.NewInt(1), big.NewInt(2)
	pBytes := make([]byte, L/8)

	// GPLoop is a label for the loop
	// We use this loop to change the prime q if we don't find a prime p
GPLoop:
	for {
		// 2. Choose a N-bit prime q
		q, err = rand.Prime(rand.Reader, N)
		if err != nil {
			panic(err)
		}

		for i := 0; i < 4*L; i++ {
			// 3. Choose a L-bit prime p such that p-1 is a multiple of q
			// In this case we generate a random number of L bits
			if _, err := io.ReadFull(rand.Reader, pBytes); err != nil {
				panic(err)
			}

			// This are the minimum conditions for p being a possible prime
			pBytes[len(pBytes)-1] |= 1 // p is odd
			pBytes[0] |= 0x80          // p has the highest bit set
			p.SetBytes(pBytes)

			// Instead of using (p-1)%q == 0
			// We ensure that p-1 is a multiple of q and validates if p is prime
			bigInt.Mod(p, q)
			bigInt.Sub(bigInt, one)

View on GitHub (pinned to 5ba447ec5f)

Solutions

  1. Fix the underlying entropy source so crypto/rand works (restore /dev/urandom access, fix container/VM configuration).
  2. Recover from the panic at the call boundary and translate it into a returned error.
  3. Replace the library's panic with error propagation (fork or upstream patch): return err from dsaParameterGeneration.

Example fix

// before
q, err = rand.Prime(rand.Reader, N)
if err != nil {
    panic(err)
}
// after
q, err = rand.Prime(rand.Reader, N)
if err != nil {
    return nil, fmt.Errorf("dsa: failed to generate prime q: %w", err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Go's crypto/rand cannot be pre-validated directly; verify entropy source availability
if _, err := os.Stat("/dev/urandom"); err != nil {
    return fmt.Errorf("entropy source unavailable: %w", err)
}

Type guard

func recoverDSAError() (err error) {
    if r := recover(); r != nil {
        if e, ok := r.(error); ok {
            err = fmt.Errorf("dsa parameter generation panicked: %w", e)
        } else {
            err = fmt.Errorf("dsa parameter generation panicked: %v", r)
        }
    }
    return
}

Try / catch

func generateParamsSafe(N, L int) (p *dsa.Params, err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("dsa: rng failure during parameter generation: %v", r)
        }
    }()
    return dsa.GenerateParameters(N, L)
}

Prevention

When it happens

Trigger: Calling any DSA key-generation entry point when crypto/rand.Reader cannot deliver bytes — e.g. a depleted or misconfigured entropy source, a sandboxed/containerized environment without proper /dev/urandom access, or a custom rand.Reader injected into the package that returns errors.

Common situations: Containers with restricted device access, stripped-down VMs or embedded systems low on entropy, tests that stub rand.Reader with a failing reader, or a broken/failed hardware RNG.

Related errors


AI-assisted analysis of TheAlgorithms/Go@5ba447ec5f (2026-09-02). Data as JSON: /api/errors/0ed5d9bdcbf5b764. Report an issue: GitHub.