commit fb5957114da56e3f794aecb48d59c451e72f651e
parent 014780d0c6110e1517077ed29a85805da56b19a9
Author: Jared Tobin <jared@jtobin.io>
Date: Sat, 10 Oct 2026 13:04:52 +0400
test: rotation from a nonce already past 1000
Diffstat:
1 file changed, 41 insertions(+), 0 deletions(-)
diff --git a/test/Main.hs b/test/Main.hs
@@ -7,6 +7,7 @@ import Data.Bits (xor)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Base16 as B16
import qualified Lightning.Protocol.BOLT8 as BOLT8
+import qualified Lightning.Protocol.BOLT8.Internal as I
import Test.Tasty
import Test.Tasty.HUnit
import Test.Tasty.QuickCheck (Gen, Property, choose, forAll,
@@ -34,6 +35,7 @@ main = defaultMain $ testGroup "ppad-bolt8" [
, framing_tests
, partial_framing_tests
, negative_tests
+ , rotation_tests
, property_tests
]
@@ -542,6 +544,45 @@ flip_byte i bs
b = BS.index post 0
in pure (pre <> BS.cons (b `xor` 0xff) (BS.drop 1 post))
+-- rotation tests ------------------------------------------------------------
+
+rotation_tests :: TestTree
+rotation_tests = testGroup "Key Rotation" [
+ testCase "send key rotates when nonce is past 1000"
+ test_rotate_past_1000_send
+ , testCase "receive key rotates when nonce is past 1000"
+ test_rotate_past_1000_recv
+ ]
+
+-- A session whose nonces are already past 1000 must still rotate on
+-- the next step rather than letting the nonce grow without bound.
+test_rotate_past_1000_send :: Assertion
+test_rotate_past_1000_send = do
+ sess <- get_initiator_session
+ let stale = sess { I.sess_sn = I.SessionNonce 1001 }
+ (_, sess') <- expectRight "encrypt" (BOLT8.encrypt stale hello)
+ I.unSessionNonce (I.sess_sn sess') @?= 1
+ assertBool "send key rotated" (I.sess_sk sess' /= I.sess_sk sess)
+ assertBool "send ck rotated" (I.sess_sck sess' /= I.sess_sck sess)
+
+test_rotate_past_1000_recv :: Assertion
+test_rotate_past_1000_recv = do
+ i_sess <- get_initiator_session
+ let i_stale = i_sess { I.sess_sn = I.SessionNonce 1001 }
+ r_stale = I.Session {
+ I.sess_sk = I.sess_rk i_sess
+ , I.sess_sn = I.SessionNonce 0
+ , I.sess_sck = I.sess_rck i_sess
+ , I.sess_rk = I.sess_sk i_sess
+ , I.sess_rn = I.SessionNonce 1001
+ , I.sess_rck = I.sess_sck i_sess
+ }
+ (ct, _) <- expectRight "encrypt" (BOLT8.encrypt i_stale hello)
+ (pt, r_sess') <- expectRight "decrypt" (BOLT8.decrypt r_stale ct)
+ pt @?= hello
+ I.unSessionNonce (I.sess_rn r_sess') @?= 1
+ assertBool "recv key rotated" (I.sess_rk r_sess' /= I.sess_rk r_stale)
+
-- utilities -----------------------------------------------------------------
-- Safe hex decode for test vectors (only called at top level with known-good