Longfellow ZK 0290cb32

Loading...
Searching...
No Matches
mdoc_revocation.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_MDOC_MDOC_REVOCATION_H_
16#define PRIVACY_PROOFS_ZK_LIB_CIRCUITS_MDOC_MDOC_REVOCATION_H_
17
18#include <cstddef>
19
20#include "circuits/compiler/compiler.h"
21#include "circuits/ecdsa/verify_circuit.h"
22#include "circuits/logic/bit_plucker.h"
23#include "circuits/mdoc/mdoc_revocation_constants.h"
24#include "circuits/sha/flatsha256_circuit.h"
25
26 namespace proofs {
27
28// The first revocation approach works for small lists that are expected to
29// be small. In this case, the prover simply asserts that their identifier is
30// different from all the identifiers in the list.
31 template <class LogicCircuit>
32 class MdocRevocationList {
33 using EltW = typename LogicCircuit::EltW;
34
35 public:
36 explicit MdocRevocationList(const LogicCircuit& lc) : lc_(lc) {}
37
38 // This function asserts that a given identifier is not on a revocation list.
39 // The method is to assert that Prod_i (list[i) - id) != 0.
40 void assert_not_on_list(EltW list[], size_t list_size,
41 /* the witness */ EltW id, EltW prodinv) const {
42 EltW prod =
43 lc_.mul(0, list_size, [&](size_t i) { return lc_.sub(&list[i], id); });
44 EltW want_one = lc_.mul(&prod, prodinv);
45 lc_.assert_eq(&want_one, lc_.konst(lc_.one()));
46 }
47
48 const LogicCircuit& lc_;
49};
50
51// The second revocation approach works for larger lists. In this case, the
52// prover retrieves a witness that their credential is *not* on the revoked
53// list by presenting a signature of the span (l,r) and proving that their
54// revocation identifier rev_id satisfied l < rev_id < r.
55// Specifically, the format of the span is:
56// epoch || l || r
57// where epoch is a 64 bit integer, l and r are 256 bit integers. All of
58// the values are encoded in little endian order.
59 template <class LogicCircuit, class Field, class EC>
60 class MdocRevocationSpan {
61 using EltW = typename LogicCircuit::EltW;
62 using Nat = typename Field::N;
63 using Ecdsa = VerifyCircuit<LogicCircuit, Field, EC>;
64 using EcdsaWitness = typename Ecdsa::Witness;
65 using v8 = typename LogicCircuit::v8;
66 using v256 = typename LogicCircuit::v256;
67 using Flatsha =
68 FlatSHA256Circuit<LogicCircuit,
69 BitPlucker<LogicCircuit, kSHARevocationPluckerBits>>;
70 using ShaBlockWitness = typename Flatsha::BlockWitness;
71 using sha_packed_v32 = typename Flatsha::packed_v32;
72
73 public:
74 class Witness {
75 public:
76 EltW r_, s_, e_;
77 EcdsaWitness rev_sig_;
78 v8 preimage_[64 * 2]; // epoch || l || r in little endian order
79 v256 id_bits_;
80 v256 e_bits_;
81 ShaBlockWitness sha_[2];
82
83 void input(QuadCircuit<Field>& Q, const LogicCircuit& lc) {
84 r_ = Q.input();
85 s_ = Q.input();
86 e_ = Q.input();
87 rev_sig_.input(Q);
88 for (size_t i = 0; i < 64 * 2; ++i) {
89 preimage_[i] = lc.template vinput<8>();
90 }
91 id_bits_ = lc.template vinput<256>();
92 e_bits_ = lc.template vinput<256>();
93 for (size_t j = 0; j < 2; j++) {
94 sha_[j].input(Q);
95 }
96 }
97 };
98
99 explicit MdocRevocationSpan(const LogicCircuit& lc, const EC& ec,
100 const Nat& order)
101 : lc_(lc), ec_(ec), order_(order), sha_(lc) {}
102
103 // This function asserts that id is not on the revocation list by verifying
104 // that the signature (r,s) on the span (l,r) is valid, and then verifying
105 // that l < id < r. The argument (craPkX, craPkY) represent the public key
106 // of the issuer of the revocation list.
107 void assert_not_on_list(EltW craPkx, EltW craPkY,
108 /* the witness */ EltW id, Witness& vw) const {
109 Ecdsa ecc(lc_, ec_, order_);
110
111 ecc.verify_signature3(craPkx, craPkY, vw.e_, vw.rev_sig_);
112
113 lc_.vassert_is_bit(vw.e_bits_);
114 lc_.vassert_is_bit(vw.id_bits_);
115
116 // Check that e = hash(epoch || l || r)
117 auto two = lc_.template vbit<8>(2);
118 sha_.assert_message_hash(2, two, vw.preimage_, vw.e_bits_, vw.sha_);
119
120 // Check that the bits of e match the EltW for e.
121 auto twok = lc_.one();
122 auto est = lc_.konst(0);
123 for (size_t i = 0; i < 256; ++i) {
124 est = lc_.axpy(&est, twok, lc_.eval(vw.e_bits_[i]));
125 lc_.f_.add(twok, twok);
126 }
127 lc_.assert_eq(&est, vw.e_);
128
129 // // Check that l < id < r
130 v256 ll, rr;
131 for (size_t i = 0; i < 256; ++i) {
132 ll[i] = vw.preimage_[8 + i / 8][i % 8];
133 rr[i] = vw.preimage_[40 + i / 8][i % 8];
134 }
135 lc_.assert1(lc_.vlt(&ll, vw.id_bits_));
136 lc_.assert1(lc_.vlt(&vw.id_bits_, rr));
137 }
138
139 const LogicCircuit& lc_;
140 const EC& ec_;
141 const Nat& order_;
142 Flatsha sha_;
143};
144
145} // namespace proofs
146
147#endif // PRIVACY_PROOFS_ZK_LIB_CIRCUITS_MDOC_MDOC_REVOCATION_H_
proofs::BitPlucker
Definition bit_plucker.h:86
proofs::FlatSHA256Circuit
Definition flatsha256_circuit.h:52
proofs::MdocRevocationSpan::Witness
Definition mdoc_revocation.h:74
proofs::QuadCircuit
Definition compiler.h:50
proofs::VerifyCircuit
Definition verify_circuit.h:32
proofs::VerifyCircuit::Witness
Definition verify_circuit.h:41