@@ -393,4 +393,74 @@ int secp256k1_surjectionproof_verify(const secp256k1_context* ctx, const secp256
393
393
return secp256k1_borromean_verify (NULL , & proof -> data [0 ], borromean_s , ring_pubkeys , rsizes , 1 , msg32 , 32 );
394
394
}
395
395
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
+
396
466
#endif
0 commit comments