Line data Source code
1 : #include "../fd_zksdk_private.h"
2 :
3 : static inline void
4 : ciphertext_ciphertext_equality_transcript_init( fd_zksdk_transcript_t * transcript,
5 63 : fd_zksdk_ciph_ciph_eq_context_t const * context ) {
6 63 : fd_zksdk_transcript_init( transcript, FD_TRANSCRIPT_LITERAL("ciphertext-ciphertext-equality-instruction") );
7 63 : fd_zksdk_transcript_append_pubkey ( transcript, FD_TRANSCRIPT_LITERAL("first-pubkey"), context->pubkey1 );
8 63 : fd_zksdk_transcript_append_pubkey ( transcript, FD_TRANSCRIPT_LITERAL("second-pubkey"), context->pubkey2 );
9 63 : fd_zksdk_transcript_append_ciphertext( transcript, FD_TRANSCRIPT_LITERAL("first-ciphertext"), context->ciphertext1 );
10 63 : fd_zksdk_transcript_append_ciphertext( transcript, FD_TRANSCRIPT_LITERAL("second-ciphertext"), context->ciphertext2 );
11 63 : }
12 :
13 : /* https://github.com/anza-xyz/agave/blob/v2.0.1/zk-sdk/src/sigma_proofs/ciphertext_ciphertext_equality.rs#L136 */
14 : static inline int
15 : fd_zksdk_verify_proof_ciphertext_ciphertext_equality(
16 : fd_zksdk_ciph_ciph_eq_proof_t const * proof,
17 : uchar const pubkey1 [ 32 ],
18 : uchar const pubkey2 [ 32 ],
19 : uchar const ciphertext1[ 64 ],
20 : uchar const ciphertext2[ 64 ],
21 63 : fd_zksdk_transcript_t * transcript ) {
22 : /*
23 : We store points and scalars in the following arrays:
24 :
25 : points scalars
26 : 0 G z_x (w + ww)
27 : 1 H -c + z_r ww
28 : 2 P1 z_s
29 : 3 D1 z_s w
30 : 4 Y_1 -w
31 : 5 C1 -w c
32 : 6 Y_2 -ww
33 : 7 C2 -ww c
34 : 8 Y_3 -www
35 : 9 D2 -www c
36 : 10 P2 www z_r
37 : ------------------------ MSM
38 : Y_0
39 : */
40 :
41 : /* Validate all inputs */
42 63 : uchar scalars[ 11 * 32 ];
43 63 : fd_ristretto255_point_t points[11];
44 63 : fd_ristretto255_point_t y0[1];
45 63 : fd_ristretto255_point_t res[1];
46 :
47 63 : if( FD_UNLIKELY( fd_curve25519_scalar_validate( proof->zs )==NULL ) ) {
48 0 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
49 0 : }
50 63 : if( FD_UNLIKELY( fd_curve25519_scalar_validate( proof->zx )==NULL ) ) {
51 0 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
52 0 : }
53 63 : if( FD_UNLIKELY( fd_curve25519_scalar_validate( proof->zr )==NULL ) ) {
54 0 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
55 0 : }
56 :
57 63 : fd_ristretto255_point_set( &points[0], fd_zksdk_basepoint_G );
58 63 : fd_ristretto255_point_set( &points[1], fd_zksdk_basepoint_H );
59 63 : if( FD_UNLIKELY( fd_ristretto255_point_decompress( y0, proof->y0 )==NULL ) ) {
60 0 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
61 0 : }
62 63 : if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[2], pubkey1 )==NULL ) ) {
63 9 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
64 9 : }
65 54 : if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[3], &ciphertext1[32] )==NULL ) ) {
66 0 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
67 0 : }
68 54 : if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[4], proof->y1 )==NULL ) ) {
69 0 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
70 0 : }
71 54 : if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[5], ciphertext1 )==NULL ) ) {
72 0 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
73 0 : }
74 54 : if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[6], proof->y2 )==NULL ) ) {
75 0 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
76 0 : }
77 54 : if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[7], ciphertext2 )==NULL ) ) {
78 0 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
79 0 : }
80 54 : if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[8], proof->y3 )==NULL ) ) {
81 0 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
82 0 : }
83 54 : if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[9], &ciphertext2[32] )==NULL ) ) {
84 0 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
85 0 : }
86 54 : if( FD_UNLIKELY( fd_ristretto255_point_decompress( &points[10], pubkey2 )==NULL ) ) {
87 0 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
88 0 : }
89 :
90 : /* Finalize transcript and extract challenges */
91 54 : fd_zksdk_transcript_domsep_ciph_ciph_eq_proof( transcript );
92 54 : int val = FD_TRANSCRIPT_SUCCESS;
93 54 : val |= fd_zksdk_transcript_validate_and_append_point( transcript, FD_TRANSCRIPT_LITERAL("Y_0"), proof->y0);
94 54 : val |= fd_zksdk_transcript_validate_and_append_point( transcript, FD_TRANSCRIPT_LITERAL("Y_1"), proof->y1);
95 54 : val |= fd_zksdk_transcript_validate_and_append_point( transcript, FD_TRANSCRIPT_LITERAL("Y_2"), proof->y2);
96 54 : val |= fd_zksdk_transcript_validate_and_append_point( transcript, FD_TRANSCRIPT_LITERAL("Y_3"), proof->y3);
97 54 : if( FD_UNLIKELY( val != FD_TRANSCRIPT_SUCCESS ) ) {
98 0 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
99 0 : }
100 :
101 54 : uchar c[ 32 ];
102 54 : uchar w[ 32 ];
103 54 : fd_zksdk_transcript_challenge_scalar( c, transcript, FD_TRANSCRIPT_LITERAL("c") );
104 54 : fd_zksdk_transcript_challenge_scalar( w, transcript, FD_TRANSCRIPT_LITERAL("w") );
105 :
106 54 : uchar ww[ 32 ];
107 54 : fd_curve25519_scalar_mul( ww, w, w );
108 :
109 : /* Compute scalars */
110 54 : fd_curve25519_scalar_add( &scalars[ 0*32 ], w, ww ); // z_x (w + ww)
111 54 : fd_curve25519_scalar_mul( &scalars[ 0*32 ], &scalars[ 0*32 ], proof->zx );
112 54 : fd_curve25519_scalar_mul( &scalars[ 1*32 ], proof->zr, ww ); // -c + z_r ww
113 54 : fd_curve25519_scalar_sub( &scalars[ 1*32 ], &scalars[ 1*32 ], c );
114 54 : fd_curve25519_scalar_set( &scalars[ 2*32 ], proof->zs ); // z_s
115 54 : fd_curve25519_scalar_mul( &scalars[ 3*32 ], &scalars[ 2*32 ], w ); // z_s w
116 54 : fd_curve25519_scalar_neg( &scalars[ 4*32 ], w ); // -w
117 54 : fd_curve25519_scalar_mul( &scalars[ 5*32 ], &scalars[ 4*32 ], c ); // -w c
118 54 : fd_curve25519_scalar_neg( &scalars[ 6*32 ], ww ); // -ww
119 54 : fd_curve25519_scalar_mul( &scalars[ 7*32 ], &scalars[ 6*32 ], c ); // -ww c
120 54 : fd_curve25519_scalar_mul( ww, ww, w );
121 54 : fd_curve25519_scalar_neg( &scalars[ 8*32 ], ww ); // -www
122 54 : fd_curve25519_scalar_mul( &scalars[ 9*32 ], &scalars[ 8*32 ], c ); // -www c
123 54 : fd_curve25519_scalar_mul( &scalars[ 10*32 ], proof->zr, ww ); // www z_r
124 :
125 : /* Compute the final MSM */
126 54 : fd_ristretto255_multi_scalar_mul( res, scalars, points, 11 );
127 :
128 54 : if( FD_LIKELY( fd_ristretto255_point_eq( res, y0 ) ) ) {
129 45 : return FD_EXECUTOR_INSTR_SUCCESS;
130 45 : }
131 9 : return FD_ZKSDK_VERIFY_PROOF_ERROR;
132 54 : }
133 :
134 : /* https://github.com/anza-xyz/agave/blob/v2.0.1/zk-sdk/src/zk_elgamal_proof_program/proof_data/ciphertext_ciphertext_equality.rs#L105 */
135 : int
136 63 : fd_zksdk_instr_verify_proof_ciphertext_ciphertext_equality( void const * _context, void const * _proof ) {
137 63 : fd_zksdk_transcript_t transcript[1];
138 63 : fd_zksdk_ciph_ciph_eq_context_t const * context = _context;
139 63 : fd_zksdk_ciph_ciph_eq_proof_t const * proof = _proof;
140 :
141 63 : ciphertext_ciphertext_equality_transcript_init( transcript, context );
142 63 : return fd_zksdk_verify_proof_ciphertext_ciphertext_equality(
143 63 : proof,
144 63 : context->pubkey1,
145 63 : context->pubkey2,
146 63 : context->ciphertext1,
147 63 : context->ciphertext2,
148 63 : transcript
149 63 : );
150 63 : }
|