VYPR
Critical severityNVD Advisory· Published Aug 8, 2021· Updated Aug 4, 2024

CVE-2021-38194

CVE-2021-38194

Description

An issue was discovered in the ark-r1cs-std crate before 0.3.1 for Rust. It does not enforce any constraints in the FieldVar::mul_by_inverse method. Thus, a prover can produce a proof that is unsound but is nonetheless verified.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

The ark-r1cs-std crate before 0.3.1 has an unconstrained mul_by_inverse method, allowing a prover to produce unsound but verified proofs.

Vulnerability

The ark-r1cs-std crate for Rust versions 0.2.0 up to (but not including) 0.3.1 contains a flaw in the FieldVar::mul_by_inverse method. The method does not enforce any R1CS constraints on the computation, meaning that the prover can supply arbitrary values without satisfying the intended mathematical relation. This affects all uses of the method, primarily in scalar multiplication for short_weierstrass::ProjectiveVar [1][3].

Exploitation

An attacker acting as a prover in a zero-knowledge proof system using the vulnerable ark-r1cs-std crate can craft a witness that does not respect the multiplicative inverse relationship. Because no constraints are enforced, the prover can generate a proof that passes verification despite being logically unsound. The attacker only needs the ability to create proofs using the affected code; no special network position or authentication is required beyond standard prover capabilities [2][3].

Impact

Successful exploitation allows a malicious prover to produce a proof that verifies as correct even though the underlying computation is invalid. This can lead to a complete breakdown of the soundness property of the zkSNARK system, potentially enabling the attacker to prove false statements and compromise the integrity of any application relying on the proof system (e.g., blockchain or privacy protocols). The CVSS severity is not yet assigned by NVD, but the RustSec advisory classifies this as a crypto-failure vulnerability [1][3].

Mitigation

The vulnerability is fixed in version 0.3.1 of ark-r1cs-std, released on July 9, 2021. The fix was implemented in commit 47ddbaa [2][3]. Users should update to >=0.3.1. No known workarounds exist for earlier versions. The crate is part of the arkworks ecosystem, which is an academic proof-of-concept and not recommended for production use without thorough review [4].

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
ark-r1cs-stdcrates.io
>= 0.2.0, < 0.3.10.3.1

Affected products

3

Patches

1
47ddbaa411af

