|
| 1 | +#include "claim.h" |
| 2 | +#include "transcript.h" |
| 3 | + |
| 4 | +namespace spark { |
| 5 | + |
| 6 | +Claim::Claim(const GroupElement& F_, const GroupElement& G_, const GroupElement& H_, const GroupElement& U_): |
| 7 | + F(F_), G(G_), H(H_), U(U_) { |
| 8 | +} |
| 9 | + |
| 10 | +Scalar Claim::challenge( |
| 11 | + const Scalar& mu, |
| 12 | + const std::vector<unsigned char>& identifier, |
| 13 | + const std::vector<unsigned char>& message, |
| 14 | + const std::vector<GroupElement>& S, |
| 15 | + const std::vector<GroupElement>& T, |
| 16 | + const GroupElement& A1, |
| 17 | + const std::vector<GroupElement>& A2 |
| 18 | +) { |
| 19 | + Transcript transcript(LABEL_TRANSCRIPT_CLAIM); |
| 20 | + transcript.add("F", F); |
| 21 | + transcript.add("G", G); |
| 22 | + transcript.add("H", H); |
| 23 | + transcript.add("U", U); |
| 24 | + transcript.add("mu", mu); |
| 25 | + transcript.add("identifier", identifier); |
| 26 | + transcript.add("message", message); |
| 27 | + transcript.add("S", S); |
| 28 | + transcript.add("T", T); |
| 29 | + transcript.add("A1", A1); |
| 30 | + transcript.add("A2", A2); |
| 31 | + |
| 32 | + return transcript.challenge("c"); |
| 33 | +} |
| 34 | + |
| 35 | +void Claim::prove( |
| 36 | + const Scalar& mu, |
| 37 | + const std::vector<unsigned char>& identifier, |
| 38 | + const std::vector<unsigned char>& message, |
| 39 | + const std::vector<Scalar>& x, |
| 40 | + const std::vector<Scalar>& y, |
| 41 | + const std::vector<Scalar>& z, |
| 42 | + const std::vector<GroupElement>& S, |
| 43 | + const std::vector<GroupElement>& T, |
| 44 | + ChaumProof& proof |
| 45 | +) { |
| 46 | + // Check statement validity |
| 47 | + std::size_t n = x.size(); |
| 48 | + if (!(y.size() == n && z.size() == n && S.size() == n && T.size() == n)) { |
| 49 | + throw std::invalid_argument("Bad claim statement!"); |
| 50 | + } |
| 51 | + for (std::size_t i = 0; i < n; i++) { |
| 52 | + if (!(F*x[i] + G*y[i] + H*z[i] == S[i] && T[i]*x[i] + G*y[i] == U)) { |
| 53 | + throw std::invalid_argument("Bad claim statement!"); |
| 54 | + } |
| 55 | + } |
| 56 | + |
| 57 | + std::vector<Scalar> r; |
| 58 | + r.resize(n); |
| 59 | + std::vector<Scalar> s; |
| 60 | + s.resize(n); |
| 61 | + for (std::size_t i = 0; i < n; i++) { |
| 62 | + r[i].randomize(); |
| 63 | + s[i].randomize(); |
| 64 | + } |
| 65 | + Scalar t; |
| 66 | + t.randomize(); |
| 67 | + |
| 68 | + proof.A1 = H*t; |
| 69 | + proof.A2.resize(n); |
| 70 | + for (std::size_t i = 0; i < n; i++) { |
| 71 | + proof.A1 += F*r[i] + G*s[i]; |
| 72 | + proof.A2[i] = T[i]*r[i] + G*s[i]; |
| 73 | + } |
| 74 | + |
| 75 | + Scalar c = challenge(mu, identifier, message, S, T, proof.A1, proof.A2); |
| 76 | + |
| 77 | + proof.t1.resize(n); |
| 78 | + proof.t3 = t; |
| 79 | + Scalar c_power(c); |
| 80 | + for (std::size_t i = 0; i < n; i++) { |
| 81 | + if (c_power.isZero()) { |
| 82 | + throw std::invalid_argument("Unexpected challenge!"); |
| 83 | + } |
| 84 | + proof.t1[i] = r[i] + c_power*x[i]; |
| 85 | + proof.t2 += s[i] + c_power*y[i]; |
| 86 | + proof.t3 += c_power*z[i]; |
| 87 | + c_power *= c; |
| 88 | + } |
| 89 | +} |
| 90 | + |
| 91 | +bool Claim::verify( |
| 92 | + const Scalar& mu, |
| 93 | + const std::vector<unsigned char>& identifier, |
| 94 | + const std::vector<unsigned char>& message, |
| 95 | + const std::vector<GroupElement>& S, |
| 96 | + const std::vector<GroupElement>& T, |
| 97 | + const ChaumProof& proof |
| 98 | +) { |
| 99 | + // Check proof semantics |
| 100 | + std::size_t n = S.size(); |
| 101 | + if (!(T.size() == n && proof.A2.size() == n && proof.t1.size() == n)) { |
| 102 | + throw std::invalid_argument("Bad claim semantics!"); |
| 103 | + } |
| 104 | + |
| 105 | + Scalar c = challenge(mu, identifier, message, S, T, proof.A1, proof.A2); |
| 106 | + if (c.isZero()) { |
| 107 | + throw std::invalid_argument("Unexpected challenge!"); |
| 108 | + } |
| 109 | + std::vector<Scalar> c_powers; |
| 110 | + c_powers.emplace_back(c); |
| 111 | + for (std::size_t i = 1; i < n; i++) { |
| 112 | + c_powers.emplace_back(c_powers[i-1]*c); |
| 113 | + if (c_powers[i].isZero()) { |
| 114 | + throw std::invalid_argument("Unexpected challenge!"); |
| 115 | + } |
| 116 | + } |
| 117 | + |
| 118 | + // Weight the verification equations |
| 119 | + Scalar w; |
| 120 | + while (w.isZero()) { |
| 121 | + w.randomize(); |
| 122 | + } |
| 123 | + |
| 124 | + std::vector<Scalar> scalars; |
| 125 | + std::vector<GroupElement> points; |
| 126 | + scalars.reserve(3*n + 5); |
| 127 | + points.reserve(3*n + 5); |
| 128 | + |
| 129 | + // F |
| 130 | + Scalar F_scalar; |
| 131 | + for (std::size_t i = 0; i < n; i++) { |
| 132 | + F_scalar -= proof.t1[i]; |
| 133 | + } |
| 134 | + scalars.emplace_back(F_scalar); |
| 135 | + points.emplace_back(F); |
| 136 | + |
| 137 | + // G |
| 138 | + scalars.emplace_back(proof.t2.negate() - w*proof.t2); |
| 139 | + points.emplace_back(G); |
| 140 | + |
| 141 | + // H |
| 142 | + scalars.emplace_back(proof.t3.negate()); |
| 143 | + points.emplace_back(H); |
| 144 | + |
| 145 | + // U |
| 146 | + Scalar U_scalar; |
| 147 | + for (std::size_t i = 0; i < n; i++) { |
| 148 | + U_scalar += c_powers[i]; |
| 149 | + } |
| 150 | + U_scalar *= w; |
| 151 | + scalars.emplace_back(U_scalar); |
| 152 | + points.emplace_back(U); |
| 153 | + |
| 154 | + // A1 |
| 155 | + scalars.emplace_back(Scalar((uint64_t) 1)); |
| 156 | + points.emplace_back(proof.A1); |
| 157 | + |
| 158 | + // {A2} |
| 159 | + GroupElement A2_sum = proof.A2[0]; |
| 160 | + for (std::size_t i = 1; i < n; i++) { |
| 161 | + A2_sum += proof.A2[i]; |
| 162 | + } |
| 163 | + scalars.emplace_back(w); |
| 164 | + points.emplace_back(A2_sum); |
| 165 | + |
| 166 | + // {S} |
| 167 | + for (std::size_t i = 0; i < n; i++) { |
| 168 | + scalars.emplace_back(c_powers[i]); |
| 169 | + points.emplace_back(S[i]); |
| 170 | + } |
| 171 | + |
| 172 | + // {T} |
| 173 | + for (std::size_t i = 0; i < n; i++) { |
| 174 | + scalars.emplace_back(w.negate()*proof.t1[i]); |
| 175 | + points.emplace_back(T[i]); |
| 176 | + } |
| 177 | + |
| 178 | + secp_primitives::MultiExponent multiexp(points, scalars); |
| 179 | + // merged equalities and doing check in one multiexponentation, |
| 180 | + // for weighting we use random w |
| 181 | + return multiexp.get_multiple().isInfinity(); |
| 182 | +} |
| 183 | + |
| 184 | +} |
0 commit comments