Longfellow ZK 0290cb32
Loading...
Searching...
No Matches
node.h
1// Copyright 2025 Google LLC.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#ifndef PRIVACY_PROOFS_ZK_LIB_CIRCUITS_COMPILER_NODE_H_
16#define PRIVACY_PROOFS_ZK_LIB_CIRCUITS_COMPILER_NODE_H_
17
18#include <stddef.h>
19#include <stdint.h>
20
21#include <algorithm>
22#include <vector>
23
24#include "sumcheck/quad.h"
25#include "util/crc64.h"
26#include "util/panic.h"
27
28namespace proofs {
29
30struct term {
31 // size_t surrogate for storing things like depth and
32 // pointers to nodes, since we only really need 32 bits.
33 using size_t_for_storage = uint32_t;
34
35 size_t_for_storage ki; // index of the constant term into constants_[]
36 size_t_for_storage op0, op1;
37
38 term() = default;
39
40 // canonicalized by op0 <= op1
41 explicit term(size_t ki, size_t op0, size_t op1)
42 : ki(ki),
43 op0(std::min<size_t>(op0, op1)),
44 op1(std::max<size_t>(op0, op1)) {
45 // Terms with k=0 are not supposed to occur, since
46 // we represent a zero node as an empty list of terms.
47 // We represent Elt(0) as index ki=0 in the table of constants.
48 proofs::check(ki != 0, "ki != 0");
49 }
50
51 // special hack for assert0
52 struct assert0_type_hack {}; // so that we don't call this constructor
53 // accidentally
54 explicit term(size_t op, assert0_type_hack& hack)
55 : ki(/*kstore(f.zero())=*/0), op0(0), op1(op) {}
56
57 bool ltndx(const term& y) const {
58 if (op1 < y.op1) return true;
59 if (op1 > y.op1) return false;
60 return op0 < y.op0;
61 }
62 bool eqndx(const term& y) const { return (op1 == y.op1 && op0 == y.op0); }
63
64 // term is a constant
65 bool constant() const { return op0 == 0 && op1 == 0; }
66
67 // linear term k * (1 * op1)
68 bool linearp() const { return op0 == 0; }
69
70 bool operator==(const term& y) const {
71 return ki == y.ki && op0 == y.op0 && op1 == y.op1;
72 }
73};
74
75template <class Field>
76struct NodeInfoF {
77 using quad_corner_t = typename Quad<Field>::quad_corner_t;
78 using size_t_for_storage = term::size_t_for_storage;
79
80 static const constexpr quad_corner_t kWireIdUndefined = quad_corner_t(-1);
81
82 size_t_for_storage depth;
83 quad_corner_t desired_wire_id_for_input;
84 quad_corner_t desired_wire_id_for_output;
85 size_t_for_storage max_needed_depth;
86 bool is_needed;
87 bool is_output;
88 bool is_input;
89 bool is_assert0;
90
91 NodeInfoF()
92 : depth(0),
93 desired_wire_id_for_input(kWireIdUndefined),
94 desired_wire_id_for_output(kWireIdUndefined),
95 max_needed_depth(0),
96 is_needed(false),
97 is_output(false),
98 is_input(false),
99 is_assert0(false) {}
100
101 // we use the desired wire id only at the appropriate depth,
102 // and not e.g. for copy wires.
103 quad_corner_t desired_wire_id(size_t depth0, size_t depth_ub) const {
104 if (is_input && depth0 == 0) {
105 return desired_wire_id_for_input;
106 }
107 if (is_output && depth0 + 1 == depth_ub) {
108 return desired_wire_id_for_output;
109 }
110 return kWireIdUndefined;
111 }
112};
113
114template <class Field>
115struct NodeF {
116 using nodeinfo = NodeInfoF<Field>;
117 using quad_corner_t = typename Quad<Field>::quad_corner_t;
118
119 std::vector<term> terms;
120 nodeinfo info;
121
122 NodeF() = delete;
123 explicit NodeF(quad_corner_t id) : terms() {
124 info.is_input = true;
125 info.desired_wire_id_for_input = id;
126 }
127
128 explicit NodeF(size_t ki, size_t op0, size_t op1) : terms() {
129 if (ki != 0) {
130 terms.push_back(term(ki, op0, op1));
131 }
132 }
133
134 explicit NodeF(const std::vector<term>& terms) : terms(terms) {}
135
136 bool zero() const { return !info.is_input && terms.empty(); }
137 bool constant() const { return terms.size() == 1 && terms[0].constant(); }
138 bool linearp() const { return terms.size() == 1 && terms[0].linearp(); }
139
140 bool operator==(const NodeF& y) const {
141 if (info.is_input != y.info.is_input) return false;
142 if (info.desired_wire_id_for_input != y.info.desired_wire_id_for_input)
143 return false;
144 if (info.is_output != y.info.is_output) return false;
145 if (info.desired_wire_id_for_output != y.info.desired_wire_id_for_output)
146 return false;
147 if (info.is_input != y.info.is_input) return false;
148 if (terms.size() != y.terms.size()) return false;
149 size_t l = terms.size();
150 for (size_t i = 0; i < l; ++i) {
151 if (!(terms[i] == y.terms[i])) return false;
152 }
153 return true;
154 }
155 uint64_t hash() const {
156 uint64_t crc = 0x1;
157 crc = crc64::update(crc,
158 static_cast<uint64_t>(info.desired_wire_id_for_input));
159 crc = crc64::update(crc,
160 static_cast<uint64_t>(info.desired_wire_id_for_output));
161 crc = crc64::update(crc, info.is_input);
162 crc = crc64::update(crc, info.is_output);
163 size_t l = terms.size();
164 crc = crc64::update(crc, l);
165 for (size_t i = 0; i < l; ++i) {
166 crc = crc64::update(crc, terms[i].ki);
167 crc = crc64::update(crc, terms[i].op0);
168 crc = crc64::update(crc, terms[i].op1);
169 }
170 return crc;
171 }
172};
173
174} // namespace proofs
175
176#endif // PRIVACY_PROOFS_ZK_LIB_CIRCUITS_COMPILER_NODE_H_
Definition quad.h:37
Definition node.h:76
Definition node.h:30