Skip to content

Commit

Permalink
Add and switch to new types for revocation
Browse files Browse the repository at this point in the history
Add the UInt48, RevocationKey, CommitmentPubKey, CommitmentSeed and
RevocationSet types.

A RevocationKey is a secret key that can be used to revoke a
transaction. It's shared in the revoke_and_ack message and stored in the
user's wallet in a RevocationSet. A CommitmentPubKey is the public key
of a RevocationKey, also known as a "per commitment point". A
CommitmentSeed is the master revocation key for a side of a channel and
can be used to derive all the revocation keys for that side of that
channel.

A RevocationSet stores a set of revocation keys in a compact form
specified in BOLT #3 which allows earlier keys to be derived from later
keys.
  • Loading branch information
canndrew committed Jun 10, 2020
1 parent e6c4820 commit 974723f
Show file tree
Hide file tree
Showing 30 changed files with 889 additions and 225 deletions.
6 changes: 2 additions & 4 deletions src/DotNetLightning.Core/Chain/KeysInterface.fs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ type ChannelKeys = {
PaymentBaseKey: Key
DelayedPaymentBaseKey: Key
HTLCBaseKey: Key
CommitmentSeed: uint256
CommitmentSeed: CommitmentSeed
}

with
Expand All @@ -65,7 +65,6 @@ type ChannelKeys = {
PaymentBasePubKey = this.PaymentBaseKey.PubKey
DelayedPaymentBasePubKey = this.DelayedPaymentBaseKey.PubKey
HTLCBasePubKey = this.HTLCBaseKey.PubKey
CommitmentSeed = this.CommitmentSeed
}

/// In usual operation we should not hold secrets on memory. So only hold pubkey
Expand All @@ -75,7 +74,6 @@ and ChannelPubKeys = {
PaymentBasePubKey: PubKey
DelayedPaymentBasePubKey: PubKey
HTLCBasePubKey: PubKey
CommitmentSeed: uint256
}


Expand Down Expand Up @@ -108,7 +106,7 @@ type DefaultKeyRepository(nodeSecret: ExtKey, channelIndex: int) =

let destinationKey = channelMasterKey.Derive(1, true).PrivateKey
let shutdownKey = channelMasterKey.Derive(2, true).PrivateKey
let commitmentSeed = channelMasterKey.Derive(3, true).PrivateKey.ToBytes() |> uint256
let commitmentSeed = channelMasterKey.Derive(3, true).PrivateKey |> CommitmentSeed

let fundingKey = channelMasterKey.Derive(4, true).PrivateKey
let fundingPubKey = fundingKey.PubKey
Expand Down
81 changes: 48 additions & 33 deletions src/DotNetLightning.Core/Channel/Channel.fs
Original file line number Diff line number Diff line change
Expand Up @@ -99,25 +99,34 @@ module Channel =
[ MutualClosePerformed nextData ]
|> Ok

let claimCurrentLocalCommitTxOutputs (_keyRepo: IKeysRepository, channelPubKeys: ChannelPubKeys, commitments: Commitments, commitTx: CommitTx) =
let claimCurrentLocalCommitTxOutputs (keyRepo: IKeysRepository, channelPubKeys: ChannelPubKeys, commitments: Commitments, commitTx: CommitTx) =
result {
let chanPrivateKeys = keyRepo.GetChannelKeys commitments.LocalParams.IsFunder
let commitmentSeed = chanPrivateKeys.CommitmentSeed
do! check (commitments.LocalCommit.PublishableTxs.CommitTx.Value.GetTxId()) (=) (commitTx.Value.GetTxId()) "txid mismatch. provided txid (%A) does not match current local commit tx (%A)"
let _localPerCommitmentPoint = ChannelUtils.buildCommitmentPoint (channelPubKeys.CommitmentSeed, commitments.LocalCommit.Index)
let _localPerCommitmentPoint =
commitmentSeed.DeriveCommitmentPubKey commitments.LocalCommit.Index
let _localRevocationPubKey = Generators.revocationPubKey
failwith "TODO"
}

