< Summary - Combined Code Coverage

Information
Class: NLightning.Infrastructure.Transport.Encryption.Transport
Assembly: NLightning.Infrastructure
File(s): /home/runner/work/nlightning/nlightning/src/NLightning.Infrastructure/Transport/Encryption/Transport.cs
Tag: 30_15166811759
Line coverage
79%
Covered lines: 38
Uncovered lines: 10
Coverable lines: 48
Total lines: 179
Line coverage: 79.1%
Branch coverage
57%
Covered branches: 16
Total branches: 28
Branch coverage: 57.1%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
WriteMessage(...)100%22100%
ReadMessageLength(...)66.67%6.39677.78%
ReadMessagePayload(...)100%11100%
WriteMessagePart(...)50%11.38862.5%
ReadMessagePart(...)50%18.781055.56%
Dispose()50%2.02283.33%

File(s)

/home/runner/work/nlightning/nlightning/src/NLightning.Infrastructure/Transport/Encryption/Transport.cs

#LineLine coverage
 1namespace NLightning.Infrastructure.Transport.Encryption;
 2
 3using Common.Utils;
 4using Domain.Crypto.Constants;
 5using Domain.Exceptions;
 6using Domain.Transport;
 7using Handshake.States;
 8using Protocol.Constants;
 9
 10/// <inheritdoc/>
 11internal sealed class Transport : ITransport
 12{
 13    private readonly bool _initiator;
 14    private readonly CipherState _sendingKey;
 15    private readonly CipherState _receivingKey;
 16
 17    private bool _disposed;
 18
 3219    public Transport(bool initiator, CipherState c1, CipherState c2)
 20    {
 3221        ArgumentNullException.ThrowIfNull(c1, nameof(c1));
 3222        ArgumentNullException.ThrowIfNull(c2, nameof(c2));
 23
 3224        _initiator = initiator;
 3225        _sendingKey = c1;
 3226        _receivingKey = c2;
 3227    }
 28
 29    /// <inheritdoc/>
 30    /// <exception cref="ObjectDisposedException">Thrown if the current instance has already been disposed.</exception>
 31    /// <exception cref="InvalidOperationException">Thrown if the responder has attempted to write a message to a one-wa
 32    /// <exception cref="ArgumentException">Thrown if the encrypted payload was greater than <see cref="ProtocolConstant
 33    public int WriteMessage(ReadOnlySpan<byte> payload, Span<byte> messageBuffer)
 34    {
 400835        ExceptionUtils.ThrowIfDisposed(_disposed, nameof(Transport));
 36
 37        // Serialize length into 2 bytes encoded as a big-endian integer
 400838        var l = BitConverter.GetBytes((ushort)payload.Length);
 400839        if (BitConverter.IsLittleEndian)
 40        {
 400841            Array.Reverse(l);
 42        }
 43
 44        // Encrypt the payload length into the message buffer
 400845        var lcLen = WriteMessagePart(l, messageBuffer);
 46
 47        // Encrypt the payload into the message buffer
 400848        var mLen = WriteMessagePart(payload, messageBuffer[lcLen..]);
 49
 400850        return lcLen + mLen;
 51    }
 52
 53    /// <inheritdoc/>
 54    public int ReadMessageLength(ReadOnlySpan<byte> lc)
 55    {
 400856        ExceptionUtils.ThrowIfDisposed(_disposed, nameof(Transport));
 57
 400858        if (lc.Length != ProtocolConstants.MESSAGE_HEADER_SIZE)
 59        {
 060            throw new ArgumentException($"Lightning Message Header must be {ProtocolConstants.MESSAGE_HEADER_SIZE} bytes
 61        }
 62
 63        // Decrypt the payload length from the message buffer
 400864        var l = new byte[2];
 65        // Bytes read should always be 2
 400866        if (ReadMessagePart(lc, l) != 2)
 67        {
 068            throw new ConnectionException("Message Length was invalid.");
 69        }
 70
 400871        if (BitConverter.IsLittleEndian)
 72        {
 400873            Array.Reverse(l);
 74        }
 400875        return BitConverter.ToUInt16(l, 0) + CryptoConstants.CHACHA20_POLY1305_TAG_LEN;
 76    }
 77
 78    /// <inheritdoc/>
 79    public int ReadMessagePayload(ReadOnlySpan<byte> message, Span<byte> payloadBuffer)
 80    {
 400881        ExceptionUtils.ThrowIfDisposed(_disposed, nameof(Transport));
 82
 83        // Decrypt the payload from the message buffer
 400884        return ReadMessagePart(message, payloadBuffer);
 85    }
 86
 87    /// <summary>
 88    /// Encrypts the <paramref name="payload"/> and writes the result into <paramref name="messageBuffer"/>.
 89    /// </summary>
 90    /// <param name="payload">The payload to encrypt.</param>
 91    /// <param name="messageBuffer">The buffer for the encrypted message.</param>
 92    /// <returns>The ciphertext size in bytes.</returns>
 93    /// <exception cref="ObjectDisposedException">
 94    /// Thrown if the current instance has already been disposed.
 95    /// </exception>
 96    /// <exception cref="InvalidOperationException">
 97    /// Thrown if the responder has attempted to write a message to a one-way stream.
 98    /// </exception>
 99    /// <exception cref="ArgumentException">
 100    /// Thrown if the encrypted payload was greater than <see cref="ProtocolConstants.MAX_MESSAGE_LENGTH"/>
 101    /// bytes in length, or if the output buffer did not have enough space to hold the ciphertext.
 102    /// </exception>
 103    private int WriteMessagePart(ReadOnlySpan<byte> payload, Span<byte> messageBuffer)
 104    {
 8016105        if (payload.Length + CryptoConstants.CHACHA20_POLY1305_TAG_LEN > ProtocolConstants.MAX_MESSAGE_LENGTH)
 106        {
 0107            throw new ArgumentException($"Noise message must be less than or equal to {ProtocolConstants.MAX_MESSAGE_LEN
 108        }
 109
 8016110        if (payload.Length + CryptoConstants.CHACHA20_POLY1305_TAG_LEN > messageBuffer.Length)
 111        {
 0112            throw new ArgumentException("Message buffer does not have enough space to hold the ciphertext.");
 113        }
 114
 8016115        var cipher = _initiator ? _sendingKey : _receivingKey;
 8016116        if (!cipher.HasKeys())
 117        {
 0118            throw new InvalidOperationException("Cipher is missing keys.");
 119        }
 120
 8016121        return cipher.Encrypt(payload, messageBuffer);
 122    }
 123
 124    /// <summary>
 125    /// Decrypts the <paramref name="message"/> and writes the result into <paramref name="payloadBuffer"/>.
 126    /// </summary>
 127    /// <param name="message">The message to decrypt.</param>
 128    /// <param name="payloadBuffer">The buffer for the decrypted payload.</param>
 129    /// <returns>The plaintext size in bytes.</returns>
 130    /// <exception cref="ObjectDisposedException">
 131    /// Thrown if the current instance has already been disposed.
 132    /// </exception>
 133    /// <exception cref="InvalidOperationException">
 134    /// Thrown if the initiator has attempted to read a message from a one-way stream.
 135    /// </exception>
 136    /// <exception cref="ArgumentException">
 137    /// Thrown if the message was greater than <see cref="ProtocolConstants.MAX_MESSAGE_LENGTH"/>
 138    /// bytes in length, or if the output buffer did not have enough space to hold the plaintext.
 139    /// </exception>
 140    /// <exception cref="System.Security.Cryptography.CryptographicException">
 141    /// Thrown if the decryption of the message has failed.
 142    /// </exception>
 143    private int ReadMessagePart(ReadOnlySpan<byte> message, Span<byte> payloadBuffer)
 144    {
 8016145        switch (message.Length)
 146        {
 147            case > ProtocolConstants.MAX_MESSAGE_LENGTH:
 0148                throw new ArgumentException($"Noise message must be less than or equal to {ProtocolConstants.MAX_MESSAGE
 149            case < CryptoConstants.CHACHA20_POLY1305_TAG_LEN:
 0150                throw new ArgumentException($"Noise message must be greater than or equal to {CryptoConstants.CHACHA20_P
 151        }
 152
 8016153        if (message.Length - CryptoConstants.CHACHA20_POLY1305_TAG_LEN > payloadBuffer.Length)
 154        {
 0155            throw new ArgumentException("Payload buffer does not have enough space to hold the plaintext.");
 156        }
 157
 8016158        var cipher = _initiator ? _receivingKey : _sendingKey;
 8016159        if (!cipher.HasKeys())
 160        {
 0161            throw new InvalidOperationException("Cipher is missing keys.");
 162        }
 163
 8016164        return cipher.Decrypt(message, payloadBuffer);
 165    }
 166
 167    public void Dispose()
 168    {
 8169        if (_disposed)
 170        {
 0171            return;
 172        }
 173
 8174        _sendingKey.Dispose();
 8175        _receivingKey.Dispose();
 176
 8177        _disposed = true;
 8178    }
 179}