Skip to content

Commit f61c323

Browse files
committed
WIP: spend transaction claims
1 parent ab389d8 commit f61c323

6 files changed

Lines changed: 379 additions & 3 deletions

File tree

src/Makefile.am

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -674,7 +674,9 @@ libspark_a_SOURCES = \
674674
libspark/f4grumble.h \
675675
libspark/f4grumble.cpp \
676676
libspark/bech32.h \
677-
libspark/bech32.cpp
677+
libspark/bech32.cpp \
678+
libspark/claim.h \
679+
libspark/claim.cpp
678680

679681
liblelantus_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
680682
liblelantus_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)

src/libspark/claim.cpp

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
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+
}

src/libspark/claim.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#ifndef FIRO_LIBSPARK_CLAIM_H
2+
#define FIRO_LIBSPARK_CLAIM_H
3+
4+
#include "chaum_proof.h"
5+
#include <secp256k1/include/MultiExponent.h>
6+
7+
namespace spark {
8+
9+
// A claim proof, which is used to assert control of the consumed coins in a spend transaction
10+
class Claim {
11+
public:
12+
Claim(const GroupElement& F, const GroupElement& G, const GroupElement& H, const GroupElement& U);
13+
14+
void prove(
15+
const Scalar& mu,
16+
const std::vector<unsigned char>& identifier,
17+
const std::vector<unsigned char>& message,
18+
const std::vector<Scalar>& x,
19+
const std::vector<Scalar>& y,
20+
const std::vector<Scalar>& z,
21+
const std::vector<GroupElement>& S,
22+
const std::vector<GroupElement>& T,
23+
ChaumProof& proof
24+
);
25+
bool verify(
26+
const Scalar& mu,
27+
const std::vector<unsigned char>& identifier,
28+
const std::vector<unsigned char>& message,
29+
const std::vector<GroupElement>& S,
30+
const std::vector<GroupElement>& T,
31+
const ChaumProof& proof
32+
);
33+
34+
private:
35+
Scalar challenge(
36+
const Scalar& mu,
37+
const std::vector<unsigned char>& identifier,
38+
const std::vector<unsigned char>& message,
39+
const std::vector<GroupElement>& S,
40+
const std::vector<GroupElement>& T,
41+
const GroupElement& A1,
42+
const std::vector<GroupElement>& A2
43+
);
44+
const GroupElement& F;
45+
const GroupElement& G;
46+
const GroupElement& H;
47+
const GroupElement& U;
48+
};
49+
50+
}
51+
52+
#endif

0 commit comments

Comments
 (0)