mpt-crypto
Confidential Multi-Purpose Tokens Cryptographic Library
Loading...
Searching...
No Matches
proof_link.c
Go to the documentation of this file.
1
44#include "secp256k1_mpt.h"
45#include <openssl/sha.h>
46#include <openssl/rand.h>
47#include <string.h>
48#include <assert.h>
49#include <stdio.h>
50
51/* --- Internal Helpers --- */
52
53static int pubkey_equal(const secp256k1_context* ctx, const secp256k1_pubkey* pk1, const secp256k1_pubkey* pk2) {
54 return secp256k1_ec_pubkey_cmp(ctx, pk1, pk2) == 0;
55}
56
57static int generate_random_scalar(const secp256k1_context* ctx, unsigned char* scalar_bytes) {
58 do {
59 if (RAND_bytes(scalar_bytes, 32) != 1) return 0;
60 } while (secp256k1_ec_seckey_verify(ctx, scalar_bytes) != 1);
61 return 1;
62}
63
65 const secp256k1_context* ctx,
66 unsigned char* e_out,
67 const secp256k1_pubkey* c1, const secp256k1_pubkey* c2,
68 const secp256k1_pubkey* pk, const secp256k1_pubkey* pcm,
69 const secp256k1_pubkey* T1, const secp256k1_pubkey* T2, const secp256k1_pubkey* T3,
70 const unsigned char* context_id)
71{
72 SHA256_CTX sha;
73 unsigned char buf[33];
74 unsigned char h[32];
75 size_t len;
76 const char* domain = "MPT_ELGAMAL_PEDERSEN_LINK";
77
78 SHA256_Init(&sha);
79 SHA256_Update(&sha, domain, strlen(domain));
80
81 /* Helper Macro */
82#define SER_AND_HASH(pk_ptr) do { \
83 len = 33; \
84 secp256k1_ec_pubkey_serialize(ctx, buf, &len, pk_ptr, SECP256K1_EC_COMPRESSED); \
85 SHA256_Update(&sha, buf, 33); \
86 } while(0)
87
88 SER_AND_HASH(c1);
89 SER_AND_HASH(c2);
90 SER_AND_HASH(pk);
91 SER_AND_HASH(pcm);
92 SER_AND_HASH(T1);
93 SER_AND_HASH(T2);
94 SER_AND_HASH(T3);
95
96#undef SER_AND_HASH
97
98 if (context_id) {
99 SHA256_Update(&sha, context_id, 32);
100 }
101
102 SHA256_Final(h, &sha);
104}
105
106/* --- Prover Implementation --- */
107
109 const secp256k1_context* ctx,
110 unsigned char* proof,
111 const secp256k1_pubkey* c1,
112 const secp256k1_pubkey* c2,
113 const secp256k1_pubkey* pk,
114 const secp256k1_pubkey* pcm,
115 uint64_t amount,
116 const unsigned char* r,
117 const unsigned char* rho,
118 const unsigned char* context_id)
119{
120 unsigned char km[32], kr[32], krho[32];
121 unsigned char e[32];
122 unsigned char sm[32], sr[32], srho[32];
123 unsigned char term[32];
124 unsigned char m_scalar[32] = {0};
125
126 secp256k1_pubkey T1, T2, T3;
127 secp256k1_pubkey H, mG;
128 size_t len;
129 int ok = 0;
130
131 /* 0. Validate Witnesses */
132 if (!secp256k1_ec_seckey_verify(ctx, r)) return 0;
133 if (!secp256k1_ec_seckey_verify(ctx, rho)) return 0;
134
135 /* 1. Generate Nonces */
136 if (!generate_random_scalar(ctx, km)) goto cleanup;
137 if (!generate_random_scalar(ctx, kr)) goto cleanup;
138 if (!generate_random_scalar(ctx, krho)) goto cleanup;
139
140 /* 2. Compute Commitments */
141
142 /* T1 = kr * G */
143 if (!secp256k1_ec_pubkey_create(ctx, &T1, kr)) goto cleanup;
144
145 /* T2 = km * G + kr * Pk */
146 if (!secp256k1_ec_pubkey_create(ctx, &mG, km)) goto cleanup; // km*G
147 secp256k1_pubkey krPk = *pk;
148 if (!secp256k1_ec_pubkey_tweak_mul(ctx, &krPk, kr)) goto cleanup; // kr*Pk
149 const secp256k1_pubkey* add_t2[2] = {&mG, &krPk};
150 if (!secp256k1_ec_pubkey_combine(ctx, &T2, add_t2, 2)) goto cleanup;
151
152 /* T3 = km * G + krho * H */
153 /* Note: mG (km*G) is reused here */
154 if (!secp256k1_mpt_get_h_generator(ctx, &H)) goto cleanup;
155 secp256k1_pubkey krhoH = H;
156 if (!secp256k1_ec_pubkey_tweak_mul(ctx, &krhoH, krho)) goto cleanup; // krho*H
157 const secp256k1_pubkey* add_t3[2] = {&mG, &krhoH};
158 if (!secp256k1_ec_pubkey_combine(ctx, &T3, add_t3, 2)) goto cleanup;
159
160 /* 3. Challenge */
161 build_link_challenge_hash(ctx, e, c1, c2, pk, pcm, &T1, &T2, &T3, context_id);
162
163 /* 4. Responses */
164 /* Convert amount to scalar */
165 for (int i = 0; i < 8; i++) m_scalar[31 - i] = (amount >> (i * 8)) & 0xFF;
166
167 /* sm = km + e * m */
168 memcpy(sm, km, 32);
169 memcpy(term, m_scalar, 32);
170 if (!secp256k1_ec_seckey_tweak_mul(ctx, term, e)) goto cleanup;
171 if (!secp256k1_ec_seckey_tweak_add(ctx, sm, term)) goto cleanup;
172
173 /* sr = kr + e * r */
174 memcpy(sr, kr, 32);
175 memcpy(term, r, 32);
176 if (!secp256k1_ec_seckey_tweak_mul(ctx, term, e)) goto cleanup;
177 if (!secp256k1_ec_seckey_tweak_add(ctx, sr, term)) goto cleanup;
178
179 /* srho = krho + e * rho */
180 memcpy(srho, krho, 32);
181 memcpy(term, rho, 32);
182 if (!secp256k1_ec_seckey_tweak_mul(ctx, term, e)) goto cleanup;
183 if (!secp256k1_ec_seckey_tweak_add(ctx, srho, term)) goto cleanup;
184
185 /* 5. Serialize Proof (195 bytes) */
186 unsigned char* ptr = proof;
187 len = 33; if (!secp256k1_ec_pubkey_serialize(ctx, ptr, &len, &T1, SECP256K1_EC_COMPRESSED)) goto cleanup; ptr += 33;
188 len = 33; if (!secp256k1_ec_pubkey_serialize(ctx, ptr, &len, &T2, SECP256K1_EC_COMPRESSED)) goto cleanup; ptr += 33;
189 len = 33; if (!secp256k1_ec_pubkey_serialize(ctx, ptr, &len, &T3, SECP256K1_EC_COMPRESSED)) goto cleanup; ptr += 33;
190
191 memcpy(ptr, sm, 32); ptr += 32;
192 memcpy(ptr, sr, 32); ptr += 32;
193 memcpy(ptr, srho, 32); ptr += 32;
194
195 ok = 1;
196
197 cleanup:
198 /* Securely clear secrets */
199 OPENSSL_cleanse(km, 32);
200 OPENSSL_cleanse(kr, 32);
201 OPENSSL_cleanse(krho, 32);
202 OPENSSL_cleanse(m_scalar, 32);
203 OPENSSL_cleanse(term, 32);
204 OPENSSL_cleanse(sm, 32);
205 OPENSSL_cleanse(sr, 32);
206 OPENSSL_cleanse(srho, 32);
207 return ok;
208}
209
210/* --- Verifier Implementation --- */
211
213 const secp256k1_context* ctx,
214 const unsigned char* proof,
215 const secp256k1_pubkey* c1,
216 const secp256k1_pubkey* c2,
217 const secp256k1_pubkey* pk,
218 const secp256k1_pubkey* pcm,
219 const unsigned char* context_id)
220{
221 secp256k1_pubkey T1, T2, T3;
222 secp256k1_pubkey LHS, RHS, term, mG, H;
223 const secp256k1_pubkey* pts[2];
224 unsigned char sm[32], sr[32], srho[32], e[32];
225 const unsigned char* ptr = proof;
226 int ok = 0;
227
228 /* 1. Deserialize */
229 if (!secp256k1_ec_pubkey_parse(ctx, &T1, ptr, 33)) goto cleanup; ptr += 33;
230 if (!secp256k1_ec_pubkey_parse(ctx, &T2, ptr, 33)) goto cleanup; ptr += 33;
231 if (!secp256k1_ec_pubkey_parse(ctx, &T3, ptr, 33)) goto cleanup; ptr += 33;
232
233 memcpy(sm, ptr, 32); ptr += 32;
234 memcpy(sr, ptr, 32); ptr += 32;
235 memcpy(srho, ptr, 32); ptr += 32;
236
237 /* Sanity Check Scalars */
238 if (!secp256k1_ec_seckey_verify(ctx, sm)) goto cleanup;
239 if (!secp256k1_ec_seckey_verify(ctx, sr)) goto cleanup;
240 if (!secp256k1_ec_seckey_verify(ctx, srho)) goto cleanup;
241
242 /* 2. Challenge */
243 build_link_challenge_hash(ctx, e, c1, c2, pk, pcm, &T1, &T2, &T3, context_id);
244
245 /* 3. Verification Equations */
246
247 /* Eq 1: sr * G == T1 + e * C1 */
248 {
249 if (!secp256k1_ec_pubkey_create(ctx, &LHS, sr)) goto cleanup; // sr*G
250
251 term = *c1;
252 if (!secp256k1_ec_pubkey_tweak_mul(ctx, &term, e)) goto cleanup; // e*C1
253 pts[0] = &T1; pts[1] = &term;
254 if (!secp256k1_ec_pubkey_combine(ctx, &RHS, pts, 2)) goto cleanup; // T1 + e*C1
255
256 if (!pubkey_equal(ctx, &LHS, &RHS)) goto cleanup;
257 }
258
259 /* Eq 2: sm * G + sr * Pk == T2 + e * C2 */
260 {
261 /* LHS = sm*G + sr*Pk */
262 if (!secp256k1_ec_pubkey_create(ctx, &mG, sm)) goto cleanup; // sm*G
263
264 term = *pk;
265 if (!secp256k1_ec_pubkey_tweak_mul(ctx, &term, sr)) goto cleanup; // sr*Pk
266
267 pts[0] = &mG; pts[1] = &term;
268 if (!secp256k1_ec_pubkey_combine(ctx, &LHS, pts, 2)) goto cleanup;
269
270 /* RHS = T2 + e*C2 */
271 term = *c2;
272 if (!secp256k1_ec_pubkey_tweak_mul(ctx, &term, e)) goto cleanup; // e*C2
273
274 pts[0] = &T2; pts[1] = &term;
275 if (!secp256k1_ec_pubkey_combine(ctx, &RHS, pts, 2)) goto cleanup;
276
277 if (!pubkey_equal(ctx, &LHS, &RHS)) goto cleanup;
278 }
279
280 /* Eq 3: sm * G + srho * H == T3 + e * Pcm */
281 {
282 /* LHS = sm*G (reusing mG calculated above) + srho*H */
283 if (!secp256k1_mpt_get_h_generator(ctx, &H)) goto cleanup;
284
285 term = H;
286 if (!secp256k1_ec_pubkey_tweak_mul(ctx, &term, srho)) goto cleanup; // srho*H
287
288 pts[0] = &mG; pts[1] = &term;
289 if (!secp256k1_ec_pubkey_combine(ctx, &LHS, pts, 2)) goto cleanup;
290
291 /* RHS = T3 + e*Pcm */
292 term = *pcm;
293 if (!secp256k1_ec_pubkey_tweak_mul(ctx, &term, e)) goto cleanup; // e*Pcm
294
295 pts[0] = &T3; pts[1] = &term;
296 if (!secp256k1_ec_pubkey_combine(ctx, &RHS, pts, 2)) goto cleanup;
297
298 if (!pubkey_equal(ctx, &LHS, &RHS)) goto cleanup;
299 }
300
301 ok = 1;
302
303 cleanup:
304 return ok;
305}
int secp256k1_mpt_get_h_generator(const secp256k1_context *ctx, secp256k1_pubkey *h)
Derives the secondary base point (H) for Pedersen commitments.
void secp256k1_mpt_scalar_reduce32(unsigned char out32[32], const unsigned char in32[32])
Definition mpt_scalar.c:106