3-vat/machine handoffs, certificates only, no handoff tables required

62 views
Skip to first unread message

Christopher Lemmer Webber

unread,
Dec 3, 2020, 3:28:56 PM12/3/20
to cap-...@googlegroups.com, Mark S. Miller
Alright, here's a stab at the handoff stuff I'm planning between 3
machines (or vats, whatever the captp boundary is) in CapTP. (I've
written a variant of this to the list before, but it wasn't clean.
Here's a cleaned up version which I'm actually on the verge of
implementing.)

Let's start out with your classic scenario:

- Machine A has an open connection to Machine B and Machine C.

- Machine A is about to perform an invocation against Bob on B, passing
an argument to Carol on C. B and C may or may not have previously
spoken.

- Carol shows up in C->A's exports and A->C's imports as slot 0.

Here's the very, very simple high-level view: we don't need swissnums,
we don't need handoff tables. All we need is a certificate.

I'll present two different versions of this certificate approach... one
which works in a level of transparency of a blockchain, where the
internal operations of the "machine" are largely exposed, and one where
things are fairly opaque.

{type: Sig,
signedObj: {type: CapabilityHandoff,
to: $B,
from: [$A, <A-to-C-session>],
;; from receiver's POV
export: 0},
signature: <signature-by-A-to-c-session-handoff-key>}

Here is the key idea:

- Every pairwise captp connection actually also establishes a
*session*. This is helpful even in store-and-forward / blockchain
systems in case eg A was restored from an old backup and is out of
sync with what B believes their captp session is; they can start
over. If such a restart happens, we don't accidentally hand out the
wrong import.

- A hands this certificate as an argument over captp, which B can then
hand to C. The certificate says "Hey C, I'm A. Remember our captp
session of A<->C with this id? If that's the session you still
consider to be active, then in that case I've signed with the handoff
key I've associated with that session that yes, the thing you
exported at slot 0 for me, you should give that to B also to use."

Relatively simple. No handoff table required.

This does leak information about A<->C's communication to B, namely what
slot number the export is; B could probably get a sense of how long this
session has been open, the ordering of when objects were exported, etc.
That's fine for a blockchain where all this information is available,
but there's an alternative: instead of signing the certificate,
seal/encrypt it. If this is a key only used pairwise for this session
between A<->C, this is just as good as a signature; if it fails to
unseal, it was no good anyway. But B need not know what it is.

Now observe! No E-Order is provided. Boo! Or not boo. Actually it's
not too hard to add E-Order on top of this, even without the lost
resolution bug, as MarkM observed here:

https://groups.google.com/g/cap-talk/c/xWv2-J62g-I/m/j5zV-4vMAQAJ

Since we're now in certificate-land, A can merely attach the series of
messages that need to be processed from A->C before B is permitted to
access Carol. If B talks to C before A talks to C, B can still deliver
the invocations A *would have* performed before the Carol handoff to B
is supposed to happen.

The question still remains to me: "Do we want E-Order?" This is some
extra complexity, but extra complexity is not too bad if it results in a
serious gain of expressive power or serious reduction in errors. I'm
not sure it will though, as I raised here:

https://groups.google.com/g/cap-talk/c/R5kc06XGqWs/m/WDraOqkQAgAJ

See MarkM's response:

https://groups.google.com/g/cap-talk/c/R5kc06XGqWs/m/KuHo7UgWAgAJ

I think we're still waiting on Dean to respond to that thread. I'm sure
he has Opinions (TM). ;)

Anyway, thoughts on the above certificate approach? Particularly
reusing the imports/exports instead of adding a handoffs gifts/wants
table? (Mark, I'm especially interested in your thoughts, given that
you're the one who mentioned the handoffs-table approach to me... I
think this accomplishes the same thing through reuse, and is simpler.)

- Chris

Christopher Lemmer Webber

unread,
Dec 4, 2020, 2:37:34 PM12/4/20
to cap-...@googlegroups.com, Mark S. Miller
Baldur pointed out that A<->C might end up garbage collecting the Carol
import/export before this is supposed to happen. Solution:

- A creates a box around its Carol reference, effectively a VineBox...
all it does is keep Carol in scope, and when invoked, nulls out the
reference.
- Once B has retrieved Carol from C, B invokes the VineBox, nulling out
A's reference to Carol.

Pretty weird but it probably works!

Christopher Lemmer Webber

unread,
Dec 4, 2020, 2:38:43 PM12/4/20
to cap-...@googlegroups.com, Mark S. Miller
Terry says we might be able to do something like this to re-introduce
E-order but my brain has not fully finished processing that idea.

Christopher Lemmer Webber

unread,
Dec 4, 2020, 2:39:40 PM12/4/20
to cap-...@googlegroups.com, Mark S. Miller
Bill suggests seeing if symmteric keys can do the same job.

Mark S. Miller

unread,
Dec 4, 2020, 3:40:53 PM12/4/20
to Christopher Lemmer Webber, cap-...@googlegroups.com
Is this different from the Vine in E’s captp?
--
  Cheers,
  --MarkM

Christopher Lemmer Webber

unread,
Dec 4, 2020, 3:54:16 PM12/4/20
to cap-...@googlegroups.com, Mark S. Miller
Okay, I've thought of a route but it's strange. (It might be exactly
the thing Terry suggested; I'm not sure because I didn't fully parse it
when Terry suggested it.) However, Terry is right; it is possible to
avoid sending *any* wormhole type operation while preserving E-order,
certificate or otherwise, and also deal with the GC problem at the same
time. I am amazed.

