mpt-crypto
Confidential Multi-Purpose Tokens Cryptographic Library
Loading...
Searching...
No Matches
equality_proof.c
Go to the documentation of this file.
1
40
41#include "secp256k1_mpt.h"
42#include <openssl/sha.h>
43#include <openssl/rand.h>
44#include <string.h>
45#include <stdlib.h>
46
47/* --- Internal Helpers --- */
48
49static int pubkey_equal(const secp256k1_context* ctx, const secp256k1_pubkey* pk1, const secp256k1_pubkey* pk2) {
50 return secp256k1_ec_pubkey_cmp(ctx, pk1, pk2) == 0;
51}
52
53static int generate_random_scalar(const secp256k1_context* ctx, unsigned char* scalar) {
54 do {
55 if (RAND_bytes(scalar, 32) != 1) return 0;
56 } while (!secp256k1_ec_seckey_verify(ctx, scalar));
57 return 1;
58}
59
60static int compute_amount_point(const secp256k1_context* ctx, secp256k1_pubkey* mG, uint64_t amount) {
61 unsigned char amount_scalar[32] = {0};
62 /* Convert amount to 32-byte BIG-ENDIAN scalar */
63 for (int i = 0; i < 8; ++i) {
64 amount_scalar[31 - i] = (amount >> (i * 8)) & 0xFF;
65 }
66 return secp256k1_ec_pubkey_create(ctx, mG, amount_scalar);
67}
68
73 const secp256k1_context* ctx,
74 unsigned char* e_out,
75 const secp256k1_pubkey* c1, const secp256k1_pubkey* c2,
76 const secp256k1_pubkey* pk,
77 const secp256k1_pubkey* mG, /* NULL if amount == 0 */
78 const secp256k1_pubkey* T1, const secp256k1_pubkey* T2,
79 const unsigned char* tx_context_id)
80{
81 SHA256_CTX sha;
82 unsigned char buf[33];
83 unsigned char h[32];
84 size_t len;
85 const char* domain = "MPT_POK_PLAINTEXT_PROOF";
86
87 SHA256_Init(&sha);
88 SHA256_Update(&sha, domain, strlen(domain));
89
90 // C1, C2, Pk
91 len = 33; secp256k1_ec_pubkey_serialize(ctx, buf, &len, c1, SECP256K1_EC_COMPRESSED); SHA256_Update(&sha, buf, 33);
92 len = 33; secp256k1_ec_pubkey_serialize(ctx, buf, &len, c2, SECP256K1_EC_COMPRESSED); SHA256_Update(&sha, buf, 33);
93 len = 33; secp256k1_ec_pubkey_serialize(ctx, buf, &len, pk, SECP256K1_EC_COMPRESSED); SHA256_Update(&sha, buf, 33);
94
95 // mG (Only if nonzero, logic from original code implied this structure)
96 // Note: The original code had two separate functions. We unify them here.
97 if (mG) {
98 len = 33; secp256k1_ec_pubkey_serialize(ctx, buf, &len, mG, SECP256K1_EC_COMPRESSED); SHA256_Update(&sha, buf, 33);
99 }
100
101 // T1, T2
102 len = 33; secp256k1_ec_pubkey_serialize(ctx, buf, &len, T1, SECP256K1_EC_COMPRESSED); SHA256_Update(&sha, buf, 33);
103 len = 33; secp256k1_ec_pubkey_serialize(ctx, buf, &len, T2, SECP256K1_EC_COMPRESSED); SHA256_Update(&sha, buf, 33);
104
105 if (tx_context_id) {
106 SHA256_Update(&sha, tx_context_id, 32);
107 }
108
109 SHA256_Final(h, &sha);
111}
112
113/* --- Public API --- */
114
116 const secp256k1_context* ctx,
117 unsigned char* proof,
118 const secp256k1_pubkey* c1,
119 const secp256k1_pubkey* c2,
120 const secp256k1_pubkey* pk_recipient,
121 uint64_t amount,
122 const unsigned char* randomness_r,
123 const unsigned char* tx_context_id)
124{
125 unsigned char t[32];
126 unsigned char e[32];
127 unsigned char s[32];
128 unsigned char term[32];
129 secp256k1_pubkey T1, T2;
130 secp256k1_pubkey mG;
131 secp256k1_pubkey* mG_ptr = NULL;
132 size_t len;
133 int ok = 0;
134
135 /* 0. Validate witness */
136 if (!secp256k1_ec_seckey_verify(ctx, randomness_r)) goto cleanup;
137
138 /* 1. Generate random t */
139 if (!generate_random_scalar(ctx, t)) goto cleanup;
140
141 /* 2. Compute commitments T1 = t*G, T2 = t*Pk */
142 if (!secp256k1_ec_pubkey_create(ctx, &T1, t)) goto cleanup;
143
144 T2 = *pk_recipient;
145 if (!secp256k1_ec_pubkey_tweak_mul(ctx, &T2, t)) goto cleanup;
146
147 /* 3. Compute Challenge */
148 if (amount > 0) {
149 if (!compute_amount_point(ctx, &mG, amount)) goto cleanup;
150 mG_ptr = &mG;
151 }
152 compute_challenge_equality(ctx, e, c1, c2, pk_recipient, mG_ptr, &T1, &T2, tx_context_id);
153
154 /* 4. Compute s = t + e * r */
155 memcpy(s, t, 32);
156 memcpy(term, randomness_r, 32);
157 if (!secp256k1_ec_seckey_tweak_mul(ctx, term, e)) goto cleanup; // term = e*r
158 if (!secp256k1_ec_seckey_tweak_add(ctx, s, term)) goto cleanup; // s = t + e*r
159
160 /* 5. Serialize Proof */
161 unsigned char* ptr = proof;
162 len = 33;
163 if (!secp256k1_ec_pubkey_serialize(ctx, ptr, &len, &T1, SECP256K1_EC_COMPRESSED)) goto cleanup;
164 ptr += 33;
165
166 len = 33;
167 if (!secp256k1_ec_pubkey_serialize(ctx, ptr, &len, &T2, SECP256K1_EC_COMPRESSED)) goto cleanup;
168 ptr += 33;
169
170 memcpy(ptr, s, 32);
171
172 ok = 1;
173
174 cleanup:
175 OPENSSL_cleanse(t, 32);
176 OPENSSL_cleanse(term, 32);
177 // s is public output, but good practice to clean stack copy
178 OPENSSL_cleanse(s, 32);
179 return ok;
180}
182 const secp256k1_context* ctx,
183 const unsigned char* proof,
184 const secp256k1_pubkey* c1,
185 const secp256k1_pubkey* c2,
186 const secp256k1_pubkey* pk_recipient,
187 uint64_t amount,
188 const unsigned char* tx_context_id)
189{
190 secp256k1_pubkey T1, T2;
191 unsigned char s[32];
192 unsigned char e[32];
193 secp256k1_pubkey mG;
194 secp256k1_pubkey* mG_ptr = NULL;
195 const unsigned char* ptr = proof;
196
197 secp256k1_pubkey LHS, RHS, term;
198 const secp256k1_pubkey* pts[2];
199 int ok = 0; // Default to failure
200
201 /* 1. Deserialize */
202 if (!secp256k1_ec_pubkey_parse(ctx, &T1, ptr, 33)) goto cleanup; ptr += 33;
203 if (!secp256k1_ec_pubkey_parse(ctx, &T2, ptr, 33)) goto cleanup; ptr += 33;
204 memcpy(s, ptr, 32);
205
206 // Check s != 0
207 if (!secp256k1_ec_seckey_verify(ctx, s)) goto cleanup;
208
209 /* 2. Recompute Challenge */
210 if (amount > 0) {
211 if (!compute_amount_point(ctx, &mG, amount)) goto cleanup;
212 mG_ptr = &mG;
213 }
214 compute_challenge_equality(ctx, e, c1, c2, pk_recipient, mG_ptr, &T1, &T2, tx_context_id);
215
216 /* 3. Verify Equations */
217
218 /* --- Eq 1: s * G == T1 + e * C1 --- */
219 if (!secp256k1_ec_pubkey_create(ctx, &LHS, s)) goto cleanup; // s*G
220
221 term = *c1;
222 if (!secp256k1_ec_pubkey_tweak_mul(ctx, &term, e)) goto cleanup; // e*C1
223 pts[0] = &T1; pts[1] = &term;
224 if (!secp256k1_ec_pubkey_combine(ctx, &RHS, pts, 2)) goto cleanup; // T1 + e*C1
225
226 if (!pubkey_equal(ctx, &LHS, &RHS)) goto cleanup;
227
228 /* --- Eq 2: s * Pk == T2 + e * (C2 - mG) --- */
229
230 /* LHS = s * Pk */
231 LHS = *pk_recipient;
232 if (!secp256k1_ec_pubkey_tweak_mul(ctx, &LHS, s)) goto cleanup;
233
234 /* RHS Construction: Y = C2 - mG */
235 secp256k1_pubkey Y = *c2;
236 if (mG_ptr) {
237 secp256k1_pubkey neg_mG = *mG_ptr;
238 if (!secp256k1_ec_pubkey_negate(ctx, &neg_mG)) goto cleanup;
239 pts[0] = c2; pts[1] = &neg_mG;
240 if (!secp256k1_ec_pubkey_combine(ctx, &Y, pts, 2)) goto cleanup;
241 }
242
243 /* RHS = T2 + e * Y */
244 term = Y;
245 if (!secp256k1_ec_pubkey_tweak_mul(ctx, &term, e)) goto cleanup; // e*Y
246 pts[0] = &T2; pts[1] = &term;
247 if (!secp256k1_ec_pubkey_combine(ctx, &RHS, pts, 2)) goto cleanup;
248
249 if (!pubkey_equal(ctx, &LHS, &RHS)) goto cleanup;
250
251 ok = 1;
252
253 cleanup:
254 return ok;
255}
int secp256k1_equality_plaintext_verify(const secp256k1_context *ctx, const unsigned char *proof, const secp256k1_pubkey *c1, const secp256k1_pubkey *c2, const secp256k1_pubkey *pk_recipient, uint64_t amount, const unsigned char *tx_context_id)
Verifies a proof of knowledge of plaintext and randomness.
int secp256k1_equality_plaintext_prove(const secp256k1_context *ctx, unsigned char *proof, const secp256k1_pubkey *c1, const secp256k1_pubkey *c2, const secp256k1_pubkey *pk_recipient, uint64_t amount, const unsigned char *randomness_r, const unsigned char *tx_context_id)
Generates a proof that an ElGamal ciphertext correctly encrypts a known plaintext m and that the prov...
static void compute_challenge_equality(const secp256k1_context *ctx, unsigned char *e_out, const secp256k1_pubkey *c1, const secp256k1_pubkey *c2, const secp256k1_pubkey *pk, const secp256k1_pubkey *mG, const secp256k1_pubkey *T1, const secp256k1_pubkey *T2, const unsigned char *tx_context_id)
static int compute_amount_point(const secp256k1_context *ctx, secp256k1_pubkey *mG, uint64_t amount)
static int pubkey_equal(const secp256k1_context *ctx, const secp256k1_pubkey *pk1, const secp256k1_pubkey *pk2)
static int generate_random_scalar(const secp256k1_context *ctx, unsigned char *scalar)
void secp256k1_mpt_scalar_reduce32(unsigned char out32[32], const unsigned char in32[32])
Definition mpt_scalar.c:106