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