Use 48-bit commitment transaction numbers

Fix SetStateNumHint and GetStateNumHint to properly
set and get the stateNumHints using the lower 24 bits
of the locktime of the commitment transaction as the
lower 24 bits of the obfuscated state number and the
lower 24 bits of the sequence field as the higher 24
bits.
This commit is contained in:
Christopher Jämthagen 2017-01-04 16:15:50 +01:00 committed by Olaoluwa Osuntokun
parent e910b12d33
commit 873211c02f
5 changed files with 32 additions and 24 deletions

@ -185,7 +185,7 @@ type OpenChannel struct {
// StateHintObsfucator are the btyes selected by the initiator (derived
// from their shachain root) to obsfucate the state-hint encoded within
// the commitment transaction.
StateHintObsfucator [4]byte
StateHintObsfucator [6]byte
// ChanType denotes which type of channel this is.
ChanType ChannelType

@ -875,7 +875,7 @@ func (lc *LightningChannel) closeObserver(channelCloseNtfn *chainntnfs.SpendEven
// Decode the state hint encoded within the commitment transaction to
// determine if this is a revoked state or not.
obsfucator := lc.channelState.StateHintObsfucator
broadcastStateNum := uint64(GetStateNumHint(commitTxBroadcast, obsfucator))
broadcastStateNum := GetStateNumHint(commitTxBroadcast, obsfucator)
currentStateNum := lc.currentHeight
@ -1125,7 +1125,7 @@ func (lc *LightningChannel) fetchCommitmentView(remoteChain bool,
// quickly recovering the necessary penalty state in the case of an
// uncooperative broadcast.
obsfucator := lc.channelState.StateHintObsfucator
stateNum := uint32(nextHeight)
stateNum := nextHeight
if err := SetStateNumHint(commitTx, stateNum, obsfucator); err != nil {
return nil, err
}

@ -29,12 +29,12 @@ const (
// StateHintSize is the total number of bytes used between the sequence
// number and locktime of the commitment transaction use to encode a hint
// to the state number of a particular commitment transaction.
StateHintSize = 4
StateHintSize = 6
// maxStateHint is the maximum state number we're able to encode using
// StateHintSize bytes amongst the sequence number and locktime fields
// of the commitment transaction.
maxStateHint = (1 << 31) - 1
maxStateHint = (1 << 48) - 1
)
// witnessScriptHash generates a pay-to-witness-script-hash public key script
@ -770,18 +770,19 @@ func deriveElkremRoot(elkremDerivationRoot *btcec.PrivateKey,
}
// SetStateNumHint encodes the current state number within the passed
// commitment transaction by re-purposing the sequence fields in the input of
// the commitment transaction to encode the obfuscated state number. The state
// number is encoded using 31-bits of the sequence number, with the top bit set
// in order to disable BIP0068 (sequence locks) semantics. Finally before
// encoding, the obfuscater is XOR'd against the state number in order to hide
// the exact state number from the PoV of outside parties.
// commitment transaction by re-purposing the locktime and sequence fields
// in the commitment transaction to encode the obfuscated state number.
// The state number is encoded using 48 bits. The lower 24 bits of the
// locktime are the lower 24 bits of the obfuscated state number and the
// lower 24 bits of the sequence field are the higher 24 bits. Finally
// before encoding, the obfuscater is XOR'd against the state number in
// order to hide the exact state number from the PoV of outside parties.
// TODO(roasbeef): unexport function after bobNode is gone
func SetStateNumHint(commitTx *wire.MsgTx, stateNum uint32,
func SetStateNumHint(commitTx *wire.MsgTx, stateNum uint64,
obsfucator [StateHintSize]byte) error {
// With the current schema we are only able able to encode state num
// hints up to 2^31. Therefore if the passed height is greater than our
// hints up to 2^48. Therefore if the passed height is greater than our
// state hint ceiling, then exit early.
if stateNum >= maxStateHint {
return fmt.Errorf("unable to encode state, %v is greater "+
@ -793,16 +794,20 @@ func SetStateNumHint(commitTx *wire.MsgTx, stateNum uint32,
"instead has %v", len(commitTx.TxIn))
}
// Convert the obfuscater into a uint32, then XOR that against the
// Convert the obfuscator into a uint64, then XOR that against the
// targeted height in order to obfuscate the state number of the
// commitment transaction in the case that either commitment
// transaction is broadcast directly on chain.
xorInt := binary.BigEndian.Uint32(obsfucator[:]) & (^wire.SequenceLockTimeDisabled)
var obfs [8]byte
copy(obfs[2:], obsfucator[:])
xorInt := binary.BigEndian.Uint64(obfs[:])
stateNum = stateNum ^ xorInt
// Set the height bit of the sequence number in order to disable any
// sequence locks semantics.
commitTx.TxIn[0].Sequence = stateNum | wire.SequenceLockTimeDisabled
commitTx.TxIn[0].Sequence = uint32(stateNum>>24) | wire.SequenceLockTimeDisabled
commitTx.LockTime = uint32(stateNum & 0xFFFFFF)
return nil
}
@ -813,14 +818,17 @@ func SetStateNumHint(commitTx *wire.MsgTx, stateNum uint32,
//
// See setStateNumHint for further details w.r.t exactly how the state-hints
// are encoded.
func GetStateNumHint(commitTx *wire.MsgTx, obsfucator [StateHintSize]byte) uint32 {
// Convert the obfuscater into a uint32, this will be used to
func GetStateNumHint(commitTx *wire.MsgTx, obsfucator [StateHintSize]byte) uint64 {
// Convert the obfuscater into a uint64, this will be used to
// de-obfuscate the final recovered state number.
xorInt := binary.BigEndian.Uint32(obsfucator[:]) & (^wire.SequenceLockTimeDisabled)
var obfs [8]byte
copy(obfs[2:], obsfucator[:])
xorInt := binary.BigEndian.Uint64(obfs[:])
// Retrieve the sole state hint from the sequence number of the
// transaction. In the process un-set the top bit.
stateNumXor := commitTx.TxIn[0].Sequence & (^wire.SequenceLockTimeDisabled)
// Retrieve the state hint from the sequence number and locktime
// of the transaction.
stateNumXor := uint64(commitTx.TxIn[0].Sequence&0xFFFFFF) << 24
stateNumXor |= uint64(commitTx.LockTime & 0xFFFFFF)
// Finally, to obtain the final state number, we XOR by the obfuscater
// value to de-obfuscate the state number.

@ -571,7 +571,7 @@ func TestCommitTxStateHint(t *testing.T) {
copy(obsfucator[:], testHdSeed[:StateHintSize])
for i := 0; i < 10000; i++ {
stateNum := uint32(i)
stateNum := uint64(i)
err := SetStateNumHint(commitTx, stateNum, obsfucator)
if err != nil {

@ -1410,7 +1410,7 @@ func deriveStateHintObsfucator(elkremRoot *elkrem.ElkremSender) ([StateHintSize]
return obsfucator, nil
}
// initStateHints properly sets the obsfucated state ints ob both commitment
// initStateHints properly sets the obsfucated state hints on both commitment
// transactions using the passed obsfucator.
func initStateHints(commit1, commit2 *wire.MsgTx,
obsfucator [StateHintSize]byte) error {