let makeChannelReestablish (data: Data.IHasCommitments): Result<ChannelEvent list, ChannelError> =
let commitmentSeed = data.Commitments.LocalParams.ChannelPubKeys.CommitmentSeed
let makeChannelReestablish (keyRepo: IKeysRepository)
(data: Data.IHasCommitments)
: Result<ChannelEvent list, ChannelError> =
let chanPrivateKeys = keyRepo.GetChannelKeys data.Commitments.LocalParams.IsFunder
let commitmentSeed = chanPrivateKeys.CommitmentSeed
let ourChannelReestablish =
{
ChannelId = data.ChannelId
NextLocalCommitmentNumber = 1UL
NextRemoteCommitmentNumber = 0UL
DataLossProtect = OptionalField.Some({
YourLastPerCommitmentSecret = PaymentPreimage.Create([|for _ in 0..31 -> 0uy|])
MyCurrentPerCommitmentPoint = ChannelUtils.buildCommitmentPoint(commitmentSeed, 0UL)
})
DataLossProtect = OptionalField.Some <| {
YourLastPerCommitmentSecret =
RevocationKey.FromBytes [|for _ in 0..31 -> 0uy|]
MyCurrentPerCommitmentPoint =
let revocationKey = commitmentSeed.DeriveRevocationKey CommitmentNumber.LastCommitment
revocationKey.CommitmentPubKey
}
}
[ WeSentChannelReestablish ourChannelReestablish ] |> Ok

