github.com/consensys/gnark@v0.11.0/internal/backend/circuits/hint.go (about)

     1  package circuits
     2  
     3  import (
     4  	"fmt"
     5  	"math/big"
     6  
     7  	"github.com/consensys/gnark/frontend"
     8  	"github.com/consensys/gnark/std/math/bits"
     9  )
    10  
    11  type hintCircuit struct {
    12  	A, B frontend.Variable
    13  }
    14  
    15  func (circuit *hintCircuit) Define(api frontend.API) error {
    16  	res, err := api.Compiler().NewHint(mulBy7, 1, circuit.A)
    17  	if err != nil {
    18  		return fmt.Errorf("mulBy7: %w", err)
    19  	}
    20  	a7 := res[0]
    21  	_a7 := api.Mul(circuit.A, 7)
    22  
    23  	api.AssertIsEqual(a7, _a7)
    24  	api.AssertIsEqual(a7, circuit.B)
    25  	res, err = api.Compiler().NewHint(make3, 1)
    26  	if err != nil {
    27  		return fmt.Errorf("make3: %w", err)
    28  	}
    29  	c := res[0]
    30  	c = api.Mul(c, c)
    31  	api.AssertIsEqual(c, 9)
    32  
    33  	return nil
    34  }
    35  
    36  type vectorDoubleCircuit struct {
    37  	A []frontend.Variable
    38  	B []frontend.Variable
    39  }
    40  
    41  func (c *vectorDoubleCircuit) Define(api frontend.API) error {
    42  	res, err := api.Compiler().NewHint(dvHint, len(c.B), c.A...)
    43  	if err != nil {
    44  		return fmt.Errorf("double newhint: %w", err)
    45  	}
    46  	if len(res) != len(c.B) {
    47  		return fmt.Errorf("expected len %d, got %d", len(c.B), len(res))
    48  	}
    49  	for i := range res {
    50  		api.AssertIsEqual(api.Mul(2, c.A[i]), c.B[i])
    51  		api.AssertIsEqual(res[i], c.B[i])
    52  	}
    53  	return nil
    54  }
    55  
    56  type recursiveHint struct {
    57  	A frontend.Variable
    58  }
    59  
    60  func (circuit *recursiveHint) Define(api frontend.API) error {
    61  	// first hint produces wire w1
    62  	w1, _ := api.Compiler().NewHint(make3, 1)
    63  
    64  	// this linear expression is not recorded in a R1CS just yet
    65  	linearExpression := api.Add(circuit.A, w1[0])
    66  
    67  	// api.ToBinary calls another hint (bits.NBits) with linearExpression as input
    68  	// however, when the solver will resolve bits[...] it will need to detect w1 as a dependency
    69  	// in order to compute the correct linearExpression value
    70  	bits := api.ToBinary(linearExpression, 6)
    71  
    72  	a := api.FromBinary(bits...)
    73  
    74  	api.AssertIsEqual(a, 45)
    75  
    76  	return nil
    77  }
    78  
    79  func init() {
    80  	{
    81  		good := []frontend.Circuit{
    82  			&recursiveHint{
    83  				A: 42,
    84  			},
    85  		}
    86  
    87  		bad := []frontend.Circuit{
    88  			&recursiveHint{
    89  				A: 1,
    90  			},
    91  		}
    92  
    93  		addNewEntry("recursive_hint", &recursiveHint{}, good, bad, nil, make3, bits.GetHints()[1])
    94  	}
    95  
    96  	{
    97  		good := []frontend.Circuit{
    98  			&hintCircuit{
    99  				A: 42,
   100  				B: 42 * 7,
   101  			},
   102  		}
   103  
   104  		bad := []frontend.Circuit{
   105  			&hintCircuit{
   106  				A: 42,
   107  				B: 42,
   108  			},
   109  		}
   110  
   111  		addNewEntry("hint", &hintCircuit{}, good, bad, nil, mulBy7, make3)
   112  	}
   113  
   114  	{
   115  		good := []frontend.Circuit{
   116  			&vectorDoubleCircuit{
   117  				A: []frontend.Variable{
   118  					1, 2, 3, 4, 5, 6, 7, 8,
   119  				},
   120  				B: []frontend.Variable{
   121  					2, 4, 6, 8, 10, 12, 14, 16,
   122  				},
   123  			},
   124  		}
   125  
   126  		bad := []frontend.Circuit{
   127  			&vectorDoubleCircuit{
   128  				A: []frontend.Variable{
   129  					1, 2, 3, 4, 5, 6, 7, 8,
   130  				},
   131  				B: []frontend.Variable{
   132  					1, 2, 3, 4, 5, 6, 7, 8,
   133  				},
   134  			},
   135  		}
   136  		addNewEntry("multi-output-hint", &vectorDoubleCircuit{A: make([]frontend.Variable, 8), B: make([]frontend.Variable, 8)}, good, bad, nil, dvHint)
   137  	}
   138  }
   139  
   140  var mulBy7 = func(q *big.Int, inputs []*big.Int, result []*big.Int) error {
   141  	result[0].Mul(inputs[0], big.NewInt(7)).Mod(result[0], q)
   142  	return nil
   143  }
   144  
   145  var make3 = func(_ *big.Int, inputs []*big.Int, result []*big.Int) error {
   146  	result[0].SetUint64(3)
   147  	return nil
   148  }
   149  
   150  var dvHint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error {
   151  	two := big.NewInt(2)
   152  	for i := range inputs {
   153  		res[i].Mul(two, inputs[i])
   154  	}
   155  	return nil
   156  }