Enforce `mul_by_inverse` (#70)

https://github.com/arkworks-rs/r1cs-stdWeikeng ChenJul 6, 2021via ghsa
3 files changed · +84 12
  • CHANGELOG.md+2 0 modified
    @@ -12,6 +12,8 @@
     
     ### Bug Fixes
     
    +- [\#70](https://github.com/arkworks-rs/r1cs-std/pull/70) Fix soundness issues of `mul_by_inverse` for field gadgets.
    +
     ## v0.3.0
     
     ### Breaking changes
    
  • src/fields/mod.rs+3 8 modified
    @@ -155,15 +155,10 @@ pub trait FieldVar<F: Field, ConstraintF: Field>:
         /// Computes `result` such that `self * result == Self::one()`.
         fn inverse(&self) -> Result<Self, SynthesisError>;
     
    -    /// Returns `(self / d)`. but requires fewer constraints than `self * d.inverse()`.
    -    /// It is up to the caller to ensure that `d` is non-zero,
    -    /// since in that case the result is unconstrained.
    +    /// Returns `(self / d)`.
    +    /// The constraint system will be unsatisfiable when `d = 0`.
         fn mul_by_inverse(&self, d: &Self) -> Result<Self, SynthesisError> {
    -        let d_inv = if self.is_constant() || d.is_constant() {
    -            d.inverse()?
    -        } else {
    -            Self::new_witness(self.cs(), || Ok(d.value()?.inverse().unwrap_or(F::zero())))?
    -        };
    +        let d_inv = d.inverse()?;
             Ok(d_inv * self)
         }
     
    
  • src/groups/curves/short_weierstrass/non_zero_affine.rs+79 4 modified
    @@ -164,20 +164,20 @@ where
     }
     
     #[cfg(test)]
    -mod test {
    +mod test_non_zero_affine {
         use crate::alloc::AllocVar;
         use crate::fields::fp::{AllocatedFp, FpVar};
         use crate::groups::curves::short_weierstrass::non_zero_affine::NonZeroAffineVar;
         use crate::groups::curves::short_weierstrass::ProjectiveVar;
         use crate::groups::CurveVar;
         use crate::R1CSVar;
    -    use ark_ec::SWModelParameters;
    +    use ark_ec::{ProjectiveCurve, SWModelParameters};
         use ark_relations::r1cs::ConstraintSystem;
         use ark_std::{vec::Vec, One};
         use ark_test_curves::bls12_381::{g1::Parameters as G1Parameters, Fq};
     
         #[test]
    -    fn test_non_zero_affine_cost() {
    +    fn correctness_test_1() {
             let cs = ConstraintSystem::<Fq>::new_ref();
     
             let x = FpVar::Var(
    @@ -216,7 +216,7 @@ mod test {
                     sum = sum + elem;
                 }
     
    -            let sum = sum.value().unwrap();
    +            let sum = sum.value().unwrap().into_affine();
                 (sum.x, sum.y)
             };
     
    @@ -242,4 +242,79 @@ mod test {
             assert_eq!(sum_a.0, sum_b.0);
             assert_eq!(sum_a.1, sum_b.1);
         }
    +
    +    #[test]
    +    fn correctness_test_2() {
    +        let cs = ConstraintSystem::<Fq>::new_ref();
    +
    +        let x = FpVar::Var(
    +            AllocatedFp::<Fq>::new_witness(cs.clone(), || {
    +                Ok(G1Parameters::AFFINE_GENERATOR_COEFFS.0)
    +            })
    +            .unwrap(),
    +        );
    +        let y = FpVar::Var(
    +            AllocatedFp::<Fq>::new_witness(cs.clone(), || {
    +                Ok(G1Parameters::AFFINE_GENERATOR_COEFFS.1)
    +            })
    +            .unwrap(),
    +        );
    +
    +        // The following code tests `double_and_add`.
    +        let sum_a = {
    +            let a = ProjectiveVar::<G1Parameters, FpVar<Fq>>::new(
    +                x.clone(),
    +                y.clone(),
    +                FpVar::Constant(Fq::one()),
    +            );
    +
    +            let mut cur = a.clone();
    +            cur.double_in_place().unwrap();
    +            for _ in 1..10 {
    +                cur.double_in_place().unwrap();
    +                cur = cur + &a;
    +            }
    +
    +            let sum = cur.value().unwrap().into_affine();
    +            (sum.x, sum.y)
    +        };
    +
    +        let sum_b = {
    +            let a = NonZeroAffineVar::<G1Parameters, FpVar<Fq>>::new(x, y);
    +
    +            let mut cur = a.double().unwrap();
    +            for _ in 1..10 {
    +                cur = cur.double_and_add(&a).unwrap();
    +            }
    +
    +            (cur.x.value().unwrap(), cur.y.value().unwrap())
    +        };
    +
    +        assert!(cs.is_satisfied().unwrap());
    +        assert_eq!(sum_a.0, sum_b.0);
    +        assert_eq!(sum_a.1, sum_b.1);
    +    }
    +
    +    #[test]
    +    fn soundness_test() {
    +        let cs = ConstraintSystem::<Fq>::new_ref();
    +
    +        let x = FpVar::Var(
    +            AllocatedFp::<Fq>::new_witness(cs.clone(), || {
    +                Ok(G1Parameters::AFFINE_GENERATOR_COEFFS.0)
    +            })
    +            .unwrap(),
    +        );
    +        let y = FpVar::Var(
    +            AllocatedFp::<Fq>::new_witness(cs.clone(), || {
    +                Ok(G1Parameters::AFFINE_GENERATOR_COEFFS.1)
    +            })
    +            .unwrap(),
    +        );
    +
    +        let a = NonZeroAffineVar::<G1Parameters, FpVar<Fq>>::new(x, y);
    +
    +        let _ = a.double_and_add(&a).unwrap();
    +        assert!(!cs.is_satisfied().unwrap());
    +    }
     }
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.