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 : }
|