@@ -120,14 +120,7 @@ public void Dispose()
120
120
/// </exception>
121
121
public void SignData ( ReadOnlySpan < byte > data , Span < byte > destination , ReadOnlySpan < byte > context = default )
122
122
{
123
- int signatureSizeInBytes = Algorithm . SignatureSizeInBytes ;
124
-
125
- if ( destination . Length != signatureSizeInBytes )
126
- {
127
- throw new ArgumentException (
128
- SR . Format ( SR . Argument_DestinationImprecise , signatureSizeInBytes ) ,
129
- nameof ( destination ) ) ;
130
- }
123
+ Helpers . ThrowIfDestinationWrongLength ( destination , Algorithm . SignatureSizeInBytes ) ;
131
124
132
125
if ( context . Length > MaxContextLength )
133
126
{
@@ -309,13 +302,7 @@ public bool VerifyData(byte[] data, byte[] signature, byte[]? context = default)
309
302
public void SignPreHash ( ReadOnlySpan < byte > hash , Span < byte > destination , string hashAlgorithmOid , ReadOnlySpan < byte > context = default )
310
303
{
311
304
ArgumentNullException . ThrowIfNull ( hashAlgorithmOid ) ;
312
-
313
- if ( destination . Length != Algorithm . SignatureSizeInBytes )
314
- {
315
- throw new ArgumentException (
316
- SR . Format ( SR . Argument_DestinationImprecise , Algorithm . SignatureSizeInBytes ) ,
317
- nameof ( destination ) ) ;
318
- }
305
+ Helpers . ThrowIfDestinationWrongLength ( destination , Algorithm . SignatureSizeInBytes ) ;
319
306
320
307
if ( context . Length > MaxContextLength )
321
308
{
@@ -507,6 +494,155 @@ public bool VerifyPreHash(byte[] hash, byte[] signature, string hashAlgorithmOid
507
494
new ReadOnlySpan < byte > ( context ) ) ;
508
495
}
509
496
497
+ /// <inheritdoc cref="SignMu(ReadOnlySpan{byte})"/>
498
+ /// <exception cref="ArgumentNullException"><paramref name="externalMu"/> is <see langword="null"/>.</exception>
499
+ public byte [ ] SignMu ( byte [ ] externalMu )
500
+ {
501
+ ArgumentNullException . ThrowIfNull ( externalMu ) ;
502
+
503
+ return SignMu ( new ReadOnlySpan < byte > ( externalMu ) ) ;
504
+ }
505
+
506
+ /// <summary>
507
+ /// Signs the specified externally computed signature mu (μ) value.
508
+ /// </summary>
509
+ /// <param name="externalMu">
510
+ /// The signature mu value to sign.
511
+ /// </param>
512
+ /// <returns>
513
+ /// ML-DSA signature for the specified mu value.
514
+ /// </returns>
515
+ /// <exception cref="ArgumentException">
516
+ /// The buffer in <paramref name="externalMu"/> is the incorrect length for the signature mu value.
517
+ /// </exception>
518
+ /// <exception cref="ObjectDisposedException">
519
+ /// This instance has been disposed.
520
+ /// </exception>
521
+ /// <exception cref="CryptographicException">
522
+ /// <para>The instance represents only a public key.</para>
523
+ /// <para>-or-</para>
524
+ /// <para>An error occurred while signing the hash.</para>
525
+ /// </exception>
526
+ /// <exception cref="PlatformNotSupportedException">
527
+ /// The current platform does not support signing with an externally computed mu value.
528
+ /// </exception>
529
+ /// <seealso cref="VerifyMu(byte[], byte[])"/>
530
+ public byte [ ] SignMu ( ReadOnlySpan < byte > externalMu )
531
+ {
532
+ byte [ ] destination = new byte [ Algorithm . SignatureSizeInBytes ] ;
533
+ SignMu ( externalMu , destination . AsSpan ( ) ) ;
534
+ return destination ;
535
+ }
536
+
537
+ /// <summary>
538
+ /// Signs the specified externally computed signature mu (μ) value,
539
+ /// writing the signature into the provided buffer.
540
+ /// </summary>
541
+ /// <param name="externalMu">
542
+ /// The signature mu value to sign.
543
+ /// </param>
544
+ /// <param name="destination">
545
+ /// The buffer to receive the signature. Its length must be exactly
546
+ /// <see cref="MLDsaAlgorithm.SignatureSizeInBytes"/>.
547
+ /// </param>
548
+ /// <exception cref="ArgumentException">
549
+ /// <para>
550
+ /// The buffer in <paramref name="externalMu"/> is the incorrect length for the signature mu value.
551
+ /// </para>
552
+ /// <para>-or-</para>
553
+ /// <para>
554
+ /// The buffer in <paramref name="destination"/> is the incorrect length to receive the signature.
555
+ /// </para>
556
+ /// </exception>
557
+ /// <exception cref="ObjectDisposedException">
558
+ /// This instance has been disposed.
559
+ /// </exception>
560
+ /// <exception cref="CryptographicException">
561
+ /// <para>The instance represents only a public key.</para>
562
+ /// <para>-or-</para>
563
+ /// <para>An error occurred while signing the hash.</para>
564
+ /// </exception>
565
+ /// <exception cref="PlatformNotSupportedException">
566
+ /// The current platform does not support signing with an externally computed mu value.
567
+ /// </exception>
568
+ /// <seealso cref="VerifyMu(ReadOnlySpan{byte}, ReadOnlySpan{byte})"/>
569
+ public void SignMu ( ReadOnlySpan < byte > externalMu , Span < byte > destination )
570
+ {
571
+ if ( externalMu . Length != Algorithm . MuSizeInBytes )
572
+ throw new ArgumentException ( SR . Argument_MLDsaMuInvalidLength , nameof ( externalMu ) ) ;
573
+
574
+ Helpers . ThrowIfDestinationWrongLength ( destination , Algorithm . SignatureSizeInBytes ) ;
575
+ ThrowIfDisposed ( ) ;
576
+
577
+ SignMuCore ( externalMu , destination ) ;
578
+ }
579
+
580
+ /// <summary>
581
+ /// When overridden in a derived class, computes the remainder of the signature from the
582
+ /// precomputed mu (μ) value, writing it into the provided buffer.
583
+ /// </summary>
584
+ /// <param name="externalMu">
585
+ /// The signature mu value to sign.
586
+ /// </param>
587
+ /// <param name="destination">
588
+ /// The buffer to receive the signature, which will always be the exactly correct size for the algorithm.
589
+ /// </param>
590
+ /// <exception cref="CryptographicException">
591
+ /// An error occurred while computing the signature.
592
+ /// </exception>
593
+ protected abstract void SignMuCore ( ReadOnlySpan < byte > externalMu , Span < byte > destination ) ;
594
+
595
+ /// <inheritdoc cref="VerifyMu(ReadOnlySpan{byte}, ReadOnlySpan{byte})"/>
596
+ /// <exception cref="ArgumentNullException">
597
+ /// <paramref name="externalMu"/> or <paramref name="signature"/> is <see langword="null"/>.
598
+ /// </exception>
599
+ public bool VerifyMu ( byte [ ] externalMu , byte [ ] signature )
600
+ {
601
+ ArgumentNullException . ThrowIfNull ( externalMu ) ;
602
+ ArgumentNullException . ThrowIfNull ( signature ) ;
603
+
604
+ return VerifyMu ( new ReadOnlySpan < byte > ( externalMu ) , new ReadOnlySpan < byte > ( signature ) ) ;
605
+ }
606
+
607
+ /// <summary>
608
+ /// Verifies that a digital signature is valid for the provided externally computed signature mu (μ) value.
609
+ /// </summary>
610
+ /// <param name="externalMu">The signature mu value.</param>
611
+ /// <param name="signature">The signature to verify.</param>
612
+ /// <returns>
613
+ /// <see langword="true"/> if the digital signature is valid for the provided mu value;
614
+ /// otherwise, <see langword="false"/>.
615
+ /// </returns>
616
+ /// <exception cref="ObjectDisposedException">
617
+ /// This instance has been disposed.
618
+ /// </exception>
619
+ /// <exception cref="CryptographicException">An error occurred while verifying the mu value.</exception>
620
+ /// <exception cref="PlatformNotSupportedException">
621
+ /// The current platform does not support verification with an externally computed mu value.
622
+ /// </exception>
623
+ public bool VerifyMu ( ReadOnlySpan < byte > externalMu , ReadOnlySpan < byte > signature )
624
+ {
625
+ if ( externalMu . Length != Algorithm . MuSizeInBytes || signature . Length != Algorithm . SignatureSizeInBytes )
626
+ {
627
+ return false ;
628
+ }
629
+
630
+ ThrowIfDisposed ( ) ;
631
+
632
+ return VerifyMuCore ( externalMu , signature ) ;
633
+ }
634
+
635
+ /// <summary>
636
+ /// When overridden in a derived class,
637
+ /// verifies that a digital signature is valid for the provided externally computed signature mu (μ) value.
638
+ /// </summary>
639
+ /// <param name="externalMu">The signature mu value.</param>
640
+ /// <param name="signature">The signature to verify.</param>
641
+ /// <returns>
642
+ /// <see langword="true"/> if the mu value is valid; otherwise, <see langword="false"/>.
643
+ /// </returns>
644
+ protected abstract bool VerifyMuCore ( ReadOnlySpan < byte > externalMu , ReadOnlySpan < byte > signature ) ;
645
+
510
646
/// <summary>
511
647
/// Exports the public-key portion of the current key in the X.509 SubjectPublicKeyInfo format.
512
648
/// </summary>
@@ -1063,15 +1199,7 @@ public byte[] ExportMLDsaPublicKey()
1063
1199
/// </remarks>
1064
1200
public void ExportMLDsaPublicKey ( Span < byte > destination )
1065
1201
{
1066
- int publicKeySizeInBytes = Algorithm . PublicKeySizeInBytes ;
1067
-
1068
- if ( destination . Length != publicKeySizeInBytes )
1069
- {
1070
- throw new ArgumentException (
1071
- SR . Format ( SR . Argument_DestinationImprecise , publicKeySizeInBytes ) ,
1072
- nameof ( destination ) ) ;
1073
- }
1074
-
1202
+ Helpers . ThrowIfDestinationWrongLength ( destination , Algorithm . PublicKeySizeInBytes ) ;
1075
1203
ThrowIfDisposed ( ) ;
1076
1204
1077
1205
ExportMLDsaPublicKeyCore ( destination ) ;
@@ -1113,15 +1241,7 @@ public byte[] ExportMLDsaSecretKey()
1113
1241
/// </exception>
1114
1242
public void ExportMLDsaSecretKey ( Span < byte > destination )
1115
1243
{
1116
- int secretKeySizeInBytes = Algorithm . SecretKeySizeInBytes ;
1117
-
1118
- if ( destination . Length != secretKeySizeInBytes )
1119
- {
1120
- throw new ArgumentException (
1121
- SR . Format ( SR . Argument_DestinationImprecise , secretKeySizeInBytes ) ,
1122
- nameof ( destination ) ) ;
1123
- }
1124
-
1244
+ Helpers . ThrowIfDestinationWrongLength ( destination , Algorithm . SecretKeySizeInBytes ) ;
1125
1245
ThrowIfDisposed ( ) ;
1126
1246
1127
1247
ExportMLDsaSecretKeyCore ( destination ) ;
@@ -1161,14 +1281,7 @@ public byte[] ExportMLDsaPrivateSeed()
1161
1281
/// </exception>
1162
1282
public void ExportMLDsaPrivateSeed ( Span < byte > destination )
1163
1283
{
1164
- int privateSeedSizeInBytes = Algorithm . PrivateSeedSizeInBytes ;
1165
- if ( destination . Length != privateSeedSizeInBytes )
1166
- {
1167
- throw new ArgumentException (
1168
- SR . Format ( SR . Argument_DestinationImprecise , privateSeedSizeInBytes ) ,
1169
- nameof ( destination ) ) ;
1170
- }
1171
-
1284
+ Helpers . ThrowIfDestinationWrongLength ( destination , Algorithm . PrivateSeedSizeInBytes ) ;
1172
1285
ThrowIfDisposed ( ) ;
1173
1286
1174
1287
ExportMLDsaPrivateSeedCore ( destination ) ;
0 commit comments