Here's how it would work. Take the same signedObj from the previous
email (the nested objects rendered horribly in the html interface so
I'll just focus on that):

{type: CapabilityHandoff,
to: $B,
from: [$A, <A-to-C-session>],
// from receiver's POV, speaking about C's exports and answers to A
giveExport: 0, // C->A export 0
afterAnswer: 45, // C->A answer 45
triggerAnswer: 46} // C->A answer 46

Here's how it works. Assume the following annotated scenario, executed
from Alice (on A) with Bob and Carol being on B and C, using E style
syntax:

carol <- x() // question 45
bob <- y(carol)
carol <- z()

Here's what happens:

- carol <- x() has the question/answer of 45. This corresponds to
afterAnswer, because we do not want Bob to receive Carol until after
carol <- x() has completed.

- A creates a VineBox(carol). VineBox has only one method, .done().
carolVineBox.done() is set up to trigger after the handoff between
C->B. This is wired to the promise at triggerAnswer 46!

- So... A hands this certificate to B *as the argument representing
Carol*.

- B hands this certificate to C, requesting Carol (A's import from C of
0).

- C waits until afterAnswer is passed, ie after C has given an answer
to A >= 45.

- C looks up what their export to giveExport was from C->A. Okay, it's
0... looks like that's Carol. Okay B, I'm exporting Carol for you at
whatever whatever number (eg 67).

- C now fulfills their answer to A of 46 (it doesn't matter to which
value). The promise handler on A now triggers carolVineBox.done(),
which nulls out carolVineBox's reference to Carol, opening up the
possibility of a Carol GC.

I can't believe it, but this manages to do all of:

- The relevant handoff
- Without introducing any new tables
- While preserving E-order
- Without accidentally garbage collecting Carol
- Without wormholing anything (holy CRAP!)

Am I missing something? This seems like a big discovery! (Thank you
Terry for pushing me to think about it!)

Tristan Slominski

unread,
Dec 4, 2020, 7:04:38 PM12/4/20
to cap-...@googlegroups.com, Mark S. Miller
Isn't this interleaving possible?

in A: carol <- x()     // question 45
in A: bob <- y(carol)
in A: carol <- z()
C fulfills 45
C fulfills 46
B hands certificate to C

I didn't follow all the properties you're after, but do those properties hold with the above interleaving?






--
You received this message because you are subscribed to the Google Groups "cap-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cap-talk+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/cap-talk/87h7p1wawd.fsf%40dustycloud.org.

Christopher Lemmer Webber

unread,
Dec 4, 2020, 7:21:51 PM12/4/20
to Mark S. Miller, cap-...@googlegroups.com
I think it might be the same. I partly called it VineBox because I was
unsure if it was the same idea or not, and also the nullification step.
It might be exactly the same (and the nullification part might also be
totally unnecessary... also unsure there...)

Christopher Lemmer Webber

unread,
Dec 4, 2020, 7:30:13 PM12/4/20
to cap-...@googlegroups.com, Mark S. Miller, Tristan Slominski
I think it's not a problem because C won't fulfill 46 before receiving
the certificate; no DeliverOp will request a 46 answerPos, only the
certificate should. The next DeliverOp will hop straight to 47.

I debated whether or not it should be a triggerAnswer or a
triggerImport; my initial analysis (might be shown different in
practice) was that the GC considerations for this approach more closely
resembled question/answer than import/export. But it is easier to think
about it in terms of a "normal promise" indexed by triggerImport which
is being fulfilled instead of the special-case question/answers because
now there is no conception of the weird possibility that C fulfills *47*
before fulfilling 46, which is a real possibility in my design.

If rewriting mentally to that model, does the interleaving problem go
away for you?

Tristan Slominski

unread,
Dec 4, 2020, 7:49:42 PM12/4/20
to Christopher Lemmer Webber, cap-...@googlegroups.com, Mark S. Miller
"I think it's not a problem because C won't fulfill 46 before receiving
the certificate;"

I don't see how C is aware that any certificate exists until B sends it to C, which can happen after C fulfilled 46

Tristan Slominski

unread,
Dec 4, 2020, 7:55:47 PM12/4/20
to Christopher Lemmer Webber, cap-...@googlegroups.com, Mark S. Miller
I can see how C can be aware of a missing 46 if A sends 45 followed by 47. So if that's what's going on, then 47 would be deadlocked until B talked to C with its 46 thing.

Christopher Lemmer Webber

unread,
Dec 5, 2020, 10:54:40 AM12/5/20
to Tristan Slominski, cap-...@googlegroups.com, Mark S. Miller
Nothing mentions 46 until that certificate. To make it clearer:

carol <- x() // question 45
bob <- y(carol)
carol <- z() // question *47*

Or, let's translate into actual CapTP operations:

carol <- x() // A->C DeliverOp(answerPos=45, ...)

bob <- y(carol) // A->B DeliverOp(...,
args=[<Handoff
delegateTo=$B
origin=$C,
afterAnswer=45,
triggerAnswer=46], ...)

carol <- z() // A->C DeliverOp(answerPos=47, ...)

See? Neither DeliverOp from A->C directly ever mentions the answer of
46... only the certificate does.

Tristan Slominski

unread,
Dec 5, 2020, 11:08:11 AM12/5/20
to Christopher Lemmer Webber, cap-...@googlegroups.com, Mark S. Miller
Ok, in that case, C can garbage collect before ever hearing about the certificate from B. Another way of highlighting this, consider a really long delay in B->C communication.

