@@ -111,6 +111,74 @@ int secp256k1_silentpayments_send_create_shared_secret(const secp256k1_context *
111111 return 1 ;
112112}
113113
114+ int secp256k1_silentpayments_create_public_tweak_data (const secp256k1_context * ctx , unsigned char * tweak_data33 , const secp256k1_pubkey * plain_pubkeys , size_t n_plain_pubkeys , const secp256k1_xonly_pubkey * xonly_pubkeys , size_t n_xonly_pubkeys , const unsigned char * outpoints_hash32 ) {
115+ size_t i ;
116+ secp256k1_pubkey A_tweaked ;
117+ size_t outputlen = 33 ;
118+
119+ /* Sanity check inputs */
120+ VERIFY_CHECK (ctx != NULL );
121+ ARG_CHECK (tweak_data33 != NULL );
122+ memset (tweak_data33 , 0 , 33 );
123+ ARG_CHECK (plain_pubkeys == NULL || n_plain_pubkeys >= 1 );
124+ ARG_CHECK (xonly_pubkeys == NULL || n_xonly_pubkeys >= 1 );
125+ ARG_CHECK ((plain_pubkeys != NULL ) || (xonly_pubkeys != NULL ));
126+ ARG_CHECK ((n_plain_pubkeys + n_xonly_pubkeys ) >= 1 );
127+ ARG_CHECK (outpoints_hash32 != NULL );
128+
129+ /* Compute input public keys tweak: A_tweaked = (A_0 + A_1 + ... + A_n) * outpoints_hash */
130+ for (i = 0 ; i < n_plain_pubkeys ; i ++ ) {
131+ secp256k1_pubkey combined ;
132+ const secp256k1_pubkey * addends [2 ];
133+ if (i == 0 ) {
134+ A_tweaked = plain_pubkeys [0 ];
135+ continue ;
136+ }
137+ addends [0 ] = & A_tweaked ;
138+ addends [1 ] = & plain_pubkeys [i ];
139+ if (!secp256k1_ec_pubkey_combine (ctx , & combined , addends , 2 )) {
140+ return 0 ;
141+ }
142+ A_tweaked = combined ;
143+ }
144+ /* X-only public keys have to be converted to regular public keys (assuming even parity) */
145+ for (i = 0 ; i < n_xonly_pubkeys ; i ++ ) {
146+ unsigned char pubkey_to_add_ser [33 ];
147+ secp256k1_pubkey combined , pubkey_to_add ;
148+ const secp256k1_pubkey * addends [2 ];
149+
150+ pubkey_to_add_ser [0 ] = 0x02 ;
151+ if (!secp256k1_xonly_pubkey_serialize (ctx , & pubkey_to_add_ser [1 ], & xonly_pubkeys [i ])) {
152+ return 0 ;
153+ }
154+ if (!secp256k1_ec_pubkey_parse (ctx , & pubkey_to_add , pubkey_to_add_ser , 33 )) {
155+ return 0 ;
156+ }
157+
158+ if (i == 0 && n_plain_pubkeys == 0 ) {
159+ A_tweaked = pubkey_to_add ;
160+ continue ;
161+ }
162+ addends [0 ] = & A_tweaked ;
163+ addends [1 ] = & pubkey_to_add ;
164+ if (!secp256k1_ec_pubkey_combine (ctx , & combined , addends , 2 )) {
165+ return 0 ;
166+ }
167+ A_tweaked = combined ;
168+ }
169+
170+ if (!secp256k1_ec_pubkey_tweak_mul (ctx , & A_tweaked , outpoints_hash32 )) {
171+ return 0 ;
172+ }
173+
174+ /* Serialize tweak_data */
175+ if (!secp256k1_ec_pubkey_serialize (ctx , tweak_data33 , & outputlen , & A_tweaked , SECP256K1_EC_COMPRESSED )) {
176+ return 0 ;
177+ }
178+
179+ return 1 ;
180+ }
181+
114182/* TODO: implement functions for receiver side. */
115183
116184#endif
0 commit comments