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