Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
ModuleLatticeEndpoint.cs
1using System;
2using System.IO;
4
6{
10 public abstract class ModuleLatticeEndpoint : E2eEndpoint
11 {
12 private const string preHashAlgorithm = "SHAKE-256";
13
14 private readonly ML_KEM keyEncapsulationMechanism;
15 private readonly ML_DSA signatureAlgorithm;
16 private readonly ML_KEM_Keys keyEncapsulationMechanismKeys;
17 private readonly ML_DSA_Keys signatureAlgorithmKeys;
18 private readonly bool hasPrivateKey;
19 private readonly byte[] publicKey;
20 private readonly string publicKeyBase64;
21
31 ML_KEM_Keys KeyEncapsulationMechanismKeys, ML_DSA SignatureAlgorithm,
34 {
35 this.keyEncapsulationMechanism = KeyEncapsulationMechanism;
36 this.keyEncapsulationMechanismKeys = KeyEncapsulationMechanismKeys;
37 this.signatureAlgorithm = SignatureAlgorithm;
38 this.signatureAlgorithmKeys = SignatureAlgorithmKeys;
39
40 this.hasPrivateKey = this.keyEncapsulationMechanismKeys.HasDecapsulationKey &&
41 this.signatureAlgorithmKeys.HasPrivateKey;
42
43 if (this.keyEncapsulationMechanismKeys.EncapsulationKey is null ||
44 this.signatureAlgorithmKeys.PublicKey is null)
45 {
46 this.publicKey = null;
47 this.publicKeyBase64 = null;
48 }
49 else
50 {
51 this.publicKey = new byte[this.keyEncapsulationMechanism.PublicKeyLength +
52 this.signatureAlgorithm.PublicKeyLength];
53
54 Buffer.BlockCopy(this.keyEncapsulationMechanismKeys.EncapsulationKey, 0,
55 this.publicKey, 0, this.keyEncapsulationMechanism.PublicKeyLength);
56
57 Buffer.BlockCopy(this.signatureAlgorithmKeys.PublicKey, 0,
58 this.publicKey, this.keyEncapsulationMechanism.PublicKeyLength,
59 this.signatureAlgorithm.PublicKeyLength);
60
61 this.publicKeyBase64 = Convert.ToBase64String(this.publicKey);
62 }
63 }
64
75 {
76 if (PublicKey is null)
77 throw new ArgumentNullException(nameof(PublicKey));
78
81 {
82 throw new ArgumentException("Public key length does not match expected length for the specified key encapsulation mechanism and signature algorithm.", nameof(PublicKey));
83 }
84
85 this.keyEncapsulationMechanism = KeyEncapsulationMechanism;
86 this.signatureAlgorithm = SignatureAlgorithm;
87 this.hasPrivateKey = false;
88 this.publicKey = PublicKey;
89 this.publicKeyBase64 = Convert.ToBase64String(PublicKey);
90
91 byte[] EncapsulationKey = new byte[this.keyEncapsulationMechanism.PublicKeyLength];
92 byte[] SignaturePublicKey = new byte[this.signatureAlgorithm.PublicKeyLength];
93
94 Buffer.BlockCopy(PublicKey, 0, EncapsulationKey, 0, EncapsulationKey.Length);
95 Buffer.BlockCopy(PublicKey, EncapsulationKey.Length, SignaturePublicKey, 0, SignaturePublicKey.Length);
96
97 this.keyEncapsulationMechanismKeys = ML_KEM_Keys.FromEncapsulationKey(EncapsulationKey);
98 this.signatureAlgorithmKeys = ML_DSA_Keys.FromPublicKey(SignaturePublicKey);
99 }
100
104 public bool HasPrivateKey => this.hasPrivateKey;
105
109 public override byte[] PublicKey => this.publicKey;
110
114 public override string PublicKeyBase64 => this.publicKeyBase64;
115
119 public ML_KEM KeyEncapsulationMechanism => this.keyEncapsulationMechanism;
120
124 public ML_DSA SignatureAlgorithm => this.signatureAlgorithm;
125
134 public override byte[] GetSharedSecretForEncryption(IE2eEndpoint RemoteEndpoint,
135 IE2eSymmetricCipher Cipher, out byte[] CipherText)
136 {
137 if (!(RemoteEndpoint is ModuleLatticeEndpoint RemoteModuleLatticeEndpoint))
138 throw new ArgumentException("Remote endpoint is not a Module Lattice endpoint.", nameof(RemoteEndpoint));
139
140 if (!this.keyEncapsulationMechanismKeys.HasDecapsulationKey)
141 throw new InvalidOperationException("Local endpoint does not have a private key for shared secret calculation.");
142
143 if (this.keyEncapsulationMechanism.PublicKeyLength !=
144 RemoteModuleLatticeEndpoint.keyEncapsulationMechanism.PublicKeyLength ||
145 this.signatureAlgorithm.PublicKeyLength !=
146 RemoteModuleLatticeEndpoint.signatureAlgorithm.PublicKeyLength)
147 {
148 throw new ArgumentException("Key lengths do not match.", nameof(RemoteEndpoint));
149 }
150
151 ML_KEM_Encapsulation Encapsulation = this.keyEncapsulationMechanism.Encapsulate(
152 RemoteModuleLatticeEndpoint.keyEncapsulationMechanismKeys.EncapsulationKey);
153
154 CipherText = Encapsulation.CipherText;
155
156 return Encapsulation.SharedSecret;
157 }
158
166 public override byte[] GetSharedSecretForDecryption(IE2eEndpoint RemoteEndpoint,
167 byte[] CipherText)
168 {
169 if (!(RemoteEndpoint is ModuleLatticeEndpoint RemoteModuleLatticeEndpoint))
170 throw new ArgumentException("Remote endpoint is not a Module Lattice endpoint.", nameof(RemoteEndpoint));
171
172 if (!this.keyEncapsulationMechanismKeys.HasDecapsulationKey)
173 throw new InvalidOperationException("Local endpoint does not have a private key for shared secret calculation.");
174
175 if (this.keyEncapsulationMechanism.PublicKeyLength !=
176 RemoteModuleLatticeEndpoint.keyEncapsulationMechanism.PublicKeyLength ||
177 this.signatureAlgorithm.PublicKeyLength !=
178 RemoteModuleLatticeEndpoint.signatureAlgorithm.PublicKeyLength)
179 {
180 throw new ArgumentException("Key lengths do not match.", nameof(RemoteEndpoint));
181 }
182
183 return this.keyEncapsulationMechanism.Decapsulate(
184 this.keyEncapsulationMechanismKeys.DecapsulationKey, CipherText);
185 }
186
190 public override bool SharedSecretUseCipherText => true;
191
197 public override byte[] Sign(byte[] Data)
198 {
199 if (!this.hasPrivateKey)
200 throw new InvalidOperationException("Signing requires private key.");
201
202 byte[] Signature;
203 bool Valid;
204
205 do
206 {
207 Signature = this.signatureAlgorithm.Sign(this.signatureAlgorithmKeys,
208 Data, null, preHashAlgorithm, out _);
209 Valid = this.signatureAlgorithm.Verify(this.signatureAlgorithmKeys, Data,
210 Signature, null, preHashAlgorithm);
211 }
212 while (!Valid);
213
214 return Signature;
215 }
216
222 public override byte[] Sign(Stream Data)
223 {
224 if (!this.hasPrivateKey)
225 throw new InvalidOperationException("Signing requires private key.");
226
227 byte[] Signature;
228 bool Valid;
229
230 do
231 {
232 Signature = this.signatureAlgorithm.Sign(this.signatureAlgorithmKeys,
233 Data, null, preHashAlgorithm, out _);
234 Valid = this.signatureAlgorithm.Verify(this.signatureAlgorithmKeys, Data,
235 Signature, null, preHashAlgorithm);
236 }
237 while (!Valid);
238
239 return Signature;
240 }
241
249 public bool Verify(byte[] Data, byte[] PublicKey, byte[] Signature)
250 {
251 return this.signatureAlgorithm.Verify(ML_DSA_Keys.FromPublicKey(PublicKey), Data,
252 Signature, null, preHashAlgorithm);
253 }
254
262 public bool Verify(Stream Data, byte[] PublicKey, byte[] Signature)
263 {
264 return this.signatureAlgorithm.Verify(ML_DSA_Keys.FromPublicKey(PublicKey), Data,
265 Signature, null, preHashAlgorithm);
266 }
267
274 public override bool Verify(byte[] Data, byte[] Signature)
275 {
276 return this.signatureAlgorithm.Verify(this.signatureAlgorithmKeys, Data,
277 Signature, null, preHashAlgorithm);
278 }
279
286 public override bool Verify(Stream Data, byte[] Signature)
287 {
288 return this.signatureAlgorithm.Verify(this.signatureAlgorithmKeys, Data,
289 Signature, null, preHashAlgorithm);
290 }
291
293 public override bool Equals(object obj)
294 {
295 return obj is ModuleLatticeEndpoint MlObj &&
296 this.publicKeyBase64 == MlObj.publicKeyBase64 &&
297 this.hasPrivateKey == MlObj.hasPrivateKey;
298 }
299
301 public override int GetHashCode()
302 {
303 int Result = this.publicKeyBase64.GetHashCode();
304 Result ^= Result << 5 ^ this.hasPrivateKey.GetHashCode();
305
306 return Result;
307 }
308
315 protected void GeneratePrivateKeys(byte[] Secret, out ML_KEM_Keys KemKeys,
316 out ML_DSA_Keys DsaKeys)
317 {
318 if (Secret is null)
319 throw new ArgumentNullException(nameof(Secret));
320
321 if (Secret.Length == 96)
322 {
323 byte[] SeedKem = new byte[64];
324 byte[] SeedDsa = new byte[32];
325
326 Buffer.BlockCopy(Secret, 0, SeedKem, 0, 64);
327 Buffer.BlockCopy(Secret, 64, SeedDsa, 0, 32);
328
329 KemKeys = this.keyEncapsulationMechanism.KeyGen_FromSeed(SeedKem, true);
330 DsaKeys = this.signatureAlgorithm.KeyGen_Internal(SeedDsa, true);
331
332 Array.Clear(SeedKem, 0, SeedKem.Length);
333 Array.Clear(SeedDsa, 0, SeedDsa.Length);
334 }
335 else
336 throw new ArgumentException("Invalid private key length.", nameof(Secret));
337 }
338
343 public byte[] ExportPrivateKey()
344 {
345 if (!(this.keyEncapsulationMechanismKeys?.HasDecapsulationKey ?? false) ||
346 !(this.signatureAlgorithmKeys?.HasPrivateKey ?? false))
347 {
348 throw new InvalidOperationException("Endpoint has no private keys.");
349 }
350
351 if (this.keyEncapsulationMechanismKeys.Seed is null ||
352 this.signatureAlgorithmKeys.Seed is null)
353 {
354 throw new InvalidOperationException("Endpoint has no seeds, which is required to export private key.");
355 }
356
357 byte[] KemKey = this.keyEncapsulationMechanismKeys.Seed;
358 byte[] DsaKey = this.signatureAlgorithmKeys.Seed;
359
360 int c = KemKey.Length;
361 int d = DsaKey.Length;
362
363 byte[] Result = new byte[c + d];
364
365 Buffer.BlockCopy(KemKey, 0, Result, 0, c);
366 Buffer.BlockCopy(DsaKey, 0, Result, c, d);
367
368 return Result;
369 }
370 }
371}
Abstract base class for End-to-End encryption schemes.
Definition: E2eEndpoint.cs:14
virtual IE2eSymmetricCipher DefaultSymmetricCipher
Default symmetric cipher.
Definition: E2eEndpoint.cs:282
Abstract base class for Module Lattice endpoints.
override byte[] GetSharedSecretForEncryption(IE2eEndpoint RemoteEndpoint, IE2eSymmetricCipher Cipher, out byte[] CipherText)
Gets a shared secret for encryption, and optionally a corresponding cipher text.
byte[] ExportPrivateKey()
Exports the private key (seed) of the endpoint.
override byte[] Sign(Stream Data)
Signs binary data using the local private key.
override bool SharedSecretUseCipherText
If the recipient needs a cipher text to generate the same shared secret.
bool Verify(Stream Data, byte[] PublicKey, byte[] Signature)
Verifies a signature.
override bool Verify(byte[] Data, byte[] Signature)
Verifies a signature.
override byte[] GetSharedSecretForDecryption(IE2eEndpoint RemoteEndpoint, byte[] CipherText)
Gets a shared secret for decryption.
ModuleLatticeEndpoint(ML_KEM KeyEncapsulationMechanism, ML_KEM_Keys KeyEncapsulationMechanismKeys, ML_DSA SignatureAlgorithm, ML_DSA_Keys SignatureAlgorithmKeys, IE2eSymmetricCipher DefaultSymmetricCipher)
Abstract base class for Module Lattice endpoints.
bool HasPrivateKey
If the key contains a private key.
ML_DSA SignatureAlgorithm
Signature Algorithm used for signing.
void GeneratePrivateKeys(byte[] Secret, out ML_KEM_Keys KemKeys, out ML_DSA_Keys DsaKeys)
Generates private keys from a 96-byte secret.
override string PublicKeyBase64
Remote public key, as a Base64 string.
bool Verify(byte[] Data, byte[] PublicKey, byte[] Signature)
Verifies a signature.
ModuleLatticeEndpoint(byte[] PublicKey, ML_KEM KeyEncapsulationMechanism, ML_DSA SignatureAlgorithm, IE2eSymmetricCipher DefaultSymmetricCipher)
Abstract base class for Module Lattice endpoints.
override byte[] Sign(byte[] Data)
Signs binary data using the local private key.
ML_KEM KeyEncapsulationMechanism
Key Encapsulation Mechanism used for key exchange.
override bool Verify(Stream Data, byte[] Signature)
Verifies a signature.
ML-DSA public and private keys, as defined in §6.1.
Definition: ML_DSA_Keys.cs:7
static ML_DSA_Keys FromPublicKey(byte[] PublicKey)
Creates a key object instance from a public key.
Definition: ML_DSA_Keys.cs:57
bool HasPrivateKey
If the key contains a private key.
Definition: ML_DSA_Keys.cs:45
Implements the ML-DSA algorithm for post-quantum cryptography, as defined in NIST FIPS 204: https://n...
Definition: ML_DSA.cs:12
override int PublicKeyLength
Length of the public key.
Definition: ML_DSA.cs:120
ML_KEM encapsulation keys, as defined in §7.2.
ML_KEM encryption and decryption keys, as defined in §6.1.
Definition: ML_KEM_Keys.cs:7
static ML_KEM_Keys FromEncapsulationKey(byte[] EncapsulationKey)
Creates a key object instance from an encapsulation key.
Definition: ML_KEM_Keys.cs:68
Implements the ML-KEM algorithm for post-quantum cryptography, as defined in NIST FIPS 203: https://n...
Definition: ML_KEM.cs:11
override int PublicKeyLength
Length of the public key.
Definition: ML_KEM.cs:138
Abstract base class for End-to-End encryption schemes.
Definition: IE2eEndpoint.cs:13
Interface for symmetric ciphers.
IElement Encapsulate(ChunkedList< IElement > Elements, ScriptNode Node)
Encapsulates a set of elements into a similar structure as that provided by the current element.
Definition: ImplTypes.g.cs:58