17 public static readonly
ML_DSA ML_DSA_44 =
new ML_DSA(39, 128, 1 << 17, (q - 1) / 88, 4, 4, 2, 80, 2560, 1312, 2420);
23 public static readonly
ML_DSA ML_DSA_65 =
new ML_DSA(49, 192, 1 << 19, (q - 1) / 32, 6, 5, 4, 55, 4032, 1952, 3309);
29 public static readonly
ML_DSA ML_DSA_87 =
new ML_DSA(60, 256, 1 << 19, (q - 1) / 32, 8, 7, 2, 75, 4896, 2592, 4627);
39 switch (Name.ToUpper())
51 throw new ArgumentException(
"Unknown model name: " + Name, nameof(Name));
55 private const int n = 256;
56 private const int q = 8380417;
57 private const int ζ = 1753;
58 private const int d = 13;
59 private const uint dBitMask = 0x1fff;
60 private const short twoDHalf = 1 << (d - 1);
61 private const short twoD = 1 << d;
63 private readonly
int τ;
64 private readonly
int λ;
65 private readonly uint γ1;
66 private readonly uint γ2;
67 private readonly
byte k;
68 private readonly
byte l;
69 private readonly
byte η;
70 private readonly
int β;
71 private readonly
int ω;
73 private readonly
int twoγ2;
75 private readonly
int privateKeySize;
76 private readonly
int publicKeySize;
77 private readonly
int signatureSize;
94 public ML_DSA(
int τ,
int λ, uint γ1, uint γ2,
byte k,
byte l,
byte η,
int ω,
95 int PrivateKeySize,
int PublicKeySize,
int SignatureSize)
98 throw new ArgumentException(
"η must be 2 or 4.", nameof(η));
110 this.twoγ2 = (int)(this.γ2 << 1);
112 this.privateKeySize = PrivateKeySize;
113 this.publicKeySize = PublicKeySize;
114 this.signatureSize = SignatureSize;
135 return this.
KeyGen(
false);
166 public byte[]
Sign(
byte[] PrivateKey,
byte[] Message, out
int RejectionCount)
183 return this.
Sign(Keys, Message, (
byte[])
null, out RejectionCount);
196 public byte[]
Sign(
byte[] PrivateKey,
byte[] Message,
byte[] Context,
197 out
int RejectionCount)
214 out
int RejectionCount)
217 byte[] Result = this.
Sign(Keys, Message, Context, ξ, out RejectionCount);
234 public byte[]
Sign(
byte[] PrivateKey,
byte[] Message,
byte[] Context,
byte[] Seed,
235 out
int RejectionCount)
238 Seed, out RejectionCount);
253 out
int RejectionCount)
255 int MessageLen = Message.Length;
260 Context = Array.Empty<
byte>();
263 else if ((ContextLen = Context.Length) > 255)
264 throw new ArgumentException(
"Context must be 255 bytes or less.", nameof(Context));
268 else if (Seed.Length != 32)
269 throw new ArgumentException(
"Seed must be 32 bytes long.", nameof(Seed));
271 byte[] Bin =
new byte[2 + ContextLen + MessageLen];
273 Bin[1] = (byte)ContextLen;
276 Buffer.BlockCopy(Context, 0, Bin, 2, ContextLen);
278 Buffer.BlockCopy(Message, 0, Bin, 2 + ContextLen, MessageLen);
280 return this.
Sign_Internal(Keys, Bin,
false, Seed, out RejectionCount);
291 public bool Verify(
byte[] PublicKey,
byte[] Message,
byte[] Signature)
306 return this.
Verify(Keys, Message, Signature,
null);
318 public bool Verify(
byte[] PublicKey,
byte[] Message,
byte[] Signature,
byte[] Context)
335 int MessageLen = Message.Length;
340 Context = Array.Empty<
byte>();
343 else if ((ContextLen = Context.Length) > 255)
346 byte[] Bin =
new byte[2 + ContextLen + MessageLen];
348 Bin[1] = (byte)ContextLen;
351 Buffer.BlockCopy(Context, 0, Bin, 2, ContextLen);
353 Buffer.BlockCopy(Message, 0, Bin, 2 + ContextLen, MessageLen);
368 public byte[]
Sign(
byte[] PrivateKey,
byte[] Message,
string HashAlgorithm,
369 out
int RejectionCount)
372 HashAlgorithm, out RejectionCount);
386 out
int RejectionCount)
388 return this.
Sign(Keys, Message,
null, HashAlgorithm, out RejectionCount);
402 public byte[]
Sign(
byte[] PrivateKey,
byte[] Message,
byte[] Context,
403 string HashAlgorithm, out
int RejectionCount)
406 HashAlgorithm, out RejectionCount);
421 string HashAlgorithm, out
int RejectionCount)
424 byte[] Result = this.
Sign(Keys, Message, Context, ξ, HashAlgorithm,
444 public byte[]
Sign(
byte[] PrivateKey,
byte[] Message,
byte[] Context,
byte[] Seed,
445 string HashAlgorithm, out
int RejectionCount)
448 Seed, HashAlgorithm, out RejectionCount);
464 string HashAlgorithm, out
int RejectionCount)
470 Context = Array.Empty<
byte>();
473 else if ((ContextLen = Context.Length) > 255)
474 throw new ArgumentException(
"Context must be 255 bytes or less.", nameof(Context));
478 else if (Seed.Length != 32)
479 throw new ArgumentException(
"Seed must be 32 bytes long.", nameof(Seed));
482 throw new ArgumentException(
"Unsupported hash algorithm: " + HashAlgorithm, nameof(HashAlgorithm));
484 Message =
H(Message);
486 int MessageLen = Message.Length;
487 int OidLen = Oid.Length;
490 byte[] Bin =
new byte[2 + ContextLen + OidLen + MessageLen];
492 Bin[1] = (byte)ContextLen;
495 Buffer.BlockCopy(Context, 0, Bin, 2, ContextLen);
497 Buffer.BlockCopy(Oid, 0, Bin, Pos = 2 + ContextLen, OidLen);
500 Buffer.BlockCopy(Message, 0, Bin, Pos, MessageLen);
502 return this.
Sign_Internal(Keys, Bin,
false, Seed, out RejectionCount);
516 public byte[]
Sign(
byte[] PrivateKey, Stream Message,
byte[] Context,
517 string HashAlgorithm, out
int RejectionCount)
520 HashAlgorithm, out RejectionCount);
535 string HashAlgorithm, out
int RejectionCount)
538 byte[] Result = this.
Sign(Keys, Message, Context, ξ, HashAlgorithm,
558 public byte[]
Sign(
byte[] PrivateKey, Stream Message,
byte[] Context,
byte[] Seed,
559 string HashAlgorithm, out
int RejectionCount)
562 Seed, HashAlgorithm, out RejectionCount);
578 string HashAlgorithm, out
int RejectionCount)
584 Context = Array.Empty<
byte>();
587 else if ((ContextLen = Context.Length) > 255)
588 throw new ArgumentException(
"Context must be 255 bytes or less.", nameof(Context));
592 else if (Seed.Length != 32)
593 throw new ArgumentException(
"Seed must be 32 bytes long.", nameof(Seed));
596 throw new ArgumentException(
"Unsupported hash algorithm: " + HashAlgorithm, nameof(HashAlgorithm));
598 Message.Position = 0;
599 byte[] Message2 =
H(Message);
601 int Message2Len = Message2.Length;
602 int OidLen = Oid.Length;
605 byte[] Bin =
new byte[2 + ContextLen + OidLen + Message2Len];
607 Bin[1] = (byte)ContextLen;
610 Buffer.BlockCopy(Context, 0, Bin, 2, ContextLen);
612 Buffer.BlockCopy(Oid, 0, Bin, Pos = 2 + ContextLen, OidLen);
615 Buffer.BlockCopy(Message2, 0, Bin, Pos, Message2Len);
617 return this.
Sign_Internal(Keys, Bin,
false, Seed, out RejectionCount);
620 private static bool TryGetHashFunction(
string Name, out
HashFunctionArray H, out
byte[] Oid)
622 switch (Name.ToUpper())
684 private static bool TryGetHashFunction(
string Name, out
HashFunctionStream H, out
byte[] Oid)
686 switch (Name.ToUpper())
748 private static readonly
byte[] oidSha256 =
new byte[]
750 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
753 private static readonly
byte[] oidSha384 =
new byte[]
755 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
758 private static readonly
byte[] oidSha512 =
new byte[]
760 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
763 private static readonly
byte[] oidSha3_224 =
new byte[]
765 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x07
767 private static readonly
byte[] oidSha3_256 =
new byte[]
769 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08
772 private static readonly
byte[] oidSha3_384 =
new byte[]
774 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09
777 private static readonly
byte[] oidSha3_512 =
new byte[]
779 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0a
782 private static readonly
byte[] oidShake128 =
new byte[]
784 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0b
787 private static readonly
byte[] oidShake256 =
new byte[]
789 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0c
802 public bool Verify(
byte[] PublicKey,
byte[] Message,
byte[] Signature,
byte[] Context,
803 string HashAlgorithm)
806 Context, HashAlgorithm);
820 string HashAlgorithm)
826 Context = Array.Empty<
byte>();
829 else if ((ContextLen = Context.Length) > 255)
833 throw new ArgumentException(
"Unsupported hash algorithm: " + HashAlgorithm, nameof(HashAlgorithm));
835 Message =
H(Message);
837 int MessageLen = Message.Length;
838 int OidLen = Oid.Length;
841 byte[] Bin =
new byte[2 + ContextLen + OidLen + MessageLen];
843 Bin[1] = (byte)ContextLen;
846 Buffer.BlockCopy(Context, 0, Bin, 2, ContextLen);
848 Buffer.BlockCopy(Oid, 0, Bin, Pos = 2 + ContextLen, OidLen);
851 Buffer.BlockCopy(Message, 0, Bin, Pos, MessageLen);
866 public bool Verify(
byte[] PublicKey, Stream Message,
byte[] Signature,
byte[] Context,
867 string HashAlgorithm)
870 Context, HashAlgorithm);
884 string HashAlgorithm)
890 Context = Array.Empty<
byte>();
893 else if ((ContextLen = Context.Length) > 255)
897 throw new ArgumentException(
"Unsupported hash algorithm: " + HashAlgorithm, nameof(HashAlgorithm));
899 Message.Position = 0;
900 byte[] Message2 =
H(Message);
902 int Message2Len = Message2.Length;
903 int OidLen = Oid.Length;
906 byte[] Bin =
new byte[2 + ContextLen + OidLen + Message2Len];
908 Bin[1] = (byte)ContextLen;
911 Buffer.BlockCopy(Context, 0, Bin, 2, ContextLen);
913 Buffer.BlockCopy(Oid, 0, Bin, Pos = 2 + ContextLen, OidLen);
916 Buffer.BlockCopy(Message2, 0, Bin, Pos, Message2Len);
944 throw new ArgumentException(
"Seed must be 32 bytes long.", nameof(ξ));
946 byte[] Bin =
new byte[34];
947 Buffer.BlockCopy(ξ, 0, Bin, 0, 32);
951 byte[] Bin2 =
H(Bin, 128);
954 byte[] ρ =
new byte[32];
955 Buffer.BlockCopy(Bin2, 0, ρ, 0, 32);
957 byte[] K =
new byte[32];
958 Buffer.BlockCopy(Bin2, 96, K, 0, 32);
960 uint[,][] Â = this.ExpandÂ(ρ);
962 byte[] B =
new byte[66];
963 Buffer.BlockCopy(Bin2, 32, B, 0, 64);
965 short[][] s1 = this.ExpandS(B, this.l);
966 short[][] s2 = this.ExpandS(B, this.k);
970 uint[][] NTTs1 =
NTT(s1);
972 uint[][] t =
new uint[this.k][];
976 for (i = 0; i < this.k; i++)
978 t[i] = f =
new uint[n];
980 for (j = 0; j < this.l; j++)
990 short[][] t0 =
new short[this.k][];
991 short[][] t1 =
new short[this.k][];
996 for (i = 0; i < this.k; i++)
999 t0[i] = f0 =
new short[n];
1000 t1[i] = f1 =
new short[n];
1002 for (j = 0; j < n; j++)
1005 r0 = (short)(r & dBitMask);
1012 r1 = (short)((r - r0) >> d);
1018 byte[] PublicKey = this.PublicKeyEncode(ρ, t1);
1019 byte[] tr =
H(PublicKey, 64);
1020 byte[] PrivateKey = this.PrivateKeyEncode(ρ, K, tr, s1, s2, t0);
1030 return new ML_DSA_Keys(Â, PublicKey, PrivateKey, ReturnSeed ? ξ :
null);
1039 private uint[,][] ExpandÂ(
byte[] ρ)
1042 throw new ArgumentException(
"Seed must be 32 bytes long.", nameof(ρ));
1044 uint[,][] Â =
new uint[this.k, this.l][];
1047 byte[] B =
new byte[34];
1048 Buffer.BlockCopy(ρ, 0, B, 0, 32);
1050 for (r = 0; r < this.k; r++)
1054 for (c = 0; c < this.l; c++)
1057 Â[r, c] = RejNttPoly(B);
1073 private short[][] ExpandS(
byte[] Seed,
int Nr)
1075 short[][] s =
new short[Nr][];
1094 private byte[] PublicKeyEncode(
byte[] ρ,
short[][] t1)
1097 throw new ArgumentException(
"Seed must be 32 bytes long.", nameof(ρ));
1099 if (t1.Length !=
this.k)
1100 throw new ArgumentException(
"Invalid polynomial size.", nameof(t1));
1102 byte[] PublicKey =
new byte[this.publicKeySize];
1105 Buffer.BlockCopy(ρ, 0, PublicKey, 0, 32);
1107 for (
int i = 0; i < this.k; i++)
1124 private byte[] PrivateKeyEncode(
byte[] ρ,
byte[] K,
byte[] tr,
short[][] s1,
short[][] s2,
short[][] t0)
1127 throw new ArgumentException(
"Seed must be 32 bytes long.", nameof(ρ));
1130 throw new ArgumentException(
"K must be 32 bytes long.", nameof(K));
1132 if (tr.Length != 64)
1133 throw new ArgumentException(
"tr must be 32 bytes long.", nameof(tr));
1135 if (s1.Length !=
this.l)
1136 throw new ArgumentException(
"s1 must be " + this.l +
" polynomials long.", nameof(s1));
1138 if (s2.Length !=
this.k)
1139 throw new ArgumentException(
"s2 must be " + this.k +
" polynomials long.", nameof(s2));
1141 if (t0.Length !=
this.k)
1142 throw new ArgumentException(
"t0 must be " + this.k +
" polynomials long.", nameof(t0));
1144 byte[] PrivateKey =
new byte[this.privateKeySize];
1148 Buffer.BlockCopy(ρ, 0, PrivateKey, 0, 32);
1149 Buffer.BlockCopy(K, 0, PrivateKey, 32, 32);
1150 Buffer.BlockCopy(tr, 0, PrivateKey, 64, 64);
1152 for (i = 0; i < this.l; i++)
1153 Pos +=
BitPack(s1[i], PrivateKey, Pos, this.η, this.η);
1155 for (i = 0; i < this.k; i++)
1156 Pos +=
BitPack(s2[i], PrivateKey, Pos, this.η, this.η);
1158 uint b = 1 << (d - 1);
1161 for (i = 0; i < this.k; i++)
1162 Pos +=
BitPack(t0[i], PrivateKey, Pos, a, b);
1179 private bool TryDecodePrivateKey(
byte[] PrivateKey, out
byte[] ρ, out
byte[] K,
1180 out
byte[] tr, out
short[][] s1, out
short[][] s2, out
short[][] t0)
1182 if (PrivateKey is
null || PrivateKey.Length !=
this.privateKeySize)
1200 s1 =
new short[this.l][];
1201 s2 =
new short[this.k][];
1202 t0 =
new short[this.k][];
1204 Buffer.BlockCopy(PrivateKey, 0, ρ, 0, 32);
1205 Buffer.BlockCopy(PrivateKey, 32, K, 0, 32);
1206 Buffer.BlockCopy(PrivateKey, 64, tr, 0, 64);
1208 for (i = 0; i < this.l; i++)
1210 s1[i] =
new short[n];
1211 Pos +=
BitUnpack(s1[i], PrivateKey, Pos, this.η, this.η);
1214 for (i = 0; i < this.k; i++)
1216 s2[i] =
new short[n];
1217 Pos +=
BitUnpack(s2[i], PrivateKey, Pos, this.η, this.η);
1220 uint b = 1 << (d - 1);
1223 for (i = 0; i < this.k; i++)
1225 t0[i] =
new short[n];
1226 Pos +=
BitUnpack(t0[i], PrivateKey, Pos, a, b);
1229 return Pos == this.privateKeySize;
1238 private static uint[] RejNttPoly(
byte[] Seed)
1242 uint[] Result =
new uint[n];
1247 byte[] C = Context.
Squeeze(3);
1251 uint i = (uint)(C[2] & 0x7f);
1274 short[] Result =
new short[n];
1282 byte b1 = (byte)(z & 0x0f);
1283 byte b2 = (byte)(z >> 4);
1288 Result[Pos++] = (short)(2 - (b1 % 5));
1290 if (Pos < n && b2 < 15)
1291 Result[Pos++] = (short)(2 - (b2 % 5));
1294 else if (this.η == 4)
1299 byte b1 = (byte)(z & 0x0f);
1300 byte b2 = (byte)(z >> 4);
1305 Result[Pos++] = (short)(4 - b1);
1307 if (Pos < n && b2 < 9)
1308 Result[Pos++] = (short)(4 - b2);
1312 throw new InvalidOperationException(
"Invalid η.");
1322 public static void NTT(uint[] f)
1325 throw new ArgumentException(
"Polynomial must have " + n +
" coefficients.", nameof(f));
1334 for (Len = n >> 1; Len >= 1; Len >>= 1)
1336 for (Start = 0; Start < n; Start += Len << 1)
1338 ζ = nttTransformZeta[++m];
1340 for (j = Start; j < Start + Len; j++)
1342 t = (uint)(ζ * f[j + Len] % q);
1343 f[j + Len] = (f[j] + q - t) % q;
1344 f[j] = (f[j] + t) % q;
1354 public static void NTT(uint[][] f)
1356 int i, c = f.Length;
1358 for (i = 0; i < c; i++)
1367 public static uint[]
NTT(
short[] f)
1369 uint[] f0 = ToUIntVector(f);
1374 private static uint[] ToUIntVector(
short[] f)
1376 int i, c = f.Length;
1377 uint[] f0 =
new uint[n];
1380 for (i = 0; i < c; i++)
1383 f0[i] = (uint)(v < 0 ? q + v : v);
1394 public static uint[][]
NTT(
short[][] f)
1396 int i, c = f.Length;
1397 uint[][] Result =
new uint[c][];
1399 for (i = 0; i < c; i++)
1400 Result[i] =
NTT(f[i]);
1413 throw new ArgumentException(
"Polynomial must have " + n +
" coefficients.", nameof(f));
1424 for (Len = 1; Len < n; Len <<= 1)
1428 for (Start = 0; Start < n; Start += Len2)
1430 ζ = nttTransformZeta[--m];
1432 StartLen = Start + Len;
1433 for (j = Start; j < StartLen; j++)
1436 f[j] = (t + f[j + Len]) % q;
1437 f[j + Len] = (uint)(ζ * (f[j + Len] + q - t) % q);
1442 for (j = 0; j < n; j++)
1443 f[j] = (uint)(8347681ul * f[j] % q);
1452 int i, c = f.Length;
1454 for (i = 0; i < c; i++)
1470 if (f.Length != n || g.Length != n)
1471 throw new ArgumentException(
"Polynomials must have " + n +
" coefficients.", nameof(f));
1475 for (i = 0; i < n; i++)
1476 Result[i] = (uint)((Result[i] + (ulong)f[i] * g[i]) % q);
1491 if (f.Length != n || g.Length != n)
1492 throw new ArgumentException(
"Polynomials must have " + n +
" coefficients.", nameof(f));
1497 for (i = 0; i < n; i++)
1502 Result[i] = (uint)((Result[i] + (ulong)f[i] * (uint)(q + v)) % q);
1504 Result[i] = (uint)((Result[i] + (ulong)f[i] * (uint)v) % q);
1513 public static void AddTo(
int[] f,
short[] g)
1517 for (i = 0; i < n; i++)
1526 public static void AddTo(
int[][] f,
short[][] g)
1528 int i, c = f.Length;
1530 throw new ArgumentException(
"Vectors must have the same number of polynomials.", nameof(g));
1532 for (i = 0; i < c; i++)
1541 public static void AddTo(uint[] f,
short[] g)
1546 for (i = 0; i < n; i++)
1551 f[i] = (uint)((f[i] + q + v) % q);
1553 f[i] = (uint)((f[i] + v) % q);
1562 public static void AddTo(uint[][] f,
short[][] g)
1564 int i, c = f.Length;
1566 throw new ArgumentException(
"Vectors must have the same number of polynomials.", nameof(g));
1568 for (i = 0; i < c; i++)
1577 public static void AddTo(uint[] f, uint[] g)
1581 for (i = 0; i < n; i++)
1582 f[i] = (f[i] + g[i]) % q;
1590 public static void AddTo(uint[][] f, uint[][] g)
1592 int i, c = f.Length;
1594 throw new ArgumentException(
"Vectors must have the same number of polynomials.", nameof(g));
1596 for (i = 0; i < c; i++)
1610 for (i = 0; i < n; i++)
1615 f[i] = (uint)((f[i] - v) % q);
1617 f[i] = (uint)((f[i] + q - v) % q);
1628 int i, c = f.Length;
1630 throw new ArgumentException(
"Vectors must have the same number of polynomials.", nameof(g));
1632 for (i = 0; i < c; i++)
1645 for (i = 0; i < n; i++)
1646 f[i] = (f[i] + q - g[i]) % q;
1656 int i, c = f.Length;
1658 throw new ArgumentException(
"Vectors must have the same number of polynomials.", nameof(g));
1660 for (i = 0; i < c; i++)
1670 int i, c = f.Length;
1672 for (i = 0; i < c; i++)
1673 f[i] = (q - f[i]) % q;
1682 int i, c = f.Length;
1684 for (i = 0; i < c; i++)
1697 int i, c = v1.Length;
1700 throw new ArgumentException(
"Vectors must have the same number of polynomials.", nameof(v2));
1702 uint[] Result =
new uint[n];
1704 for (i = 0; i < c; i++)
1720 throw new ArgumentException(
"Polynomials must have " + n +
" coefficients.", nameof(c));
1722 int i, j, k = s.Length;
1723 uint[][] Result =
new uint[k][];
1727 for (i = 0; i < k; i++)
1729 Result[i] = f =
new uint[n];
1733 throw new ArgumentException(
"Polynomials must have " + n +
" coefficients.", nameof(s));
1735 for (j = 0; j < n; j++)
1736 f[j] = (uint)((long)c[j] * si[j] % q);
1749 int i, c = f.Length;
1751 for (i = 0; i < c; i++)
1752 f[i] = (uint)(((ulong)f[i] << d) % q);
1762 int i, c = f.Length;
1764 for (i = 0; i < c; i++)
1778 public static int SimpleBitPack(
short[] Values,
int d,
byte[] Output,
int Index)
1780 if (d < 1 || d > 15)
1781 throw new ArgumentOutOfRangeException(nameof(d),
"d must be between 1 and 15.");
1783 int i, c = Values.Length;
1787 for (i = 0; i < c; i++)
1789 ushort Value = (ushort)Values[i];
1792 Output[Index] |= (byte)(Value << BitOffset);
1801 Output[Index] = (byte)(Value >> (d - BitOffset));
1809 Output[Index] = (byte)(Value >> (d - BitOffset));
1815 return Index - Index0;
1829 if (d < 1 || d > 15)
1830 throw new ArgumentOutOfRangeException(nameof(d),
"Bitlength of a+b must be between 1 and 15.");
1832 int c = Values.Length;
1838 for (i = 0; i < c; i++)
1840 Value = Input[Index] >> BitOffset;
1843 while (BitOffset >= 8)
1852 Value |= Input[Index] << j;
1859 return Index - Index0;
1873 public static int BitPack(
short[] Values,
byte[] Output,
int Index, uint a, uint b)
1875 int d = BitLen(b + a);
1876 if (d < 1 || d > 15)
1877 throw new ArgumentOutOfRangeException(nameof(b),
"d must be between 1 and 15.");
1879 int c = Values.Length;
1885 for (i = 0; i < c; i++)
1887 Value = (int)(b - Values[i]);
1892 Output[Index] |= (byte)(Value << BitOffset);
1895 while (BitOffset >= 8)
1901 Output[Index] = (byte)(Value >> (d - BitOffset));
1905 return Index - Index0;
1921 public static int BitPack(uint[] Values,
byte[] Output,
int Index, uint a, uint b,
bool MakeSigned)
1923 int d = BitLen(b + a);
1924 if (d < 1 || d > 30)
1925 throw new ArgumentOutOfRangeException(nameof(b),
"d must be between 1 and 30.");
1927 int c = Values.Length;
1934 for (i = 0; i < c; i++)
1936 Value = (int)Values[i];
1944 if (q - Value < Value)
1948 Value = (int)(b - Value);
1955 Output[Index] |= (byte)(Value << BitOffset);
1967 BitOffset += BitsLeft;
1972 while (BitsLeft >= 8)
1974 Output[Index++] = (byte)Value;
1981 Output[Index] = (byte)Value;
1982 BitOffset += BitsLeft;
1989 return Index - Index0;
1997 private static int BitLen(uint i)
2021 public static int BitUnpack(
short[] Values,
byte[] Input,
int Index, uint a, uint b)
2023 int d = BitLen(b + a);
2024 if (d < 1 || d > 15)
2025 throw new ArgumentOutOfRangeException(nameof(b),
"Bitlength of a+b must be between 1 and 15.");
2027 int c = Values.Length;
2033 for (i = 0; i < c; i++)
2035 Value = Input[Index] >> BitOffset;
2038 while (BitOffset >= 8)
2047 Value |= Input[Index] << j;
2052 Values[i] = (short)(b - Value);
2055 return Index - Index0;
2071 public static int BitUnpack(uint[] Values,
byte[] Input,
int Index, uint a, uint b,
bool MakeUnsigned)
2073 int d = BitLen(b + a);
2074 if (d < 1 || d > 30)
2075 throw new ArgumentOutOfRangeException(nameof(b),
"Bitlength of a+b must be between 1 and 30.");
2077 int c = Values.Length;
2083 for (i = 0; i < c; i++)
2085 Value = Input[Index] >> BitOffset;
2088 while (BitOffset >= 8)
2097 Value |= Input[Index] << j;
2102 j = Mod((
int)(b - Value), q);
2114 Values[i] = (uint)j;
2120 return Index - Index0;
2129 public static byte[]
H(
byte[] Data,
int l)
2140 public static byte[]
G(
byte[] Data,
int l)
2149 private static readonly uint[] nttTransformZeta =
new uint[256]
2151 0, 4808194, 3765607, 3761513, 5178923, 5496691, 5234739, 5178987,
2152 7778734, 3542485, 2682288, 2129892, 3764867, 7375178, 557458, 7159240,
2153 5010068, 4317364, 2663378, 6705802, 4855975, 7946292, 676590, 7044481,
2154 5152541, 1714295, 2453983, 1460718, 7737789, 4795319, 2815639, 2283733,
2155 3602218, 3182878, 2740543, 4793971, 5269599, 2101410, 3704823, 1159875,
2156 394148, 928749, 1095468, 4874037, 2071829, 4361428, 3241972, 2156050,
2157 3415069, 1759347, 7562881, 4805951, 3756790, 6444618, 6663429, 4430364,
2158 5483103, 3192354, 556856, 3870317, 2917338, 1853806, 3345963, 1858416,
2159 3073009, 1277625, 5744944, 3852015, 4183372, 5157610, 5258977, 8106357,
2160 2508980, 2028118, 1937570, 4564692, 2811291, 5396636, 7270901, 4158088,
2161 1528066, 482649, 1148858, 5418153, 7814814, 169688, 2462444, 5046034,
2162 4213992, 4892034, 1987814, 5183169, 1736313, 235407, 5130263, 3258457,
2163 5801164, 1787943, 5989328, 6125690, 3482206, 4197502, 7080401, 6018354,
2164 7062739, 2461387, 3035980, 621164, 3901472, 7153756, 2925816, 3374250,
2165 1356448, 5604662, 2683270, 5601629, 4912752, 2312838, 7727142, 7921254,
2166 348812, 8052569, 1011223, 6026202, 4561790, 6458164, 6143691, 1744507,
2167 ζ, 6444997, 5720892, 6924527, 2660408, 6600190, 8321269, 2772600,
2168 1182243, 87208, 636927, 4415111, 4423672, 6084020, 5095502, 4663471,
2169 8352605, 822541, 1009365, 5926272, 6400920, 1596822, 4423473, 4620952,
2170 6695264, 4969849, 2678278, 4611469, 4829411, 635956, 8129971, 5925040,
2171 4234153, 6607829, 2192938, 6653329, 2387513, 4768667, 8111961, 5199961,
2172 3747250, 2296099, 1239911, 4541938, 3195676, 2642980, 1254190, 8368000,
2173 2998219, 141835, 8291116, 2513018, 7025525, 613238, 7070156, 6161950,
2174 7921677, 6458423, 4040196, 4908348, 2039144, 6500539, 7561656, 6201452,
2175 6757063, 2105286, 6006015, 6346610, 586241, 7200804, 527981, 5637006,
2176 6903432, 1994046, 2491325, 6987258, 507927, 7192532, 7655613, 6545891,
2177 5346675, 8041997, 2647994, 3009748, 5767564, 4148469, 749577, 4357667,
2178 3980599, 2569011, 6764887, 1723229, 1665318, 2028038, 1163598, 5011144,
2179 3994671, 8368538, 7009900, 3020393, 3363542, 214880, 545376, 7609976,
2180 3105558, 7277073, 508145, 7826699, 860144, 3430436, 140244, 6866265,
2181 6195333, 3123762, 2358373, 6187330, 5365997, 6663603, 2926054, 7987710,
2182 8077412, 3531229, 4405932, 4606686, 1900052, 7598542, 1054478, 7648983
2195 public byte[]
Sign_Internal(
byte[] PrivateKey,
byte[] Message,
bool μPrecomputed,
2196 byte[] Seed, out
int RejectionCount)
2199 μPrecomputed, Seed, out RejectionCount);
2213 byte[] Seed, out
int RejectionCount)
2216 !
this.TryDecodePrivateKey(Keys.
PrivateKey, out
byte[] ρ, out
byte[] K,
2217 out
byte[] tr, out
short[][] s1, out
short[][] s2, out
short[][] t0))
2219 throw new ArgumentException(
"Invalid private key.", nameof(Keys));
2223 Seed =
new byte[32];
2224 else if (Seed.Length != 32)
2225 throw new ArgumentException(
"Seed must be 32 bytes long.", nameof(Seed));
2229 uint[][] NTTs1 =
NTT(s1);
2230 uint[][] NTTs2 =
NTT(s2);
2231 uint[][] NTTt0 =
NTT(t0);
2233 uint[,][] Â = Keys.
Â;
2236 Keys. =  = this.ExpandÂ(ρ);
2237 else if (Â.GetLength(0) !=
this.k || Â.GetLength(1) !=
this.l)
2238 throw new ArgumentException(
"Matrix  must be " + this.k +
"x" + this.l +
".", nameof(Â));
2251 int MessageLen = Message.Length;
2252 Bin =
new byte[64 + MessageLen];
2254 Buffer.BlockCopy(tr, 0, Bin, 0, 64);
2255 Buffer.BlockCopy(Message, 0, Bin, 64, MessageLen);
2262 Bin =
new byte[128];
2263 Buffer.BlockCopy(K, 0, Bin, 0, 32);
2264 Buffer.BlockCopy(Seed, 0, Bin, 32, 32);
2265 Buffer.BlockCopy(μ, 0, Bin, 64, 64);
2267 byte[] ρ2 =
H(Bin, 64);
2272 byte[] cSeed =
null;
2275 int IterationLimit = 10000;
2279 if (--IterationLimit <= 0 || κ > ushort.MaxValue)
2280 throw new InvalidOperationException(
"Unable to calculate signature.");
2282 uint[][] y = this.ExpandMask(ρ2, (ushort)κ);
2290 uint[][] w =
new uint[this.k][];
2294 for (i = 0; i < this.k; i++)
2296 w[i] = f =
new uint[n];
2298 for (j = 0; j < this.l; j++)
2304 short[][] w1 = this.HighBits(w);
2308 int w1Len = BitLen((uint)((q - 1) / this.twoγ2 - 1));
2310 Bin =
new byte[64 + this.k * (w1Len << 5)];
2311 Buffer.BlockCopy(μ, 0, Bin, 0, 64);
2315 for (i = 0; i < this.k; i++)
2318 cSeed =
H(Bin, this.λ >> 2);
2321 short[] c = this.SampleInBall(cSeed);
2322 uint[] NTTc =
NTT(c);
2332 if (InfinityNorm(z) < this.γ1 - this.β)
2335 int[][] r0 = this.LowBits(w);
2337 if (InfinityNorm(r0) < this.γ2 - this.β)
2345 if (InfinityNorm(ct0) < this.γ2)
2350 h = this.MakeAndEncodeHint(ct0, w);
2385 return this.EncodeSignature(cSeed, z, h);
2388 private static uint[][] Clone(uint[][] v)
2390 int i, c = v.Length;
2391 uint[][] Result =
new uint[c][];
2393 for (i = 0; i < c; i++)
2394 Result[i] = (uint[])v[i].Clone();
2404 private static uint InfinityNorm(uint[] f)
2407 int i, c = f.Length;
2410 for (i = 0; i < c; i++)
2430 private static uint InfinityNorm(uint[][] f)
2433 int i, c = f.Length;
2436 for (i = 0; i < c; i++)
2438 v = InfinityNorm(f[i]);
2451 private static int InfinityNorm(
int[] f)
2454 int i, c = f.Length;
2457 for (i = 0; i < c; i++)
2482 private static int InfinityNorm(
int[][] f)
2485 int i, c = f.Length;
2488 for (i = 0; i < c; i++)
2490 v = InfinityNorm(f[i]);
2498 private uint[][] ExpandMask(
byte[] ρ, ushort μ)
2500 uint[][] y =
new uint[this.l][];
2501 int c = BitLen(this.γ1 - 1) + 1;
2505 byte[] ρ1 =
new byte[66];
2506 Buffer.BlockCopy(ρ, 0, ρ1, 0, 64);
2508 for (r = 0; r < this.l; r++)
2511 ρ1[65] = (byte)(μ >> 8);
2517 BitUnpack(y[r], v, 0, this.γ1 - 1, this.γ1,
true);
2529 private short[][] HighBits(uint[][] w)
2531 this.Decompose(w, out
_, out
short[][] Result);
2541 private int[][] LowBits(uint[][] w)
2543 this.Decompose(w, out
int[][] Result, out
_);
2554 private void Decompose(uint[][] w, out
int[][] w0, out
short[][] w1)
2556 w0 =
new int[this.k][];
2557 w1 =
new short[this.k][];
2566 for (i = 0; i < this.k; i++)
2569 w0[i] = f0 =
new int[n];
2570 w1[i] = f1 =
new short[n];
2572 for (j = 0; j < n; j++)
2575 r0 = r % this.twoγ2;
2595 private short[] SampleInBall(
byte[] Seed)
2597 short[] c =
new short[n];
2600 byte[] s = Context.
Squeeze(8);
2605 for (i = n - this.τ, k = 0, Bit = 1; i < n; i++)
2612 c[j] = (s[k] & Bit) == 0 ? (
short)1 : (short)-1;
2633 private byte[] MakeAndEncodeHint(uint[][] z, uint[][] r)
2637 short[][] r1 = this.HighBits(r);
2641 short[][] v1 = this.HighBits(r);
2645 byte[] y =
new byte[this.ω + this.k];
2650 for (i = 0; i < this.k; i++)
2655 for (j = 0; j < n; j++)
2659 if (Index >= this.ω)
2662 y[Index++] = (byte)j;
2666 y[this.ω + i] = Index;
2680 private byte[] EncodeSignature(
byte[] c, uint[][] z,
byte[] h)
2683 int l2 = this.l * ((1 + BitLen(this.γ1 - 1)) << 5);
2685 int Len = l1 + l2 + l3;
2687 byte[] Result =
new byte[Len];
2689 Buffer.BlockCopy(c, 0, Result, 0, l1);
2691 for (i = 0; i < this.l; i++)
2692 l1 +=
BitPack(z[i], Result, l1, this.γ1 - 1, this.γ1,
true);
2694 Buffer.BlockCopy(h, 0, Result, l1, l3);
2711 μPrecomputed, Signature);
2726 !
this.TryDecodePublicKey(Keys.
PublicKey, out
byte[] ρ, out
short[][] t1))
2731 if (!this.TryDecodeSignature(Signature, out
byte[] cSeed, out uint[][] z,
2737 if (InfinityNorm(z) >= this.γ1 - this.β)
2740 uint[,][] Â = Keys.
Â;
2743 Keys. =  = this.ExpandÂ(ρ);
2744 else if (Â.GetLength(0) !=
this.k || Â.GetLength(1) !=
this.l)
2745 throw new ArgumentException(
"Matrix  must be " + this.k +
"x" + this.l +
".", nameof(Â));
2755 int MessageLen = Message.Length;
2756 Bin =
new byte[64 + MessageLen];
2758 Buffer.BlockCopy(tr, 0, Bin, 0, 64);
2759 Buffer.BlockCopy(Message, 0, Bin, 64, MessageLen);
2764 short[] c = this.SampleInBall(cSeed);
2768 uint[] NTTc =
NTT(c);
2769 uint[][] NTTt1 =
NTT(t1);
2778 for (i = 0; i < this.k; i++)
2782 for (j = 0; j < this.l; j++)
2788 short[][] w1 = this.UseHint(h, w);
2792 int w1Len = BitLen((uint)((q - 1) / this.twoγ2 - 1));
2794 Bin =
new byte[64 + this.k * (w1Len << 5)];
2795 Buffer.BlockCopy(μ, 0, Bin, 0, 64);
2799 for (i = 0; i < this.k; i++)
2802 int cLen = this.λ >> 2;
2803 byte[] cSeed2 =
H(Bin, cLen);
2805 for (i = 0; i < cLen; i++)
2807 if (cSeed[i] != cSeed2[i])
2820 private short[][] UseHint(
bool[][] h, uint[][] r)
2822 short[][] Result =
new short[this.k][];
2828 int m = (q - 1) / this.twoγ2;
2832 this.Decompose(r, out
int[][] r0v, out
short[][] r1v);
2834 for (i = 0; i < this.k; i++)
2836 Result[i] = f =
new short[n];
2841 for (j = 0; j < n; j++)
2849 f[j] = (short)((r1 + 1) % m);
2851 f[j] = (short)((r1 + m - 1) % m);
2869 private bool TryDecodePublicKey(
byte[] PublicKey, out
byte[] ρ, out
short[][] t1)
2874 if (PublicKey is
null || PublicKey.Length !=
this.publicKeySize)
2878 Buffer.BlockCopy(PublicKey, 0, ρ, 0, 32);
2883 t1 =
new short[this.k][];
2885 for (
int i = 0; i < this.k; i++)
2887 t1[i] = f =
new short[n];
2891 return Pos == this.publicKeySize;
2904 private bool TryDecodeSignature(
byte[] Signature, out
byte[] c, out uint[][] z,
2911 if (Signature is
null || Signature.Length !=
this.signatureSize)
2914 int l1 = this.λ >> 2;
2917 Buffer.BlockCopy(Signature, 0, c, 0, l1);
2922 z =
new uint[this.l][];
2924 for (i = 0; i < this.l; i++)
2926 z[i] = f =
new uint[n];
2927 l1 +=
BitUnpack(f, Signature, l1, this.γ1 - 1, this.γ1,
true);
2930 int l3 = Signature.Length - l1;
2931 if (l3 != this.ω + this.k)
2934 h = this.HintBitUnpack(Signature, l1);
2948 private bool[][] HintBitUnpack(
byte[] Input,
int Pos)
2950 bool[][] h =
new bool[this.k][];
2957 for (i = 0, j = this.ω; i < this.k; i++, j++)
2959 h[i] = f =
new bool[n];
2962 if (b < Index || b > this.ω)
2967 b2 = b1 = Input[Index + Pos];
2973 else if (b2 >= (b1 = Input[Index + Pos]))
2982 while (Index < this.ω)
2984 if (Input[Index++ + Pos] != 0)
2997 private static int Mod(
int x,
int y)
Contains methods for simple hash calculations.
static byte[] ComputeSHA384Hash(byte[] Data)
Computes the SHA-384 hash of a block of binary data.
static byte[] ComputeSHA512Hash(byte[] Data)
Computes the SHA-512 hash of a block of binary data.
static byte[] ComputeSHA256Hash(byte[] Data)
Computes the SHA-256 hash of a block of binary data.
Methods common to ML algorithms.
static void Clear(byte[] Bin)
Clears a byte array.
static readonly int[] intBitMask
Bit masks corresponding to mod 2^d arithmetic, where d is the index of the mask in the array.
static readonly ushort[] ushortBitMask
Bit masks corresponding to mod 2^d arithmetic, where d is the index of the mask in the array.
static byte[] CreateSeed()
Creates a random seed value.
ML-DSA public and private keys, as defined in §6.1.
uint[,][] Â
Matrix of encryption keys, as defined in §6.1.
static ML_DSA_Keys FromPublicKey(byte[] PublicKey)
Creates a key object instance from a public key.
byte[] PublicKey
Encoded public key, as defined in §6.1.
static ML_DSA_Keys FromPrivateKey(byte[] PrivateKey)
Creates a key object instance from a private key.
byte[] PrivateKey
Encoded private key, as defined in §6.1.
Implements the ML-DSA algorithm for post-quantum cryptography, as defined in NIST FIPS 204: https://n...
bool Verify(byte[] PublicKey, byte[] Message, byte[] Signature)
Verifies a digital signature using the ML-DSA algorithm. (Algorithm 3 ML-DSA.Verify() in §5....
byte[] Sign(byte[] PrivateKey, byte[] Message, byte[] Context, byte[] Seed, out int RejectionCount)
Signs a message using the ML-DSA algorithm. (Algorithm 2 ML-DSA.Sign() in §5.2)
static byte[] G(byte[] Data, int l)
Hash function G, as defined in §3.7.
bool Verify(ML_DSA_Keys Keys, byte[] Message, byte[] Signature)
Verifies a digital signature using the ML-DSA algorithm. (Algorithm 3 ML-DSA.Verify() in §5....
static int BitUnpack(uint[] Values, byte[] Input, int Index, uint a, uint b, bool MakeUnsigned)
Decodes an array of integers between [-a,b] from a byte array, as defined by Algorithm 19 in §7....
static void SubtractFrom(uint[] f, short[] g)
Subtracts g from f .
static void SubtractFrom(uint[][] f, short[][] g)
Subtracts g from f .
static void ShiftLeft(uint[][] f, int d)
Multiplies a vector of polynomials by 2^d
bool Verify(byte[] PublicKey, Stream Message, byte[] Signature, byte[] Context, string HashAlgorithm)
Verifies a digital signature using the ML-DSA pre-hash algorithm. (Algorithm 5 HashML-DSA....
static void AddTo(uint[][] f, short[][] g)
Adds vector g to vector f .
static void AddTo(uint[] f, short[] g)
Adds g to f .
byte[] Sign(ML_DSA_Keys Keys, byte[] Message, byte[] Context, string HashAlgorithm, out int RejectionCount)
Signs a message using the ML-DSA pre-hash algorithm. (Algorithm 4 HashML-DSA.Sign() in §5....
bool Verify(byte[] PublicKey, byte[] Message, byte[] Signature, byte[] Context, string HashAlgorithm)
Verifies a digital signature using the ML-DSA pre-hash algorithm. (Algorithm 5 HashML-DSA....
static uint[] DotProductNTT(uint[][] v1, uint[][] v2)
Computes the dot product of two vectors of polynomials in 𝑇𝑞.
static void NTT(uint[][] f)
Canonical extension of NTT(uint[]).
byte[] Sign(ML_DSA_Keys Keys, byte[] Message, out int RejectionCount)
Signs a message using the ML-DSA algorithm. (Algorithm 2 ML-DSA.Sign() in §5.2)
byte[] Sign(byte[] PrivateKey, byte[] Message, byte[] Context, out int RejectionCount)
Signs a message using the ML-DSA algorithm. (Algorithm 2 ML-DSA.Sign() in §5.2)
bool Verify(ML_DSA_Keys Keys, byte[] Message, byte[] Signature, byte[] Context, string HashAlgorithm)
Verifies a digital signature using the ML-DSA pre-hash algorithm. (Algorithm 5 HashML-DSA....
static int SimpleBitPack(short[] Values, int d, byte[] Output, int Index)
Encodes an array of integers (mod 2^d) into a byte array, as defined by Algorithm 16 in §7....
byte[] Sign_Internal(ML_DSA_Keys Keys, byte[] Message, bool μPrecomputed, byte[] Seed, out int RejectionCount)
Internal signature interface (Algorithm 7, §6.2)
static int SimpleBitUnpack(short[] Values, byte[] Input, int Index, int d)
Decodes an array of integers (mod 2^d) from a byte array, as defined by Algorithm 18 in §7....
byte[] Sign(ML_DSA_Keys Keys, byte[] Message, byte[] Context, out int RejectionCount)
Signs a message using the ML-DSA algorithm. (Algorithm 2 ML-DSA.Sign() in §5.2)
byte[] Sign_Internal(byte[] PrivateKey, byte[] Message, bool μPrecomputed, byte[] Seed, out int RejectionCount)
Internal signature interface (Algorithm 7, §6.2)
byte[] Sign(byte[] PrivateKey, byte[] Message, byte[] Context, string HashAlgorithm, out int RejectionCount)
Signs a message using the ML-DSA pre-hash algorithm. (Algorithm 4 HashML-DSA.Sign() in §5....
bool Verify(ML_DSA_Keys Keys, Stream Message, byte[] Signature, byte[] Context, string HashAlgorithm)
Verifies a digital signature using the ML-DSA pre-hash algorithm. (Algorithm 5 HashML-DSA....
static void InverseNTT(uint[] f)
Computes the NTT^-1 representation f of the given polynomial f̂ ∈ 𝑇𝑞. (Algorithm 42 in §7....
byte[] Sign(ML_DSA_Keys Keys, Stream Message, byte[] Context, byte[] Seed, string HashAlgorithm, out int RejectionCount)
Signs a message using the ML-DSA pre-hash algorithm. (Algorithm 4 HashML-DSA.Sign() in §5....
static readonly ML_DSA ML_DSA_44
Model parameters for a required RBG strength 128 (cryptographic security strength),...
static void AddTo(uint[][] f, uint[][] g)
Adds vector g to vector f .
bool Verify_Internal(byte[] PublicKey, byte[] Message, bool μPrecomputed, byte[] Signature)
Internal signature verification interface (Algorithm 8, §6.3)
static void ShiftLeft(uint[] f, int d)
Multiplies a polynomial by 2^d
static void NTT(uint[] f)
Computes the NTT representation f̂ of the given polynomial f ∈ 𝑅𝑞. (Algorithm 41 in §7....
static void Negate(uint[][] f)
Negates an array of polynomials in 𝑅𝑞.
byte[] Sign(ML_DSA_Keys Keys, byte[] Message, string HashAlgorithm, out int RejectionCount)
Signs a message using the ML-DSA pre-hash algorithm. (Algorithm 4 HashML-DSA.Sign() in §5....
ML_DSA(int τ, int λ, uint γ1, uint γ2, byte k, byte l, byte η, int ω, int PrivateKeySize, int PublicKeySize, int SignatureSize)
Implements the ML-DSA algorithm for post-quantum cryptography, as defined in NIST FIPS 204: https://n...
byte[] Sign(byte[] PrivateKey, Stream Message, byte[] Context, string HashAlgorithm, out int RejectionCount)
Signs a message using the ML-DSA pre-hash algorithm. (Algorithm 4 HashML-DSA.Sign() in §5....
bool Verify_Internal(ML_DSA_Keys Keys, byte[] Message, bool μPrecomputed, byte[] Signature)
Internal signature verification interface (Algorithm 8, §6.3)
bool Verify(ML_DSA_Keys Keys, byte[] Message, byte[] Signature, byte[] Context)
Verifies a digital signature using the ML-DSA algorithm. (Algorithm 3 ML-DSA.Verify() in §5....
short[] RejBoundedPoly(byte[] Seed)
The algorithm RejBoundedPoly (Algorithm 31, §7.3) converts a seed together with an index into a polyn...
static void InverseNTT(uint[][] f)
Canonical extension of InverseNTT(uint[]).
ML_DSA_Keys KeyGen(bool ReturnSeed)
Generates a public and private key. (Algorithm 1 ML-DSA.KeyGen() in §5.1)
byte[] Sign(ML_DSA_Keys Keys, byte[] Message, byte[] Context, byte[] Seed, out int RejectionCount)
Signs a message using the ML-DSA algorithm. (Algorithm 2 ML-DSA.Sign() in §5.2)
override int PrivateKeyLength
Length of the private key.
static void SubtractFrom(uint[][] f, uint[][] g)
Subtracts g from f .
static void SubtractFrom(uint[] f, uint[] g)
Subtracts g from f .
static void AddTo(int[] f, short[] g)
Adds g to f .
static uint[] NTT(short[] f)
Canonical extension of NTT(uint[]).
static int BitPack(short[] Values, byte[] Output, int Index, uint a, uint b)
Encodes an array of integers between [-a,b] into a byte array, as defined by Algorithm 17 in §7....
byte[] Sign(ML_DSA_Keys Keys, byte[] Message, byte[] Context, byte[] Seed, string HashAlgorithm, out int RejectionCount)
Signs a message using the ML-DSA pre-hash algorithm. (Algorithm 4 HashML-DSA.Sign() in §5....
ML_DSA_Keys KeyGen()
Generates a public and private key. (Algorithm 1 ML-DSA.KeyGen() in §5.1)
static readonly ML_DSA ML_DSA_65
Model parameters for a required RBG strength 192 (cryptographic security strength),...
static int BitPack(uint[] Values, byte[] Output, int Index, uint a, uint b, bool MakeSigned)
Encodes an array of integers between [-a,b] into a byte array, as defined by Algorithm 17 in §7....
bool Verify(byte[] PublicKey, byte[] Message, byte[] Signature, byte[] Context)
Verifies a digital signature using the ML-DSA algorithm. (Algorithm 3 ML-DSA.Verify() in §5....
static ML_DSA GetModel(string Name)
Gets a model by name, as defined in §8.
static void AddTo(int[][] f, short[][] g)
Adds vector g to vector f .
byte[] Sign(byte[] PrivateKey, byte[] Message, byte[] Context, byte[] Seed, string HashAlgorithm, out int RejectionCount)
Signs a message using the ML-DSA pre-hash algorithm. (Algorithm 4 HashML-DSA.Sign() in §5....
static void MultiplyNTTsAndAdd(uint[] f, short[] g, uint[] Result)
Computes the product (in the ring 𝑇𝑞) of two NTT representations (Algorithm 45 in §7....
override int PublicKeyLength
Length of the public key.
static int BitUnpack(short[] Values, byte[] Input, int Index, uint a, uint b)
Decodes an array of integers between [-a,b] from a byte array, as defined by Algorithm 19 in §7....
static void MultiplyNTTsAndAdd(uint[] f, uint[] g, uint[] Result)
Computes the product (in the ring 𝑇𝑞) of two NTT representations (Algorithm 45 in §7....
byte[] Sign(byte[] PrivateKey, Stream Message, byte[] Context, byte[] Seed, string HashAlgorithm, out int RejectionCount)
Signs a message using the ML-DSA pre-hash algorithm. (Algorithm 4 HashML-DSA.Sign() in §5....
ML_DSA_Keys KeyGen_Internal(byte[] ξ)
Generates a public and private key. (Algorithm 6 ML-DSA.KeyGen_Internal() in §6.1)
byte[] Sign(byte[] PrivateKey, byte[] Message, string HashAlgorithm, out int RejectionCount)
Signs a message using the ML-DSA pre-hash algorithm. (Algorithm 4 HashML-DSA.Sign() in §5....
byte[] Sign(ML_DSA_Keys Keys, Stream Message, byte[] Context, string HashAlgorithm, out int RejectionCount)
Signs a message using the ML-DSA pre-hash algorithm. (Algorithm 4 HashML-DSA.Sign() in §5....
static uint[][] ScalarProductNTT(uint[] c, uint[][] s)
Computes the scalar product of a polynomial in 𝑇𝑞 with a vector of polynomials in 𝑇𝑞.
ML_DSA_Keys KeyGen_Internal(byte[] ξ, bool ReturnSeed)
Generates a public and private key. (Algorithm 6 ML-DSA.KeyGen_Internal() in §6.1)
static void Negate(uint[] f)
Negates a polynomial in 𝑅𝑞.
static readonly ML_DSA ML_DSA_87
Model parameters for a required RBG strength 256 (cryptographic security strength),...
static void AddTo(uint[] f, uint[] g)
Adds g to f .
byte[] Sign(byte[] PrivateKey, byte[] Message, out int RejectionCount)
Signs a message using the ML-DSA algorithm. (Algorithm 2 ML-DSA.Sign() in §5.2)
static byte[] H(byte[] Data, int l)
Hash function H, as defined in §3.7.
static uint[][] NTT(short[][] f)
Canonical extension of NTT(short[]).
Hash digest computation context.
byte[] Squeeze(int NrBytes)
Calculates another NrBytes number of bytes of the digest.
byte Squeeze1()
Calculates another byte of the digest.
byte[] ComputeVariable(byte[] N)
Computes the SPONGE function, as defined in section 4 of NIST FIPS 202.
Implements the SHA3-224 hash function, as defined in section 6.1 in the NIST FIPS 202: https://nvlpub...
Implements the SHA3-256 hash function, as defined in section 6.1 in the NIST FIPS 202: https://nvlpub...
Implements the SHA3-384 hash function, as defined in section 6.1 in the NIST FIPS 202: https://nvlpub...
Implements the SHA3-512 hash function, as defined in section 6.1 in the NIST FIPS 202: https://nvlpub...
Implements the SHA3 SHAKE128 extendable-output functions, as defined in section 6....
Implements the SHA3 SHAKE256 extendable-output functions, as defined in section 6....
delegate byte[] HashFunctionStream(Stream Data)
Delegate to hash function.
delegate byte[] HashFunctionArray(byte[] Data)
Delegate to hash function.
HashFunction
Hash method enumeration.