Wow, these are (mostly) great responses, and exactly what I was looking for. Thank you! To call out a couple responses:
6, the ratchet protocol produces a hash of previous messages that provides for detection of dropped data, among many other things. pgp does not do this.
It feels like there are easier ways to detect dropped/tampered message, such as with an a simple accumulated hash of all past messages (or even a CBC mode). We do this with
https://bedrockdb.com/blockchain.html and it works great. However, I get your point that the double ratchet provides other benefits beyond just forward secrecy.
Decryption of destroyed messages is a big thing that signal deters. Journalists can get seriously physically injured when that happens.
Yes, I agree, it seems that forward secrecy is both 1) very valuable, 2) very hard to do, and 3) Signal's primary design goal.
Re Signal and Javascript, Signal offers its code in a signed binary, and offers the source to that binary for anybody to build and check.
Signal offers source, but given that it's distributing binaries via app stores, there's really no way to guarantee that the binary matches that source code. Open source is great (Expensify.cash is as well), but still requires that you trust the party giving you the binaries.
They [Signal] have an automated system that gives their donated money to people who contribute improvements.
Arguably the simplest method is to do what you describe [encrypting every message with the recipient's public key]. However, public-key crypto produces a shared-number of ~256-4096 bits. If the message is longer than this, these shared-secret bits must be "stretched" without revealing the secret. This is why (nearly all) public-key crypto systems are paired with some symmetric cipher.
I'd really love to learn more about this, as I think I almost understand it, but not quite. Can you elaborate on what you mean by "If the message is longer than this, these shared-secret bits must be "stretched" without revealing the secret."
I get that any encryption (symmetric or otherwise) works on blocks, so to encrypt anything larger than one block requires splitting the input up into many blocks. And I get that there are concerns with accidentally revealing information by encrypting the same exact block back to back (ie, it reveals "the same block appeared twice", without revealing the actual block content itself). (More on all that here:
https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Confidentiality_only_modes)
But I'm not quite understanding why you suggest that you couldn't just use a CBC strategy (where each block is derived from the block that preceded it) in conjunction with public key encryption to just encrypt every block with the recipient's public key, eliminating the need for the shared symmetric encryption key.
Now, understand the performance advantages of symmetric over asymmetric encryption, and certainly the convenience (and bandwidth) advantages of having multiple parties all use the same key (ie, to avoid re-encrypting the same message separately for each recipient). But I don't see any actual security advantage to introducing the symmetric key (and arguably a disadvantage given the increased complexity it adds).
Thanks for all these answers, I really appreciate them!
-david