- Drop X3DH tests
- Drop cross-version tests with libsignal v0.12 and v0.21
- Change session benchmarks to use PQXDH, which is relevant if doing
comparisons before/after this commit.
This PR integrates a post-quantum ratchet (SPQR) into libsignal, using an API that maintains its own internal chain and provides per-message keys. In doing so, it also aims to be fully backwards-compatible with current clients and stored session state.
## Backwards compatibility with current clients
Remote clients that connect to us or that we connect to may not have this integration. If they don't, their SignalMessage wire format should still deserialize, and in doing so we'll receive an empty pq_ratchet field. SQPR handles this internally, by downgrading the protocol version to "version 0" or "don't do anything". Note that should we eventually want to disallow this, we can do so via increasing the `min_version` field passed into the SQPR init functions to V1. This is also the method by which we would upgrade SQPR from v1 to a future v2, etc.
## Opt-in
The publicly facing API calls for this now expose an explicit opt-in via a passed-in `use_pq_ratchet` bool (and associated enums in language-specific APIs). If false, they default to SQPR `v0`, IE: none. If true, they try to set up SPQR on new sessions, but will downgrade if the remote party cannot or will not do the same.
This fixes a bug introduced by cd36118 where starting a new session
locally would prevent incoming messages on a previous session from
being decrypted if that session hadn't advanced past the "pre-key"
stage. Fix this by promoting the session *before* successful
decryption instead of after; since we won't *save* the promotion
unless the message decrypts successfully, there's ultimately no change
in either the failure or success cases *except* when hitting this bug.
For the most part this should happen transparently without any
explicit adoption, like the previous change, but for Java code the
NoSessionException is now properly declared on SessionCipher.encrypt.
(This was always technically possible, but clients were expected to
have previously checked for session validity before using
SessionCipher; now that there's an expiration involved, that's not
strictly possible.)
Only the iOS client ever used this extra parameter, and it's one
that's easily stored alongside the reference to a store. This is
massively simpler than having it threaded down to the Rust
libsignal_protocol and back up through the bridging layer.
This marks that a session is being opened by Alice to reply to Bob,
who has sent a message to Alice's phone number rather than her account
UUID. Apps can check this flag to determine if they need to include
extra information in the message content to certify that yes, this
account is the owner of this phone number. The state is automatically
cleared once the current session receives a response from Bob.
Both futures::executor::block_on and our own expect_ready were being
used to resolve futures that were, in practice, known to be
non-blocking. FutureExt::now_or_never handles that case more lightly
than block_on and more uniformly than expect_ready.
This lets us drop the dependency on the full 'futures' crate down to
just futures_util, which should help with compile time.
This simplifies SignalProtocolError at the cost of an extra heap
allocation for other errors. On its own, that probably isn't worth it,
but this lays groundwork for propagating exceptions / errors back up
in the native environment.
These still need to be exposed for the Java tests but they only
need to see the SessionRecord not the SessionState.
The internal functions still need to return a SessionState due to how
these functions are used within the crate.
In preparation for Desktop, which must asynchronously access its
database (rather than putting the entire operation on a background
thread with synchronization at the database layer).
The FFI and JNI wrappers (as well as the tests) use
futures::executor::block_on to turn the operations back into
synchronous ones.