| | 1 | | namespace NLightning.Domain.Protocol.Models; |
| | 2 | |
|
| | 3 | | using Bitcoin.ValueObjects; |
| | 4 | | using Crypto.Hashes; |
| | 5 | | using Crypto.ValueObjects; |
| | 6 | |
|
| | 7 | | /// <summary> |
| | 8 | | /// Manages Lightning Network commitment numbers and their obscuring as defined in BOLT3. |
| | 9 | | /// </summary> |
| | 10 | | public class CommitmentNumber |
| | 11 | | { |
| | 12 | | /// <summary> |
| | 13 | | /// Gets the commitment number value. |
| | 14 | | /// </summary> |
| 392 | 15 | | public ulong Value { get; private set; } |
| | 16 | |
|
| | 17 | | /// <summary> |
| | 18 | | /// Gets the obscuring factor derived from payment basepoints. |
| | 19 | | /// </summary> |
| 156 | 20 | | public ulong ObscuringFactor { get; } |
| | 21 | |
|
| | 22 | | /// <summary> |
| | 23 | | /// Gets the obscured commitment number (value XOR obscuring factor). |
| | 24 | | /// </summary> |
| 148 | 25 | | public ulong ObscuredValue => Value ^ ObscuringFactor; |
| | 26 | |
|
| | 27 | | /// <summary> |
| | 28 | | /// Represents a commitment number in the Lightning Network. |
| | 29 | | /// </summary> |
| 228 | 30 | | public CommitmentNumber(CompactPubKey localPaymentBasepoint, CompactPubKey remotePaymentBasepoint, ISha256 sha256, |
| 228 | 31 | | ulong initialValue = 0) |
| | 32 | | { |
| 228 | 33 | | Value = initialValue; |
| 228 | 34 | | ObscuringFactor = CalculateObscuringFactor(localPaymentBasepoint, remotePaymentBasepoint, sha256); |
| 228 | 35 | | } |
| | 36 | |
|
| | 37 | | /// <summary> |
| | 38 | | /// Increments the commitment number. |
| | 39 | | /// </summary> |
| | 40 | | /// <returns>This instance for chaining.</returns> |
| | 41 | | public CommitmentNumber Increment() |
| | 42 | | { |
| 4 | 43 | | Value++; |
| 4 | 44 | | return this; |
| | 45 | | } |
| | 46 | |
|
| | 47 | | /// <summary> |
| | 48 | | /// Calculates the transaction locktime value using the obscured commitment number. |
| | 49 | | /// </summary> |
| | 50 | | /// <returns>The transaction locktime.</returns> |
| | 51 | | public BitcoinLockTime CalculateLockTime() |
| | 52 | | { |
| 72 | 53 | | return new BitcoinLockTime((0x20 << 24) | (uint)(ObscuredValue & 0xFFFFFF)); |
| | 54 | | } |
| | 55 | |
|
| | 56 | | /// <summary> |
| | 57 | | /// Calculates the transaction sequence value using the obscured commitment number. |
| | 58 | | /// </summary> |
| | 59 | | /// <returns>The transaction sequence.</returns> |
| | 60 | | public BitcoinSequence CalculateSequence() |
| | 61 | | { |
| 72 | 62 | | return new BitcoinSequence((uint)((0x80UL << 24) | ((ObscuredValue >> 24) & 0xFFFFFF))); |
| | 63 | | } |
| | 64 | |
|
| | 65 | | /// <summary> |
| | 66 | | /// Calculates the 48-bit obscuring factor by hashing the concatenation of payment basepoints. |
| | 67 | | /// </summary> |
| | 68 | | /// <param name="localBasepoint">The local payment basepoint.</param> |
| | 69 | | /// <param name="remoteBasepoint">The remote payment basepoint.</param> |
| | 70 | | /// <param name="sha256">The SHA256 hash function instance.</param> |
| | 71 | | /// <returns>The 48-bit obscuring factor as ulong.</returns> |
| | 72 | | private static ulong CalculateObscuringFactor(CompactPubKey localBasepoint, CompactPubKey remoteBasepoint, |
| | 73 | | ISha256 sha256) |
| | 74 | | { |
| | 75 | | // Hash the concatenation of payment basepoints |
| 228 | 76 | | sha256.AppendData(localBasepoint); |
| 228 | 77 | | sha256.AppendData(remoteBasepoint); |
| | 78 | |
|
| 228 | 79 | | Span<byte> hashResult = stackalloc byte[32]; |
| 228 | 80 | | sha256.GetHashAndReset(hashResult); |
| | 81 | |
|
| | 82 | | // Extract the lower 48 bits (6 bytes) of the hash |
| 228 | 83 | | ulong obscuringFactor = 0; |
| 3192 | 84 | | for (var i = 26; i < 32; i++) // Last 6 bytes of the 32-byte hash |
| 1368 | 85 | | obscuringFactor = (obscuringFactor << 8) | hashResult[i]; |
| | 86 | |
|
| 228 | 87 | | return obscuringFactor; |
| | 88 | | } |
| | 89 | | } |