+local function dissect_chal(buf, tree, label, pos, sz)
+ local len = buf(pos, 2):uint()
+ local t = tree:add(PF[label], buf(pos, len + 2))
+ t:add(PF["tripe.chal.len"], buf(pos, 2)); pos = pos + 2
+ t:add(PF["tripe.chal.sequence"], buf(pos, 4)); pos = pos + 4; len = len - 4
+ t:add(PF["tripe.chal.tag"], buf(pos, len))
+ return pos + len
+end
+
+local function dissect_my_chal(buf, tree, pos, sz)
+ return dissect_chal(buf, tree, "tripe.knock.mychal", pos, sz)
+end
+
+local function dissect_your_chal(buf, tree, pos, sz)
+ return dissect_chal(buf, tree, "tripe.knock.yourchal", pos, sz)
+end
+
+local function dissect_keyid(buf, tree, pos, sz)
+ tree:add(PF["tripe.knock.keyid"], buf(pos, 4))
+ return pos + 4
+end
+
+local function dissect_ies(buf, tree, pos, sz)
+ local len = buf(pos, 2):uint()
+ local lim = pos + len + 2
+ local t = tree:add(PF["tripe.knock.ies"], buf(pos, len + 2))
+ t:add(PF["tripe.ies.len"], buf(pos, 2)); pos = pos + 2
+ pos = dissect_ge[C.kx](buf, t, pos, sz)
+ return dissect_ciphertext(buf, t, "tripe.ies.ciphertext", pos, lim)
+end
+