Christopher Lemmer Webber

unread,
Dec 5, 2020, 1:20:17 PM12/5/20
to Tristan Slominski, cap-...@googlegroups.com, Mark S. Miller
C does not garbage collect Carol because Carol is imported from the vine
on A's end, which is not releasing Carol.

Triggering the "answer" on 46 is what releases Carol, by clearing the
vine. And that comes *only after processing the certificate*.

Tristan Slominski

unread,
Dec 5, 2020, 2:37:37 PM12/5/20
to Christopher Lemmer Webber, cap-...@googlegroups.com, Mark S. Miller
I see. That makes sense. Feels like carol <- z() is extraneous in the example. Here's how I translated this in my mind (not saying anything differently, but favoring local framing over global framing)

view inside A:
A->C: carol <- x()
A: create VineBox(carol)
A->B: bob <- y(carol)
C->A: carolVineBox.done()
A->C: release carol

view inside B:
A->B: bob <- y(carol)
B->C: carolVineBox, gimme carol
C->B: carol

view inside C:
A->C: carol <- x()
B->C: carolVineBox, gimme carol
C->B: carol
C->A: carolVineBox.done()

desired invariants:
C->A: carolVineBox.done() happens after C->B: carol (can be enforced since both happen at C in response to B->C: carolVineBox, gimme carol)

ordering inside B is the same so we can not think about it
ordering inside A is the same so we can not think about it
ordering inside C is variable

A->C: carol <- x()
B->C: carolVineBox, gimme carol

or 

B->C: carolVineBox, gimme carol
A->C: carol <- x()

but since carolVineBox forces a wait for carol <- x() then B->C: carolVineBox, gimme carol has to wait for A->C: carol <- x() to arrive and the order:

A->C: carol <- x()
B->C: carolVineBox, gimme carol

is enforced at C.


Christopher Lemmer Webber

unread,
Dec 5, 2020, 7:13:35 PM12/5/20
to Tristan Slominski, cap-...@googlegroups.com, Mark S. Miller
Tristan Slominski writes:

> I see. That makes sense. Feels like carol <- z() is extraneous in the
> example.

Yes, sorry, it's extraneous; I was copying the e-order example from
erights.org. The carol <- z() kind of shows what *isn't* impacted.

Mark S. Miller

unread,
Dec 5, 2020, 8:25:05 PM12/5/20
to Christopher Lemmer Webber, Tristan Slominski, cap-...@googlegroups.com
Yes. It is there to explain how E-order is weaker than causal order.
--
  Cheers,
  --MarkM

Christopher Lemmer Webber

unread,
Dec 8, 2020, 3:17:09 PM12/8/20
to cap-...@googlegroups.com, Mark S. Miller
Christopher Lemmer Webber writes:

> Bill suggests seeing if symmteric keys can do the same job.

I spent a bunch of time today trying to think this way: an entire system
with symmetric keys only, no asymmetric keys involved.

Actually I have probably figured it out for both: a path with asymmetric
keys, and a path with symmetric keys.

It struck me, and this is maybe obvious, that there are two different
cryptographic scenarios, both highly desirable, but which seem to be at
odds. Tell me if I'm wrong:

- Symmetric key protocol: More likely to survive post-quantum
cryptographic cypher vulnerabilities. However, can't be used in a
"transparent" system like a blockchain or even zcap-ld stuff.

- Asymmetric key protocol: The reverse.

Thus, it seems nice to provide a solution for each, but they are also
incompatible directions. I suppose this is probably obvious. So what
to optimize for?

I'm not sure, but I guess maybe it's good to at least provide the
asymmetric key option, because that means we can see if whatever
solution I come up with can also work nicely with Agoric's systems,
which are committed to also working with blockchain'y worlds.

Thoughts?
- Chris

Jonathan Frederickson

unread,
Dec 8, 2020, 5:05:22 PM12/8/20
to cap-...@googlegroups.com
On 12/8/20 3:16 PM, Christopher Lemmer Webber wrot> - Symmetric key
protocol: More likely to survive post-quantum
> cryptographic cypher vulnerabilities. However, can't be used in a
> "transparent" system like a blockchain or even zcap-ld stuff.
>
> - Asymmetric key protocol: The reverse.

IMHO: I don't know that I would worry too much about quantum computers
breaking asymmetric crypto so long as you don't tie yourself too
strongly into a particular cryptosystem. By the time quantum computers
are a practical threat to asymmetric crypto, *everyone's* gonna be
scrambling to migrate to quantum-resistant algorithms; asymmetric crypto
is widespread enough that I don't think it's ever going away if at all
possible.

Christopher Lemmer Webber

unread,
Dec 8, 2020, 8:24:04 PM12/8/20
to cap-...@googlegroups.com, Jonathan Frederickson
Yes, that's likely right...!

Bill Frantz

