Line data Source code
1 : #include "../fd_zksdk_private.h"
2 :
3 : static inline void
4 : batched_grouped_ciphertext_validity_transcript_init(
5 : fd_zksdk_transcript_t * transcript,
6 39 : fd_zksdk_batched_grp_ciph_2h_val_context_t const * context ) {
7 39 : fd_zksdk_transcript_init( transcript, FD_TRANSCRIPT_LITERAL("batched-grouped-ciphertext-validity-2-handles-instruction") );
8 39 : fd_zksdk_transcript_append_pubkey ( transcript, FD_TRANSCRIPT_LITERAL("first-pubkey"), context->pubkey1 );
9 39 : fd_zksdk_transcript_append_pubkey ( transcript, FD_TRANSCRIPT_LITERAL("second-pubkey"), context->pubkey2 );
10 39 : fd_zksdk_transcript_append_message( transcript, FD_TRANSCRIPT_LITERAL("grouped-ciphertext-lo"), (uchar *)&context->grouped_ciphertext_lo, sizeof(grp_ciph_2h_t) );
11 39 : fd_zksdk_transcript_append_message( transcript, FD_TRANSCRIPT_LITERAL("grouped-ciphertext-hi"), (uchar *)&context->grouped_ciphertext_hi, sizeof(grp_ciph_2h_t) );
12 39 : }
13 :
14 : int
15 : fd_zksdk_verify_proof_batched_grouped_ciphertext_2_handles_validity(
16 : fd_zksdk_grp_ciph_2h_val_proof_t const * proof,
17 : uchar const pubkey1 [ 32 ],
18 : uchar const pubkey2 [ 32 ],
19 : uchar const comm [ 32 ],
20 : uchar const handle1 [ 32 ],
21 : uchar const handle2 [ 32 ],
22 : uchar const comm_hi [ 32 ],
23 : uchar const handle1_hi [ 32 ],
24 : uchar const handle2_hi [ 32 ],
25 : bool const batched,
26 75 : fd_zksdk_transcript_t * transcript ) {
27 : /*
28 : We need to verify the 3 following equivalences.
29 : Instead of verifying them one by one, it's more efficient to pack
30 : them up in a single MSM (and to do so we have to mul by 1, w, w^2).
31 :
32 : ( z_r H + z_x G =?= c C + Y_0 ) * 1
33 : ( z_r pub1 =?= c h1 + Y_1 ) * w
34 : ( z_r pub2 =?= c h2 + Y_2 ) * w^2
35 :
36 : When batched==false, C, h1, h2 are given and C_hi, h1_hi, h2_hi are NULL.
37 : When batched==true, they are computed as C = C_lo + t C_hi.
38 :
39 : When pubkey2 is 0, also proof->y2, handle2 and handle2_hi should be 0.
40 :
41 : Because of batched and pubkey2_not_zero, the length of the MSM varies
42 : between 6 and 12.
43 : Points/scalars from 7 to 12 are only computed when required.
44 :
45 : We store points and scalars in the following arrays:
46 :
47 : points scalars
48 : 0 G z_x
49 : 1 H z_r
50 : 2 Y_1 -w
51 : 3 Y_2 -w^2
52 : 4 pub1 z_r w
53 : 5 C -c
54 : 6 h1 -c w
55 : 7 C_hi -c t (if batched)
56 : 8 h1_hi -c w t (if batched)
57 : 9 pub2 z_r w^2 (if pubkey2_not_zero)
58 : 10 h2 -c w^2 (if pubkey2_not_zero)
59 : 11 h2_hi -c w^2 t (if batched && pubkey2_not_zero)
60 : ----------------------- MSM
61 : Y_0
62 : */
63 :
64 : /* pubkey2 extra check: if pubkey2 is 0, then handle2,
65 : handle2_hi (when set) and proof->y2 must all be 0. */
66 75 : bool pubkey2_not_zero = true;
67 75 : if ( fd_memeq( pubkey2, fd_ristretto255_compressed_zero, 32 ) ) {
68 0 : pubkey2_not_zero = false;
69 0 : if (
70 0 : !fd_memeq( handle2, fd_ristretto255_compressed_zero, 32 )
71 0 : || !fd_memeq( proof->y2, fd_ristretto255_compressed_zero, 32 )
72 0 : || ( batched && !fd_memeq( handle2_hi, fd_ristretto255_compressed_zero, 32 ) )
73 0 : ) {
74 0 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
75 0 : }
76 0 : }
77 :
78 : /* Validate all inputs */
79 75 : uchar scalars[ 12 * 32 ];
80 75 : fd_ristretto255_point_t points[12];
81 75 : fd_ristretto255_point_t y0[1];
82 75 : fd_ristretto255_point_t res[1];
83 :
84 75 : if( FD_UNLIKELY( fd_curve25519_scalar_validate( proof->zr )==NULL ) ) {
85 0 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
86 0 : }
87 75 : if( FD_UNLIKELY( fd_curve25519_scalar_validate( proof->zx )==NULL ) ) {
88 3 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
89 3 : }
90 :
91 72 : fd_ristretto255_point_set( &points[0], fd_zksdk_basepoint_G );
92 72 : fd_ristretto255_point_set( &points[1], fd_zksdk_basepoint_H );
93 72 : if( FD_UNLIKELY( fd_ristretto255_point_decompress( y0, proof->y0 )==NULL ) ) {
94 0 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
95 0 : }
96 72 : if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[2], proof->y1 )==NULL ) ) {
97 0 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
98 0 : }
99 72 : if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[3], proof->y2 )==NULL ) ) {
100 0 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
101 0 : }
102 72 : if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[4], pubkey1 )==NULL ) ) {
103 6 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
104 6 : }
105 66 : if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[5], comm )==NULL ) ) {
106 0 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
107 0 : }
108 66 : if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[6], handle1 )==NULL ) ) {
109 0 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
110 0 : }
111 :
112 66 : ulong idx = 7;
113 66 : if( batched ) {
114 36 : if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[idx++], comm_hi )==NULL ) ) {
115 0 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
116 0 : }
117 36 : if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[idx++], handle1_hi )==NULL ) ) {
118 0 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
119 0 : }
120 36 : }
121 :
122 66 : if( pubkey2_not_zero ) {
123 66 : if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[idx++], pubkey2 )==NULL ) ) {
124 0 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
125 0 : }
126 66 : if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[idx++], handle2 )==NULL ) ) {
127 0 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
128 0 : }
129 66 : }
130 :
131 66 : if( batched && pubkey2_not_zero ) {
132 36 : if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[idx++], handle2_hi )==NULL ) ) {
133 0 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
134 0 : }
135 36 : }
136 :
137 : /* Finalize transcript and extract challenges */
138 66 : uchar t[ 32 ];
139 66 : if( batched ) {
140 36 : fd_zksdk_transcript_domsep_batched_grp_ciph_val_proof( transcript, 2 );
141 36 : fd_zksdk_transcript_challenge_scalar( t, transcript, FD_TRANSCRIPT_LITERAL("t") );
142 36 : }
143 :
144 66 : fd_zksdk_transcript_domsep_grp_ciph_val_proof( transcript, 2 );
145 66 : int val = FD_TRANSCRIPT_SUCCESS;
146 66 : val |= fd_zksdk_transcript_validate_and_append_point( transcript, FD_TRANSCRIPT_LITERAL("Y_0"), proof->y0);
147 66 : val |= fd_zksdk_transcript_validate_and_append_point( transcript, FD_TRANSCRIPT_LITERAL("Y_1"), proof->y1);
148 66 : if( FD_UNLIKELY( val != FD_TRANSCRIPT_SUCCESS ) ) {
149 0 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
150 0 : }
151 : /* Y_2 can be an all zero point if the pubkey2 is all zero */
152 66 : fd_zksdk_transcript_append_point( transcript, FD_TRANSCRIPT_LITERAL("Y_2"), proof->y2);
153 :
154 66 : uchar c[ 32 ];
155 66 : uchar w[ 32 ];
156 66 : fd_zksdk_transcript_challenge_scalar( c, transcript, FD_TRANSCRIPT_LITERAL("c") );
157 66 : fd_zksdk_transcript_challenge_scalar( w, transcript, FD_TRANSCRIPT_LITERAL("w") );
158 :
159 : /* Compute scalars */
160 66 : fd_curve25519_scalar_set( &scalars[ 0*32 ], proof->zx ); // z_x
161 66 : fd_curve25519_scalar_set( &scalars[ 1*32 ], proof->zr ); // z_r
162 66 : fd_curve25519_scalar_neg( &scalars[ 2*32 ], w ); // -w
163 66 : fd_curve25519_scalar_mul( &scalars[ 3*32 ], &scalars[ 2*32 ], w ); // -w^2
164 66 : fd_curve25519_scalar_mul( &scalars[ 4*32 ], proof->zr, w ); // z_r w
165 66 : fd_curve25519_scalar_neg( &scalars[ 5*32 ], c ); // -c
166 66 : fd_curve25519_scalar_mul( &scalars[ 6*32 ], &scalars[ 5*32 ], w ); // -c w
167 66 : idx = 7;
168 66 : if( batched ) {
169 36 : fd_curve25519_scalar_mul( &scalars[ (idx++)*32 ], &scalars[ 5*32 ], t ); // -c t
170 36 : fd_curve25519_scalar_mul( &scalars[ (idx++)*32 ], &scalars[ 6*32 ], t ); // -c w t
171 36 : }
172 66 : if( pubkey2_not_zero ) {
173 66 : fd_curve25519_scalar_mul( &scalars[ (idx++)*32 ], &scalars[ 4*32 ], w ); // z_r w^2
174 66 : fd_curve25519_scalar_mul( &scalars[ (idx++)*32 ], &scalars[ 6*32 ], w ); // -c w^2
175 66 : }
176 66 : if( batched && pubkey2_not_zero ) {
177 36 : fd_curve25519_scalar_mul( &scalars[ (idx++)*32 ], &scalars[ 8*32 ], w ); // -c w^2 t
178 36 : }
179 :
180 : /* Compute the final MSM */
181 66 : fd_ristretto255_multi_scalar_mul( res, scalars, points, idx );
182 :
183 66 : if( FD_LIKELY( fd_ristretto255_point_eq( res, y0 ) ) ) {
184 63 : return FD_EXECUTOR_INSTR_SUCCESS;
185 63 : }
186 3 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
187 66 : }
188 :
189 : int
190 39 : fd_zksdk_instr_verify_proof_batched_grouped_ciphertext_2_handles_validity( void const * _context, void const * _proof ) {
191 39 : fd_zksdk_transcript_t transcript[1];
192 39 : fd_zksdk_batched_grp_ciph_2h_val_context_t const * context = _context;
193 39 : fd_zksdk_batched_grp_ciph_2h_val_proof_t const * proof = _proof;
194 :
195 39 : batched_grouped_ciphertext_validity_transcript_init( transcript, context );
196 39 : return fd_zksdk_verify_proof_batched_grouped_ciphertext_2_handles_validity(
197 39 : proof,
198 39 : context->pubkey1,
199 39 : context->pubkey2,
200 39 : context->grouped_ciphertext_lo.commitment,
201 39 : context->grouped_ciphertext_lo.handles[0].handle,
202 39 : context->grouped_ciphertext_lo.handles[1].handle,
203 39 : context->grouped_ciphertext_hi.commitment,
204 39 : context->grouped_ciphertext_hi.handles[0].handle,
205 39 : context->grouped_ciphertext_hi.handles[1].handle,
206 39 : true,
207 39 : transcript
208 39 : );
209 39 : }
|