68 const secp256k1_context* ctx,
71 const secp256k1_pubkey* R,
72 const secp256k1_pubkey* S,
73 const secp256k1_pubkey* Pk,
74 const secp256k1_pubkey* Tm,
75 const secp256k1_pubkey* TrG,
76 const secp256k1_pubkey* TrP,
77 const unsigned char* tx_id
80 unsigned char buf[33];
84 const char* domain =
"MPT_POK_SAME_PLAINTEXT_PROOF";
87 SHA256_Update(&sha, domain, strlen(domain));
90 for (i = 0; i < n; ++i) {
92 secp256k1_ec_pubkey_serialize(ctx, buf, &len, &R[i], SECP256K1_EC_COMPRESSED);
93 SHA256_Update(&sha, buf, 33);
96 secp256k1_ec_pubkey_serialize(ctx, buf, &len, &S[i], SECP256K1_EC_COMPRESSED);
97 SHA256_Update(&sha, buf, 33);
100 secp256k1_ec_pubkey_serialize(ctx, buf, &len, &Pk[i], SECP256K1_EC_COMPRESSED);
101 SHA256_Update(&sha, buf, 33);
106 secp256k1_ec_pubkey_serialize(ctx, buf, &len, Tm, SECP256K1_EC_COMPRESSED);
107 SHA256_Update(&sha, buf, 33);
109 for (i = 0; i < n; ++i) {
111 secp256k1_ec_pubkey_serialize(ctx, buf, &len, &TrG[i], SECP256K1_EC_COMPRESSED);
112 SHA256_Update(&sha, buf, 33);
115 secp256k1_ec_pubkey_serialize(ctx, buf, &len, &TrP[i], SECP256K1_EC_COMPRESSED);
116 SHA256_Update(&sha, buf, 33);
121 SHA256_Update(&sha, tx_id, 32);
124 SHA256_Final(h, &sha);
136 const secp256k1_context* ctx,
137 unsigned char* proof_out,
141 const secp256k1_pubkey* R,
142 const secp256k1_pubkey* S,
143 const secp256k1_pubkey* Pk,
144 const unsigned char* r_array,
145 const unsigned char* tx_id
148 if (!proof_len || *proof_len < required_len) {
149 if (proof_len) *proof_len = required_len;
152 *proof_len = required_len;
155 unsigned char* k_r_flat = NULL;
156 secp256k1_pubkey* TrG = NULL;
157 secp256k1_pubkey* TrP = NULL;
159 unsigned char k_m[32];
162 unsigned char s_m[32];
166 unsigned char* ptr = proof_out;
169 k_r_flat = (
unsigned char*)malloc(n * 32);
170 TrG = (secp256k1_pubkey*)malloc(n *
sizeof(secp256k1_pubkey));
171 TrP = (secp256k1_pubkey*)malloc(n *
sizeof(secp256k1_pubkey));
173 if (!k_r_flat || !TrG || !TrP)
goto cleanup;
179 if (!secp256k1_ec_pubkey_create(ctx, &Tm, k_m))
goto cleanup;
181 for (i = 0; i < n; i++) {
182 unsigned char* kri = &k_r_flat[i * 32];
186 if (!secp256k1_ec_pubkey_create(ctx, &TrG[i], kri))
goto cleanup;
190 if (!secp256k1_ec_pubkey_tweak_mul(ctx, &TrP[i], kri))
goto cleanup;
200 unsigned char m_scalar[32] = {0};
202 for (i = 0; i < 8; ++i) m_scalar[31 - i] = (amount_m >> (i * 8)) & 0xFF;
204 memcpy(s_m, k_m, 32);
205 if (!secp256k1_ec_seckey_tweak_mul(ctx, m_scalar, e))
goto cleanup;
206 if (!secp256k1_ec_seckey_tweak_add(ctx, s_m, m_scalar))
goto cleanup;
211 secp256k1_ec_pubkey_serialize(ctx, ptr, &len, &Tm, SECP256K1_EC_COMPRESSED); ptr += 33;
213 secp256k1_ec_pubkey_serialize(ctx, ptr, &len, &TrG[i], SECP256K1_EC_COMPRESSED); ptr += 33;
216 secp256k1_ec_pubkey_serialize(ctx, ptr, &len, &TrP[i], SECP256K1_EC_COMPRESSED); ptr += 33;
220 memcpy(ptr, s_m, 32); ptr += 32;
223 for (i = 0; i < n; i++) {
224 unsigned char s_ri[32];
225 unsigned char term[32];
227 memcpy(s_ri, &k_r_flat[i*32], 32);
228 memcpy(term, &r_array[i*32], 32);
230 if (!secp256k1_ec_seckey_tweak_mul(ctx, term, e))
goto cleanup;
231 if (!secp256k1_ec_seckey_tweak_add(ctx, s_ri, term))
goto cleanup;
233 memcpy(ptr, s_ri, 32); ptr += 32;
241 OPENSSL_cleanse(k_r_flat, n * 32);
244 OPENSSL_cleanse(k_m, 32);
251 const secp256k1_context* ctx,
252 const unsigned char* proof,
255 const secp256k1_pubkey* R,
256 const secp256k1_pubkey* S,
257 const secp256k1_pubkey* Pk,
258 const unsigned char* tx_id
263 secp256k1_pubkey* TrG = NULL;
264 secp256k1_pubkey* TrP = NULL;
265 unsigned char s_m[32];
269 const unsigned char* ptr = proof;
271 TrG = (secp256k1_pubkey*)malloc(n *
sizeof(secp256k1_pubkey));
272 TrP = (secp256k1_pubkey*)malloc(n *
sizeof(secp256k1_pubkey));
273 if (!TrG || !TrP)
goto cleanup;
276 if (!secp256k1_ec_pubkey_parse(ctx, &Tm, ptr, 33))
goto cleanup; ptr += 33;
279 if (!secp256k1_ec_pubkey_parse(ctx, &TrG[i], ptr, 33))
goto cleanup; ptr += 33;
282 if (!secp256k1_ec_pubkey_parse(ctx, &TrP[i], ptr, 33))
goto cleanup; ptr += 33;
285 memcpy(s_m, ptr, 32); ptr += 32;
286 if (!secp256k1_ec_seckey_verify(ctx, s_m))
goto cleanup;
294 secp256k1_pubkey SmG;
295 if (!secp256k1_ec_pubkey_create(ctx, &SmG, s_m))
goto cleanup;
298 unsigned char s_ri[32];
299 memcpy(s_ri, ptr, 32); ptr += 32;
300 if (!secp256k1_ec_seckey_verify(ctx, s_ri))
goto cleanup;
302 secp256k1_pubkey LHS, RHS, term;
303 const secp256k1_pubkey* pts[3];
306 if (!secp256k1_ec_pubkey_create(ctx, &LHS, s_ri))
goto cleanup;
309 if (!secp256k1_ec_pubkey_tweak_mul(ctx, &term, e))
goto cleanup;
310 pts[0] = &TrG[i]; pts[1] = &term;
311 if (!secp256k1_ec_pubkey_combine(ctx, &RHS, pts, 2))
goto cleanup;
320 if (!secp256k1_ec_pubkey_tweak_mul(ctx, &term, s_ri))
goto cleanup;
321 pts[0] = &SmG; pts[1] = &term;
322 if (!secp256k1_ec_pubkey_combine(ctx, &LHS, pts, 2))
goto cleanup;
326 if (!secp256k1_ec_pubkey_tweak_mul(ctx, &term, e))
goto cleanup;
327 pts[0] = &Tm; pts[1] = &TrP[i]; pts[2] = &term;
328 if (!secp256k1_ec_pubkey_combine(ctx, &RHS, pts, 3))
goto cleanup;
333 if ((
size_t)(ptr - proof) != proof_len)
goto cleanup;
size_t secp256k1_mpt_prove_same_plaintext_multi_size(size_t n)
Calculates the expected proof size for a given number of ciphertexts.
int secp256k1_mpt_verify_same_plaintext_multi(const secp256k1_context *ctx, const unsigned char *proof, size_t proof_len, size_t n, const secp256k1_pubkey *R, const secp256k1_pubkey *S, const secp256k1_pubkey *Pk, const unsigned char *tx_id)
Verifies a proof that N ciphertexts encrypt the same secret amount.
static void compute_challenge_multi(const secp256k1_context *ctx, unsigned char *e_out, size_t n, const secp256k1_pubkey *R, const secp256k1_pubkey *S, const secp256k1_pubkey *Pk, const secp256k1_pubkey *Tm, const secp256k1_pubkey *TrG, const secp256k1_pubkey *TrP, const unsigned char *tx_id)
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)
int secp256k1_mpt_prove_same_plaintext_multi(const secp256k1_context *ctx, unsigned char *proof_out, size_t *proof_len, uint64_t amount_m, size_t n, const secp256k1_pubkey *R, const secp256k1_pubkey *S, const secp256k1_pubkey *Pk, const unsigned char *r_array, const unsigned char *tx_id)
Generates a proof that N ciphertexts encrypt the same secret amount 'm'.