unread,
Dec 8, 2020, 9:55:11 PM12/8/20
to cap-...@googlegroups.com
On 12/8/20 at 8:23 PM, cwe...@dustycloud.org (Christopher
I agree that people will put out considerable effort to build
quantum resistant public key systems. I just don't know that
they will succeed. There may be some fundamental problems we
don't yet understand.

<https://en.wikipedia.org/wiki/Post-quantum_cryptography> has an
overview of the state of the art. NTRU seems to be attractive,
but it doesn't directly support forward secrecy.

NIST is running a standardization effort: <https://en.wikipedia.org/wiki/Post-Quantum_Cryptography_Standardization>

Originally, Kerberos
<https://en.wikipedia.org/wiki/Kerberos_(protocol)> used only
symmetric keys. Later versions also supported public key
systems, but it might be a good place to look for symmetric key techniques.

Cheers - Bill

-----------------------------------------------------------------------
Bill Frantz | When an old person dies, a | Periwinkle
(408)348-7900 | library burns. - Joe McGawon | 150
Rivermead Rd #235
www.pwpconsult.com | Irish Ethnographer |
Peterborough, NH 03458

Christopher Lemmer Webber

unread,
Dec 9, 2020, 11:49:14 AM12/9/20
to cap-...@googlegroups.com, Bill Frantz
"What we're designing for" came up more in some conversations on the
#erights irc channel, and that conversation helped illuminate some
things... one thing is that this is NOT about establishing a secure
channel between each vat/machine, assume I already have that from some
off-the-shelf mechanism.

Also, since often we're dealing with keys-as-identity in a context of
delicious self-authenticating-designator type systems, we might be
tempted to think about how the key in <key>.onion might be part of the
negotiation process of the handoff certificate. However, we can see
that this is not a universal solution if we think about building a
generalized CapTP handoff mechanism that could also work with something
like Ocap-OS references, where there might abe a process but no notion
of a "key". (Okay, never mind that the Ocap-OS could also get around
the need for handoffs with something more direct... it's still useful to
realize that the session-establishing key maybe shouldn't be reused for
this.)

Imagine developing a handoff mechanism which could survive two or three
of these, either mixed together or just the same general code for each:

- Ocap-OS systems, with no "crytpographically-oriented names" per vat.
(shh, don't talk about the fact that this system already provides
a way of transmitting ocaps between processes... or do think about it)

- Bidirectional connection-oriented systems, such as TCP + TLS, TCP +
tor .onion services or I2P

- Store-and-forward messaging systems, certificate systems, etc, some
of them where the nodes "cannot hold secrets" (eg blockchains)

The needs for these seem varied: the first one doesn't have a
cryptographic key at all for its vat names, the last one can't use
symmetric encryption.

The most general approach that survives all three is asymmetric keys,
but yes, might not be future-proof, but also an easy starting point if
what we wish for is generality.

The Ocap-OS one insults me in that it provides its own solution,
certificate-free, in re-establishing capabilities. How dare you,
Ocap-OS system, in providing a system nicer and more general that simply
does not work across instantiations of that OS... I suppose networking
together multiple Ocap OS'es will hit the same boundary barrier that the
rest of these systems suffer from, cutting them down to size to satisfy
our egoes, the same barriers that incentivize something like CapTP at
all.

Some other things on my mind this morning:

- Corbin Simpson said something very interesting: "A sturdyref is like
a continuation." At first I found this shocking; sturdyrefs feel
more like functions to me. But oh: then I thought about the way that
E captp sessions would die, and indeed, "rehydrating" a dessicated
sturdyref seems to be a way to re-establish context across a barrier.
Continuation-like indeed.

- I am disturbed to find VatTP encroaching on CapTP once handoffs are
introduced, at least with appropriate shortening. This has disturbed
me a LOT. But maybe it is the source of another email.

- Identity is a Katamari, language is a continuous reverse engineering
effort, and thus language is a quadratic explosion of Katamaris.
(Expansion of this riddle available upon request!)

Mark S. Miller

unread,
Dec 9, 2020, 12:14:15 PM12/9/20
to cap-...@googlegroups.com, Bill Frantz
Requested!

 

--
You received this message because you are subscribed to the Google Groups "cap-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cap-talk+u...@googlegroups.com.

Christopher Lemmer Webber

unread,
Dec 9, 2020, 1:18:38 PM12/9/20
to cap-...@googlegroups.com, Bill Frantz, Mark S. Miller

Alan Karp

unread,
Dec 9, 2020, 2:07:51 PM12/9/20
to cap-...@googlegroups.com
I wonder about your n^2 scaling.  That's certainly true if everybody knows everybody, but that's not how things work in the real world.  Once you get past 150 or so people, you start relying on friends of friends, which makes the scaling more like log(n).  Does that apply in the online world?  

I like the model of identity as the rolling ball collecting stuff.  That seems to fit Joe Andrieu's definition of identity is correlation.

--------------
Alan Karp


--
You received this message because you are subscribed to the Google Groups "cap-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cap-talk+u...@googlegroups.com.

Christopher Lemmer Webber

unread,
Dec 9, 2020, 3:57:57 PM12/9/20
to cap-...@googlegroups.com, Alan Karp
It's probably not true that it's O(n^2); big-O-notation for
big-O-dramatic-effect I guess. What the hell is n here? Well, presumably
something identified. This assumes that all entities are agents which
perform some identifying-task; very true of humans, reasonably true of a
large number of nonhuman animals but in quite varying capacity, not true of
plants except in perhaps the most minimal case (most "plant intelligence"
articles haven't described something resembling cognition to me, excepting
maybe some fungal structures) and definitely not true of rocks.

Thus it's O(n^2) in the worst case: a sealed building filled with only
identity-reasoning agents (slap an IoT-plus-AI type computing agent onto
the coffeemaker and friends). But probably more realistically somewhere
near O(log(n)). O(jokeWillingnessToStretch(n)).

Bill Frantz

unread,
Dec 9, 2020, 9:01:08 PM12/9/20
to cap-...@googlegroups.com
On 12/9/20 at 11:48 AM, cwe...@dustycloud.org (Christopher
Lemmer Webber) wrote:
>- Ocap-OS systems, with no "crytpographically-oriented names" per vat.
>(shh, don't talk about the fact that this system already provides
>a way of transmitting ocaps between processes... or do think about it)
>...
>
>The Ocap-OS one insults me in that it provides its own solution,
>certificate-free, in re-establishing capabilities. How dare you,
>Ocap-OS system, in providing a system nicer and more general that simply
>does not work across instantiations of that OS... I suppose networking
>together multiple Ocap OS'es will hit the same boundary barrier that the
>rest of these systems suffer from, cutting them down to size to satisfy
>our egoes, the same barriers that incentivize something like CapTP at
>all.

These Ocap-OS systems do avoid a lot of risks that seem to be
tightly linked to distributed Cap systems. Including stealing
cryptographic keys and weak algorithms.

But it seems to me, that in some way these risks are mirrored by
the risks inherent with cooperating with mutual suspicion. In
both cases, there is more risk that you must accept. Here you
are possibly providing data, or authority to someone/thing that
may misuse it.


When we discussed extending KeyKOS over a network, we were
assuming a small number of relatively stable systems with a
single system image. We never quite got to the point of detailed
communication protocols, but for this application, with 20-20
hindsight, I would think about a system with pre-shared keys
which are used for authentication and perhaps nonce based key
agreement for session keys.

Cheers - Bill

-----------------------------------------------------------------------
Bill Frantz | Truth and love must prevail | Periwinkle
(408)348-7900 | over lies and hate. | 150
Rivermead Rd #235
www.pwpconsult.com | - Vaclav Havel |
Peterborough, NH 03458

Matt Rice

unread,
Dec 11, 2020, 11:03:57 AM12/11/20
to cap-talk
When i look at identity as a relation between capabilities, I see the good old functions vs relations diagram
squarely "Not a function" where big-O notation is applicable to functions, i'm probably being obtuse but while Chris wonders what n is,
I wonder what the function is supposed to be after bringing least authority into the fold.

Raoul Duke

unread,
Dec 11, 2020, 4:49:42 PM12/11/20
to cap-...@googlegroups.com
(can one hack relations into being functions by returning a datatype/tuple/dict/blob? ;-)

Christopher Lemmer Webber

unread,
Dec 11, 2020, 5:53:05 PM12/11/20
to cap-...@googlegroups.com, Raoul Duke
Indeed. Imagine calling:

associativeInquiry(symbol, brain[, social-context]) => {set-of-associated-symbols}

(social context is an optional argument, and how strongly you believe that
exists might depend on how much you believe in bear goo)

To query multiple brains:

associativeInquiry(symbol, list-of-brains[, social-context]) => {set-of-associated-symbols}

Therefore:

- every brain maps a symbol (identifier/katamari-center) to a set of
associations (identity/things-stuck-to-katamari)
- thus querying one brain for identity associations of an identifier
returns a set
- querying multiple brains for identity associations thus returns an
array of sets

The explosion results somewhere about there, with how much overlap in
the array-of-sets depending on what experiences entities have. Even if
I had a mildly-traumatic experience with mayonnaise; I don't expect
trauma-related-associations to appear in everyone's mayonnaise-katamari.

Matt Rice

unread,
Dec 11, 2020, 7:12:03 PM12/11/20
to cap-talk
My point is largely that future responses may influence further-future responses to the same symbol, brain[,social-context] experienced today leading to contradictory {set-of-associated-symbols} given the same input.

i.e. for any non-function relation there are many (mathematical definition of) functions.
as well as anything which depends upon the response to associativeInquiries.

contrasted with capability invocation where contextual choice is entirely within the realm of the caller/invoker, the capability invoked may meet the mathematical definition, precisely because it is isolated from having to make said contextual choice, by acting merely on what is given.



--
You received this message because you are subscribed to the Google Groups "cap-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cap-talk+u...@googlegroups.com.

Christopher Lemmer Webber

unread,
Dec 14, 2020, 11:12:30 AM12/14/20
to cap-...@googlegroups.com, Mark S. Miller
I think I've now made enough planning-progress where I might be able to
get the handoffs implemented in an intense hacking session between today
and tomorrow.

Here's the plan:

https://dustycloud.org/tmp/captp-handoff-musings.org.txt

And here's a whiteboard drawing, which I used to plan:

https://dustycloud.org/misc/3vat-handoff.jpg

I proceeded under the assumption of asymmetric keys which (yes, Bill)
are maybe not as post-quantum-foo-certified but which I could think
about more easily with my prior zcap-ld experience. I think there's a
translation here for hmacs but I'm not going to worry about it at the
second.

Most of it makes sense now I think, excepting being troubled by the
VapTP crossover suffering" bit. But life is suffused with suffering,
and so protocol implementation/development life must contain some as
well.

- Chris

Mark S. Miller

unread,
Dec 14, 2020, 11:54:31 AM12/14/20
to cap-...@googlegroups.com, Mark S. Miller
One of your e trapezoids is flipped


--
You received this message because you are subscribed to the Google Groups "cap-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cap-talk+u...@googlegroups.com.

Christopher Lemmer Webber

unread,
Dec 14, 2020, 4:03:56 PM12/14/20
to cap-...@googlegroups.com, Mark S. Miller, Mark S. Miller
Wow, good catch!

Christopher Lemmer Webber

unread,
Dec 23, 2020, 4:04:47 PM12/23/20
to cap-...@googlegroups.com
Okay, ignore that one of the trapezoids is flipped but pull up that same
image again.

Between A<->B, A<->C, and a (potentially future) B<->C, in my version of
captp I'm also introducing the concept of a "session name". Thus A is
not only handing B access to their A<->C import/export (A/C
respectively) of Carol at 0, they're handing 0 from *within a specific
session* of A<->C. This is important because if something goes wrong
(irrepairable connection, or irrepairable state negotiation), A<->C
might have to establish a new session, and what is imported/exported at
slot 0 might no longer be the same.

I'm not sure it's the right thing, but I've generated a unique session
name per machine<->machine connection the following way. At the
beginning of booting up a vattp (or machinetp?) & captp pairwise
connection, both sides exchange the following structures: [PS:MTP]

;; A -> C
(send-message (mtp:op:start-session <a-atoc-handoff-pubkey>))
;; C -> A
(send-message (mtp:op:start-session <c-atoc-handoff-pubkey>))

Note that this is a NEW KEY generated for this session. That both sides
generate a BRAND NEW KEYPAIR is critical to this design.

From there, a session name can be constructed (thus maybe it should be
called session-pubkey, I dunno... I'm only using it for handoffs so
far). From my code:

;; Both sides should converge on the same session name if all goes well
;; because both sides should have sorted by bytes
(define session-name
(sha256d (apply bytes-append
#"prot0"
(sort (list remote-side-name our-side-name)
bytes<?))))

Since each side is contributing a fresh new handoff key, we should have
a new session name every time.

So I have this and it works. Good/fine/etc.

It has an interesting implication for the certificates then.
While A is granting B authority to Carol on C, observe that the
certificate should actually say the following:

- A is referring to the import/export of carol *from their particular
session*

- A is *signing their end of the certificate* from the key they
provided to the A<->C session

- But curiously, A is *granting* the certificate to the key B provided
from the A<->B handoff session. Nothing about B's identity is
actually encoded in the certificate, surprisingly!

- This does mean what C needs to do to verify that this signature came
"from A":

- Look up what "active session" they have open (if any) matching the
certificate's mentioned session name

- Make sure that the certifiate is signed by the *other end of that
session*

- Curiously this also means that nothing about "A", identity-wise,
necessarily needs to appear on the certificate for the handoff to
work, since what C really cares about is gifting from an *open
session with the mentioned name*, in this case.

That's kind of surprising. No "identity" really at all of "A" mentioned
on the certificate, neither of "B"... only keys related to two specific
sessions.

But C's "identity" does come in somehow... the reason being that B needs
to know:

1. Whether they already have an open connection to C

2. How to start a new connection to C if they don't yet have an open
connection

For now, I'm going to call this particular kind of identity "location".
What it really does is tell B how to route messages to C... and also
whether they already have a way to route messages to C. It's critical
to shortening, network monitoring and routing attacks, and to some
degree, integrity... though less than it may appear, because if A tries
to specify a session name they had no part of, it doesn't really help
them do anything interesting... or does it? They could maybe mislead B
into setting up a "path" to C that is snooped on by A. I need some more
time to think of the ways in which things could go badly, especially the
ways that A could misdirect B. My brain is curdling a bit here.

But maybe here is a path out. Consider an adjustment to the
start-session op: [PS:LOCATIONS]

;; A -> C
(send-message
(mtp:op:start-session <a-atoc-handoff-pubkey>
<signed-by-that-key <acceptable-a-location>>))
;; C -> A
(send-message
(mtp:op:start-session <c-atoc-handoff-pubkey>
<signed-by-that-key <acceptable-c-location>>))

It might be then that A has to hand a <acceptable-c-location> that was
signed by C's part of the session-name, thus meaning that A can't insert
*A's preferred way to get to C*. This can also be compared (eq? eek!)
for shortening / lack of duplicate connections/sessions purposes.

But my brain is roughly cottage cheese at this point. Assuming
brain-curdling is not a one-way function, I'll have to see if I can
analyze this as being reasonably "safe" and "sane" once I've
reconstituted it.

- Chris

[PS:MTP] Why mtp:? All other op: are for captp, but this crosses over
into the machinetp, aka vattp, territory because it involves some
weird-ass connection establishment and identity crap. Yeah maybe it's
just an op: because maybe this is captp'ish, I dunno. I hate the amount
of crossover happening here.

[PS:LOCATIONS] Yes, I put "location" here and not "locations". Having
one identity used for shortening, rather than a set, seems easier. My
brain is broken enough already.

Christopher Lemmer Webber

unread,
Jan 21, 2021, 4:08:29 PM1/21/21
to cap-...@googlegroups.com, Mark S. Miller
It turns out there's an incredibly elegant way to do this that fully
preserves E-order that might fall out naturally. Actually, I think it's
more or less the way that E-order worked originally. And actually it's
mostly what MarkM has already suggested: handoff tables, instead of the
"give me your export" thing I suggested before. It also eliminates the
vine (which I think Mark said he realized might be true in a prior part
of the other thread). It also appears to preserve e-order
"naturally"...!

Just briefly, before it leaves my brain:

- You'll still need a "Description" type for the handoff. That part
does not change.

- The sending vat also still needs to recognize that it's *doing* a
handoff of course, and the receiving vat still needs to interpret the
handoff certificate type.

- However, there does not need to be *any* handoff "Op" type at all.

- Instead, we rely on "Bootstrap" objects that each side has. Common
already in CapTP, and this historically was where SturdyRefs live.
(This can also eliminate the need for sturdyrefs, as I will explain
in a moment.)

- What we add instead is that each Bootstrap object has *two* methods:

- bootstrap~.depositGift(id, objRefr): Deposits an
object reference on this vat for someone else... note it must be
*near* to the vat where this object is being deposited (or local to
this machine, if you want to look at things that way).

- bootstrap~.retrieveGift(signedCert): Demonstrates access to the handoff
cert (which specifies both the id of the handoff and the which
associated deposit box to retrieve from, probably mapped to a session).

- (Not critical but:) in general, there's an implicit default argument
to the deposit method:

bootstrap~.depositGift(id, objRefr, explicitDrop=False)

By default, upon retrieval, the gifts table drops the reference.

- The id could be a uuid/nonce (swissNum rights amplification?!?) or an
integer. Integer has an advantage that it could be detected if the
retriever is requesting an object that has already been delivered.
uuid has the advatage of now I don't need to do that extra work
(which probably isn't too much).

- Here's why it preserves E-order:

// alice's perspective
carol~.x() // A->C DeliverOnlyOp(<ExportDesc carolImportId>, "x", [])
bob~.y(carol) // A->B DeliverOnlyOp(<ExportDesc bobImportId>, "y", [<signed-handoff-cert-here ... "d374b7dd-eee3-4d9e-94bf-85cac7952e95">])
carol~.z() // A->C DeliverOnlyOp(<ExportDesc bootstrapImportId>, "depositGift", [carol, "d374b7dd-eee3-4d9e-94bf-85cac7952e95"])

// B, after getting the certificate:
// B->C DeliverOnlyOp(<ExportDesc bootstrapImportId>, "retrieveGift", [<signed-retrieve-handoff-cert-here>])

// bob, after getting carol
carol~.w() // B->C DeliverOnlyOp(<AnswerDesc carolRetrieveQuestionId>, "w", [])

What's important to realize is that the carolRetrieveQuestionId, which
is really what matches to Bob's carol, is dependent on A->C delivery of
the depositGift, which won't come until after carol~.x() happens anyway.

Hope that's clear. This seems like the right thing I think?
>>> serious gain of expressive power or serious reduction in errors. I'm

Christopher Lemmer Webber

unread,
Jan 21, 2021, 4:23:39 PM1/21/21
to cap-...@googlegroups.com, Mark S. Miller
Still has the lost resolution bug, in the case you consider it a bug,
but you can deal with that with the existing proposals for sending the
operations to-be-done as part of the certificate.

I'm not too certain the lost resolution bug is a particularly
significant bug though, but I know I'm in the minority on that.
I'm also not certain that implicit E-Order is a feature, but E-Order
nonetheless appears to be preserved.

Christopher Lemmer Webber

unread,
Jan 21, 2021, 4:43:28 PM1/21/21
to cap-...@googlegroups.com, Mark S. Miller
Christopher Lemmer Webber writes:

> Christopher Lemmer Webber writes:
>
>> - Here's why it preserves E-order:
>>
>> // alice's perspective
>> carol~.x() // A->C DeliverOnlyOp(<ExportDesc carolImportId>, "x", [])
>> bob~.y(carol) // A->B DeliverOnlyOp(<ExportDesc bobImportId>, "y", [<signed-handoff-cert-here ... "d374b7dd-eee3-4d9e-94bf-85cac7952e95">])
>> carol~.z() // A->C DeliverOnlyOp(<ExportDesc bootstrapImportId>, "depositGift", [carol, "d374b7dd-eee3-4d9e-94bf-85cac7952e95"])
>>
>> // B, after getting the certificate:
>> // B->C DeliverOnlyOp(<ExportDesc bootstrapImportId>, "retrieveGift", [<signed-retrieve-handoff-cert-here>])
>>
>> // bob, after getting carol
>> carol~.w() // B->C DeliverOnlyOp(<AnswerDesc carolRetrieveQuestionId>, "w", [])
>>
>> What's important to realize is that the carolRetrieveQuestionId, which
>> is really what matches to Bob's carol, is dependent on A->C delivery of
>> the depositGift, which won't come until after carol~.x() happens anyway.
>>
>> Hope that's clear. This seems like the right thing I think?
>
> Still has the lost resolution bug, in the case you consider it a bug,
> but you can deal with that with the existing proposals for sending the
> operations to-be-done as part of the certificate.
>
> I'm not too certain the lost resolution bug is a particularly
> significant bug though, but I know I'm in the minority on that.
> I'm also not certain that implicit E-Order is a feature, but E-Order
> nonetheless appears to be preserved.

Actually, I think the "lost resolution bug" still isn't a bug. It was
stated as WONTFIX NOTABUG over a decade ago:

http://wiki.erights.org/wiki/The_lost_resolution_bug_isn%27t

I'm convinced this is still the case but for a different reason (I
think?) than what's stated.

If the real question is "does Carol come in as a promise or a farRef?"
I think Carol should always show up as a promise when given to Bob as a
handoff.

Consider that if Carol *isn't* a promise, *even if* we wormhole
operations on a certificate, does this mean that bob.y(carol) cannot
proceed until B and C establish a conversation and talk? Am I missing
something...?

That seems strange to me. Bob should be able to start handling
.y(carolVow) as soon as the message from A arrives.

That and the possible quadratic messages says to me: just live with
promises in the case of handoffs. Too much "eek!" for a little bit of
"eq?".

- Chris

Mark S. Miller

unread,
Jan 21, 2021, 8:01:32 PM1/21/21
to cap-...@googlegroups.com, Mark S. Miller
This is a huge topic. For now I'll just say that we (Agoric) probably cannot live with the lost resolution bug. But neither have we adequately faced it. Our handoff such as it is is a stopgap to be replaced by a real handoff mechanism. Your explorations of this design space are welcome, valuable, and timely! Thanks for doing this.



--
You received this message because you are subscribed to the Google Groups "cap-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cap-talk+u...@googlegroups.com.

Christopher Lemmer Webber

unread,
Jan 21, 2021, 11:17:11 PM1/21/21
to cap-...@googlegroups.com, Mark S. Miller, Mark S. Miller
It is a huge topic, probably.

I'm curious why you say you cannot live with the lost resolution
bug... I feel like I'd need more context to believe it (I believe you
believe it and have good reason to, but I do not yet believe it).

