Rust Interface for the Stateless OpenPGP Interface
==================================================

A set of types and traits formalizing the [Stateless OpenPGP
Protocol].  Currently, SOP is only defined as a command line
interface, but we are working on a [C Interface].  This interface is
the Rust equivalent of the yet to be defined C API.

To use this as a consumer, you will need a concrete implementation of
the interface, such as [sequoia-sop].

[Stateless OpenPGP Protocol]: https://gitlab.com/dkg/openpgp-stateless-cli
[C Interface]: https://gitlab.com/dkg/openpgp-stateless-cli/-/issues/32
[sequoia-sop]: https://docs.rs/sequoia-sop

# Example use

Given a reference to a [`SOP`] implementation, which is the main
entry point for every SOP operation, generate keys, extract certs,
sign, verify, encrypt, and decrypt:

```rust
let alice_sec = sop.generate_key()?
    .userid("Alice Lovelace <alice@openpgp.example>")
    .generate()?;
let alice_pgp = sop.extract_cert()?
    .keys(&alice_sec)?;

let bob_sec = sop.generate_key()?
    .userid("Bob Babbage <bob@openpgp.example>")
    .generate()?;
let bob_pgp = sop.extract_cert()?
    .keys(&bob_sec)?;

let statement = b"Hello World :)";
let mut data = Cursor::new(&statement);
let (_micalg, signature) = sop.sign()?
    .mode(ops::SignAs::Text)
    .keys(&alice_sec)?
    .data(&mut data)?;

let verifications = sop.verify()?
    .certs(&alice_pgp)?
    .signatures(&signature)?
    .data(&mut Cursor::new(&statement))?;
assert_eq!(verifications.len(), 1);

let mut statement_cur = Cursor::new(&statement);
let (_session_key, ciphertext) = sop.encrypt()?
    .sign_with_keys(&alice_sec)?
    .with_certs(&bob_pgp)?
    .plaintext(&mut statement_cur)?
    .to_vec()?;

let mut ciphertext_cur = Cursor::new(&ciphertext);
let (_, plaintext) = sop.decrypt()?
    .with_keys(&bob_sec)?
    .ciphertext(&mut ciphertext_cur)?
    .to_vec()?;
assert_eq!(&plaintext, statement);
```

The above snippet is the equivalent of the following SOP command
line example from the SOP spec:

```sh
$ sop generate-key "Alice Lovelace <alice@openpgp.example>" > alice.sec
$ sop extract-cert < alice.sec > alice.pgp

$ sop sign --as=text alice.sec < statement.txt > statement.txt.asc
$ sop verify announcement.txt.asc alice.pgp < announcement.txt

$ sop encrypt --sign-with=alice.sec bob.pgp < msg.eml > encrypted.asc
$ sop decrypt alice.sec < ciphertext.asc > cleartext.out
```

# Notes for SOP implementers

This section is for those who implement the interface using some
OpenPGP implementation.

Command Line Interface
----------------------

This crate contains an implementation of the Stateless OpenPGP Command
Line Interface in terms of the Rust types and traits.  Once you
implemented the traits, you get the command line interface basically
for free by adding this snippet to your `Cargo.toml`:

```toml
[[bin]]
path = "src/main.rs"
required-features = ["cli"]

[[bin]]
path = "src/mainv.rs"
required-features = ["cliv"]

[features]
cli = ["sop/cli"]
cliv = ["sop/cliv"]
```

And creating `src/main.rs` and `src/mainv.rs` along the lines of:

```rust
fn main() {
    sop::cli::main(&MySOPImplementation::default());
}
```

Note: If you don't need to tweak your implementation for the
verification subset of SOP, you can also build both binaries from the
same source.

Note for packagers: Since features in Rust are additive, building both
binaries in one cargo invocation (i.e. `cargo build
--features=cli,cliv`) will enable the full SOP functionality in the
SOPV binary.  To avoid that, build both targets individually.
