From 2d23080cc7f78dbe2979eaa8984d1d2024977e90 Mon Sep 17 00:00:00 2001 From: Heiko Schaefer Date: Mon, 10 Jul 2023 00:12:55 +0200 Subject: [PATCH] Query: break out backwardPropagate(), keep semantics unchanged! Use backwardPropagate() as a wrapper from authenticate() --- .../org/pgpainless/wot/BackPropagationTest.kt | 139 +++++++++--------- .../org/pgpainless/wot/dijkstra/Query.kt | 118 ++++++++------- 2 files changed, 135 insertions(+), 122 deletions(-) diff --git a/pgpainless-wot/src/test/kotlin/org/pgpainless/wot/BackPropagationTest.kt b/pgpainless-wot/src/test/kotlin/org/pgpainless/wot/BackPropagationTest.kt index 77cb5bd3..767bda04 100644 --- a/pgpainless-wot/src/test/kotlin/org/pgpainless/wot/BackPropagationTest.kt +++ b/pgpainless-wot/src/test/kotlin/org/pgpainless/wot/BackPropagationTest.kt @@ -30,6 +30,9 @@ class BackPropagationTest { assert(gotCerts.size == expectedPath.size) assert(gotCerts.zip(expectedPath).none { it.first != it.second }) // FIXME: debug output? + println("got $gotPath") + println("expected $expectedPath") + assert(gotAmount == amount) { "Amount mismatch, got $gotAmount, expected $amount" } assert(gotPath.residualDepth.value() == residualDepth ) { "Residual depth mismatch, got " + gotPath.residualDepth.value() + ", expected " + residualDepth } @@ -82,13 +85,13 @@ class BackPropagationTest { val q = Query(network, Roots(), false) - val a1 = q.backwardPropagate(ellenFpr, ellenUid, false, IdempotentCertificationFilter()) + val a1 = q.backwardPropagate(ellenFpr, ellenUid, IdempotentCertificationFilter()) checkResult(a1[daveFpr]!!, 1, 100, listOf(daveFpr, ellenFpr)); checkResult(a1[carolFpr]!!, 0, 100, listOf(carolFpr, daveFpr, ellenFpr)); - val a2 = q.backwardPropagate(daveFpr, daveUid, false, IdempotentCertificationFilter()); + val a2 = q.backwardPropagate(daveFpr, daveUid, IdempotentCertificationFilter()); assert(a2[ellenFpr] == null); checkResult(a2[carolFpr]!!, 1, 100, listOf(carolFpr, daveFpr)); @@ -96,7 +99,7 @@ class BackPropagationTest { checkResult(a2[aliceFpr]!!, 0, 100, listOf(aliceFpr, bobFpr, carolFpr, daveFpr)); - val a3 = q.backwardPropagate(daveFpr, daveUid, false, IdempotentCertificationFilter()); + val a3 = q.backwardPropagate(daveFpr, daveUid, IdempotentCertificationFilter()); assert(a3[ellenFpr] == null); checkResult(a3[carolFpr]!!, 1, 100, listOf(carolFpr, daveFpr)); @@ -105,7 +108,7 @@ class BackPropagationTest { // This should work even though Bob is the root and the path is via Bob. checkResult(a3[aliceFpr]!!, 0, 100, listOf(aliceFpr, bobFpr, carolFpr, daveFpr)); - val a4 = q.backwardPropagate(daveFpr, daveUid, false, IdempotentCertificationFilter()); + val a4 = q.backwardPropagate(daveFpr, daveUid, IdempotentCertificationFilter()); assert(a4[ellenFpr] == null) checkResult(a4[carolFpr]!!, 1, 100, listOf(carolFpr, daveFpr)); @@ -115,7 +118,7 @@ class BackPropagationTest { checkResult(a4[aliceFpr]!!, 0, 100, listOf(aliceFpr, bobFpr, carolFpr, daveFpr)); // Try to authenticate dave's key for an User ID that no one has certified. - val a5 = q.backwardPropagate(daveFpr, ellenUid, false, IdempotentCertificationFilter()); + val a5 = q.backwardPropagate(daveFpr, ellenUid, IdempotentCertificationFilter()); assert(a5[ellenFpr] == null); assert(a5[daveFpr] == null); @@ -125,7 +128,7 @@ class BackPropagationTest { // A target that is not in the network. val fpr = Fingerprint("0123456789ABCDEF0123456789ABCDEF01234567") - val a6 = q.backwardPropagate(fpr, ellenUid, false, IdempotentCertificationFilter()); + val a6 = q.backwardPropagate(fpr, ellenUid, IdempotentCertificationFilter()); assert(a6[ellenFpr] == null); assert(a6[daveFpr] == null); @@ -165,7 +168,7 @@ class BackPropagationTest { println("Network contains " + network.nodes.size + " nodes with " + network.numberOfEdges + " edges built from " + network.numberOfSignatures + " signatures.") val q = Query(network, Roots(), false) - val a1 = q.backwardPropagate(frankFpr, frankUid, false, IdempotentCertificationFilter()); + val a1 = q.backwardPropagate(frankFpr, frankUid, IdempotentCertificationFilter()); checkResult(a1[edFpr]!!, 0, 120, listOf(edFpr, frankFpr)); checkResult(a1[daveFpr]!!, 0, 30, listOf(daveFpr, edFpr, frankFpr)); @@ -173,7 +176,7 @@ class BackPropagationTest { checkResult(a1[bobFpr]!!, 0, 30, listOf(bobFpr, carolFpr, daveFpr, edFpr, frankFpr)); assert(a1[aliceFpr] == null) - val a2 = q.backwardPropagate(frankFpr, frankUid, false, IdempotentCertificationFilter()); + val a2 = q.backwardPropagate(frankFpr, frankUid, IdempotentCertificationFilter()); checkResult(a2[edFpr]!!, 0, 120, listOf(edFpr, frankFpr)); checkResult(a2[daveFpr]!!, 0, 30, listOf(daveFpr, edFpr, frankFpr)); @@ -181,7 +184,7 @@ class BackPropagationTest { checkResult(a2[bobFpr]!!, 0, 30, listOf(bobFpr, carolFpr, daveFpr, edFpr, frankFpr)); assert(a2[aliceFpr] == null) - val a3 = q.backwardPropagate(edFpr, edUid, false, IdempotentCertificationFilter()); + val a3 = q.backwardPropagate(edFpr, edUid, IdempotentCertificationFilter()); assert(a3[frankFpr] == null) checkResult(a3[daveFpr]!!, 1, 30, listOf(daveFpr, edFpr)); @@ -189,7 +192,7 @@ class BackPropagationTest { checkResult(a3[bobFpr]!!, 1, 30, listOf(bobFpr, carolFpr, daveFpr, edFpr)); checkResult(a3[aliceFpr]!!, 0, 30, listOf(aliceFpr, bobFpr, carolFpr, daveFpr, edFpr)); - val a4 = q.backwardPropagate(carolFpr, carolUid, false, IdempotentCertificationFilter()); + val a4 = q.backwardPropagate(carolFpr, carolUid, IdempotentCertificationFilter()); assert(a4[frankFpr] == null); assert(a4[edFpr] == null); @@ -243,7 +246,7 @@ class BackPropagationTest { val n1 = getNetwork("/home/heiko/src/sequoia-wot/tests/data/cliques.pgp") val q1 = Query(n1, Roots(), false) - val a1 = q1.backwardPropagate(target_fpr, target_uid, false, IdempotentCertificationFilter()); + val a1 = q1.backwardPropagate(target_fpr, target_uid, IdempotentCertificationFilter()); // root -> a-0 -> b-0 -> ... -> f-0 -> target checkResult(a1[root_fpr]!!, 90, 120, @@ -264,7 +267,7 @@ class BackPropagationTest { val n2 = getNetwork("/home/heiko/src/sequoia-wot/tests/data/cliques-local-optima.pgp") val q2 = Query(n2, Roots(), false) - val a2 = q2.backwardPropagate(target_fpr, target_uid, false, IdempotentCertificationFilter()); + val a2 = q2.backwardPropagate(target_fpr, target_uid, IdempotentCertificationFilter()); // root -> a-0 -> b-0 -> ... -> f-0 -> target checkResult(a2[root_fpr]!!, @@ -283,7 +286,7 @@ class BackPropagationTest { val n3 = getNetwork("/home/heiko/src/sequoia-wot/tests/data/cliques-local-optima-2.pgp") val q3 = Query(n3, Roots(), false) - val a3 = q3.backwardPropagate(target_fpr, target_uid, false, IdempotentCertificationFilter()); + val a3 = q3.backwardPropagate(target_fpr, target_uid, IdempotentCertificationFilter()); // root -> a-0 -> b-0 -> ... -> f-0 -> target checkResult(a3[root_fpr]!!, 94, 30, @@ -347,14 +350,14 @@ class BackPropagationTest { val q1 = Query(n1, Roots(), false) - val a1 = q1.backwardPropagate(isaacFpr, isaacUid, false, IdempotentCertificationFilter()); + val a1 = q1.backwardPropagate(isaacFpr, isaacUid, IdempotentCertificationFilter()); checkResult(a1[aliceFpr]!!, 0, 60, listOf(aliceFpr, bobFpr, georgeFpr, henryFpr, isaacFpr)); assert(a1[carolFpr] == null) assert(a1[jennyFpr] == null) - val a2 = q1.backwardPropagate(henryFpr, henryUid, false, IdempotentCertificationFilter()); + val a2 = q1.backwardPropagate(henryFpr, henryUid, IdempotentCertificationFilter()); // The backward propagation algorithm doesn't know that jenny // is not reachable from the root (alice). @@ -404,7 +407,7 @@ class BackPropagationTest { val n1 = getNetwork("/home/heiko/src/sequoia-wot/tests/data/local-optima.pgp") val q = Query(n1, Roots(), false) - val a1 = q.backwardPropagate(henry_fpr, henry_uid, false, IdempotentCertificationFilter()); + val a1 = q.backwardPropagate(henry_fpr, henry_uid, IdempotentCertificationFilter()); checkResult(a1[alice_fpr]!!, 0, 100, listOf(alice_fpr, bob_fpr, carol_fpr, ellen_fpr, henry_fpr)); checkResult(a1[bob_fpr]!!, 0, 100, listOf(bob_fpr, carol_fpr, ellen_fpr, henry_fpr)); @@ -414,7 +417,7 @@ class BackPropagationTest { assert(a1[francis_fpr] == null) assert(a1[georgina_fpr] == null) - val a2 = q.backwardPropagate(francis_fpr, francis_uid, false, IdempotentCertificationFilter()); + val a2 = q.backwardPropagate(francis_fpr, francis_uid, IdempotentCertificationFilter()); // Recall: given a choice, we prefer the forward pointer that // has the least depth. @@ -457,13 +460,13 @@ class BackPropagationTest { val n1 = getNetwork("/home/heiko/src/sequoia-wot/tests/data/best-via-root.pgp") val q1 = Query(n1, Roots(), false) - val a1 = q1.backwardPropagate(target_fpr, target_uid, false, IdempotentCertificationFilter()); + val a1 = q1.backwardPropagate(target_fpr, target_uid, IdempotentCertificationFilter()); checkResult(a1[bob_fpr]!!, 9, 120, listOf(bob_fpr, carol_fpr, target_fpr)); checkResult(a1[carol_fpr]!!, 10, 120, listOf(carol_fpr, target_fpr)); checkResult(a1[alice_fpr]!!, 8, 120, listOf(alice_fpr, bob_fpr, carol_fpr, target_fpr)); - val a2 = q1.backwardPropagate(target_fpr, target_uid, false, IdempotentCertificationFilter()); + val a2 = q1.backwardPropagate(target_fpr, target_uid, IdempotentCertificationFilter()); checkResult(a2[alice_fpr]!!, 8, 120, listOf(alice_fpr, bob_fpr, carol_fpr, target_fpr)); checkResult(a2[bob_fpr]!!, 9, 120, listOf(bob_fpr, carol_fpr, target_fpr)); @@ -472,7 +475,7 @@ class BackPropagationTest { // Again, but this time we specify the roots. val q2 = Query(n1, Roots(listOf(Root(alice_fpr, 120))), false) - val a3 = q2.backwardPropagate(target_fpr, target_uid, false, IdempotentCertificationFilter()); + val a3 = q2.backwardPropagate(target_fpr, target_uid, IdempotentCertificationFilter()); checkResult(a3[alice_fpr]!!, 8, 120, listOf(alice_fpr, bob_fpr, carol_fpr, target_fpr)); @@ -484,7 +487,7 @@ class BackPropagationTest { Root(alice_fpr, 120), Root(bob_fpr, 120))), false) - val a4 = q3.backwardPropagate(target_fpr, target_uid, false, IdempotentCertificationFilter()); + val a4 = q3.backwardPropagate(target_fpr, target_uid, IdempotentCertificationFilter()); checkResult(a4[bob_fpr]!!, 9, 120, listOf(bob_fpr, carol_fpr, target_fpr)); checkResult(a4[alice_fpr]!!, 8, 50, listOf(alice_fpr, yellow_fpr, zebra_fpr, target_fpr)); @@ -520,23 +523,23 @@ class BackPropagationTest { val q1 = Query(n1, Roots(), false) // alice as root. - val a1 = q1.backwardPropagate(bob_fpr, bob_uid, false, IdempotentCertificationFilter()); + val a1 = q1.backwardPropagate(bob_fpr, bob_uid, IdempotentCertificationFilter()); checkResult(a1[alice_fpr]!!, 3, 100, listOf(alice_fpr, bob_fpr)); - val a2 = q1.backwardPropagate(carol_fpr, carol_uid, false, IdempotentCertificationFilter()); + val a2 = q1.backwardPropagate(carol_fpr, carol_uid, IdempotentCertificationFilter()); checkResult(a2[alice_fpr]!!, 1, 100, listOf(alice_fpr, bob_fpr, carol_fpr)); - val a3 = q1.backwardPropagate(dave_fpr, dave_uid, false, IdempotentCertificationFilter()); + val a3 = q1.backwardPropagate(dave_fpr, dave_uid, IdempotentCertificationFilter()); // There is no path, because dave@example.org does not match // the constraint on bob (domain: example.org). assert(a3[alice_fpr] == null) - val a4 = q1.backwardPropagate(ed_fpr, ed_uid, false, IdempotentCertificationFilter()) + val a4 = q1.backwardPropagate(ed_fpr, ed_uid, IdempotentCertificationFilter()) // There is no path, because ed@example.org does not match // the constraint on dave (domain: other.org). assert(a4[alice_fpr] == null) - val a5 = q1.backwardPropagate(frank_fpr, frank_uid, false, IdempotentCertificationFilter()) + val a5 = q1.backwardPropagate(frank_fpr, frank_uid, IdempotentCertificationFilter()) // There is no path, because frank@other.org does not match // the constraint on bob (domain: example.org). @@ -544,27 +547,27 @@ class BackPropagationTest { // bob as root. - val a6 = q1.backwardPropagate(carol_fpr, carol_uid, false, IdempotentCertificationFilter()) + val a6 = q1.backwardPropagate(carol_fpr, carol_uid, IdempotentCertificationFilter()) checkResult(a6[bob_fpr]!!, 1, 100, listOf(bob_fpr, carol_fpr)) - val a7 = q1.backwardPropagate(dave_fpr, dave_uid, false, IdempotentCertificationFilter()) + val a7 = q1.backwardPropagate(dave_fpr, dave_uid, IdempotentCertificationFilter()) checkResult(a7[bob_fpr]!!, 1, 100, listOf(bob_fpr, dave_fpr)) - val a8 = q1.backwardPropagate(ed_fpr, ed_uid, false, IdempotentCertificationFilter()) + val a8 = q1.backwardPropagate(ed_fpr, ed_uid, IdempotentCertificationFilter()) // There is no path, because ed@example.org does not match // the constraint on dave (domain: other.org). assert(a8[bob_fpr] == null) - val a9 = q1.backwardPropagate(frank_fpr, frank_uid, false, IdempotentCertificationFilter()) + val a9 = q1.backwardPropagate(frank_fpr, frank_uid, IdempotentCertificationFilter()) checkResult(a9[bob_fpr]!!, 0, 100, listOf(bob_fpr, dave_fpr, frank_fpr)) // dave as root. - val a10 = q1.backwardPropagate(ed_fpr, ed_uid, false, IdempotentCertificationFilter()) + val a10 = q1.backwardPropagate(ed_fpr, ed_uid, IdempotentCertificationFilter()) checkResult(a10[dave_fpr]!!, 1, 100, listOf(dave_fpr, ed_fpr)); - val a11 = q1.backwardPropagate(frank_fpr, frank_uid, false, IdempotentCertificationFilter()) + val a11 = q1.backwardPropagate(frank_fpr, frank_uid, IdempotentCertificationFilter()) checkResult(a11[dave_fpr]!!, 1, 100, listOf(dave_fpr, frank_fpr)) } @@ -594,40 +597,40 @@ class BackPropagationTest { val q1 = Query(n1, Roots(), false) - val a1 = q1.backwardPropagate(bob_fpr, bob_uid, false, IdempotentCertificationFilter()) + val a1 = q1.backwardPropagate(bob_fpr, bob_uid, IdempotentCertificationFilter()) checkResult(a1[alice_fpr]!!, 7, 100, listOf(alice_fpr, bob_fpr)) - val a2 = q1.backwardPropagate(carol_fpr, carol_uid, false, IdempotentCertificationFilter()) + val a2 = q1.backwardPropagate(carol_fpr, carol_uid, IdempotentCertificationFilter()) // There is no path, because carol@other.org does not match // the constraint on carol (domain: example.org). assert(a2[alice_fpr] == null) - val a3 = q1.backwardPropagate(dave_fpr, dave_uid, false, IdempotentCertificationFilter()) + val a3 = q1.backwardPropagate(dave_fpr, dave_uid, IdempotentCertificationFilter()) // There is no path, because dave@their.org does not match // the constraint on carol (domain: example.org). assert(a3[alice_fpr] == null) - val a4 = q1.backwardPropagate(ed_fpr, ed_uid, false, IdempotentCertificationFilter()) + val a4 = q1.backwardPropagate(ed_fpr, ed_uid, IdempotentCertificationFilter()) checkResult(a4[alice_fpr]!!, 4, 100, listOf(alice_fpr, bob_fpr, carol_fpr, dave_fpr, ed_fpr)) - val a5 = q1.backwardPropagate(carol_fpr, carol_uid, false, IdempotentCertificationFilter()); + val a5 = q1.backwardPropagate(carol_fpr, carol_uid, IdempotentCertificationFilter()); // There is no path, because carol@other.org does not match // the constraint on carol (domain: example.org). assert(a5[bob_fpr] == null) - val a6 = q1.backwardPropagate(dave_fpr, dave_uid, false, IdempotentCertificationFilter()) + val a6 = q1.backwardPropagate(dave_fpr, dave_uid, IdempotentCertificationFilter()) // There is no path, because dave@their.org does not match // the constraint on carol (domain: example.org). assert(a6[bob_fpr] == null) - val a7 = q1.backwardPropagate(ed_fpr, ed_uid, false, IdempotentCertificationFilter()) + val a7 = q1.backwardPropagate(ed_fpr, ed_uid, IdempotentCertificationFilter()) checkResult(a7[bob_fpr]!!, 5, 100, listOf(bob_fpr, carol_fpr, dave_fpr, ed_fpr)) - val a8 = q1.backwardPropagate(dave_fpr, dave_uid, false, IdempotentCertificationFilter()) + val a8 = q1.backwardPropagate(dave_fpr, dave_uid, IdempotentCertificationFilter()) checkResult(a8[carol_fpr]!!, 7, 100, listOf(carol_fpr, dave_fpr)); - val a9 = q1.backwardPropagate(ed_fpr, ed_uid, false, IdempotentCertificationFilter()) + val a9 = q1.backwardPropagate(ed_fpr, ed_uid, IdempotentCertificationFilter()) checkResult(a9[carol_fpr]!!, 6, 100, listOf(carol_fpr, dave_fpr, ed_fpr)) } @@ -670,60 +673,60 @@ class BackPropagationTest { // alice as root. - val a1 = q1.backwardPropagate(bob_fpr, bob_uid, false, IdempotentCertificationFilter()) + val a1 = q1.backwardPropagate(bob_fpr, bob_uid, IdempotentCertificationFilter()) checkResult(a1[alice_fpr]!!, 3, 100, listOf(alice_fpr, bob_fpr)) - val a2 = q1.backwardPropagate(carol_fpr, carol_uid, false, IdempotentCertificationFilter()) + val a2 = q1.backwardPropagate(carol_fpr, carol_uid, IdempotentCertificationFilter()) checkResult(a2[alice_fpr]!!, 1, 100, listOf(alice_fpr, bob_fpr, carol_fpr)) - val a3 = q1.backwardPropagate(dave_fpr, dave_uid, false, IdempotentCertificationFilter()) + val a3 = q1.backwardPropagate(dave_fpr, dave_uid, IdempotentCertificationFilter()) checkResult(a3[alice_fpr]!!, 1, 100, listOf(alice_fpr, bob_fpr, dave_fpr)) - val a4 = q1.backwardPropagate(ed_fpr, ed_uid, false, IdempotentCertificationFilter()) + val a4 = q1.backwardPropagate(ed_fpr, ed_uid, IdempotentCertificationFilter()) // There is no path, because ed@example.org does not match // the constraint on dave (domain: other.org). assert(a4[alice_fpr] == null) - val a5 = q1.backwardPropagate(frank_fpr, frank_uid, false, IdempotentCertificationFilter()) + val a5 = q1.backwardPropagate(frank_fpr, frank_uid, IdempotentCertificationFilter()) checkResult(a5[alice_fpr]!!, 0, 100, listOf(alice_fpr, bob_fpr, dave_fpr, frank_fpr)) - val a6 = q1.backwardPropagate(george_fpr, george_uid, false, IdempotentCertificationFilter()) + val a6 = q1.backwardPropagate(george_fpr, george_uid, IdempotentCertificationFilter()) assert(a6[alice_fpr] == null) - val a7 = q1.backwardPropagate(henry_fpr, henry_uid, false, IdempotentCertificationFilter()) + val a7 = q1.backwardPropagate(henry_fpr, henry_uid, IdempotentCertificationFilter()) assert(a7[alice_fpr] == null) // bob as root. - val a8 = q1.backwardPropagate(carol_fpr, carol_uid, false, IdempotentCertificationFilter()) + val a8 = q1.backwardPropagate(carol_fpr, carol_uid, IdempotentCertificationFilter()) checkResult(a8[bob_fpr]!!, 1, 100, listOf(bob_fpr, carol_fpr)) - val a9 = q1.backwardPropagate(dave_fpr, dave_uid, false, IdempotentCertificationFilter()) + val a9 = q1.backwardPropagate(dave_fpr, dave_uid, IdempotentCertificationFilter()) checkResult(a9[bob_fpr]!!, 1, 100, listOf(bob_fpr, dave_fpr)) - val a10 = q1.backwardPropagate(ed_fpr, ed_uid, false, IdempotentCertificationFilter()) + val a10 = q1.backwardPropagate(ed_fpr, ed_uid, IdempotentCertificationFilter()) // There is no path, because ed@example.org does not match // the constraint on dave (domain: other.org). assert(a10[bob_fpr] == null) - val a11 = q1.backwardPropagate(frank_fpr, frank_uid, false, IdempotentCertificationFilter()) + val a11 = q1.backwardPropagate(frank_fpr, frank_uid, IdempotentCertificationFilter()) checkResult(a11[bob_fpr]!!, 0, 100, listOf(bob_fpr, dave_fpr, frank_fpr)) - val a12 = q1.backwardPropagate(george_fpr, george_uid, false, IdempotentCertificationFilter()) + val a12 = q1.backwardPropagate(george_fpr, george_uid, IdempotentCertificationFilter()) checkResult(a12[bob_fpr]!!, 0, 100, listOf(bob_fpr, dave_fpr, george_fpr)) - val a13 = q1.backwardPropagate(henry_fpr, henry_uid, false, IdempotentCertificationFilter()) + val a13 = q1.backwardPropagate(henry_fpr, henry_uid, IdempotentCertificationFilter()) checkResult(a13[bob_fpr]!!, 1, 100, listOf(bob_fpr, henry_fpr)) // dave as root. - val a14 = q1.backwardPropagate(ed_fpr, ed_uid, false, IdempotentCertificationFilter()) + val a14 = q1.backwardPropagate(ed_fpr, ed_uid, IdempotentCertificationFilter()) checkResult(a14[dave_fpr]!!, 1, 100, listOf(dave_fpr, ed_fpr)) - val a15 = q1.backwardPropagate(frank_fpr, frank_uid, false, IdempotentCertificationFilter()) + val a15 = q1.backwardPropagate(frank_fpr, frank_uid, IdempotentCertificationFilter()) checkResult(a15[dave_fpr]!!, 1, 100, listOf(dave_fpr, frank_fpr)) - val a16 = q1.backwardPropagate(george_fpr, george_uid, false, IdempotentCertificationFilter()) + val a16 = q1.backwardPropagate(george_fpr, george_uid, IdempotentCertificationFilter()) checkResult(a16[dave_fpr]!!, 1, 100, listOf(dave_fpr, george_fpr)) } @@ -753,10 +756,10 @@ class BackPropagationTest { val q1 = Query(n1, Roots(), false) - val a1 = q1.backwardPropagate(carol_fpr, carol_uid, false, IdempotentCertificationFilter()) + val a1 = q1.backwardPropagate(carol_fpr, carol_uid, IdempotentCertificationFilter()) checkResult(a1[alice_fpr]!!, 0, 70, listOf(alice_fpr, bob_fpr, carol_fpr)) - val a2 = q1.backwardPropagate(dave_fpr, dave_uid, false, IdempotentCertificationFilter()) + val a2 = q1.backwardPropagate(dave_fpr, dave_uid, IdempotentCertificationFilter()) checkResult(a2[alice_fpr]!!, 0, 50, listOf(alice_fpr, bob_fpr, carol_fpr, dave_fpr)) } @@ -792,22 +795,22 @@ class BackPropagationTest { val q1 = Query(n1, Roots(), false) - val a1 = q1.backwardPropagate(bob_fpr, bob_uid, false, IdempotentCertificationFilter()) + val a1 = q1.backwardPropagate(bob_fpr, bob_uid, IdempotentCertificationFilter()) checkResult(a1[alice_fpr]!!, DEPTH_UNCONSTRAINED, 70, listOf(alice_fpr, bob_fpr)) - val a2 = q1.backwardPropagate(bob_fpr, bob_some_org_uid, false, IdempotentCertificationFilter()) + val a2 = q1.backwardPropagate(bob_fpr, bob_some_org_uid, IdempotentCertificationFilter()) checkResult(a2[alice_fpr]!!, 1, 50, listOf(alice_fpr, bob_fpr)) - val a3 = q1.backwardPropagate(carol_fpr, carol_uid, false, IdempotentCertificationFilter()) + val a3 = q1.backwardPropagate(carol_fpr, carol_uid, IdempotentCertificationFilter()) checkResult(a3[alice_fpr]!!, 0, 50, listOf(alice_fpr, bob_fpr, carol_fpr)) - val a4 = q1.backwardPropagate(dave_fpr, dave_uid, false, IdempotentCertificationFilter()) + val a4 = q1.backwardPropagate(dave_fpr, dave_uid, IdempotentCertificationFilter()) checkResult(a4[alice_fpr]!!, 0, 70, listOf(alice_fpr, bob_fpr, carol_fpr, dave_fpr)) - val a5 = q1.backwardPropagate(ed_fpr, ed_uid, false, IdempotentCertificationFilter()) + val a5 = q1.backwardPropagate(ed_fpr, ed_uid, IdempotentCertificationFilter()) assert(a5[alice_fpr] == null) - val a6 = q1.backwardPropagate(frank_fpr, frank_uid, false, IdempotentCertificationFilter()) + val a6 = q1.backwardPropagate(frank_fpr, frank_uid, IdempotentCertificationFilter()) checkResult(a6[alice_fpr]!!, 0, 70, listOf(alice_fpr, bob_fpr, frank_fpr)) } @@ -837,10 +840,10 @@ class BackPropagationTest { val q1 = Query(n1, Roots(), false) - val a1 = q1.backwardPropagate(carol_fpr, carol_uid, false, IdempotentCertificationFilter()) + val a1 = q1.backwardPropagate(carol_fpr, carol_uid, IdempotentCertificationFilter()) checkResult(a1[alice_fpr]!!, 0, 70, listOf(alice_fpr, bob_fpr, carol_fpr)) - val a2 = q1.backwardPropagate(dave_fpr, dave_uid, false, IdempotentCertificationFilter()) + val a2 = q1.backwardPropagate(dave_fpr, dave_uid, IdempotentCertificationFilter()) checkResult(a2[alice_fpr]!!, 0, 50, listOf(alice_fpr, bob_fpr, carol_fpr, dave_fpr)) } @@ -878,7 +881,7 @@ class BackPropagationTest { val q1 = Query(n1, Roots(), false) - val auth = q1.backwardPropagate(frank_fpr, frank_uid, false, IdempotentCertificationFilter()) + val auth = q1.backwardPropagate(frank_fpr, frank_uid, IdempotentCertificationFilter()) checkResult(auth[alice_fpr]!!, 0, 20, listOf(alice_fpr, bob_fpr, carol_fpr, frank_fpr)) } diff --git a/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/Query.kt b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/Query.kt index 8823e7b4..61d296ef 100644 --- a/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/Query.kt +++ b/wot-dijkstra/src/main/kotlin/org/pgpainless/wot/dijkstra/Query.kt @@ -114,10 +114,7 @@ class Query( // remain) - var progress = true - - // On this iteration approach - // [https://gitlab.com/sequoia-pgp/sequoia-wot/-/commit/ff006688155aaa3ee0c14b88bef1a143b0ecae23] + // On iteration/looping: // // "Better mimic GnuPG's trust root semantics // @@ -127,60 +124,57 @@ class Query( // considered a trust root, because he is certified by Alice. // // In other words, we need to iterate." - nextPath@ while (progress && paths.amount < targetTrustAmount) { + // + // https://gitlab.com/sequoia-pgp/sequoia-wot/-/commit/ff006688155aaa3ee0c14b88bef1a143b0ecae23 + var progress = true + while (progress && paths.amount < targetTrustAmount) { progress = false - for (selfSigned in listOf(true, false)) { - val authPaths = backwardPropagate(targetFpr, targetUserid, selfSigned, filters) + val authPaths = backwardPropagate(targetFpr, targetUserid, filters) - // The paths returned by backward_propagate may overlap. - // So we only use one (picking one of the best, by trust and length). - // - // Then we subtract the path from the network and run backward_propagate - // again, if we haven't yet reached 'targetTrustAmount'. - val bestPath = roots.fingerprints() - .mapNotNull { authPaths[it] } // Only consider paths that start at a root. - .maxWithOrNull(compareBy( - // We want the *most* amount of trust, - { it.second }, // path amount - // but the *shortest* path. - { -it.first.length }, // -path.len - // Be predictable. Break ties based on the fingerprint of the root. - { it.first.root.fingerprint }) - ) + // The paths returned by backward_propagate may overlap. + // So we only use one (picking one of the best, by trust and length). + // + // Then we subtract the path from the network and run backward_propagate + // again, if we haven't yet reached 'targetTrustAmount'. + val bestPath = roots.fingerprints() + .mapNotNull { authPaths[it] } // Only consider paths that start at a root. + .maxWithOrNull(compareBy( + // We want the *most* amount of trust, + { it.second }, // path amount + // but the *shortest* path. + { -it.first.length }, // -path.len + // Be predictable. Break ties based on the fingerprint of the root. + { it.first.root.fingerprint }) + ) - if (bestPath != null) { - val (path, amount) = bestPath + if (bestPath != null) { + val (path, amount) = bestPath - if (path.length == 1) { - // This path is a root. - // - // We've used 'amount' of trust from this root, so we'll detract that amount - // from that root, with a filter. - val suppress = SuppressIssuerFilter() - suppress.suppressIssuer(path.root.fingerprint, amount) - filters.add(suppress) - } else { - // Add the path to the filter to create a residual - // network without this path. - val suppress = SuppressCertificationFilter() - - suppress.suppressPath(path, amount) - filters.add(suppress) - } - - paths.add(path, amount) - progress = true - - // Prefer paths where the target User ID is self-signed as long as possible. - continue@nextPath + if (path.length == 1) { + // This path is a root. + // + // We've used 'amount' of trust from this root, so we'll suppress + // that amount from it. + val suppress = SuppressIssuerFilter() + suppress.suppressIssuer(path.root.fingerprint, amount) + filters.add(suppress) + } else { + // We create a residual network by suppressing this path. + val suppress = SuppressCertificationFilter() + suppress.suppressPath(path, amount) + filters.add(suppress) } + + paths.add(path, amount) + progress = true } } return paths } + /** * Finds a path in the network from one or multiple `roots` that * authenticates the target binding. @@ -188,13 +182,29 @@ class Query( * If `roots` is empty, authenticated paths starting from any node * are returned. * + * + * Does one backwards propagation run. By default, always with self-sig 'true'. + * Repeats the call with 'false', if 'true' returns no results. + * + * Note: the algorithm in backwardPropagateInternal() prefers shorter paths + * to longer paths. So the returned path(s) may not be optimal in terms of the amount of trust. + * To compensate for this, the caller should run the algorithm again on + * a residual network. + */ + private fun backwardPropagate(targetFpr: Fingerprint, targetUserid: String, filter: CertificationFilter): HashMap> { + + // Prefer paths where the target User ID is self-signed as long as possible. (But .. Why?) + val authPaths = backwardPropagateInternal(targetFpr, targetUserid, true, filter) + if (authPaths.isNotEmpty()) return authPaths + + // If we find no "self-signed" paths, return any others + return backwardPropagateInternal(targetFpr, targetUserid, false, filter) + } + + /** * Implements the algorithm outlined in: * https://gitlab.com/sequoia-pgp/sequoia-wot/-/blob/main/spec/sequoia-wot.md#implementation-strategy * - * Note: the algorithm prefers shorter paths to longer paths. So the - * returned path(s) may not be optimal in terms of the amount of trust. - * To compensate for this, the caller should run the algorithm again on - * a residual network. * * `selfSigned` picks between two variants of this algorithm. Each of the * modes finds a distinct subset of authenticated paths: @@ -206,10 +216,10 @@ class Query( * - If `false`, this function only finds paths that don't use * a self-certification as the last edge. */ - private fun backwardPropagate(targetFpr: Fingerprint, - targetUserid: String, - selfSigned: Boolean, - filter: CertificationFilter) + private fun backwardPropagateInternal(targetFpr: Fingerprint, + targetUserid: String, + selfSigned: Boolean, + filter: CertificationFilter) : HashMap> { logger.debug("Query.backward_propagate")