- Chris

Christopher Lemmer Webber

unread,
Jan 21, 2021, 11:33:38 PM1/21/21
to cap-...@googlegroups.com, Mark S. Miller, Mark S. Miller
Let me make an argument for why I think Agoric can survive it.

Effectively, the problem is one of eq?-ness, right? Particularly keying
of hashtables.

In Goblins, at least, you can still send a hashtable across the
wire... but indeed, it'll have promises as keys. Le sad, but only kind
of. But the hashtable uses literal scheme "eq?" so we can still hash
things, it's not that the hashtable fails to deserialize. Disturbingly
if you have a promise and a resolved reference that both point to the
same Carol, the promise and the resolved reference do show up as
separate keys.

In the case where an actor's method handler absolutely must have
promises resolved anyway, then here's a solution: set up a wrapper
around it that waits until all promise values are resolved for the keys,
and then rewrite the hashtable with those resolved live far refs, and
done; now you can invoke at last. Why not?

Besides, live references which are resolved but far can still break on
some sort of session-breakage (network or session corruption) anyway,
right? How does *that* affect hashtable keying for you?

Sounds like there's lots more to discuss though...!

- Chris

Kevin Reid

unread,
Jan 21, 2021, 11:42:35 PM1/21/21
to cap-...@googlegroups.com
On Thu, Jan 21, 2021 at 8:33 PM Christopher Lemmer Webber <cwe...@dustycloud.org> wrote:
In the case where an actor's method handler absolutely must have promises resolved anyway, then here's a solution: set up a wrapper around it that waits until all promise values are resolved for the keys, and then rewrite the hashtable with those resolved live far refs, and done; now you can invoke at last.  Why not?

