Right now the benefits of receiving GroupSendEndorsementsResponse
using member ciphertexts are balanced by the increased cost of
deserializing the full ciphertexts instead of just the part we need.
We can improve things here if needed, but for now let's just not claim
that the ciphertext approach is "significantly" better than the
alternative.
Previously we'd attempt to create a combination of zero endorsements
for the everybody-but-me credential, and panic (throw an error). Now
we correctly create an endorsement that represents zero people, which
is better than returning some dummy value because it behaves
reasonably if endorsements from multiple groups are combined wholesale
(not something we plan to do, but something that shouldn't have weird
edge cases if we end up needing to).
If apps want to cache these tokens, they should prefer to cache the
non-"full" version because it won't redundantly contain the
expiration, but if they don't, dealing with two token types is
unnecessary complexity.
Specifically, make this on the Rust side bridge layer, and tack it on
to the end of per-member endorsements for the app side to peel off
later, rather than the app layer calling back down to Rust to compute
it. This saves a fair amount of marshalling work.
...since we sometimes create them in bulk from data coming right out
of libsignal_jni, and for a large enough group the cost of that can be
significant. If data coming from libsignal_jni is wrong, we have
bigger problems! (And we'll also get AssertionErrors when the bad
endorsements used, saying they should have been validated ahead of
time. So it won't go completely unnoticed.)
Add a new version of the existing auth credential used for groups, but
implemented with the zkcredential crate instead of hand-written proofs. Expose
issuance point for the server, and extend existing client methods to support it
and the existing formats transparently.
Each of these updates is required for the following update, and the
final one allows us to use 'record'.
The target SDK version is set to 33, matching the Android app.
And use this to cut down CI testing time: only build armv7 and aarch64
slices of the real library, and x86_64 for the testing library (which
we don't even run in the every-commit CI, but we want to make sure we
haven't broken something in that configuration).
Add a flag to the CLI validation tool and an argument to the bridged validation
functions so users can specify whether a provided message backup should be
validated according to the rules for device-to-device transfers or backups
intended for remote storage.
Then, use FilterExceptions to filter out any exceptions that aren't
declared in the calling method's exception spec. Note that this isn't
perfect: Java's checks for typed exceptions prevents an *extra*
exception from being thrown this way, but it's still possible to
forget to *allow* an exception using FilterExceptions.
This is 99% a mechanical change; the interesting bit is in
gen_java_decl.py and one unusual pattern in NativeErrorsTest.java. No
exception specs were changed here.
These methods wrap any unexpected checked exceptions in AssertionError
after logging them. The next commit will use this to enforce our
exception specifications for methods that wrap JNI calls.
Use the class loader from the main thread to cache java.lang.Class
instances for some libsignal classes.
This enables constructing instances of libsignal classes on threads
where the classes aren't accessible via the default class loader. This
can occur on Android, where threads spawned via the native API only get
access to the system class loader, not the application loader that has
access to the application's class files. Since Tokio worker threads are
spawned via the native API, and the completion process for async tasks
converts results to Java objects, application class instances can't be
used there unless they are preloaded.
Since classes used in client code are only included in the client .jar
file, failure to load classes is a normal occurrence. If there are ever
separate builds for server and client .so library files, this could be
changed to a fatal error.
Run tests that call native TESTING_ functions on Android. This requires
building a separate version of libsignal_jni.so with the testing functions
included. The test code is still omitted from the published artifacts.
CDSI error handling code would attempt to instantiate a nonexistent Java class.
Add the missing class and split up the handling for CDSI lookup errors to reuse
existing error types.
Use the string bridging code introduced previously to provide string arrays to
client directly instead of joining and splitting. This eliminates the use of a
magic ',' character as a delimiter.
Re-raise errors produced by an input stream after bubbling them through Rust
code. This makes the interface less magic and avoids unnecessary
stringification of error values.
Use the GitHub CLI utility, if present, to fetch the size from the logs of the
"Build and Test" workflow run for the merge-base of the current branch and
upstream main. This represents the true "delta" attributable to the current
branch, as opposed to the integral of changes since the last release.
If a client already has the members of a group as ciphertexts, it's
more efficient to receive a GroupSendCredential that way, because then
they get to skip the conversion from ServiceId to UidStruct. If they
don't, however, the existing entry point is going to be both more
convenient and faster.
For Swift and Java, this is an overload of the existing receive()
method; for TypeScript, it's receiveWithCiphertexts.