Expand All @@ -143,7 +152,7 @@ module Channel =
PaymentBasepoint = inputInitFunder.ChannelKeys.PaymentBaseKey.PubKey
DelayedPaymentBasepoint = inputInitFunder.ChannelKeys.DelayedPaymentBaseKey.PubKey
HTLCBasepoint = inputInitFunder.ChannelKeys.HTLCBaseKey.PubKey
FirstPerCommitmentPoint = ChannelUtils.buildCommitmentPoint(inputInitFunder.ChannelKeys.CommitmentSeed, 0UL)
FirstPerCommitmentPoint = inputInitFunder.ChannelKeys.CommitmentSeed.DeriveCommitmentPubKey CommitmentNumber.FirstCommitment
ChannelFlags = inputInitFunder.ChannelFlags
ShutdownScriptPubKey = cs.Config.ChannelOptions.ShutdownScriptPubKey
}
Expand Down Expand Up @@ -177,7 +186,7 @@ module Channel =
state.LastSent.FeeRatePerKw
outIndex
(fundingTx.Value.GetHash() |> TxId)
(ChannelUtils.buildCommitmentPoint(commitmentSeed, 0UL))
(commitmentSeed.DeriveCommitmentPubKey CommitmentNumber.FirstCommitment)
msg.FirstPerCommitmentPoint
cs.Secp256k1Context
cs.Network
Expand All @@ -194,7 +203,7 @@ module Channel =
Data.WaitForFundingSignedData.FundingTx = fundingTx
Data.WaitForFundingSignedData.LocalSpec = commitmentSpec
LocalCommitTx = localCommitTx
RemoteCommit = { RemoteCommit.Index = 0UL;
RemoteCommit = { RemoteCommit.Index = CommitmentNumber.FirstCommitment
Spec = remoteSpec
TxId = remoteCommitTx.Value.GetGlobalTransaction().GetTxId()
RemotePerCommitmentPoint = msg.FirstPerCommitmentPoint }
Expand All @@ -221,7 +230,7 @@ module Channel =
state.LastSent.FundingTxId
state.LastSent.FundingOutputIndex
amount
LocalCommit = { Index = 0UL;
LocalCommit = { Index = CommitmentNumber.FirstCommitment;
Spec = state.LocalSpec;
PublishableTxs = { PublishableTxs.CommitTx = finalizedLocalCommitTx
HTLCTxs = [] }
Expand All @@ -233,8 +242,8 @@ module Channel =
RemoteNextHTLCId = HTLCId.Zero
OriginChannels = Map.empty
// we will receive their next per-commitment point in the next msg, so we temporarily put a random byte array
RemoteNextCommitInfo = DataEncoders.HexEncoder() .DecodeData("0101010101010101010101010101010101010101010101010101010101010101") |> Key |> fun k -> k.PubKey |> RemoteNextCommitInfo.Revoked
RemotePerCommitmentSecrets = ShaChain.Zero
RemoteNextCommitInfo = DataEncoders.HexEncoder().DecodeData("0101010101010101010101010101010101010101010101010101010101010101") |> Key |> fun k -> k.PubKey |> CommitmentPubKey |> RemoteNextCommitInfo.Revoked
RemotePerCommitmentSecrets = RevocationSet()
ChannelId =
msg.ChannelId }
let nextState = { WaitForFundingConfirmedData.Commitments = commitments
Expand All @@ -249,15 +258,15 @@ module Channel =
[ NewInboundChannelStarted({ InitFundee = inputInitFundee }) ] |> Ok

| WaitForFundingConfirmed state, CreateChannelReestablish ->
makeChannelReestablish state
makeChannelReestablish cs.KeysRepository state
| ChannelState.Normal state, CreateChannelReestablish ->
makeChannelReestablish state
makeChannelReestablish cs.KeysRepository state
| WaitForOpenChannel state, ApplyOpenChannel msg ->
result {
do! Validation.checkOpenChannelMsgAcceptable (cs.FeeEstimator) (cs.Config) msg
let localParams = state.InitFundee.LocalParams
let channelKeys = state.InitFundee.ChannelKeys
let localCommitmentSecret = ChannelUtils.buildCommitmentSecret (channelKeys.CommitmentSeed, 0UL)
let localCommitmentPubKey = channelKeys.CommitmentSeed.DeriveCommitmentPubKey CommitmentNumber.FirstCommitment
let acceptChannelMsg: AcceptChannelMsg = {
TemporaryChannelId = msg.TemporaryChannelId
DustLimitSatoshis = localParams.DustLimitSatoshis
Expand All @@ -272,7 +281,7 @@ module Channel =
PaymentBasepoint = channelKeys.PaymentBaseKey.PubKey
DelayedPaymentBasepoint = channelKeys.DelayedPaymentBaseKey.PubKey
HTLCBasepoint = channelKeys.HTLCBaseKey.PubKey
FirstPerCommitmentPoint = localCommitmentSecret.PubKey
FirstPerCommitmentPoint = localCommitmentPubKey
ShutdownScriptPubKey = cs.Config.ChannelOptions.ShutdownScriptPubKey
}
let remoteParams = RemoteParams.FromOpenChannel cs.RemoteNodeId state.InitFundee.RemoteInit msg cs.Config.ChannelHandshakeConfig
Expand Down Expand Up @@ -313,12 +322,12 @@ module Channel =
RemoteParams = state.RemoteParams
ChannelFlags = state.ChannelFlags
FundingScriptCoin = ChannelHelpers.getFundingScriptCoin state.LocalParams.ChannelPubKeys state.RemoteParams.FundingPubKey msg.FundingTxId msg.FundingOutputIndex state.FundingSatoshis
LocalCommit = { LocalCommit.Index = 0UL;
LocalCommit = { LocalCommit.Index = CommitmentNumber.FirstCommitment
Spec = localSpec
PublishableTxs = { PublishableTxs.CommitTx = finalizedCommitTx;
HTLCTxs = [] }
PendingHTLCSuccessTxs = [] }
RemoteCommit = { RemoteCommit.Index = 0UL;
RemoteCommit = { RemoteCommit.Index = CommitmentNumber.FirstCommitment
Spec = remoteSpec
TxId = remoteCommitTx.Value.GetGlobalTransaction().GetTxId()
RemotePerCommitmentPoint = state.RemoteFirstPerCommitmentPoint }
Expand All @@ -327,8 +336,8 @@ module Channel =
LocalNextHTLCId = HTLCId.Zero
RemoteNextHTLCId = HTLCId.Zero
OriginChannels = Map.empty
RemoteNextCommitInfo = DataEncoders.HexEncoder() .DecodeData("0101010101010101010101010101010101010101010101010101010101010101") |> Key |> fun k -> k.PubKey |> RemoteNextCommitInfo.Revoked
RemotePerCommitmentSecrets = ShaChain.Zero
RemoteNextCommitInfo = DataEncoders.HexEncoder().DecodeData("0101010101010101010101010101010101010101010101010101010101010101") |> Key |> fun k -> k.PubKey |> CommitmentPubKey |> RemoteNextCommitInfo.Revoked
RemotePerCommitmentSecrets = RevocationSet()
ChannelId = channelId }
let nextState = { WaitForFundingConfirmedData.Commitments = commitments
Deferred = None
Expand All @@ -343,8 +352,9 @@ module Channel =
if state.Commitments.RemoteParams.MinimumDepth > depth then
[] |> Ok
else
let chanPrivateKeys = cs.KeysRepository.GetChannelKeys state.Commitments.LocalParams.IsFunder
let nextPerCommitmentPoint =
ChannelUtils.buildCommitmentPoint (state.Commitments.LocalParams.ChannelPubKeys.CommitmentSeed, 1UL)
chanPrivateKeys.CommitmentSeed.DeriveCommitmentPubKey CommitmentNumber.FirstCommitment.NextCommitment
let msgToSend: FundingLockedMsg = { ChannelId = state.Commitments.ChannelId; NextPerCommitmentPoint = nextPerCommitmentPoint }

// This is temporary channel id that we will use in our channel_update message, the goal is to be able to use our channel
Expand Down Expand Up @@ -485,22 +495,27 @@ module Channel =
| ChannelState.Normal state, ApplyRevokeAndACK msg ->
let cm = state.Commitments
match cm.RemoteNextCommitInfo with
| RemoteNextCommitInfo.Waiting _ when (msg.PerCommitmentSecret.ToPubKey() <> cm.RemoteCommit.RemotePerCommitmentPoint) ->
| RemoteNextCommitInfo.Waiting _ when (msg.PerCommitmentSecret.CommitmentPubKey <> cm.RemoteCommit.RemotePerCommitmentPoint) ->
let errorMsg = sprintf "Invalid revoke_and_ack %A; must be %A" msg.PerCommitmentSecret cm.RemoteCommit.RemotePerCommitmentPoint
invalidRevokeAndACK msg errorMsg
| RemoteNextCommitInfo.Revoked _ ->
let errorMsg = sprintf "Unexpected revocation"
invalidRevokeAndACK msg errorMsg
| RemoteNextCommitInfo.Waiting({ NextRemoteCommit = theirNextCommit }) ->
let commitments1 = { cm with LocalChanges = { cm.LocalChanges with Signed = []; ACKed = cm.LocalChanges.ACKed @ cm.LocalChanges.Signed }
RemoteChanges = { cm.RemoteChanges with Signed = [] }
RemoteCommit = theirNextCommit
RemoteNextCommitInfo = RemoteNextCommitInfo.Revoked(msg.NextPerCommitmentPoint)
RemotePerCommitmentSecrets = cm.RemotePerCommitmentSecrets.AddHash (msg.PerCommitmentSecret.ToByteArray(), 0xffffffffffffUL - cm.RemoteCommit.Index) }
let result = [ WeAcceptedRevokeAndACK(commitments1) ]
result |> Ok
failwith "needs update"

let remotePerCommitmentSecretsOpt =
cm.RemotePerCommitmentSecrets.InsertRevocationKey
cm.RemoteCommit.Index
msg.PerCommitmentSecret
match remotePerCommitmentSecretsOpt with
| Error err -> invalidRevokeAndACK msg err.Message
| Ok remotePerCommitmentSecrets ->
let commitments1 = { cm with LocalChanges = { cm.LocalChanges with Signed = []; ACKed = cm.LocalChanges.ACKed @ cm.LocalChanges.Signed }
RemoteChanges = { cm.RemoteChanges with Signed = [] }
RemoteCommit = theirNextCommit
RemoteNextCommitInfo = RemoteNextCommitInfo.Revoked msg.NextPerCommitmentPoint
RemotePerCommitmentSecrets = remotePerCommitmentSecrets }
let result = Ok [ WeAcceptedRevokeAndACK(commitments1) ]
failwith "needs update"

| ChannelState.Normal state, ChannelCommand.Close cmd ->
let localSPK = cmd.ScriptPubKey |> Option.defaultValue (state.Commitments.LocalParams.DefaultFinalScriptPubKey)
Expand Down
4 changes: 2 additions & 2 deletions src/DotNetLightning.Core/Channel/ChannelTypes.fs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ module Data =
FundingSatoshis: Money
PushMsat: LNMoney
InitialFeeRatePerKw: FeeRatePerKw
RemoteFirstPerCommitmentPoint: PubKey
RemoteFirstPerCommitmentPoint: CommitmentPubKey
LastSent: OpenChannelMsg
}
with interface IChannelStateData
Expand All @@ -88,7 +88,7 @@ module Data =
FundingSatoshis: Money
PushMSat: LNMoney
InitialFeeRatePerKw: FeeRatePerKw
RemoteFirstPerCommitmentPoint: PubKey
RemoteFirstPerCommitmentPoint: CommitmentPubKey
ChannelFlags: uint8
LastSent: AcceptChannelMsg
}
Expand Down
20 changes: 0 additions & 20 deletions src/DotNetLightning.Core/Channel/ChannelUtils.fs

This file was deleted.

Loading

0 comments on commit 974723f

Please sign in to comment.