You can describe this as having the pass-by-construction object be not "a hashtable" but an application-specific object which incidentally uses a hashtable to implement its functionality. It must return promises, errors, or tentative results until the key identities are stabilized, but that policy can be set to suit the application.

Also, in E, nothing stops makeFoo(somePromise), which happens to be called by deserialization, from returning a promise for the "Foo" that doesn't resolve until its arguments do. This pushes the protocol-level lost resolution into a coarser but potentially more handleable application-chosen lost resolution; Foo can now guarantee to return synchronous results, if that's what it wants to do.

Mark S. Miller

unread,
Jan 22, 2021, 12:06:28 AM1/22/21
to Christopher Lemmer Webber, cap-talk, Mark S. Miller
Sadly, we have not yet gotten back up to passable hash tables, or maps, as they're called in JS. We're working ourselves back there.

Because of the constraints of JS promises, in particular because of some of the ways they deviated from E promises, our distributed object system has both remote promises which may be resolved, and presences, which are the fulfillment of a fulfilled remote promise. A presence is not promise-like. It is most analogous to the E far reference, but it is object-like rather than promise-like. 

The argument (not result) passing rules preserve the gross type distinctions. Arguments sent as promises arrive as promises --- no great surprise. Arguments sent as pass-by-copy objects arrive as the pass-by-copy objects you expect. What in various versions of captp have been called pass-by-proxy or pass-by-reference or interface objects we call pass-by-presence objects. Arguments sent as pass-by-presence objects arrive as presences. Arguments sent as presences towards home --- toward the vat hosting the object they are a presence of --- arrive as that pass-by-presence object. The category "remotable" covers both presences and pass-by-presence objects. Arguments sent as remotables arrive as remotables. This means that arguments sent as presences not towards home arrive as presences for the same remote pass-by-presence object.

By our distributed object system semantics, promises are not comparable for equality, as you'd expect from E. Pass-by-copy objects compare structurally, as you'd expect from E. Remotables compare by identity, which always uniquely represents the identity of the pass-by-presence object they either are or remotely represent, as you'd expect from E. As with E far references, presences are canonical and shortest. A message sent on a presence should be delivered to its pass-by-presence object depending only on those two vats, with no vulnerability to a third vat. Because the identity is canonical, it supports grant matching.

I'm sorry. All this was worth saying and builds to a conclusion I thought I'd get to quicker. But in any case it lays out the constraints we're working with, which are close to E but somewhat more constrained. More later.

Stay skeptical! Until I have made a convincing case, remain unconvinced!

--
  Cheers,
  --MarkM
Reply all
Reply to author
Forward
0 new messages