Skip to content

Commit

Permalink
Merge pull request joemphilips#115 from canndrew/more-revocation-fixes
Browse files Browse the repository at this point in the history
More revocation fixes
  • Loading branch information
joemphilips committed Jul 9, 2020
2 parents 2f2a90d + 2bdb043 commit d485e88
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 28 deletions.
14 changes: 8 additions & 6 deletions src/DotNetLightning.Core/Channel/Channel.fs
Original file line number Diff line number Diff line change
Expand Up @@ -109,19 +109,21 @@ module Channel =
let makeChannelReestablish (keyRepo: IKeysRepository)
(data: Data.IHasCommitments)
: Result<ChannelEvent list, ChannelError> =
let chanPrivateKeys = keyRepo.GetChannelKeys data.Commitments.LocalParams.IsFunder
let commitments = data.Commitments
let chanPrivateKeys = keyRepo.GetChannelKeys commitments.LocalParams.IsFunder
let commitmentSeed = chanPrivateKeys.CommitmentSeed
let ourChannelReestablish =
{
ChannelId = data.ChannelId
NextLocalCommitmentNumber = 1UL
NextRemoteCommitmentNumber = 0UL
NextCommitmentNumber =
commitments.RemotePerCommitmentSecrets.NextCommitmentNumber.NextCommitment
NextRevocationNumber =
commitments.RemotePerCommitmentSecrets.NextCommitmentNumber
DataLossProtect = OptionalField.Some <| {
YourLastPerCommitmentSecret =
RevocationKey.FromBytes [|for _ in 0..31 -> 0uy|]
commitments.RemotePerCommitmentSecrets.LastRevocationKey()
MyCurrentPerCommitmentPoint =
let revocationKey = commitmentSeed.DeriveRevocationKey CommitmentNumber.LastCommitment
revocationKey.CommitmentPubKey
commitments.RemoteCommit.RemotePerCommitmentPoint
}
}
[ WeSentChannelReestablish ourChannelReestablish ] |> Ok
Expand Down
32 changes: 31 additions & 1 deletion src/DotNetLightning.Core/Crypto/RevocationSet.fs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,30 @@ type InsertRevocationKeyError =
type RevocationSet private (keys: list<CommitmentNumber * RevocationKey>) =
new() = RevocationSet(List.empty)

member private this.Keys = keys
member this.Keys = keys

static member FromKeys (keys: list<CommitmentNumber * RevocationKey>): RevocationSet =
let rec sanityCheck (commitmentNumbers: list<CommitmentNumber>): bool =
if commitmentNumbers.IsEmpty then
true
else
let commitmentNumber = commitmentNumbers.Head
let tail = commitmentNumbers.Tail
match commitmentNumber.PreviousUnsubsumed with
| None -> tail.IsEmpty
| Some expectedCommitmentNumber ->
if tail.IsEmpty then
false
else
let nextCommitmentNumber = tail.Head
if nextCommitmentNumber <> expectedCommitmentNumber then
false
else
sanityCheck tail
let commitmentNumbers, _ = List.unzip keys
if not (sanityCheck commitmentNumbers) then
failwith "commitment number list is malformed: %A" commitmentNumbers
RevocationSet keys

member this.NextCommitmentNumber: CommitmentNumber =
if this.Keys.IsEmpty then
Expand Down Expand Up @@ -71,3 +94,10 @@ type RevocationSet private (keys: list<CommitmentNumber * RevocationKey>) =
| None -> fold keys.Tail
fold this.Keys

member this.LastRevocationKey(): Option<RevocationKey> =
if this.Keys.IsEmpty then
None
else
let _, revocationKey = this.Keys.Head
Some revocationKey

6 changes: 6 additions & 0 deletions src/DotNetLightning.Core/Serialize/LightningStream.fs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ type LightningWriterStream(inner: Stream) =
this.Inner.WriteByte(data.Red)
this.Inner.WriteByte(data.Green)
this.Inner.WriteByte(data.Blue)
member this.Write(commitmentNumber: CommitmentNumber) =
this.Write((UInt48.MaxValue - commitmentNumber.Index).UInt64, false)

member this.WriteWithLen(data: byte[]) =
let length = data.Length
Expand Down Expand Up @@ -336,6 +338,10 @@ type LightningReaderStream(inner: Stream) =
let bytes = this.ReadBytes CommitmentPubKey.BytesLength
CommitmentPubKey.FromBytes bytes

