LCOV - code coverage report
Current view: top level - ballet/zksdk/instructions - fd_zksdk_ciphertext_commitment_equality.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 69 91 75.8 %
Date: 2026-03-19 18:19:27 Functions: 3 3 100.0 %

          Line data    Source code
       1             : #include "../fd_zksdk_private.h"
       2             : 
       3             : /* https://github.com/solana-program/zk-elgamal-proof/blob/zk-sdk%40v5.0.1/zk-sdk/src/sigma_proofs/ciphertext_commitment_equality.rs#L229 */
       4             : static inline void
       5             : ciph_comm_eq_hash_context( fd_zksdk_transcript_t * transcript,
       6             :                            uchar const             pubkey    [ 32 ],
       7             :                            uchar const             ciphertext[ 64 ],
       8           5 :                            uchar const             commitment[ 32 ] ) {
       9           5 :   fd_zksdk_transcript_append_pubkey    ( transcript, FD_TRANSCRIPT_LITERAL("pubkey"),     pubkey );
      10           5 :   fd_zksdk_transcript_append_ciphertext( transcript, FD_TRANSCRIPT_LITERAL("ciphertext"), ciphertext );
      11           5 :   fd_zksdk_transcript_append_commitment( transcript, FD_TRANSCRIPT_LITERAL("commitment"), commitment );
      12           5 : }
      13             : 
      14             : /* https://github.com/solana-program/zk-elgamal-proof/blob/zk-sdk%40v5.0.1/zk-sdk/src/sigma_proofs/ciphertext_commitment_equality.rs#L139 */
      15             : int
      16             : fd_zksdk_verify_proof_ciphertext_commitment_equality(
      17             :   fd_zksdk_ciph_comm_eq_proof_t const * proof,
      18             :   uchar const                           pubkey     [ 32 ],
      19             :   uchar const                           ciphertext [ 64 ],
      20             :   uchar const                           commitment [ 32 ],
      21           6 :   fd_zksdk_transcript_t *               transcript ) {
      22             :   /*
      23             :     We need to verify the 3 following equivalences.
      24             :     Instead of verifying them one by one, it's more efficient to pack
      25             :     them up in a single MSM (and to do so we have to mul by 1, w, w^2).
      26             : 
      27             :     (         z_s P_src =?= c H + Y_0     ) * w^2
      28             :     ( z_x G + z_s D_src =?= c C_src + Y_1 ) * w
      29             :     (     z_x G + z_r H =?= c C_dst + Y_2 ) * 1
      30             : 
      31             :     We store points and scalars in the following arrays:
      32             : 
      33             :         points  scalars
      34             :     0   G       z_x w + z_x
      35             :     1   H       z_r - c w^2
      36             :     2   Y_0     -w^2
      37             :     3   Y_1     -w
      38             :     4   P_src   z_s w^2
      39             :     5   C_src   -c w
      40             :     6   D_src   z_s w
      41             :     7   C_dst   -c
      42             :     ----------------------- MSM
      43             :         Y_2
      44             :   */
      45             : 
      46             :   /* Validate all inputs */
      47           6 :   uchar scalars[ 8 * 32 ];
      48           6 :   fd_ristretto255_point_t points[8];
      49           6 :   fd_ristretto255_point_t y2[1];
      50           6 :   fd_ristretto255_point_t res[1];
      51             : 
      52             :   /* https://github.com/solana-program/zk-elgamal-proof/blob/zk-sdk%40v5.0.1/zk-sdk/src/sigma_proofs/ciphertext_commitment_equality.rs#L146-L152 */
      53           6 :   if( FD_UNLIKELY( fd_memeq( pubkey,          fd_ristretto255_compressed_zero, 32 )
      54           6 :                 || fd_memeq( &ciphertext[0],  fd_ristretto255_compressed_zero, 32 )
      55           6 :                 || fd_memeq( &ciphertext[32], fd_ristretto255_compressed_zero, 32 )
      56           6 :                 || fd_memeq( commitment,      fd_ristretto255_compressed_zero, 32 ) ) ) {
      57           0 :     return FD_ZKSDK_VERIFY_PROOF_ERROR;
      58           0 :   }
      59             : 
      60           6 :   if( FD_UNLIKELY( fd_curve25519_scalar_validate( proof->zs )==NULL ) ) {
      61           0 :     return FD_ZKSDK_VERIFY_PROOF_ERROR;
      62           0 :   }
      63           6 :   if( FD_UNLIKELY( fd_curve25519_scalar_validate( proof->zx )==NULL ) ) {
      64           0 :     return FD_ZKSDK_VERIFY_PROOF_ERROR;
      65           0 :   }
      66           6 :   if( FD_UNLIKELY( fd_curve25519_scalar_validate( proof->zr )==NULL ) ) {
      67           0 :     return FD_ZKSDK_VERIFY_PROOF_ERROR;
      68           0 :   }
      69             : 
      70           6 :   fd_ristretto255_point_set( &points[0], fd_zksdk_basepoint_G );
      71           6 :   fd_ristretto255_point_set( &points[1], fd_zksdk_basepoint_H );
      72           6 :   if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[2], proof->y0 )==NULL ) ) {
      73           0 :     return FD_ZKSDK_VERIFY_PROOF_ERROR;
      74           0 :   }
      75           6 :   if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[3], proof->y1 )==NULL ) ) {
      76           0 :     return FD_ZKSDK_VERIFY_PROOF_ERROR;
      77           0 :   }
      78           6 :   if( FD_UNLIKELY( fd_ristretto255_point_decompress( y2, proof->y2 )==NULL ) ) {
      79           0 :     return FD_ZKSDK_VERIFY_PROOF_ERROR;
      80           0 :   }
      81           6 :   if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[4], pubkey )==NULL ) ) {
      82           1 :     return FD_ZKSDK_VERIFY_PROOF_ERROR;
      83           1 :   }
      84           5 :   if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[5], ciphertext )==NULL ) ) {
      85           0 :     return FD_ZKSDK_VERIFY_PROOF_ERROR;
      86           0 :   }
      87           5 :   if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[6], &ciphertext[32] )==NULL ) ) {
      88           0 :     return FD_ZKSDK_VERIFY_PROOF_ERROR;
      89           0 :   }
      90           5 :   if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[7], commitment )==NULL ) ) {
      91           0 :     return FD_ZKSDK_VERIFY_PROOF_ERROR;
      92           0 :   }
      93             : 
      94             :   /* Finalize transcript and extract challenges */
      95             : 
      96             :   /* https://github.com/solana-program/zk-elgamal-proof/blob/zk-sdk%40v5.0.1/zk-sdk/src/sigma_proofs/ciphertext_commitment_equality.rs#L154-L155 */
      97           5 :   ciph_comm_eq_hash_context( transcript, pubkey, ciphertext, commitment );
      98           5 :   fd_zksdk_transcript_domsep_ciph_comm_eq_proof( transcript );
      99             : 
     100             :   /* https://github.com/solana-program/zk-elgamal-proof/blob/zk-sdk%40v5.0.1/zk-sdk/src/sigma_proofs/ciphertext_commitment_equality.rs#L158-L173 */
     101           5 :   int val = FD_TRANSCRIPT_SUCCESS;
     102           5 :   val |= fd_zksdk_transcript_validate_and_append_point( transcript, FD_TRANSCRIPT_LITERAL("Y_0"), proof->y0);
     103           5 :   val |= fd_zksdk_transcript_validate_and_append_point( transcript, FD_TRANSCRIPT_LITERAL("Y_1"), proof->y1);
     104           5 :   val |= fd_zksdk_transcript_validate_and_append_point( transcript, FD_TRANSCRIPT_LITERAL("Y_2"), proof->y2);
     105           5 :   if( FD_UNLIKELY( val != FD_TRANSCRIPT_SUCCESS ) ) {
     106           0 :     return FD_ZKSDK_VERIFY_PROOF_ERROR;
     107           0 :   }
     108             : 
     109           5 :   uchar c[ 32 ];
     110           5 :   uchar w[ 32 ];
     111           5 :   fd_zksdk_transcript_challenge_scalar( c, transcript, FD_TRANSCRIPT_LITERAL("c") );
     112             : 
     113           5 :   fd_zksdk_transcript_append_scalar( transcript, FD_TRANSCRIPT_LITERAL("z_s"), proof->zs );
     114           5 :   fd_zksdk_transcript_append_scalar( transcript, FD_TRANSCRIPT_LITERAL("z_x"), proof->zx );
     115           5 :   fd_zksdk_transcript_append_scalar( transcript, FD_TRANSCRIPT_LITERAL("z_r"), proof->zr );
     116             : 
     117           5 :   fd_zksdk_transcript_challenge_scalar( w, transcript, FD_TRANSCRIPT_LITERAL("w") );
     118             : 
     119             :   /* https://github.com/solana-program/zk-elgamal-proof/blob/zk-sdk%40v5.0.1/zk-sdk/src/sigma_proofs/ciphertext_commitment_equality.rs#L174-L220
     120             :      Note: we use a slightly different MSM but they're equivalent. */
     121             : 
     122             :   /* Compute scalars */
     123           5 :   fd_curve25519_scalar_neg(    &scalars[ 7*32 ], c );                              // -c
     124           5 :   fd_curve25519_scalar_mul(    &scalars[ 6*32 ], proof->zs, w );                   // z_s w
     125           5 :   fd_curve25519_scalar_mul(    &scalars[ 5*32 ], &scalars[ 7*32 ], w );            // -c w
     126           5 :   fd_curve25519_scalar_mul(    &scalars[ 4*32 ], &scalars[ 6*32 ], w );            // z_s w^2
     127           5 :   fd_curve25519_scalar_neg(    &scalars[ 3*32 ], w );                              // -w
     128           5 :   fd_curve25519_scalar_mul(    &scalars[ 2*32 ], &scalars[ 3*32 ], w );            // -w^2
     129           5 :   fd_curve25519_scalar_muladd( &scalars[ 1*32 ], &scalars[ 5*32 ], w, proof->zr ); // z_r - c w^2
     130           5 :   fd_curve25519_scalar_muladd( &scalars[ 0*32 ], proof->zx, w, proof->zx );        // z_x w + z_x
     131             : 
     132             :   /* Compute the final MSM */
     133           5 :   fd_ristretto255_multi_scalar_mul( res, scalars, points, 8 );
     134             : 
     135             :   /* https://github.com/solana-program/zk-elgamal-proof/blob/zk-sdk%40v5.0.1/zk-sdk/src/sigma_proofs/ciphertext_commitment_equality.rs#L222-L226 */
     136           5 :   if( FD_LIKELY( fd_ristretto255_point_eq( res, y2 ) ) ) {
     137           4 :     return FD_ZKSDK_VERIFY_PROOF_SUCCESS;
     138           4 :   }
     139           1 :   return FD_ZKSDK_VERIFY_PROOF_ERROR;
     140           5 : }
     141             : 
     142             : int
     143           6 : fd_zksdk_instr_verify_proof_ciphertext_commitment_equality( void const * _context, void const * _proof ) {
     144           6 :   fd_zksdk_transcript_t transcript[1];
     145           6 :   fd_zksdk_transcript_init( transcript, FD_TRANSCRIPT_LITERAL("ciphertext-commitment-equality-instruction") );
     146             : 
     147           6 :   fd_zksdk_ciph_comm_eq_context_t const * context = _context;
     148           6 :   fd_zksdk_ciph_comm_eq_proof_t const *   proof   = _proof;
     149           6 :   return fd_zksdk_verify_proof_ciphertext_commitment_equality(
     150           6 :     proof,
     151           6 :     context->pubkey,
     152           6 :     context->ciphertext,
     153           6 :     context->commitment,
     154           6 :     transcript
     155           6 :   );
     156           6 : }

Generated by: LCOV version 1.14