commit 963d7eac442d5585b8cb18948c2cc146081b1189
parent 554dfdbdacc2d80e7a8d66bcebcfecef017cd7ba
Author: Jared Tobin <jared@jtobin.io>
Date: Sat, 10 Oct 2026 13:18:24 +0400
test: add onion-test.json vector and multi-hop roundtrips
Assert that construct reproduces the spec onion byte for byte, and
that process peels it at every hop with the expected payload, shared
secret and forwarded ephemeral key. Add construct-then-process
roundtrips for routes of 1 to 20 hops, both fixed and random.
Vectors live in test/Vectors.hs; the suite now depends on ppad-sha256.
Diffstat:
| M | ppad-bolt4.cabal | | | 2 | ++ |
| M | test/Main.hs | | | 220 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | test/Vectors.hs | | | 523 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
3 files changed, 745 insertions(+), 0 deletions(-)
diff --git a/ppad-bolt4.cabal b/ppad-bolt4.cabal
@@ -48,6 +48,7 @@ test-suite bolt4-tests
default-language: Haskell2010
hs-source-dirs: test
main-is: Main.hs
+ other-modules: Vectors
ghc-options:
-rtsopts -Wall -O2
build-depends:
@@ -56,6 +57,7 @@ test-suite bolt4-tests
, ppad-base16
, ppad-bolt4
, ppad-secp256k1
+ , ppad-sha256
, tasty
, tasty-hunit
, tasty-quickcheck
diff --git a/test/Main.hs b/test/Main.hs
@@ -6,6 +6,8 @@ import Data.Bits (xor)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Base16 as B16
import qualified Crypto.Curve.Secp256k1 as Secp256k1
+import qualified Crypto.Hash.SHA256 as SHA256
+import Data.Maybe (isJust)
import Data.Word (Word8, Word16, Word32)
import Lightning.Protocol.BOLT4.Blinding
import Lightning.Protocol.BOLT4.Codec
@@ -18,12 +20,28 @@ import Lightning.Protocol.BOLT4.Types
import Test.Tasty
import Test.Tasty.HUnit
import Test.Tasty.QuickCheck
+import qualified Vectors as V
-- | Demand a Just value in IO, failing the test on Nothing.
demand :: String -> Maybe a -> IO a
demand _ (Just a) = pure a
demand msg Nothing = assertFailure msg
+-- | Decode hex, failing the test on invalid input.
+unhex :: BS.ByteString -> IO BS.ByteString
+unhex = demand "invalid hex" . B16.decode
+
+-- | Decode a hex-encoded public key, failing the test if invalid.
+unhexPoint :: BS.ByteString -> IO Secp256k1.Projective
+unhexPoint h = unhex h >>= demand "invalid point" . Secp256k1.parse_point
+
+-- | Strip a BigSize length prefix, checking that it is exact.
+unprefix :: BS.ByteString -> IO BS.ByteString
+unprefix bs = do
+ (len, body) <- demand "invalid length prefix" (decodeBigSize bs)
+ assertEqual "length prefix" (fromIntegral len) (BS.length body)
+ pure body
+
-- | Construct a ShortChannelId, failing if invalid.
assertScid :: Word32 -> Word32 -> Word16
-> IO ShortChannelId
@@ -73,6 +91,12 @@ main = defaultMain $ testGroup "ppad-bolt4" [
, blindingCreatePathTests
, blindingProcessHopTests
]
+ , testGroup "spec vectors" [
+ onionVectorTests
+ ]
+ , testGroup "multi-hop" [
+ multiHopTests
+ ]
]
-- BigSize tests ------------------------------------------------------------
@@ -1419,3 +1443,199 @@ genFailureMessage = do
dlen <- choose (0, 100 :: Int)
dat <- BS.pack <$> vectorOf dlen arbitrary
pure (FailureMessage code dat [])
+
+-- Spec vectors: onion-test.json --------------------------------------------
+
+-- | Shared secrets for the onion-test.json route (identical to those
+-- listed in onion-error-test.json).
+onionSharedSecrets :: IO [BS.ByteString]
+onionSharedSecrets = mapM unhex
+ [ V.errSharedSecret0, V.errSharedSecret1, V.errSharedSecret2
+ , V.errSharedSecret3, V.errSharedSecret4 ]
+
+-- | (node key, node pubkey, payload without length prefix) per hop.
+onionVectorHops
+ :: IO [(BS.ByteString, Secp256k1.Projective, BS.ByteString)]
+onionVectorHops = mapM hop
+ [ (V.onionNodeKey0, V.onionPubKey0, V.onionPayload0)
+ , (V.onionNodeKey1, V.onionPubKey1, V.onionPayload1)
+ , (V.onionNodeKey2, V.onionPubKey2, V.onionPayload2)
+ , (V.onionNodeKey3, V.onionPubKey3, V.onionPayload3)
+ , (V.onionNodeKey4, V.onionPubKey4, V.onionPayload4)
+ ]
+ where
+ hop (k, p, pl) = do
+ key <- unhex k
+ pub <- unhexPoint p
+ body <- unhex pl >>= unprefix
+ pure (key, pub, body)
+
+-- | Next ephemeral key per spec: SHA256(E || ss) * E.
+nextEphemeralKey
+ :: Secp256k1.Projective -> BS.ByteString -> Maybe Secp256k1.Projective
+nextEphemeralKey e ss = do
+ tweak <- Secp256k1.roll32
+ (SHA256.hash (Secp256k1.serialize_point e <> ss))
+ Secp256k1.mul e tweak
+
+-- | Process an onion hop by hop, checking each hop's payload and
+-- shared secret, and that each forwarded packet is a well-formed
+-- 1366-byte packet carrying the expected ephemeral key.
+peelOnion
+ :: BS.ByteString
+ -> [(BS.ByteString, BS.ByteString, BS.ByteString)]
+ -- ^ (node key, expected payload, expected shared secret)
+ -> Secp256k1.Projective
+ -- ^ expected ephemeral key of the packet
+ -> OnionPacket
+ -> Assertion
+peelOnion _ [] _ _ = assertFailure "no hops"
+peelOnion ad ((key, body, ss) : rest) eph pkt = do
+ opVersion pkt @?= versionByte
+ opEphemeralKey pkt @?= Secp256k1.serialize_point eph
+ case (process key pkt ad, rest) of
+ (Left e, _) -> assertFailure ("process failed: " ++ show e)
+ (Right (Receive ri), []) -> do
+ encodeHopPayload (riPayload ri) @?= body
+ riSharedSecret ri @?= SharedSecret ss
+ (Right (Forward fi), _ : _) -> do
+ encodeHopPayload (fiPayload fi) @?= body
+ fiSharedSecret fi @?= SharedSecret ss
+ let next = fiNextPacket fi
+ bytes = encodeOnionPacket next
+ BS.length bytes @?= onionPacketSize
+ decodeOnionPacket bytes @?= Just next
+ eph' <- demand "next ephemeral key" (nextEphemeralKey eph ss)
+ peelOnion ad rest eph' next
+ (Right (Receive _), _ : _) ->
+ assertFailure "expected Forward, got Receive"
+ (Right (Forward _), []) ->
+ assertFailure "expected Receive, got Forward"
+
+onionVectorTests :: TestTree
+onionVectorTests = testGroup "onion-test.json" [
+ testCase "construct reproduces the spec onion" $ do
+ hops <- onionVectorHops
+ sk <- unhex V.onionSessionKey
+ ad <- unhex V.onionAssocData
+ expected <- unhex V.onionPacket
+ sss <- onionSharedSecrets
+ route <- mapM (\(_, pub, body) -> do
+ hp <- demand "decodeHopPayload" (decodeHopPayload body)
+ encodeHopPayload hp @?= body
+ pure (Hop pub hp)) hops
+ case construct sk route ad of
+ Left e -> assertFailure ("construct failed: " ++ show e)
+ Right (pkt, secrets) -> do
+ encodeOnionPacket pkt @?= expected
+ secrets @?= map SharedSecret sss
+
+ , testCase "process peels the spec onion at every hop" $ do
+ hops <- onionVectorHops
+ sk <- unhex V.onionSessionKey
+ ad <- unhex V.onionAssocData
+ sss <- onionSharedSecrets
+ pkt <- unhex V.onionPacket >>=
+ demand "decodeOnionPacket" . decodeOnionPacket
+ e0 <- demand "session pubkey"
+ (Secp256k1.roll32 sk >>= Secp256k1.derive_pub)
+ let expect = zipWith (\(k, _, body) ss -> (k, body, ss)) hops sss
+ peelOnion ad expect e0 pkt
+ ]
+
+-- Multi-hop construct/process ----------------------------------------------
+
+-- | Construct an onion over a route of (node key, payload) pairs, then
+-- process it at every hop, checking payloads and shared secrets.
+roundtripRoute :: BS.ByteString -> [(BS.ByteString, HopPayload)] -> Bool
+roundtripRoute sk route = case mapM mkHop route of
+ Nothing -> False
+ Just hops -> case construct sk hops ad of
+ Left _ -> False
+ Right (pkt, secrets) ->
+ length secrets == length route && go (zip route secrets) pkt
+ where
+ ad = BS.replicate 32 0x42
+ mkHop (k, hp) = do
+ pub <- Secp256k1.roll32 k >>= Secp256k1.derive_pub
+ pure (Hop pub hp)
+ go [] _ = False
+ go [((k, hp), ss)] pkt = case process k pkt ad of
+ Right (Receive ri) -> riPayload ri == hp && riSharedSecret ri == ss
+ _ -> False
+ go (((k, hp), ss) : rest) pkt = case process k pkt ad of
+ Right (Forward fi) ->
+ fiPayload fi == hp
+ && fiSharedSecret fi == ss
+ && BS.length (encodeOnionPacket (fiNextPacket fi))
+ == onionPacketSize
+ && go rest (fiNextPacket fi)
+ _ -> False
+
+multiHopTests :: TestTree
+multiHopTests = testGroup "construct then process" [
+ testCase "routes of 1 to 20 hops" $
+ mapM_ (\n -> do
+ route <- mapM (\i -> do
+ scid <- assertScid (700000 + i) i 1
+ let hp = HopPayload
+ { hpAmtToForward = Just (1000 * fromIntegral i)
+ , hpOutgoingCltv = Just (500000 + i)
+ , hpShortChannelId = Just scid
+ , hpPaymentData = Nothing
+ , hpEncryptedData = Nothing
+ , hpCurrentPathKey = Nothing
+ , hpUnknownTlvs = []
+ }
+ pure (BS.replicate 32 (fromIntegral i), hp)) [1 .. n]
+ assertBool ("route of " ++ show n ++ " hops")
+ (roundtripRoute sessionKey route)) [1 .. 20 :: Word32]
+
+ , testProperty "random routes of 1 to 20 hops" $
+ forAll (choose (1, 20)) $ \n ->
+ forAll genSecKey $ \sk ->
+ forAll (vectorOf n genSecKey) $ \keys ->
+ forAll (vectorOf n (genRoutePayload n)) $ \pls ->
+ roundtripRoute sk (zip keys pls)
+ ]
+
+-- | A valid 32-byte secret key.
+genSecKey :: Gen BS.ByteString
+genSecKey = (BS.pack <$> vectorOf 32 arbitrary) `suchThat` valid
+ where
+ valid k = isJust (Secp256k1.roll32 k >>= Secp256k1.derive_pub)
+
+-- | A hop payload whose shift size fits n hops in 1300 bytes.
+--
+-- The fixed fields take at most 26 bytes; an odd TLV of type 65537
+-- adds at most 8 bytes of framing plus its value. With a 3-byte
+-- length prefix and 32-byte HMAC a hop then shifts at most 69 bytes
+-- plus the value length.
+genRoutePayload :: Int -> Gen HopPayload
+genRoutePayload n = do
+ amt <- arbitrary
+ cltv <- arbitrary
+ scid <- oneof [pure Nothing, genScid]
+ let budget = hopPayloadsSize `div` n - 69
+ extra <- if budget < 0
+ then pure []
+ else do
+ len <- choose (0, budget)
+ blob <- BS.pack <$> vectorOf len arbitrary
+ pure [TlvRecord 65537 blob]
+ pure HopPayload
+ { hpAmtToForward = Just amt
+ , hpOutgoingCltv = Just cltv
+ , hpShortChannelId = scid
+ , hpPaymentData = Nothing
+ , hpEncryptedData = Nothing
+ , hpCurrentPathKey = Nothing
+ , hpUnknownTlvs = extra
+ }
+ where
+ genScid :: Gen (Maybe ShortChannelId)
+ genScid = do
+ bh <- choose (0, 0xFFFFFF)
+ ti <- choose (0, 0xFFFFFF)
+ oi <- arbitrary
+ pure (shortChannelId bh ti oi)
diff --git a/test/Vectors.hs b/test/Vectors.hs
@@ -0,0 +1,523 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+-- |
+-- Module: Vectors
+-- Copyright: (c) 2025 Jared Tobin
+-- License: MIT
+-- Maintainer: Jared Tobin <jared@ppad.tech>
+--
+-- BOLT4 test vectors, hex-encoded.
+--
+-- Taken from the bolt04/*.json files in lightning/bolts, and from the
+-- 'Returning Errors' trace in 04-onion-routing.md.
+
+module Vectors where
+
+import qualified Data.ByteString as BS
+
+-- onion-test.json ---------------------------------------------------------
+
+-- | Session key.
+onionSessionKey :: BS.ByteString
+onionSessionKey =
+ "4141414141414141414141414141414141414141414141414141414141414141"
+
+-- | Associated data.
+onionAssocData :: BS.ByteString
+onionAssocData =
+ "4242424242424242424242424242424242424242424242424242424242424242"
+
+-- | Hop 0 public key.
+onionPubKey0 :: BS.ByteString
+onionPubKey0 =
+ "02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619"
+
+-- | Hop 0 payload, with its length prefix.
+onionPayload0 :: BS.ByteString
+onionPayload0 = "1202023a98040205dc06080000000000000001"
+
+-- | Hop 1 public key.
+onionPubKey1 :: BS.ByteString
+onionPubKey1 =
+ "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c"
+
+-- | Hop 1 payload, with its length prefix.
+onionPayload1 :: BS.ByteString
+onionPayload1 = BS.concat
+ [ "52020236b00402057806080000000000000002fd02013c010203040506070809"
+ , "0a0b0c0d0e0f0102030405060708090a0b0c0d0e0f0102030405060708090a0b"
+ , "0c0d0e0f0102030405060708090a0b0c0d0e0f"
+ ]
+
+-- | Hop 2 public key.
+onionPubKey2 :: BS.ByteString
+onionPubKey2 =
+ "027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007"
+
+-- | Hop 2 payload, with its length prefix.
+onionPayload2 :: BS.ByteString
+onionPayload2 = "12020230d4040204e206080000000000000003"
+
+-- | Hop 3 public key.
+onionPubKey3 :: BS.ByteString
+onionPubKey3 =
+ "032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991"
+
+-- | Hop 3 payload, with its length prefix.
+onionPayload3 :: BS.ByteString
+onionPayload3 = "1202022710040203e806080000000000000004"
+
+-- | Hop 4 public key.
+onionPubKey4 :: BS.ByteString
+onionPubKey4 =
+ "02edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145"
+
+-- | Hop 4 payload, with its length prefix.
+onionPayload4 :: BS.ByteString
+onionPayload4 = BS.concat
+ [ "fd011002022710040203e8082224a33562c54507a9334e79f0dc4f17d407e6d7"
+ , "c61f0e2f3d0d38599502f617042710fd012de02a2a2a2a2a2a2a2a2a2a2a2a2a"
+ , "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a"
+ , "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a"
+ , "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a"
+ , "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a"
+ , "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a"
+ , "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a"
+ , "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a"
+ ]
+
+-- | The resulting onion packet.
+onionPacket :: BS.ByteString
+onionPacket = BS.concat
+ [ "0002eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f28368"
+ , "6619f7f3416a5aa36dc7eeb3ec6d421e9615471ab870a33ac07fa5d5a51df0a8"
+ , "823aabe3fea3f90d387529d4f72837f9e687230371ccd8d263072206dbed0234"
+ , "f6505e21e282abd8c0e4f5b9ff8042800bbab065036eadd0149b37f27dde6647"
+ , "25a49866e052e809d2b0198ab9610faa656bbf4ec516763a59f8f42c171b1791"
+ , "66ba38958d4f51b39b3e98706e2d14a2dafd6a5df808093abfca5aeaaca16ede"
+ , "d5db7d21fb0294dd1a163edf0fb445d5c8d7d688d6dd9c541762bf5a5123bf99"
+ , "39d957fe648416e88f1b0928bfa034982b22548e1a4d922690eecf546275afb2"
+ , "33acf4323974680779f1a964cfe687456035cc0fba8a5428430b390f0057b6d1"
+ , "fe9a8875bfa89693eeb838ce59f09d207a503ee6f6299c92d6361bc335fcbf9b"
+ , "5cd44747aadce2ce6069cfdc3d671daef9f8ae590cf93d957c9e873e9a1bc62d"
+ , "9640dc8fc39c14902d49a1c80239b6c5b7fd91d05878cbf5ffc7db2569f47c43"
+ , "d6c0d27c438abff276e87364deb8858a37e5a62c446af95d8b786eaf0b5fcf78"
+ , "d98b41496794f8dcaac4eef34b2acfb94c7e8c32a9e9866a8fa0b6f2a06f00a1"
+ , "ccde569f97eec05c803ba7500acc96691d8898d73d8e6a47b8f43c3d5de74458"
+ , "d20eda61474c426359677001fbd75a74d7d5db6cb4feb83122f133206203e4e2"
+ , "d293f838bf8c8b3a29acb321315100b87e80e0edb272ee80fda944e3fb6084ed"
+ , "4d7f7c7d21c69d9da43d31a90b70693f9b0cc3eac74c11ab8ff655905688916c"
+ , "fa4ef0bd04135f2e50b7c689a21d04e8e981e74c6058188b9b1f9dfc3eec6838"
+ , "e9ffbcf22ce738d8a177c19318dffef090cee67e12de1a3e2a39f61247547ba5"
+ , "257489cbc11d7d91ed34617fcc42f7a9da2e3cf31a94a210a1018143173913c3"
+ , "8f60e62b24bf0d7518f38b5bab3e6a1f8aeb35e31d6442c8abb5178efc892d2e"
+ , "787d79c6ad9e2fc271792983fa9955ac4d1d84a36c024071bc6e431b625519d5"
+ , "56af38185601f70e29035ea6a09c8b676c9d88cf7e05e0f17098b584c4168735"
+ , "940263f940033a220f40be4c85344128b14beb9e75696db37014107801a59b13"
+ , "e89cd9d2258c169d523be6d31552c44c82ff4bb18ec9f099f3bf0e5b1bb2ba9a"
+ , "87d7e26f98d294927b600b5529c47e04d98956677cbcee8fa2b60f49776d8b8c"
+ , "367465b7c626da53700684fb6c918ead0eab8360e4f60edd25b4f43816a75ecf"
+ , "70f909301825b512469f8389d79402311d8aecb7b3ef8599e79485a4388d8774"
+ , "4d899f7c47ee644361e17040a7958c8911be6f463ab6a9b2afacd688ec55ef51"
+ , "7b38f1339efc54487232798bb25522ff4572ff68567fe830f92f7b8113efce3e"
+ , "98c3fffbaedce4fd8b50e41da97c0c08e423a72689cc68e68f752a5e3a9003e6"
+ , "4e35c957ca2e1c48bb6f64b05f56b70b575ad2f278d57850a7ad568c24a4d32a"
+ , "3d74b29f03dc125488bc7c637da582357f40b0a52d16b3b40bb2c2315d03360b"
+ , "c24209e20972c200566bcf3bbe5c5b0aedd83132a8a4d5b4242ba370b6d67d9b"
+ , "67eb01052d132c7866b9cb502e44796d9d356e4e3cb47cc527322cd24976fe7c"
+ , "9257a2864151a38e568ef7a79f10d6ef27cc04ce382347a2488b1f404fdbf407"
+ , "fe1ca1c9d0d5649e34800e25e18951c98cae9f43555eef65fee1ea8f15828807"
+ , "366c3b612cd5753bf9fb8fced08855f742cddd6f765f74254f03186683d646e6"
+ , "f09ac2805586c7cf11998357cafc5df3f285329366f475130c928b2dceba4aa3"
+ , "83758e7a9d20705c4bb9db619e2992f608a1ba65db254bb389468741d0502e25"
+ , "88aeb54390ac600c19af5c8e61383fc1bebe0029e4474051e4ef908828db9cca"
+ , "13277ef65db3fd47ccc2179126aaefb627719f421e20"
+ ]
+
+-- | Hop 0 node private key.
+onionNodeKey0 :: BS.ByteString
+onionNodeKey0 =
+ "4141414141414141414141414141414141414141414141414141414141414141"
+
+-- | Hop 1 node private key.
+onionNodeKey1 :: BS.ByteString
+onionNodeKey1 =
+ "4242424242424242424242424242424242424242424242424242424242424242"
+
+-- | Hop 2 node private key.
+onionNodeKey2 :: BS.ByteString
+onionNodeKey2 =
+ "4343434343434343434343434343434343434343434343434343434343434343"
+
+-- | Hop 3 node private key.
+onionNodeKey3 :: BS.ByteString
+onionNodeKey3 =
+ "4444444444444444444444444444444444444444444444444444444444444444"
+
+-- | Hop 4 node private key.
+onionNodeKey4 :: BS.ByteString
+onionNodeKey4 =
+ "4545454545454545454545454545454545454545454545454545454545454545"
+
+-- onion-error-test.json ---------------------------------------------------
+
+-- | Failure message.
+errFailureMessage :: BS.ByteString
+errFailureMessage = "2002"
+
+-- | Hop 0 shared secret.
+errSharedSecret0 :: BS.ByteString
+errSharedSecret0 =
+ "53eb63ea8a3fec3b3cd433b85cd62a4b145e1dda09391b348c4e1cd36a03ea66"
+
+-- | Hop 0 ammag key.
+errAmmagKey0 :: BS.ByteString
+errAmmagKey0 =
+ "3761ba4d3e726d8abb16cba5950ee976b84937b61b7ad09e741724d7dee12eb5"
+
+-- | Hop 1 shared secret.
+errSharedSecret1 :: BS.ByteString
+errSharedSecret1 =
+ "a6519e98832a0b179f62123b3567c106db99ee37bef036e783263602f3488fae"
+
+-- | Hop 1 ammag key.
+errAmmagKey1 :: BS.ByteString
+errAmmagKey1 =
+ "59ee5867c5c151daa31e36ee42530f429c433836286e63744f2020b980302564"
+
+-- | Hop 2 shared secret.
+errSharedSecret2 :: BS.ByteString
+errSharedSecret2 =
+ "3a6b412548762f0dbccce5c7ae7bb8147d1caf9b5471c34120b30bc9c04891cc"
+
+-- | Hop 2 ammag key.
+errAmmagKey2 :: BS.ByteString
+errAmmagKey2 =
+ "1bf08df8628d452141d56adfd1b25c1530d7921c23cecfc749ac03a9b694b0d3"
+
+-- | Hop 3 shared secret.
+errSharedSecret3 :: BS.ByteString
+errSharedSecret3 =
+ "21e13c2d7cfe7e18836df50872466117a295783ab8aab0e7ecc8c725503ad02d"
+
+-- | Hop 3 ammag key.
+errAmmagKey3 :: BS.ByteString
+errAmmagKey3 =
+ "cd9ac0e09064f039fa43a31dea05f5fe5f6443d40a98be4071af4a9d704be5ad"
+
+-- | Hop 4 shared secret.
+errSharedSecret4 :: BS.ByteString
+errSharedSecret4 =
+ "b5756b9b542727dbafc6765a49488b023a725d631af688fc031217e90770c328"
+
+-- | Hop 4 ammag key.
+errAmmagKey4 :: BS.ByteString
+errAmmagKey4 =
+ "2f36bb8822e1f0d04c27b7d8bb7d7dd586e032a3218b8d414afbba6f169a4d68"
+
+-- | Hop 4 um key.
+errUmKey4 :: BS.ByteString
+errUmKey4 = "4da7f2923edce6c2d85987d1d9fa6d88023e6c3a9c3d20f07d3b10b61a78d646"
+
+-- | Hop 4 return packet, without its HMAC.
+errPayload4 :: BS.ByteString
+errPayload4 = BS.concat
+ [ "0002200200fe0000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "00000000"
+ ]
+
+-- | The return packet received by the origin.
+errPacket :: BS.ByteString
+errPacket = BS.concat
+ [ "9c5add3963fc7f6ed7f148623c84134b5647e1306419dbe2174e523fa9e2fbed"
+ , "3a06a19f899145610741c83ad40b7712aefaddec8c6baf7325d92ea4ca4d1df8"
+ , "bce517f7e54554608bf2bd8071a4f52a7a2f7ffbb1413edad81eeea5785aa9d9"
+ , "90f2865dc23b4bc3c301a94eec4eabebca66be5cf638f693ec256aec514620cc"
+ , "28ee4a94bd9565bc4d4962b9d3641d4278fb319ed2b84de5b665f307a2db0f7f"
+ , "bb757366067d88c50f7e829138fde4f78d39b5b5802f1b92a8a820865af5cc79"
+ , "f9f30bc3f461c66af95d13e5e1f0381c184572a91dee1c849048a647a1158cf8"
+ , "84064deddbf1b0b88dfe2f791428d0ba0f6fb2f04e14081f69165ae66d9297c1"
+ , "18f0907705c9c4954a199bae0bb96fad763d690e7daa6cfda59ba7f2c8d11448"
+ , "b604d12d"
+ ]
+
+-- BOLT4 'Returning Errors' trace ------------------------------------------
+
+-- | Encoded failure message.
+traceFailureMessage :: BS.ByteString
+traceFailureMessage = BS.concat
+ [ "400f0000000000000064000c3500fd84d1fd012c808080808080808080808080"
+ , "8080808080808080808080808080808080808080808080808080808080808080"
+ , "8080808080808080808080808080808080808080808080808080808080808080"
+ , "8080808080808080808080808080808080808080808080808080808080808080"
+ , "8080808080808080808080808080808080808080808080808080808080808080"
+ , "8080808080808080808080808080808080808080808080808080808080808080"
+ , "8080808080808080808080808080808080808080808080808080808080808080"
+ , "8080808080808080808080808080808080808080808080808080808080808080"
+ , "8080808080808080808080808080808080808080808080808080808080808080"
+ , "8080808080808080808080808080808080808080808080808080808080808080"
+ , "02c0000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000"
+ ]
+
+-- | Return packet before obfuscation.
+traceRawPacket :: BS.ByteString
+traceRawPacket = BS.concat
+ [ "fda7e11974f78ca6cc456f2d17ae54463664696e93842548245dd2a2c513a626"
+ , "0140400f0000000000000064000c3500fd84d1fd012c80808080808080808080"
+ , "8080808080808080808080808080808080808080808080808080808080808080"
+ , "8080808080808080808080808080808080808080808080808080808080808080"
+ , "8080808080808080808080808080808080808080808080808080808080808080"
+ , "8080808080808080808080808080808080808080808080808080808080808080"
+ , "8080808080808080808080808080808080808080808080808080808080808080"
+ , "8080808080808080808080808080808080808080808080808080808080808080"
+ , "8080808080808080808080808080808080808080808080808080808080808080"
+ , "8080808080808080808080808080808080808080808080808080808080808080"
+ , "8080808080808080808080808080808080808080808080808080808080808080"
+ , "808002c000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "0000000000000000000000000000000000000000000000000000000000000000"
+ , "00000000"
+ ]
+
+-- | Return packet as sent by node 4.
+tracePacket4 :: BS.ByteString
+tracePacket4 = BS.concat
+ [ "146e94a9086dbbed6a0ab6932d00c118a7195dbf69b7d7a12b0e6956fc54b5e0"
+ , "a989f165b5f12fd45edd73a5b0c48630ff5be69500d3d82a29c0803f0a0679a6"
+ , "a073c33a6fb8250090a3152eba3f11a85184fa87b67f1b0354d6f48e3b342e33"
+ , "2a17b7710f342f342a87cf32eccdf0afc2160808d58abb5e5840d2c760c538e6"
+ , "3a6f841970f97d2e6fe5b8739dc45e2f7f5f532f227bcc2988ab0f9cc6d3f129"
+ , "09cd5842c37bc8c7608475a5ebbe10626d5ecc1f3388ad5f645167b44a4d166f"
+ , "87863fe34918cea25c18059b4c4d9cb414b59f6bc50c1cea749c80c43e2344f5"
+ , "d23159122ed4ab9722503b212016470d9610b46c35dbeebaf2e342e09770b383"
+ , "92a803bc9d2e7c8d6d384ffcbeb74943fe3f64afb2a543a6683c7db3088441c5"
+ , "31eeb4647518cb41992f8954f1269fb969630944928c2d2b45593731b5da0c4e"
+ , "70d04a0a57afe4af42e99912fbb4f8883a5ecb9cb29b883cb6bfa0f4db2279ff"
+ , "8c6d2b56a232f55ba28fe7dfa70a9ab0433a085388f25cce8d53de6a2fbd7546"
+ , "377d6ede9027ad173ba1f95767461a3689ef405ab608a21086165c64b02c1782"
+ , "b04a6dba2361a7784603069124e12f2f6dcb1ec7612a4fbf94c0e14631a2bef6"
+ , "190c3d5f35e0c4b32aa85201f449d830fd8f782ec758b0910428e3ec3ca1dba3"
+ , "b6c7d89f69e1ee1b9df3dfbbf6d361e1463886b38d52e8f43b73a3bd48c6f36f"
+ , "5897f514b93364a31d49d1d506340b1315883d425cb36f4ea553430d538fd6f3"
+ , "596d4afc518db2f317dd051abc0d4bfb0a7870c3db70f19fe78d6604bbf088fc"
+ , "b4613f54e67b038277fedcd9680eb97bdffc3be1ab2cbcbafd625b8a7ac34d8c"
+ , "190f98d3064ecd3b95b8895157c6a37f31ef4de094b2cb9dbf8ff1f419ba0eca"
+ , "cb1bb13df0253b826bec2ccca1e745dd3b3e7cc6277ce284d649e7b828572773"
+ , "5ff4ef6cca6c18e2714f4e2a1ac67b25213d3bb49763b3b94e7ebf72507b71fb"
+ , "2fe0329666477ee7cb7ebd6b88ad5add8b217188b1ca0fa13de1ec09cc674346"
+ , "875105be6e0e0d6c8928eb0df23c39a639e04e4aedf535c4e093f08b2c905a14"
+ , "f25c0c0fe47a5a1535ab9eae0d9d67bdd79de13a08d59ee05385c7ea4af1ad32"
+ , "48e61dd22f8990e9e99897d653dd7b1b1433a6d464ea9f74e377f2d8ce99ba7d"
+ , "bc753297644234d25ecb5bd528e2e2082824681299ac30c05354baaa9c3967d8"
+ , "6d7c07736f87fc0f63e5036d47235d7ae12178ced3ae36ee5919c093a02579e4"
+ , "fc9edad2c446c656c790704bfc8e2c491a42500aa1d75c8d4921ce29b753f883"
+ , "e17c79b09ea324f1f32ddf1f3284cd70e847b09d90f6718c42e5c94484cc9cbb"
+ , "0df659d255630a3f5a27e7d5dd14fa6b974d1719aa98f01a20fb4b7b1c77b42d"
+ , "57fab3c724339d459ee4a1c6b5d3bd4e08624c786a257872acc9ad3ff62222f2"
+ , "265a658d9f2a007229a5293b67ec91c84c4b4407c228434bad8a815ca9b256c7"
+ , "76bd2c9f"
+ ]
+
+-- | Return packet as sent by node 3.
+tracePacket3 :: BS.ByteString
+tracePacket3 = BS.concat
+ [ "7512354d6a26781d25e65539772ba049b7ed7c530bf75ab7ef80cf974b978a07"
+ , "a1c3dabc61940011585323f70fa98cfa1d4c868da30b1f751e44a72d9b3f7980"
+ , "9c8c51c9f0843daa8fe83587844fedeacb7348362003b31922cbb4d6169b2087"
+ , "b6f8d192d9cfe5363254cd1fde24641bde9e422f170c3eb146f194c48a459ae2"
+ , "889d706dc654235fa9dd20307ea54091d09970bf956c067a3bcc05af03c41e01"
+ , "af949a131533778bf6ee3b546caf2eabe9d53d0fb2e8cc952b7e0f5326a69ed2"
+ , "e58e088729a1d85971c6b2e129a5643f3ac43da031e655b27081f10543262cf9"
+ , "d72d6f64d5d96387ac0d43da3e3a03da0c309af121dcf3e99192efa754eab696"
+ , "0c256ffd4c546208e292e0ab9894e3605db098dc16b40f17c320aa4a0e42fc8b"
+ , "105c22f08c9bc6537182c24e32062c6cd6d7ec7062a0c2c2ecdae1588c82185c"
+ , "dc61d874ee916a7873ac54cddf929354f307e870011704a0e9fbc5c7802d6140"
+ , "134028aca0e78a7e2f3d9e5c7e49e20c3a56b624bfea51196ec9e88e4e56be38"
+ , "ff56031369f45f1e03be826d44a182f270c153ee0d9f8cf9f1f4132f33974e37"
+ , "c7887d5b857365c873cb218cbf20d4be3abdb2a2011b14add0a5672e01e58454"
+ , "21cf6dd6faca1f2f443757aae575c53ab797c2227ecdab03882bbbf4599318ce"
+ , "fafa72fa0c9a0f5a51d13c9d0e5d25bfcfb0154ed25895260a9df8743ac18871"
+ , "4a3f16960e6e2ff663c08bffda41743d50960ea2f28cda0bc3bd4a180e297b5b"
+ , "41c700b674cb31d99c7f2a1445e121e772984abff2bbe3f42d757ceeda3d03fb"
+ , "1ffe710aecabda21d738b1f4620e757e57b123dbc3c4aa5d9617dfa72f4a12d7"
+ , "88ca596af14bea583f502f16fdc13a5e739afb0715424af2767049f6b9aa107f"
+ , "69c5da0e85f6d8c5e46507e14616d5d0b797c3dea8b74a1b12d4e47ba7f57f09"
+ , "d515f6c7314543f78b5e85329d50c5f96ee2f55bbe0df742b4003b24ccbd4598"
+ , "a64413ee4807dc7f2a9c0b92424e4ae1b418a3cdf02ea4da5c3b12139348aa70"
+ , "22cc8272a3a1714ee3e4ae111cffd1bdfd62c503c80bdf27b2feaea0d5ab8fe0"
+ , "0f9cec66e570b00fd24b4a2ed9a5f6384f148a4d6325110a41ca5659ebc5b987"
+ , "21d298a52819b6fb150f273383f1c5754d320be428941922da790e17f482989c"
+ , "365c078f7f3ae100965e1b38c052041165295157e1a7c5b7a57671b842d4d85a"
+ , "7d971323ad1f45e17a16c4656d889fc75c12fc3d8033f598306196e29571e414"
+ , "281c5da19c12605f48347ad5b4648e371757cbe1c40adb93052af1d6110cfbf6"
+ , "11af5c8fc682b7e2ade3bfca8b5c7717d19fc9f97964ba6025aebbc91a6671e2"
+ , "59949dcf40984342118de1f6b514a7786bd4f6598ffbe1604cef476b2a4cb134"
+ , "3db608aca09d1d38fc23e98ee9c65e7f6023a8d1e61fd4f34f753454bd8e858c"
+ , "8ad6be6403edc599c220e03ca917db765980ac781e758179cd93983e9c1e769e"
+ , "4241d47c"
+ ]
+
+-- | Return packet as sent by node 2.
+tracePacket2 :: BS.ByteString
+tracePacket2 = BS.concat
+ [ "145bc1c63058f7204abbd2320d422e69fb1b3801a14312f81e5e29e6b5f4774c"
+ , "fed8a25241d3dfb7466e749c1b3261559e49090853612e07bd669dfb5f4c5416"
+ , "2fa504138dabd6ebcf0db8017840c35f12a2cfb84f89cc7c8959a6d51815b1d2"
+ , "c5136cedec2e4106bb5f2af9a21bd0a02c40b44ded6e6a90a145850614fb1b0e"
+ , "ef2a03389f3f2693bc8a755630fc81fff1d87a147052863a71ad5aebe8770537"
+ , "f333e07d841761ec448257f948540d8f26b1d5b66f86e073746106dfdbb86ac9"
+ , "475acf59d95ece037fba360670d924dce53aaa74262711e62a8fc9eb70cd8618"
+ , "fbedae22853d3053c7f10b1a6f75369d7f73c419baa7dbf9f1fc5895362dcc8b"
+ , "6bd60cca4943ef7143956c91992119bccbe1666a20b7de8a2ff30a46112b53a6"
+ , "bb79b763903ecbd1f1f74952fb1d8eb0950c504df31fe702679c23b463f82a92"
+ , "1a2c931500ab08e686cffb2d87258d254fb17843959cccd265a57ba26c740f0f"
+ , "231bb76df932b50c12c10be90174b37d454a3f8b284c849e86578a6182c4a7b2"
+ , "e47dd57d44730a1be9fec4ad07287a397e28dce4fda57e9cdfdb2eb5afdf0d38"
+ , "ef19d982341d18d07a556bb16c1416f480a396f278373b8fd9897023a4ac506e"
+ , "65cf4c306377730f9c8ca63cf47565240b59c4861e52f1dab84d938e96fb3182"
+ , "0064d534aca05fd3d2600834fe4caea98f2a748eb8f200af77bd9fbf46141952"
+ , "b9ddda66ef0ebea17ea1e7bb5bce65b6e71554c56dd0d4e14f4cf74c77a15077"
+ , "6bf31e7419756c71e7421dc22efe9cf01de9e19fc8808d5b525431b944400db1"
+ , "21a77994518d6025711cb25a18774068bba7faaa16d8f65c91bec87688483331"
+ , "56dcb4a08dfbbd9fef392da3e4de13d4d74e83a7d6e46cfe530ee7a6f711e2ca"
+ , "f8ad5461ba8177b2ef0a518baf9058ff9156e6aa7b08d938bd8d1485a787809d"
+ , "7b4c8aed97be880708470cd2b2cdf8e2f13428cc4b04ef1f2acbc9562f3693b9"
+ , "48d0aa94b0e6113cafa684f8e4a67dc431dfb835726874bef1de36f273f52ee6"
+ , "94ec46b0700f77f8538067642a552968e866a72a3f2031ad116663ac17b172b4"
+ , "46c5bc705b84777363a9a3fdc6443c07b2f4ef58858122168d4ebbaee920cefc"
+ , "312e1cea870ed6e15eec046ab2073bbf08b0a3366f55cfc6ad4681a12ab09465"
+ , "34e7b6f90ea8992d530ec3daa6b523b3cf03101c60cadd914f30dec932c1ef43"
+ , "41b5a8efac3c921e203574cfe0f1f83433fddb8ccfd273f7c3cab7bc27efe3bb"
+ , "61fdccd5146f1185364b9b621e7fb2b74b51f5ee6be72ab6ff46a6359dc2c855"
+ , "e61469724c1dbeb273df9d2e1c1fb74891239c0019dc12d5c7535f7238f963b7"
+ , "61d7102b585372cf021b64c4fc85bfb3161e59d2e298bba44cfd34d6859d9dba"
+ , "9dc6271e5047d525468c814f2ae438474b0a977273036da1a2292f88fcfb8957"
+ , "4a6bdca1185b40f8aa54026d5926725f99ef028da1be892e3586361efe15f4a1"
+ , "48ff1bc9"
+ ]
+
+-- | Return packet as sent by node 1.
+tracePacket1 :: BS.ByteString
+tracePacket1 = BS.concat
+ [ "1b4b09a935ce7af95b336baae307f2b400e3a7e808d9b4cf421cc4b3955620ac"
+ , "b69dcdb656128dae8857adbd4e6b37fbb1be9c1f2f02e61e9e59a630c4c77cf3"
+ , "83cb37b07413aa4de2f2fbf5b40ae40a91a8f4c6d74aeacef1bb1be4ecbc26ec"
+ , "2c824d2bc45db4b9098e732a769788f1cff3f5b41b0d25c132d40dc5ad045ef0"
+ , "043b15332ca3c5a09de2cdb17455a0f82a8f20da08346282823dab062cdbd211"
+ , "1e238528141d69de13de6d83994fbc711e3e269df63a12d3a4177c5c149150eb"
+ , "4dc2f589cd8acabcddba14dec3b0dada12d663b36176cd3c257c5460bab93981"
+ , "ad99f58660efa9b31d7e63b39915329695b3fa60e0a3bdb93e7e29a54ca6a8f3"
+ , "60d3848866198f9c3da3ba958e7730847fe1e6478ce8597848d3412b4ae48b06"
+ , "e05ba9a104e648f6eaf183226b5f63ed2e68f77f7e38711b393766a6fab7921b"
+ , "03eba82b5d7cb78e34dc961948d6161eadd7cf5d95d9c56df2ff5faa6ccf85ea"
+ , "cdc9ff2fc3abafe41c365a5bd14fd486d6b5e2f24199319e7813e02e798877ff"
+ , "e31a70ae2398d9e31b9e3727e6c1a3c0d995c67d37bb6e72e9660aaaa9232670"
+ , "f382add2edd468927e3303b6142672546997fe105583e7c5a3c4c2b599731308"
+ , "b5416e6c9a3f3ba55b181ad0439d3535356108b059f2cb8742eed7a58d4eba9f"
+ , "e79eaa77c34b12aff1abdaea93197aabd0e74cb271269ca464b3b06aef1d6573"
+ , "df5e1224179616036b368677f26479376681b772d3760e871d99efd34cca5cd6"
+ , "beca95190d967da820b21e5bec60082ea46d776b0517488c84f26d12873912d1"
+ , "f68fafd67bcf4c298e43cfa754959780682a2db0f75f95f0598c0d04fd014c50"
+ , "e4beb86a9e37d95f2bba7e5065ae052dc306555bca203d104c44a538b438c976"
+ , "2de299e1c4ad30d5b4a6460a76484661fc907682af202cd69b9a4473813b2fdc"
+ , "1142f1403a49b7e69a650b7cde9ff133997dcc6d43f049ecac5fce097a21e2bc"
+ , "e49c810346426585e3a5a18569b4cddd5ff6bdec66d0b69fcbc5ab3b137b34cc"
+ , "8aefb8b850a764df0e685c81c326611d901c392a519866e132bbb73234f6a358"
+ , "ba284fbafb21aa3605cacbaf9d0c901390a98b7a7dac9d4f0b405f7291c88b2f"
+ , "f45874241c90ac6c5fc895a440453c344d3a365cb929f9c91b9e39cb98b14244"
+ , "4aae03a6ae8284c77eb04b0a163813d4c21883df3c0f398f47bf127b5525f222"
+ , "107a2d8fe55289f0cfd3f4bbad6c5387b0594ef8a966afc9e804ccaf75fe39f3"
+ , "5c6446f7ee076d433f2f8a44dba1515acc78e589fa8c71b0a006fe14feebd51d"
+ , "0e0aa4e51110d16759eee86192eee90b34432130f387e0ccd2ee71023f1f641c"
+ , "ddb571c690107e08f592039fe36d81336a421e89378f351e633932a2f5f697d2"
+ , "5b620ffb8e84bb6478e9bd229bf3b164b48d754ae97bd23f319e3c56b3bcdaae"
+ , "b3bd7fc02ec02066b324cb72a09b6b43dec1097f49d69d3c138ce6f1a6402898"
+ , "baf7568c"
+ ]
+
+-- | Return packet as sent by node 0.
+tracePacket0 :: BS.ByteString
+tracePacket0 = BS.concat
+ [ "2dd2f49c1f5af0fcad371d96e8cddbdcd5096dc309c1d4e110f955926506b3c0"
+ , "3b44c192896f45610741c85ed4074212537e0c118d472ff3a559ae244acd9d78"
+ , "3c65977765c5d4e00b723d00f12475aafaafff7b31c1be5a589e6e25f8da2959"
+ , "107206dd42bbcb43438129ce6cce2b6b4ae63edc76b876136ca5ea6cd1c6a04c"
+ , "a86eca143d15e53ccdc9e23953e49dc2f87bb11e5238cd6536e57387225b8fff"
+ , "3bf5f3e686fd08458ffe0211b87d64770db9353500af9b122828a006da754cf9"
+ , "79738b4374e146ea79dd93656170b89c98c5f2299d6e9c0410c826c721950c78"
+ , "0486cd6d5b7130380d7eaff994a8503a8fef3270ce94889fe996da66ed121741"
+ , "987010f785494415ca991b2e8b39ef2df6bde98efd2aec7d251b2772485194c8"
+ , "368451ad49c2354f9d30d95367bde316fec6cbdddc7dc0d25e99d3075e13d3de"
+ , "0822669861dafcd29de74eac48b64411987285491f98d78584d0c2a163b7221e"
+ , "a796f9e8671b2bb91e38ef5e18aaf32c6c02f2fb690358872a1ed28166172631"
+ , "a82c2568d23238017188ebbd48944a147f6cdb3690d5f88e51371cb70adf1fa0"
+ , "2afe4ed8b581afc8bcc5104922843a55d52acde09bc9d2b71a663e178788280f"
+ , "3c3eae127d21b0b95777976b3eb17be40a702c244d0e5f833ff49dae6403ff44"
+ , "b131e66df8b88e33ab0a58e379f2c34bf5113c66b9ea8241fc7aa2b1fa53cf4e"
+ , "d3cdd91d407730c66fb039ef3a36d4050dde37d34e80bcfe02a48a6b14ae2822"
+ , "7b1627b5ad07608a7763a531f2ffc96dff850e8c583461831b19feffc783bc1b"
+ , "eab6301f647e9617d14c92c4b1d63f5147ccda56a35df8ca4806b8884c4aa3c3"
+ , "cc6a174fdc2232404822569c01aba686c1df5eecc059ba97e9688c8b16b70f0d"
+ , "24eacfdba15db1c71f72af1b2af85bd168f0b0800483f115eeccd9b02adf03bd"
+ , "d4a88eab03e43ce342877af2b61f9d3d85497cd1c6b96674f3d4f07f635bb26a"
+ , "dd1e36835e321d70263b1c04234e222124dad30ffb9f2a138e3ef453442df1af"
+ , "7e566890aedee568093aa922dd62db188aa8361c55503f8e2c2e6ba93de744b5"
+ , "5c15260f15ec8e69bb01048ca1fa7bbbd26975bde80930a5b95054688a0ea73a"
+ , "f0353cc84b997626a987cc06a517e18f91e02908829d4f4efc011b9867bd9bfe"
+ , "04c5f94e4b9261d30cc39982eb7b250f12aee2a4cce0484ff34eebba89bc6e35"
+ , "bd48d3968e4ca2d77527212017e202141900152f2fd8af0ac3aa456aae13276a"
+ , "13b9b9492a9a636e18244654b3245f07b20eb76b8e1cea8c55e5427f08a63a16"
+ , "b0a633af67c8e48ef8e53519041c9138176eb14b8782c6c2ee76146b8490b979"
+ , "78ee73cd0104e12f483be5a4af414404618e9f6633c55dda6f22252cb793d3d1"
+ , "6fae4f0e1431434e7acc8fa2c009d4f6e345ade172313d558a4e61b4377e31b8"
+ , "ed4e28f7cd13a7fe3f72a409bc3bdabfe0ba47a6d861e21f64d2fac706dab18b"
+ , "3e546df4"
+ ]