member this.ReadCommitmentNumber() =
let n = this.ReadUInt64 false
CommitmentNumber <| (UInt48.MaxValue - (UInt48.FromUInt64 n))

member this.ReadECDSACompact() =
let data = this.ReadBytes(64)
LNECDSASignature.FromBytesCompact(data)
Expand Down
31 changes: 20 additions & 11 deletions src/DotNetLightning.Core/Serialize/Msgs/Msgs.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ namespace rec DotNetLightning.Serialize.Msgs
open System
open System.IO
open System.Runtime.CompilerServices
open System.Linq

open NBitcoin

Expand Down Expand Up @@ -842,40 +843,48 @@ with

[<CLIMutable>]
type DataLossProtect = {
mutable YourLastPerCommitmentSecret: RevocationKey
mutable YourLastPerCommitmentSecret: Option<RevocationKey>
mutable MyCurrentPerCommitmentPoint: CommitmentPubKey
}
with
interface ILightningSerializable<DataLossProtect> with
member this.Deserialize(ls: LightningReaderStream) =
this.YourLastPerCommitmentSecret <- ls.ReadRevocationKey()
this.YourLastPerCommitmentSecret <-
let bytes = ls.ReadBytes RevocationKey.BytesLength
if bytes.All(fun b -> b = 0uy) then
None
else
Some <| RevocationKey.FromBytes bytes
this.MyCurrentPerCommitmentPoint <- ls.ReadCommitmentPubKey()
member this.Serialize(ls: LightningWriterStream): unit =
ls.Write(this.YourLastPerCommitmentSecret.ToByteArray())
match this.YourLastPerCommitmentSecret with
| Some revocationKey -> ls.Write(revocationKey.ToByteArray())
| None -> ls.Write(Array.zeroCreate RevocationKey.BytesLength)
ls.Write(this.MyCurrentPerCommitmentPoint.ToByteArray())


[<CLIMutable>]
type ChannelReestablishMsg = {
mutable ChannelId: ChannelId
mutable NextLocalCommitmentNumber: uint64
mutable NextRemoteCommitmentNumber: uint64
mutable NextCommitmentNumber: CommitmentNumber
mutable NextRevocationNumber: CommitmentNumber
mutable DataLossProtect: OptionalField<DataLossProtect>
}
with
interface IChannelMsg
interface ILightningSerializable<ChannelReestablishMsg> with
member this.Deserialize(ls) =
this.ChannelId <- ls.ReadUInt256(true) |> ChannelId
this.NextLocalCommitmentNumber <- ls.ReadUInt64(false)
this.NextRemoteCommitmentNumber <- ls.ReadUInt64(false)
this.NextCommitmentNumber <- ls.ReadCommitmentNumber()
this.NextRevocationNumber <- ls.ReadCommitmentNumber()
this.DataLossProtect <- ls.TryReadAll() |> Option.map ILightningSerializable.fromBytes<DataLossProtect>
member this.Serialize(ls) =
ls.Write(this.ChannelId.Value.ToBytes())
ls.Write(Utils.ToBytes(this.NextLocalCommitmentNumber, false))
ls.Write(Utils.ToBytes(this.NextRemoteCommitmentNumber, false))
ls.Write(this.DataLossProtect |> Option.map(fun x -> x.YourLastPerCommitmentSecret.ToByteArray()))
ls.Write(this.DataLossProtect |> Option.map(fun x -> x.MyCurrentPerCommitmentPoint.ToByteArray()))
ls.Write this.NextCommitmentNumber
ls.Write this.NextRevocationNumber
match this.DataLossProtect with
| None -> ()
| Some dataLossProtect -> (dataLossProtect :> ILightningSerializable<DataLossProtect>).Serialize ls

