mpt-crypto
Confidential Multi-Purpose Tokens Cryptographic Library
Loading...
Searching...
No Matches
proof_same_plaintext.c File Reference

Zero-Knowledge Proof of Plaintext Equality (1-to-1). More...

#include "secp256k1_mpt.h"
#include <openssl/sha.h>
#include <openssl/rand.h>
#include <string.h>
#include <stdlib.h>
Include dependency graph for proof_same_plaintext.c:

Go to the source code of this file.

Macros

#define SER_AND_HASH(pk)

Functions

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)
static void build_same_plaintext_hash_input (const secp256k1_context *ctx, unsigned char *e_out, const secp256k1_pubkey *R1, const secp256k1_pubkey *S1, const secp256k1_pubkey *P1, const secp256k1_pubkey *R2, const secp256k1_pubkey *S2, const secp256k1_pubkey *P2, const secp256k1_pubkey *T_m, const secp256k1_pubkey *T_r1_G, const secp256k1_pubkey *T_r1_P1, const secp256k1_pubkey *T_r2_G, const secp256k1_pubkey *T_r2_P2, const unsigned char *tx_context_id)
int secp256k1_mpt_prove_same_plaintext (const secp256k1_context *ctx, unsigned char *proof_out, const secp256k1_pubkey *R1, const secp256k1_pubkey *S1, const secp256k1_pubkey *P1, const secp256k1_pubkey *R2, const secp256k1_pubkey *S2, const secp256k1_pubkey *P2, uint64_t amount_m, const unsigned char *randomness_r1, const unsigned char *randomness_r2, const unsigned char *tx_context_id)
 Generates a proof that two ciphertexts (under different keys) encrypt the same secret amount 'm'.
int secp256k1_mpt_verify_same_plaintext (const secp256k1_context *ctx, const unsigned char *proof, const secp256k1_pubkey *R1, const secp256k1_pubkey *S1, const secp256k1_pubkey *P1, const secp256k1_pubkey *R2, const secp256k1_pubkey *S2, const secp256k1_pubkey *P2, const unsigned char *tx_context_id)
 Verifies a proof that two ciphertexts encrypt the same secret amount.

Detailed Description

Zero-Knowledge Proof of Plaintext Equality (1-to-1).

This module implements a multi-statement Sigma protocol to prove that two different ElGamal ciphertexts encrypt the same underlying plaintext amount, potentially under different public keys and using different randomness.

Statement: Given two ciphertexts \( (R_1, S_1) \) and \( (R_2, S_2) \) encrypted under public keys \( P_1 \) and \( P_2 \) respectively, the prover demonstrates knowledge of scalars \( m, r_1, r_2 \) such that:

  1. \( R_1 = r_1 \cdot G \) and \( S_1 = m \cdot G + r_1 \cdot P_1 \)
  2. \( R_2 = r_2 \cdot G \) and \( S_2 = m \cdot G + r_2 \cdot P_2 \)

Protocol Logic (Shared Nonce): To prove that \( m \) is identical in both ciphertexts without revealing it, the prover uses a shared random nonce \( k_m \) for the amount commitment across both logical branches of the proof.

  1. Commitments:
  • \( T_m = k_m \cdot G \) (Shared commitment to amount nonce)
  • \( T_{r1,G} = k_{r1} \cdot G \), \( T_{r1,P1} = k_{r1} \cdot P_1 \)
  • \( T_{r2,G} = k_{r2} \cdot G \), \( T_{r2,P2} = k_{r2} \cdot P_2 \)
  1. Challenge: \( e = H(\dots \parallel T_m \parallel \dots) \)
  2. Responses:
  • \( s_m = k_m + e \cdot m \) (Shared response for amount)
  • \( s_{r1} = k_{r1} + e \cdot r_1 \)
  • \( s_{r2} = k_{r2} + e \cdot r_2 \)
  1. Verification: The verifier checks 4 equations. Crucially, the "Amount" equations for both ciphertexts use the same \( s_m \) and \( T_m \), mathematically enforcing equality:
  • \( s_m \cdot G + s_{r1} \cdot P_1 \stackrel{?}{=} T_m + T_{r1,P1} + e \cdot S_1 \)
  • \( s_m \cdot G + s_{r2} \cdot P_2 \stackrel{?}{=} T_m + T_{r2,P2} + e \cdot S_2 \)

