Longfellow ZK 0290cb32

Loading...
Searching...
No Matches
small.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_ANONCRED_SMALL_H_
16#define PRIVACY_PROOFS_ZK_LIB_CIRCUITS_ANONCRED_SMALL_H_
17
18#include <cstddef>
19#include <vector>
20
21#include "circuits/anoncred/small_io.h"
22#include "circuits/compiler/compiler.h"
23#include "circuits/ecdsa/verify_circuit.h"
24#include "circuits/logic/bit_plucker.h"
25#include "circuits/logic/memcmp.h"
26#include "circuits/logic/routing.h"
27#include "circuits/sha/flatsha256_circuit.h"
28
29 namespace proofs {
30
31// This class creates a circuit to verify the signatures in a "small" MDOC.
32// A small credential is a 183-byte document formatted as:
33// first_name 32 0
34// family_name 32 32
35// date_of_birth YYYYMMDD 64
36// gender B 72
37// age_over_X. BBBBBBB 73 [16, 18, 21, 25, 62, 65, 67]
38// issuerid BBBB 80
39// validfrom YYYYMMDD 84
40// validuntil YYYYMMDD 92
41// DPKX 32x 100
42// DPKY 32x 132
43// <arbitrary bytes of information>
44 template <class LogicCircuit, class Field, class EC, size_t kNumAttr>
45 class Small {
46 using EltW = typename LogicCircuit::EltW;
47 using Elt = typename LogicCircuit::Elt;
48 using Nat = typename Field::N;
49 using Ecdsa = VerifyCircuit<LogicCircuit, Field, EC>;
50 using EcdsaWitness = typename Ecdsa::Witness;
51
52 using v8 = typename LogicCircuit::v8;
53 using v32 = typename LogicCircuit::v32;
54 static constexpr size_t kIndexBits = 5;
55 static constexpr size_t kMaxSHABlocks = 7;
56 static constexpr size_t kMaxMsoLen = kMaxSHABlocks * 64 - 9;
57
58 using vind = typename LogicCircuit::template bitvec<kIndexBits>;
59 using Flatsha = FlatSHA256Circuit<LogicCircuit, BitPlucker<LogicCircuit, 3>>;
60 using RoutingL = Routing<LogicCircuit>;
61 using ShaBlockWitness = typename Flatsha::BlockWitness;
62
63 const LogicCircuit& lc_;
64 const EC& ec_;
65 const Nat& order_;
66
67 public:
68 class Witness {
69 public:
70 EltW e_;
71 EltW dpkx_, dpky_;
72
73 EcdsaWitness sig_;
74 EcdsaWitness dpk_sig_;
75
76 v8 in_[64 * kMaxSHABlocks]; /* input bytes, 64 * MAX */
77 v8 nb_; /* index of sha block that contains the real hash */
78 ShaBlockWitness sig_sha_[kMaxSHABlocks];
79
80 void input(QuadCircuit<Field>& Q, const LogicCircuit& lc) {
81 e_ = Q.input();
82 dpkx_ = Q.input();
83 dpky_ = Q.input();
84
85 sig_.input(Q);
86 dpk_sig_.input(Q);
87
88 nb_ = lc.template vinput<8>();
89
90 // sha input init =========================
91 for (size_t i = 0; i < 64 * kMaxSHABlocks; ++i) {
92 in_[i] = lc.template vinput<8>();
93 }
94 for (size_t j = 0; j < kMaxSHABlocks; j++) {
95 sig_sha_[j].input(Q);
96 }
97 }
98 };
99
100 struct OpenedAttribute {
101 v8 ind; /* index of attribute */
102 v8 len; /* length of attribute, 1--32 */
103 v8 v1[32]; /* attribute value */
104 void input(const LogicCircuit& lc) {
105 ind = lc.template vinput<8>();
106 len = lc.template vinput<8>();
107 for (size_t j = 0; j < 32; ++j) {
108 v1[j] = lc.template vinput<8>();
109 }
110 }
111 };
112
113 EltW repack(const v8 in[], size_t ind) const {
114 EltW h = lc_.konst(0);
115 EltW base = lc_.konst(0x2);
116 for (size_t i = 0; i < 32; ++i) {
117 for (size_t j = 0; j < 8; ++j) {
118 auto t = lc_.mul(&h, base);
119 auto tin = lc_.eval(in[ind + i][7 - j]);
120 h = lc_.add(&tin, t);
121 }
122 }
123 return h;
124 }
125
126 explicit Small(const LogicCircuit& lc, const EC& ec, const Nat& order)
127 : lc_(lc), ec_(ec), order_(order), sha_(lc), r_(lc) {}
128
129 void assert_credential(EltW pkX, EltW pkY, EltW hash_tr,
130 OpenedAttribute oa[/* NUM_ATTR */],
131 const v8 now[/*kDateLen*/], const Witness& vw) const {
132 Ecdsa ecc(lc_, ec_, order_);
133
134 ecc.verify_signature3(pkX, pkY, vw.e_, vw.sig_);
135 ecc.verify_signature3(vw.dpkx_, vw.dpky_, hash_tr, vw.dpk_sig_);
136
137 sha_.assert_message(kMaxSHABlocks, vw.nb_, vw.in_, vw.sig_sha_);
138
139 const Memcmp<LogicCircuit> CMP(lc_);
140 // // validFrom <= now
141 lc_.assert1(CMP.leq(kDateLen, &vw.in_[84], &now[0]));
142
143 // // now <= validUntil
144 lc_.assert1(CMP.leq(kDateLen, &now[0], &vw.in_[92]));
145
146 // // DPK_{x,y}
147 EltW dpkx = repack(vw.in_, 100);
148 EltW dpky = repack(vw.in_, 132);
149 lc_.assert_eq(&dpkx, vw.dpkx_);
150 lc_.assert_eq(&dpky, vw.dpky_);
151
152 // Attributes parsing
153 const v8 zz = lc_.template vbit<8>(0xff); // cannot appear in strings
154 std::vector<v8> cmp_buf(32);
155 for (size_t ai = 0; ai < kNumAttr; ++ai) {
156 r_.shift(oa[ai].ind, 32, &cmp_buf[0], kMaxMsoLen, vw.in_, zz, 3);
157 assert_attribute(32, oa[ai].len, &cmp_buf[0], &oa[ai].v1[0]);
158 }
159 }
160
161 private:
162 // Checks that an attribute id or attribute value is as expected.
163 // The len parameter holds the byte length of the expected id or value.
164 void assert_attribute(size_t max, const v8& vlen, const v8 got[/*max*/],
165 const v8 want[/*max*/]) const {
166 for (size_t j = 0; j < max; ++j) {
167 auto ll = lc_.vlt(j, vlen);
168 auto cmp = lc_.veq(got[j], want[j]);
169 lc_.assert_implies(&ll, cmp);
170 }
171 }
172
173 Flatsha sha_;
174 RoutingL r_;
175};
176} // namespace proofs
177
178#endif // PRIVACY_PROOFS_ZK_LIB_CIRCUITS_ANONCRED_SMALL_H_
proofs::FlatSHA256Circuit
Definition flatsha256_circuit.h:52
proofs::QuadCircuit
Definition compiler.h:50
proofs::Routing
Definition routing.h:108
proofs::Small::Witness
Definition small.h:68
proofs::VerifyCircuit
Definition verify_circuit.h:32
proofs::Small::OpenedAttribute
Definition small.h:100
proofs::VerifyCircuit::Witness
Definition verify_circuit.h:41