[<CLIMutable>]
type AnnouncementSignaturesMsg = {
Expand Down
8 changes: 8 additions & 0 deletions src/DotNetLightning.Core/Utils/Primitives.fs
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,14 @@ module Primitives =
let trailingZeros = this.Index.TrailingZeros
(this.Index >>> trailingZeros) = (other.Index >>> trailingZeros)

member this.PreviousUnsubsumed: Option<CommitmentNumber> =
let trailingZeros = this.Index.TrailingZeros
let prev = this.Index.UInt64 + (1UL <<< trailingZeros)
if prev > UInt48.MaxValue.UInt64 then
None
else
Some <| CommitmentNumber(UInt48.FromUInt64 prev)

member this.Obscure (isFunder: bool)
(localPaymentBasePoint: PubKey)
(remotePaymentBasePoint: PubKey)
Expand Down
10 changes: 5 additions & 5 deletions tests/DotNetLightning.Core.Tests/Generators/Msgs.fs
Original file line number Diff line number Diff line change
Expand Up @@ -272,21 +272,21 @@ let private dataLossProtectGen = gen {
let! revocationKey = revocationKeyGen
let! pk = commitmentPubKeyGen
return {
YourLastPerCommitmentSecret = revocationKey
YourLastPerCommitmentSecret = Some revocationKey
MyCurrentPerCommitmentPoint = pk
}
}

let channelReestablishGen = gen {
let! c = ChannelId <!> uint256Gen
let! n1 = Arb.generate<uint64>
let! n2 = Arb.generate<uint64>
let! n1 = commitmentNumberGen
let! n2 = commitmentNumberGen
let! d = Gen.optionOf dataLossProtectGen

return {
ChannelId = c
NextLocalCommitmentNumber = n1
NextRemoteCommitmentNumber = n2
NextCommitmentNumber = n1
NextRevocationNumber = n2
DataLossProtect = d
}
}
Expand Down
6 changes: 6 additions & 0 deletions tests/DotNetLightning.Core.Tests/Generators/Primitives.fs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ open System
let byteGen = byte <!> Gen.choose(0, 127)
let bytesGen = Gen.listOf(byteGen) |> Gen.map(List.toArray)
let bytesOfNGen(n) = Gen.listOfLength n byteGen |> Gen.map(List.toArray)
let uint48Gen = bytesOfNGen(6) |> Gen.map(fun bs -> UInt48.FromBytesBigEndian bs)
let uint256Gen = bytesOfNGen(32) |> Gen.map(fun bs -> uint256(bs))
let temporaryChannelGen = uint256Gen |> Gen.map ChannelId
let moneyGen = Arb.generate<uint64> |> Gen.map(Money.Satoshis)
Expand All @@ -33,6 +34,11 @@ let commitmentPubKeyGen = gen {
return CommitmentPubKey pubKey
}

let commitmentNumberGen = gen {
let! n = uint48Gen
return CommitmentNumber n
}

let signatureGen: Gen<LNECDSASignature> = gen {
let! h = uint256Gen
let! k = keyGen
Expand Down
10 changes: 5 additions & 5 deletions tests/DotNetLightning.Core.Tests/Serialization.fs
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ module SerializationTest =
let cid = ChannelId (uint256([|4; 0; 0; 0; 0; 0; 0; 0; 5; 0; 0; 0; 0; 0; 0; 0; 6; 0; 0; 0; 0; 0; 0; 0; 7; 0; 0; 0; 0; 0; 0; 0|] |> Array.map((uint8))))
let channelReestablishMsg = {
ChannelId = cid
NextLocalCommitmentNumber = 3UL
NextRemoteCommitmentNumber = 4UL
NextCommitmentNumber = CommitmentNumber <| (UInt48.MaxValue - UInt48.FromUInt64 3UL)
NextRevocationNumber = CommitmentNumber <| (UInt48.MaxValue - UInt48.FromUInt64 4UL)
DataLossProtect = None
}
let actual = channelReestablishMsg.ToBytes()
Expand All @@ -78,11 +78,11 @@ module SerializationTest =
testCase "channel_reestablish with secret" <| fun _ ->
let channelReestablishMsg = {
ChannelId = ChannelId(uint256([|4; 0; 0; 0; 0; 0; 0; 0; 5; 0; 0; 0; 0; 0; 0; 0; 6; 0; 0; 0; 0; 0; 0; 0; 7; 0; 0; 0; 0; 0; 0; 0 |] |> Array.map(uint8)))
NextLocalCommitmentNumber = 3UL
NextRemoteCommitmentNumber = 4UL
NextCommitmentNumber = CommitmentNumber <| (UInt48.MaxValue - UInt48.FromUInt64 3UL)
NextRevocationNumber = CommitmentNumber <| (UInt48.MaxValue - UInt48.FromUInt64 4UL)
DataLossProtect = OptionalField.Some <| {
YourLastPerCommitmentSecret =
RevocationKey.FromBytes
Some <| RevocationKey.FromBytes
[| for _ in 0..(RevocationKey.BytesLength - 1) -> 9uy |]
MyCurrentPerCommitmentPoint = CommitmentPubKey pubkey1
}
Expand Down

0 comments on commit d485e88

Please sign in to comment.