Security Context: This is used when transferring confidential tokens between accounts (re-encrypting the sender's balance for the receiver) or updating keys, ensuring no value is created or destroyed during the transformation.

See also
[Spec (ConfidentialMPT_20260106.pdf) Section 3.3.3] Proof of Equality of Plaintexts (Different Keys, Same Secret Amount)

Definition in file proof_same_plaintext.c.

Macro Definition Documentation

◆ SER_AND_HASH

#define SER_AND_HASH ( pk)
Value:
do { \
len = 33; \
secp256k1_ec_pubkey_serialize(ctx, buf, &len, pk, SECP256K1_EC_COMPRESSED); \
SHA256_Update(&sha, buf, 33); \
} while(0)

Function Documentation

◆ build_same_plaintext_hash_input()

void build_same_plaintext_hash_input ( const secp256k1_context * ctx,
unsigned char * e_out,
const secp256k1_pubkey * R1,
const secp256k1_pubkey * S1,
const secp256k1_pubkey * P1,
const secp256k1_pubkey * R2,
const secp256k1_pubkey * S2,
const secp256k1_pubkey * P2,
const secp256k1_pubkey * T_m,
const secp256k1_pubkey * T_r1_G,
const secp256k1_pubkey * T_r1_P1,
const secp256k1_pubkey * T_r2_G,
const secp256k1_pubkey * T_r2_P2,
const unsigned char * tx_context_id )
static

Builds the challenge hash input.

Definition at line 70 of file proof_same_plaintext.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ generate_random_scalar()

int generate_random_scalar ( const secp256k1_context * ctx,
unsigned char * scalar )
static

Definition at line 60 of file proof_same_plaintext.c.

Here is the caller graph for this function:

◆ pubkey_equal()

int pubkey_equal ( const secp256k1_context * ctx,
const secp256k1_pubkey * pk1,
const secp256k1_pubkey * pk2 )
static

Definition at line 56 of file proof_same_plaintext.c.

Here is the caller graph for this function:

◆ secp256k1_mpt_prove_same_plaintext()

int secp256k1_mpt_prove_same_plaintext ( const secp256k1_context * ctx,
unsigned char * proof_out,
const secp256k1_pubkey * R1,
const secp256k1_pubkey * S1,
const secp256k1_pubkey * P1,
const secp256k1_pubkey * R2,
const secp256k1_pubkey * S2,
const secp256k1_pubkey * P2,
uint64_t amount_m,
const unsigned char * randomness_r1,
const unsigned char * randomness_r2,
const unsigned char * tx_context_id )

Generates a proof that two ciphertexts (under different keys) encrypt the same secret amount 'm'.

Parameters
[in]ctxA pointer to a valid secp256k1 context.
[out]proof_outA pointer to a 261-byte buffer to store the proof.
[in]R1,S1,P1The first ciphertext (R1, S1) and its public key (P1).
[in]R2,S2,P2The second ciphertext (R2, S2) and its public key (P2).
[in]amount_mThe secret common uint64_t plaintext value 'm'.
[in]randomness_r1The 32-byte secret random scalar 'r1' for C1.
[in]randomness_r2The 32-byte secret random scalar 'r2' for C2.
[in]tx_context_idA 32-byte unique identifier for the transaction.
Returns
1 on success, 0 on failure.

Definition at line 117 of file proof_same_plaintext.c.

Here is the call graph for this function:

◆ secp256k1_mpt_verify_same_plaintext()

int secp256k1_mpt_verify_same_plaintext ( const secp256k1_context * ctx,
const unsigned char * proof,
const secp256k1_pubkey * R1,
const secp256k1_pubkey * S1,
const secp256k1_pubkey * P1,
const secp256k1_pubkey * R2,
const secp256k1_pubkey * S2,
const secp256k1_pubkey * P2,
const unsigned char * tx_context_id )

Verifies a proof that two ciphertexts encrypt the same secret amount.

Parameters
[in]ctxA pointer to a valid secp256k1 context.
[in]proofA pointer to the 261-byte proof to verify.
[in]R1,S1,P1The first ciphertext (R1, S1) and its public key (P1).
[in]R2,S2,P2The second ciphertext (R2, S2) and its public key (P2).
[in]tx_context_idA 32-byte unique identifier for the transaction.
Returns
1 if the proof is valid, 0 otherwise.

Definition at line 201 of file proof_same_plaintext.c.

Here is the call graph for this function: