LCOV - code coverage report
Current view: top level - ballet/zksdk/instructions - fd_zksdk_ciphertext_ciphertext_equality.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 83 111 74.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_ciphertext_equality.rs#L263 */
       4             : static inline void
       5             : ciphertext_ciphertext_equality_hash_context( fd_zksdk_transcript_t * transcript,
       6             :                                              uchar const             pubkey1    [ 32 ],
       7             :                                              uchar const             pubkey2    [ 32 ],
       8             :                                              uchar const             ciphertext1[ 64 ],
       9          15 :                                              uchar const             ciphertext2[ 64 ] ) {
      10          15 :   fd_zksdk_transcript_append_pubkey    ( transcript, FD_TRANSCRIPT_LITERAL("first-pubkey"),      pubkey1 );
      11          15 :   fd_zksdk_transcript_append_pubkey    ( transcript, FD_TRANSCRIPT_LITERAL("second-pubkey"),     pubkey2 );
      12          15 :   fd_zksdk_transcript_append_ciphertext( transcript, FD_TRANSCRIPT_LITERAL("first-ciphertext"),  ciphertext1 );
      13          15 :   fd_zksdk_transcript_append_ciphertext( transcript, FD_TRANSCRIPT_LITERAL("second-ciphertext"), ciphertext2 );
      14          15 : }
      15             : 
      16             : /* https://github.com/solana-program/zk-elgamal-proof/blob/zk-sdk%40v5.0.1/zk-sdk/src/sigma_proofs/ciphertext_ciphertext_equality.rs#L147 */
      17             : static inline int
      18             : fd_zksdk_verify_proof_ciphertext_ciphertext_equality(
      19             :   fd_zksdk_ciph_ciph_eq_proof_t const * proof,
      20             :   uchar const                           pubkey1    [ 32 ],
      21             :   uchar const                           pubkey2    [ 32 ],
      22             :   uchar const                           ciphertext1[ 64 ],
      23             :   uchar const                           ciphertext2[ 64 ],
      24          18 :   fd_zksdk_transcript_t *               transcript ) {
      25             :   /*
      26             :     We store points and scalars in the following arrays:
      27             : 
      28             :         points  scalars
      29             :     0   G        z_x (w + ww)
      30             :     1   H       -c + z_r ww
      31             :     2   P1       z_s
      32             :     3   D1       z_s w
      33             :     4   Y_1     -w
      34             :     5   C1      -w c
      35             :     6   Y_2     -ww
      36             :     7   C2      -ww c
      37             :     8   Y_3     -www
      38             :     9   D2      -www c
      39             :    10   P2       www z_r
      40             :    ------------------------ MSM
      41             :         Y_0
      42             :   */
      43             : 
      44             :   /* Validate all inputs */
      45          18 :   uchar scalars[ 11 * 32 ];
      46          18 :   fd_ristretto255_point_t points[11];
      47          18 :   fd_ristretto255_point_t y0[1];
      48          18 :   fd_ristretto255_point_t res[1];
      49             : 
      50             :   /* https://github.com/solana-program/zk-elgamal-proof/blob/zk-sdk%40v5.0.1/zk-sdk/src/sigma_proofs/ciphertext_ciphertext_equality.rs#L158-L164 */
      51          18 :   if( FD_UNLIKELY( fd_memeq( pubkey1,          fd_ristretto255_compressed_zero, 32 )
      52          18 :                 || fd_memeq( pubkey2,          fd_ristretto255_compressed_zero, 32 )
      53          18 :                 || fd_memeq( &ciphertext1[0],  fd_ristretto255_compressed_zero, 32 )
      54          18 :                 || fd_memeq( &ciphertext1[32], fd_ristretto255_compressed_zero, 32 ) ) ) {
      55           0 :     return FD_ZKSDK_VERIFY_PROOF_ERROR;
      56           0 :   }
      57             : 
      58          18 :   if( FD_UNLIKELY( fd_curve25519_scalar_validate( proof->zs )==NULL ) ) {
      59           0 :     return FD_ZKSDK_VERIFY_PROOF_ERROR;
      60           0 :   }
      61          18 :   if( FD_UNLIKELY( fd_curve25519_scalar_validate( proof->zx )==NULL ) ) {
      62           0 :     return FD_ZKSDK_VERIFY_PROOF_ERROR;
      63           0 :   }
      64          18 :   if( FD_UNLIKELY( fd_curve25519_scalar_validate( proof->zr )==NULL ) ) {
      65           0 :     return FD_ZKSDK_VERIFY_PROOF_ERROR;
      66           0 :   }
      67             : 
      68          18 :   fd_ristretto255_point_set( &points[0], fd_zksdk_basepoint_G );
      69          18 :   fd_ristretto255_point_set( &points[1], fd_zksdk_basepoint_H );
      70          18 :   if( FD_UNLIKELY( fd_ristretto255_point_decompress( y0, proof->y0 )==NULL ) ) {
      71           0 :     return FD_ZKSDK_VERIFY_PROOF_ERROR;
      72           0 :   }
      73          18 :   if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[2], pubkey1 )==NULL ) ) {
      74           3 :     return FD_ZKSDK_VERIFY_PROOF_ERROR;
      75           3 :   }
      76          15 :   if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[3], &ciphertext1[32] )==NULL ) ) {
      77           0 :     return FD_ZKSDK_VERIFY_PROOF_ERROR;
      78           0 :   }
      79          15 :   if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[4], proof->y1 )==NULL ) ) {
      80           0 :     return FD_ZKSDK_VERIFY_PROOF_ERROR;
      81           0 :   }
      82          15 :   if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[5], ciphertext1 )==NULL ) ) {
      83           0 :     return FD_ZKSDK_VERIFY_PROOF_ERROR;
      84           0 :   }
      85          15 :   if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[6], proof->y2 )==NULL ) ) {
      86           0 :     return FD_ZKSDK_VERIFY_PROOF_ERROR;
      87           0 :   }
      88          15 :   if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[7], ciphertext2 )==NULL ) ) {
      89           0 :     return FD_ZKSDK_VERIFY_PROOF_ERROR;
      90           0 :   }
      91          15 :   if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[8], proof->y3 )==NULL ) ) {
      92           0 :     return FD_ZKSDK_VERIFY_PROOF_ERROR;
      93           0 :   }
      94          15 :   if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[9], &ciphertext2[32] )==NULL ) ) {
      95           0 :     return FD_ZKSDK_VERIFY_PROOF_ERROR;
      96           0 :   }
      97          15 :   if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[10], pubkey2 )==NULL ) ) {
      98           0 :     return FD_ZKSDK_VERIFY_PROOF_ERROR;
      99           0 :   }
     100             : 
     101             :   /* Finalize transcript and extract challenges */
     102             : 
     103             :   /* https://github.com/solana-program/zk-elgamal-proof/blob/zk-sdk%40v5.0.1/zk-sdk/src/sigma_proofs/ciphertext_ciphertext_equality.rs#L166-L173 */
     104          15 :   ciphertext_ciphertext_equality_hash_context( transcript, pubkey1, pubkey2, ciphertext1, ciphertext2 );
     105          15 :   fd_zksdk_transcript_domsep_ciph_ciph_eq_proof( transcript );
     106             : 
     107             :   /* https://github.com/solana-program/zk-elgamal-proof/blob/zk-sdk%40v5.0.1/zk-sdk/src/sigma_proofs/ciphertext_ciphertext_equality.rs#L185-L195 */
     108          15 :   int val = FD_TRANSCRIPT_SUCCESS;
     109          15 :   val |= fd_zksdk_transcript_validate_and_append_point( transcript, FD_TRANSCRIPT_LITERAL("Y_0"), proof->y0);
     110          15 :   val |= fd_zksdk_transcript_validate_and_append_point( transcript, FD_TRANSCRIPT_LITERAL("Y_1"), proof->y1);
     111          15 :   val |= fd_zksdk_transcript_validate_and_append_point( transcript, FD_TRANSCRIPT_LITERAL("Y_2"), proof->y2);
     112          15 :   val |= fd_zksdk_transcript_validate_and_append_point( transcript, FD_TRANSCRIPT_LITERAL("Y_3"), proof->y3);
     113          15 :   if( FD_UNLIKELY( val != FD_TRANSCRIPT_SUCCESS ) ) {
     114           0 :     return FD_ZKSDK_VERIFY_PROOF_ERROR;
     115           0 :   }
     116             : 
     117          15 :   uchar c[ 32 ];
     118          15 :   uchar w[ 32 ];
     119          15 :   fd_zksdk_transcript_challenge_scalar( c, transcript, FD_TRANSCRIPT_LITERAL("c") );
     120             : 
     121          15 :   fd_zksdk_transcript_append_scalar( transcript, FD_TRANSCRIPT_LITERAL("z_s"), proof->zs );
     122          15 :   fd_zksdk_transcript_append_scalar( transcript, FD_TRANSCRIPT_LITERAL("z_x"), proof->zx );
     123          15 :   fd_zksdk_transcript_append_scalar( transcript, FD_TRANSCRIPT_LITERAL("z_r"), proof->zr );
     124             : 
     125          15 :   fd_zksdk_transcript_challenge_scalar( w, transcript, FD_TRANSCRIPT_LITERAL("w") );
     126             : 
     127             :   /* https://github.com/solana-program/zk-elgamal-proof/blob/zk-sdk%40v5.0.1/zk-sdk/src/sigma_proofs/ciphertext_ciphertext_equality.rs#L196-L254
     128             :      Note: we use a slightly different MSM but they're equivalent. */
     129          15 :   uchar ww[ 32 ];
     130          15 :   fd_curve25519_scalar_mul( ww, w, w );
     131             : 
     132             :   /* Compute scalars */
     133          15 :   fd_curve25519_scalar_add( &scalars[  0*32 ], w, ww );                //  z_x (w + ww)
     134          15 :   fd_curve25519_scalar_mul( &scalars[  0*32 ], &scalars[ 0*32 ], proof->zx );
     135          15 :   fd_curve25519_scalar_mul( &scalars[  1*32 ], proof->zr, ww );        // -c + z_r ww
     136          15 :   fd_curve25519_scalar_sub( &scalars[  1*32 ], &scalars[ 1*32 ], c );
     137          15 :   fd_curve25519_scalar_set( &scalars[  2*32 ], proof->zs );            //  z_s
     138          15 :   fd_curve25519_scalar_mul( &scalars[  3*32 ], &scalars[ 2*32 ], w );  //  z_s w
     139          15 :   fd_curve25519_scalar_neg( &scalars[  4*32 ], w );                    // -w
     140          15 :   fd_curve25519_scalar_mul( &scalars[  5*32 ], &scalars[ 4*32 ], c );  // -w c
     141          15 :   fd_curve25519_scalar_neg( &scalars[  6*32 ], ww );                   // -ww
     142          15 :   fd_curve25519_scalar_mul( &scalars[  7*32 ], &scalars[ 6*32 ], c );  // -ww c
     143          15 :   fd_curve25519_scalar_mul( ww, ww, w );
     144          15 :   fd_curve25519_scalar_neg( &scalars[  8*32 ], ww );                   // -www
     145          15 :   fd_curve25519_scalar_mul( &scalars[  9*32 ], &scalars[ 8*32 ], c );  // -www c
     146          15 :   fd_curve25519_scalar_mul( &scalars[ 10*32 ], proof->zr, ww );        //  www z_r
     147             : 
     148             :   /* Compute the final MSM */
     149          15 :   fd_ristretto255_multi_scalar_mul( res, scalars, points, 11 );
     150             : 
     151             :   /* https://github.com/solana-program/zk-elgamal-proof/blob/zk-sdk%40v5.0.1/zk-sdk/src/sigma_proofs/ciphertext_ciphertext_equality.rs#L256-L260 */
     152          15 :   if( FD_LIKELY( fd_ristretto255_point_eq( res, y0 ) ) ) {
     153          12 :     return FD_ZKSDK_VERIFY_PROOF_SUCCESS;
     154          12 :   }
     155           3 :   return FD_ZKSDK_VERIFY_PROOF_ERROR;
     156          15 : }
     157             : 
     158             : /* https://github.com/solana-program/zk-elgamal-proof/blob/zk-sdk%40v5.0.1/zk-sdk/src/zk_elgamal_proof_program/proof_data/ciphertext_ciphertext_equality.rs#L122 */
     159             : int
     160          18 : fd_zksdk_instr_verify_proof_ciphertext_ciphertext_equality( void const * _context, void const * _proof ) {
     161          18 :   fd_zksdk_transcript_t transcript[1];
     162          18 :   fd_zksdk_transcript_init( transcript, FD_TRANSCRIPT_LITERAL("ciphertext-ciphertext-equality-instruction") );
     163             : 
     164          18 :   fd_zksdk_ciph_ciph_eq_context_t const * context = _context;
     165          18 :   fd_zksdk_ciph_ciph_eq_proof_t const *   proof   = _proof;
     166          18 :   return fd_zksdk_verify_proof_ciphertext_ciphertext_equality(
     167          18 :     proof,
     168          18 :     context->pubkey1,
     169          18 :     context->pubkey2,
     170          18 :     context->ciphertext1,
     171          18 :     context->ciphertext2,
     172          18 :     transcript
     173          18 :   );
     174          18 : }

Generated by: LCOV version 1.14