golang/go · error
crypto/rsa: precomputed values are inconsistent with the key
Error message
crypto/rsa: precomputed values are inconsistent with the key
What it means
Returned by PrivateKey.Validate when Precomputed.fips is non-nil but precomputedIsConsistent() returns false — i.e. the cached FIPS key handle was built for different N/E/D/p/q/dP/dQ/qInv than the key currently carries. This means somebody mutated the struct fields after Precompute (or after NewPrivateKey), invalidating the cached CRT values. The library treats this as a hard error rather than silently using stale CRT data.
Source
Thrown at src/crypto/rsa/rsa.go:252
// Validate performs basic sanity checks on the key.
// It returns nil if the key is valid, or else an error describing a problem.
//
// It runs faster on valid keys if run after [PrivateKey.Precompute].
func (priv *PrivateKey) Validate() error {
// We can operate on keys based on d alone, but they can't be encoded with
// [crypto/x509.MarshalPKCS1PrivateKey], which unfortunately doesn't return
// an error, so we need to reject them here.
if len(priv.Primes) < 2 {
return errors.New("crypto/rsa: missing primes")
}
// If Precomputed.fips is set and consistent, then the key has been
// validated by [rsa.NewPrivateKey] or [rsa.NewPrivateKeyWithoutCRT].
if priv.precomputedIsConsistent() {
return nil
}
if priv.Precomputed.fips != nil {
return errors.New("crypto/rsa: precomputed values are inconsistent with the key")
}
_, err := priv.precompute()
return err
}
func (priv *PrivateKey) precomputedIsConsistent() bool {
if priv.Precomputed.fips == nil {
return false
}
N, e, d, P, Q, dP, dQ, qInv := priv.Precomputed.fips.Export()
if !bigIntEqualToBytes(priv.N, N) || priv.E != e || !bigIntEqualToBytes(priv.D, d) {
return false
}
if len(priv.Primes) != 2 {
return P == nil && Q == nil && dP == nil && dQ == nil && qInv == nil
}
return bigIntEqualToBytes(priv.Primes[0], P) &&
bigIntEqualToBytes(priv.Primes[1], Q) &&View on GitHub (pinned to b6b368adc5)
Solutions
- Treat *rsa.PrivateKey as immutable after construction — build a fresh struct for a new key.
- If you must mutate, zero out priv.Precomputed (set Precomputed to PrecomputedValues{}) and call Precompute() again before Validate().
- Re-construct the key via rsa.NewPrivateKey / x509.ParsePKCS1PrivateKey to get a clean Precomputed handle.
Example fix
// before: mutate in place
priv.N = newN
err := priv.Validate() // err: precomputed values are inconsistent
// after: reset and recompute, or rebuild
priv.Precomputed = rsa.PrecomputedValues{}
priv.Precompute()
err := priv.Validate() Defensive patterns
Strategy: validation
Validate before calling
// Reset cached precomputation before mutating a key, then recompute.
func safeMutate(priv *rsa.PrivateKey) {
priv.Precomputed = rsa.PrecomputedValues{}
// ... apply field changes ...
priv.Precompute()
} Prevention
- Treat *rsa.PrivateKey as immutable after construction.
- If you must reuse a variable, zero Precomputed before changing fields.
- Re-obtain keys from the parser instead of mutating in place.
When it happens
Trigger: Mutate priv.N, priv.E, priv.D, priv.Primes[i], or priv.Precomputed.Dp/Dq/Qinv after Precompute()/NewPrivateKey(); unmarshal a key on top of an already-precomputed one without resetting Precomputed.
Common situations: Reusing a *rsa.PrivateKey variable across keys to avoid allocation; a deserializer that fills fields in two passes (first N/E, then primes) after the struct was already Precomputed; test fixtures that mutate keys in place.
Related errors
- crypto/rsa: invalid prime
- crypto/rsa: p * q != n
- crypto/rsa: invalid CRT exponent
- crypto/rsa: invalid CRT coefficient
- crypto/rsa: d does not match dP
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/4883c3fb44ffe96c.
Report an issue: GitHub.