@@ -352,6 +352,171 @@ public void transactionSizeComparisonByScheme() {
352352 Assert .assertTrue (trc20 [1 ][2 ] < trc20 [0 ][2 ]);
353353 }
354354
355+ @ Test
356+ public void pqAuthSigWrongPublicKeyLengthRejected () throws Exception {
357+ dbManager .getDynamicPropertiesStore ().saveAllowFnDsa512 (1L );
358+ FNDSA kp = new FNDSA ();
359+ putAccountWithPQPermission (PQ_OWNER_HEX , kp .getPublicKey (), PQScheme .FN_DSA_512 );
360+
361+ Transaction tx = buildTransferTx (PQ_OWNER_HEX , 0 );
362+ byte [] txid = Sha256Hash .of (true , tx .getRawData ().toByteArray ()).getBytes ();
363+ byte [] sig = FNDSA .sign (kp .getPrivateKey (), txid );
364+
365+ // Truncate public key by one byte to force the length-mismatch branch.
366+ byte [] shortPub = new byte [FNDSA .PUBLIC_KEY_LENGTH - 1 ];
367+ System .arraycopy (kp .getPublicKey (), 0 , shortPub , 0 , shortPub .length );
368+
369+ Transaction signed = tx .toBuilder ()
370+ .addPqAuthSig (PQAuthSig .newBuilder ()
371+ .setScheme (PQScheme .FN_DSA_512 )
372+ .setPublicKey (ByteString .copyFrom (shortPub ))
373+ .setSignature (ByteString .copyFrom (sig ))
374+ .build ())
375+ .build ();
376+ TransactionCapsule cap = new TransactionCapsule (signed );
377+ try {
378+ cap .validatePubSignature (dbManager .getAccountStore (),
379+ dbManager .getDynamicPropertiesStore ());
380+ Assert .fail ("wrong public key length must be rejected" );
381+ } catch (ValidateSignatureException e ) {
382+ Assert .assertTrue (e .getMessage ().contains ("public key or signature length mismatch" ));
383+ }
384+ }
385+
386+ @ Test
387+ public void pqAuthSigWrongSignatureLengthRejected () throws Exception {
388+ dbManager .getDynamicPropertiesStore ().saveAllowFnDsa512 (1L );
389+ FNDSA kp = new FNDSA ();
390+ putAccountWithPQPermission (PQ_OWNER_HEX , kp .getPublicKey (), PQScheme .FN_DSA_512 );
391+
392+ Transaction tx = buildTransferTx (PQ_OWNER_HEX , 0 );
393+
394+ // Empty signature is not a valid FN-DSA-512 length, hits the same branch.
395+ Transaction signed = tx .toBuilder ()
396+ .addPqAuthSig (PQAuthSig .newBuilder ()
397+ .setScheme (PQScheme .FN_DSA_512 )
398+ .setPublicKey (ByteString .copyFrom (kp .getPublicKey ()))
399+ .setSignature (ByteString .EMPTY )
400+ .build ())
401+ .build ();
402+ TransactionCapsule cap = new TransactionCapsule (signed );
403+ try {
404+ cap .validatePubSignature (dbManager .getAccountStore (),
405+ dbManager .getDynamicPropertiesStore ());
406+ Assert .fail ("wrong signature length must be rejected" );
407+ } catch (ValidateSignatureException e ) {
408+ Assert .assertTrue (e .getMessage ().contains ("public key or signature length mismatch" ));
409+ }
410+ }
411+
412+ @ Test
413+ public void pqAuthSigUnsupportedSchemeRejected () throws Exception {
414+ dbManager .getDynamicPropertiesStore ().saveAllowFnDsa512 (1L );
415+ FNDSA kp = new FNDSA ();
416+ putAccountWithPQPermission (PQ_OWNER_HEX , kp .getPublicKey (), PQScheme .FN_DSA_512 );
417+
418+ Transaction tx = buildTransferTx (PQ_OWNER_HEX , 0 );
419+ byte [] txid = Sha256Hash .of (true , tx .getRawData ().toByteArray ()).getBytes ();
420+ byte [] sig = FNDSA .sign (kp .getPrivateKey (), txid );
421+
422+ // setSchemeValue(99) sets an unknown numeric tag; reading back yields
423+ // PQScheme.UNRECOGNIZED, which PQSchemeRegistry.contains() rejects.
424+ Transaction signed = tx .toBuilder ()
425+ .addPqAuthSig (PQAuthSig .newBuilder ()
426+ .setSchemeValue (99 )
427+ .setPublicKey (ByteString .copyFrom (kp .getPublicKey ()))
428+ .setSignature (ByteString .copyFrom (sig ))
429+ .build ())
430+ .build ();
431+ TransactionCapsule cap = new TransactionCapsule (signed );
432+ try {
433+ cap .validatePubSignature (dbManager .getAccountStore (),
434+ dbManager .getDynamicPropertiesStore ());
435+ Assert .fail ("unsupported scheme must be rejected" );
436+ } catch (ValidateSignatureException e ) {
437+ Assert .assertTrue (e .getMessage ().contains ("unsupported pq scheme" ));
438+ }
439+ }
440+
441+ @ Test
442+ public void validatePubSignatureRejectsMissingSig () {
443+ Transaction tx = buildTransferTx (PQ_OWNER_HEX , 0 );
444+ TransactionCapsule cap = new TransactionCapsule (tx );
445+ try {
446+ cap .validatePubSignature (dbManager .getAccountStore (),
447+ dbManager .getDynamicPropertiesStore ());
448+ Assert .fail ("transaction with no signatures must be rejected" );
449+ } catch (ValidateSignatureException e ) {
450+ Assert .assertTrue (e .getMessage ().contains ("miss sig" ));
451+ }
452+ }
453+
454+ @ Test
455+ public void validatePubSignatureRejectsMissingContract () throws Exception {
456+ dbManager .getDynamicPropertiesStore ().saveAllowFnDsa512 (1L );
457+ FNDSA kp = new FNDSA ();
458+ byte [] sig = FNDSA .sign (kp .getPrivateKey (), new byte [32 ]);
459+
460+ // No contracts in raw_data, but a pq_auth_sig is attached so we get past
461+ // the "miss sig" guard and into the "miss contract" branch.
462+ Transaction tx = Transaction .newBuilder ()
463+ .setRawData (raw .newBuilder ().build ())
464+ .addPqAuthSig (PQAuthSig .newBuilder ()
465+ .setScheme (PQScheme .FN_DSA_512 )
466+ .setPublicKey (ByteString .copyFrom (kp .getPublicKey ()))
467+ .setSignature (ByteString .copyFrom (sig ))
468+ .build ())
469+ .build ();
470+ TransactionCapsule cap = new TransactionCapsule (tx );
471+ try {
472+ cap .validatePubSignature (dbManager .getAccountStore (),
473+ dbManager .getDynamicPropertiesStore ());
474+ Assert .fail ("transaction with no contracts must be rejected" );
475+ } catch (ValidateSignatureException e ) {
476+ Assert .assertTrue (e .getMessage ().contains ("miss contract" ));
477+ }
478+ }
479+
480+ @ Test
481+ public void validatePubSignatureRejectsTooManySignatures () throws Exception {
482+ dbManager .getDynamicPropertiesStore ().saveAllowFnDsa512 (1L );
483+ int original = dbManager .getDynamicPropertiesStore ().getTotalSignNum ();
484+ try {
485+ dbManager .getDynamicPropertiesStore ().saveTotalSignNum (1 );
486+ FNDSA a = new FNDSA ();
487+ FNDSA b = new FNDSA ();
488+ putAccountWithPQPermission (PQ_OWNER_HEX , a .getPublicKey (), PQScheme .FN_DSA_512 );
489+
490+ Transaction tx = buildTransferTx (PQ_OWNER_HEX , 0 );
491+ byte [] txid = Sha256Hash .of (true , tx .getRawData ().toByteArray ()).getBytes ();
492+ byte [] sigA = FNDSA .sign (a .getPrivateKey (), txid );
493+ byte [] sigB = FNDSA .sign (b .getPrivateKey (), txid );
494+
495+ Transaction signed = tx .toBuilder ()
496+ .addPqAuthSig (PQAuthSig .newBuilder ()
497+ .setScheme (PQScheme .FN_DSA_512 )
498+ .setPublicKey (ByteString .copyFrom (a .getPublicKey ()))
499+ .setSignature (ByteString .copyFrom (sigA ))
500+ .build ())
501+ .addPqAuthSig (PQAuthSig .newBuilder ()
502+ .setScheme (PQScheme .FN_DSA_512 )
503+ .setPublicKey (ByteString .copyFrom (b .getPublicKey ()))
504+ .setSignature (ByteString .copyFrom (sigB ))
505+ .build ())
506+ .build ();
507+ TransactionCapsule cap = new TransactionCapsule (signed );
508+ try {
509+ cap .validatePubSignature (dbManager .getAccountStore (),
510+ dbManager .getDynamicPropertiesStore ());
511+ Assert .fail ("more sigs than totalSignNum must be rejected" );
512+ } catch (ValidateSignatureException e ) {
513+ Assert .assertTrue (e .getMessage ().contains ("too many signatures" ));
514+ }
515+ } finally {
516+ dbManager .getDynamicPropertiesStore ().saveTotalSignNum (original );
517+ }
518+ }
519+
355520 @ Test
356521 public void fnDsaPQAuthSigRejectedWhenNotActivated () throws Exception {
357522 dbManager .getDynamicPropertiesStore ().saveAllowFnDsa512 (0L );
0 commit comments