github.com/consensys/gnark@v0.11.0/internal/security_tests/advisory-9xcg/advisory_test.go (about)

     1  // Package advisory9xcg implements a test for advisory GHSA-9xcg-3q8v-7fq6.
     2  package advisory9xcg
     3  
     4  import (
     5  	"crypto/rand"
     6  	"fmt"
     7  	"math/big"
     8  	"testing"
     9  
    10  	"github.com/consensys/gnark-crypto/ecc"
    11  	"github.com/consensys/gnark-crypto/ecc/bn254"
    12  	"github.com/consensys/gnark/backend/groth16"
    13  	groth16_bn254 "github.com/consensys/gnark/backend/groth16/bn254"
    14  	"github.com/consensys/gnark/frontend"
    15  	"github.com/consensys/gnark/frontend/cs/r1cs"
    16  	"github.com/consensys/gnark/test"
    17  )
    18  
    19  type Circuit struct {
    20  	SecretWitness frontend.Variable `gnark:",private"`
    21  }
    22  
    23  func (circuit *Circuit) Define(api frontend.API) error {
    24  	// the goal of the test is to show that we are able to predict the private
    25  	// input solely from the stored commitment.
    26  	commitCompiler, ok := api.Compiler().(frontend.Committer)
    27  	if !ok {
    28  		return fmt.Errorf("compiler does not commit")
    29  	}
    30  
    31  	commit, err := commitCompiler.Commit(circuit.SecretWitness)
    32  	if err != nil {
    33  		return err
    34  	}
    35  
    36  	api.AssertIsDifferent(commit, 0)
    37  	api.AssertIsDifferent(circuit.SecretWitness, 0)
    38  	return nil
    39  }
    40  
    41  func TestAdvisory_ghsa_9xcg_3q8v_7fq6(t *testing.T) {
    42  	assert := test.NewAssert(t)
    43  	// the goal of the test is to show that we are able to predict the private
    44  	// input solely from the stored commitment
    45  
    46  	// Generating a random secret witness.
    47  	var bound int64 = 1024 // ten bits of entropy for testing
    48  	secretWitness, err := rand.Int(rand.Reader, big.NewInt(bound))
    49  	assert.NoError(err, "random generation failed")
    50  	assert.Log("random secret witness: ", secretWitness)
    51  
    52  	// Assigning some values.
    53  	assignment := Circuit{SecretWitness: secretWitness}
    54  	witness, err := frontend.NewWitness(&assignment, ecc.BN254.ScalarField())
    55  	assert.NoError(err, "witness creation failed")
    56  	witnessPublic, err := witness.Public()
    57  	assert.NoError(err, "witness public failed")
    58  
    59  	// Setup circuit
    60  	ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &Circuit{})
    61  	assert.NoError(err, "compilation failed")
    62  
    63  	// run the setup and prover
    64  	pk, vk, err := groth16.Setup(ccs)
    65  	assert.NoError(err, "setup failed")
    66  	proof, err := groth16.Prove(ccs, pk, witness)
    67  	assert.NoError(err, "proof failed")
    68  
    69  	// sanity check, check that the proof verifies
    70  	err = groth16.Verify(proof, vk, witnessPublic)
    71  	assert.NoError(err, "verification failed")
    72  
    73  	// we're ready to set up the attack. For that first we need to assert the
    74  	// exact types for being able to extract the proving key information.
    75  	pkConcrete, ok := pk.(*groth16_bn254.ProvingKey)
    76  	assert.True(ok, "unexpected type for proving key")
    77  	proofConcrete, ok := proof.(*groth16_bn254.Proof)
    78  	assert.True(ok, "unexpected type for proof")
    79  
    80  	var guessedCommitment bn254.G1Affine
    81  	for i := int64(0); i < bound; i++ {
    82  		// We check our guess for the secret witness.
    83  		guessedCommitment.ScalarMultiplication(&pkConcrete.CommitmentKeys[0].Basis[0], big.NewInt(int64(i)))
    84  		if guessedCommitment.Equal(&proofConcrete.Commitments[0]) {
    85  			assert.Fail("secret witness found: ", i)
    86  			return
    87  		}
    88  	}
    89  }