[noise] rev32b (Release Candidate)
alex at centromere.net
Sat May 13 16:24:51 PDT 2017
On Sat, 13 May 2017 21:40:20 +0200
"Jason A. Donenfeld" <Jason at zx2c4.com> wrote:
> > The `psk` token unlike all other tokens: It is parameterized. There
> > is no way for a Noise library to know ahead of time what the value
> > will be.
> That's really not true. It's the same type semantically as any other
> token. A particular static key, for example, could be dependent on
> something like the source IP address, or other framing. However, in
> most circumstances, you simply tell the particular "instance" of Noise
> what keys will be used for different points of a handshake.
I think there is a huge mindset difference in how you and I are
approaching the spec. Compare the Noise_IK handshake in WireGuard to
cacophony. WireGuard is not meant to be a general purpose Noise
library, so I understand why these things seem trivial to you. But from
my perspective, I'm implementing a general purpose library that should
contain the functionality required to represent every single handshake
pattern possible without repeating myself. As a result, the design
choices I need to make are different.
WireGuard weaves together the Noise logic and the application logic,
and that's perfectly fine for your use case. When that's your mindset
it's easy to say, "just look up the static key in a hash table". I can
not do that, because I can not make any assumptions about who will be
using this library.
> > In an ideal general purpose Noise library, would you expect the
> > end-user to write the handshake pattern themselves, with their
> > application-specific logic (e.g. lookup_psk_in_database) woven in?
> > Or, would you want to have the library provide a set of pre-packaged
> > off-the-shelf handshake patterns, and users will only very rarely
> > define their own?
> A library should probably provide pre-packaged off-the-shelf handshake
> patterns, which is why Trevor has taken the pains to document and name
> several useful ones.
When I say, "write the handshake pattern themselves", I don't mean "the
user should design, from scratch, a handshake pattern". I mean to say
that the user would copy/paste the pattern from the spec and make any
tweaks (like adding a `psk` token here or there) on their own.
> > My goal is to have cacophony be "idiot proof" -- it should be
> > difficult to shoot yourself in the foot. It is not clear to me how
> > to meet this goal while also making the library flexible enough to
> > support parameterized tokens like `psk`.
> `psk` is not a necessarily parameterized token. You could choose to
> implement it this way, just like all the other tokens -- which could
> be parameterized on _something_ -- but you could also choose to
> implement it a simpler way.
The psk is not necessarily known at the time the handshake pattern is
defined and delivered to the library. It's only after the Noise
exchange begins (and tokens are consumed) that the psk becomes known,
and it's chosen by application logic, not Noise logic.
> From my own personal experience working on three different Noise
> libraries, this is _not_ a hard thing to implement. But if you'd like
> to complicate it with various complicated lookup semantics, then I
> guess you can do that if you want?
I've literally created a domain specific language to describe handshake
patterns. There is a *single data structure* that is used to represent
all possible handshake patterns along with an interpreter to provide
the implementation. Both the initiator *and* responder are running off
the same "script". I find this to be a valuable abstraction, and I'm
willing to put in considerable effort to make it work.
> > What if the user wants to add their own Noise extension that
> > introduces a new token? Will they be required to fork your library,
> > or would there be an interface for adding new tokens? How would the
> > code that applies user-specified modifications take in to account
> > user-specified extensions?
> I think what you should do is take things incrementally. If an actual
> use arises where something odd and complicated is needed, then you'll
> look into it at that time.
When I see you write "look into it at that time", I hear, "kick the can
down the road".
The psk changes in rev32b alone require large breaking API changes
because my abstractions are based on the assumption that *all*
handshake parameters (such as the psk from previous revisions, as well
as the ephemeral key) are known to the library before the handshake
begins. As a result, the entire handshake can be thought of as a "pure
computation" whose output is solely dependent on its input. But if the
application can arbitrarily choose a psk half-way through the
computation, all purity is lost.
> There is _always_ some direction you could go in that requires an
> additional abstraction. I think there are even theorems from
> programming language theory that demonstrate this sort of thing. The
> goal in writing a library is to provide APIs that are simple and
> sane, while enabling future growth as needed. As a decent example of
> this, the Qt library is commonly cited as a good example of rigorous
> library API design. Not too abstracted, not too constrained. But in
> any case, these decisions are up to you. And again, from my own
> experience working on this, there are some really straight forward
> ways of implementing this.
API design is by no means trivial, and I will not half-ass it.
> > I think I may have no choice but to have the user to write their own
> > handshake patterns. Ideally a Noise library would perform static
> > analysis on the handshake pattern before even starting, as opposed
> > to waiting until some assertion is violated half way through a
> > handshake.
> I think you certainly have many choices that aren't that.
You're right, I could provide a module containing every psk-permutation
of every defined handshake pattern.
I think specifying the handshake patterns in a DSL is a good thing,
especially if the data structure used permits static analysis.
More information about the Noise