@@ -393,4 +393,74 @@ int secp256k1_surjectionproof_verify(const secp256k1_context* ctx, const secp256
393393 return secp256k1_borromean_verify (NULL , & proof -> data [0 ], borromean_s , ring_pubkeys , rsizes , 1 , msg32 , 32 );
394394}
395395
396+ int secp256k1_surjectionproof_verify_single (const secp256k1_context * ctx , const secp256k1_surjectionproof * proof , const secp256k1_generator * input_tag , const secp256k1_generator * output_tag ) {
397+ secp256k1_ge inputp ;
398+ secp256k1_ge outputp ;
399+ secp256k1_gej tmpj ;
400+ secp256k1_gej xj ;
401+ secp256k1_ge rp ;
402+ secp256k1_scalar es ;
403+ secp256k1_scalar ss ;
404+ secp256k1_sha256 sha2 ;
405+ unsigned char tmpch [33 ];
406+ unsigned char pp_comm [32 ];
407+ size_t sz ;
408+ int overflow ;
409+
410+ /* Validate and decode surjectionproof data */
411+ VERIFY_CHECK (ctx != NULL );
412+ ARG_CHECK (proof != NULL );
413+ ARG_CHECK (input_tag != NULL );
414+ ARG_CHECK (output_tag != NULL );
415+ #ifdef VERIFY
416+ CHECK (proof -> initialized == 1 );
417+ #endif
418+
419+ if (proof -> n_inputs != 1 || proof -> used_inputs [0 ] != 1 ) {
420+ return 0 ;
421+ }
422+
423+ secp256k1_generator_load (& inputp , input_tag );
424+ secp256k1_generator_load (& outputp , output_tag );
425+ secp256k1_ge_neg (& inputp , & inputp );
426+ secp256k1_gej_set_ge (& xj , & inputp );
427+ secp256k1_gej_add_ge (& xj , & xj , & outputp );
428+
429+ /* Now we just have a Schnorr signature in (e, s) form. The verification
430+ * equation is e == H(sG - eX || proof params), where X is the difference
431+ * between the output and input. */
432+
433+ /* 1. Compute slow/overwrought commitment to proof params */
434+ secp256k1_surjection_genmessage (pp_comm , input_tag , 1 , output_tag );
435+ /* (past this point the code is identical to rangeproof_verify_value) */
436+
437+ /* ... feed this into our hash */
438+ secp256k1_borromean_hash (tmpch , pp_comm , 32 , & proof -> data [0 ], 32 , 0 , 0 );
439+ secp256k1_scalar_set_b32 (& es , tmpch , & overflow );
440+ if (overflow || secp256k1_scalar_is_zero (& es )) {
441+ return 0 ;
442+ }
443+
444+ /* 1. Compute R = sG - eX */
445+ secp256k1_scalar_set_b32 (& ss , & proof -> data [32 ], & overflow );
446+ if (overflow || secp256k1_scalar_is_zero (& ss )) {
447+ return 0 ;
448+ }
449+ secp256k1_ecmult (& tmpj , & xj , & es , & ss );
450+ if (secp256k1_gej_is_infinity (& tmpj )) {
451+ return 0 ;
452+ }
453+ secp256k1_ge_set_gej (& rp , & tmpj );
454+ secp256k1_eckey_pubkey_serialize (& rp , tmpch , & sz , 1 );
455+
456+ /* 2. Compute e = H(R || proof params) */
457+ secp256k1_sha256_initialize (& sha2 );
458+ secp256k1_sha256_write (& sha2 , tmpch , sz );
459+ secp256k1_sha256_write (& sha2 , pp_comm , sizeof (pp_comm ));
460+ secp256k1_sha256_finalize (& sha2 , tmpch );
461+
462+ /* 3. Check computed e against original e */
463+ return !memcmp (tmpch , & proof -> data [0 ], 32 );
464+ }
465+
396466#endif
0 commit comments