README.md

# Univrse

![Univrse](https://github.com/libitx/univrse/raw/master/media/poster.png)

![Hex.pm](https://img.shields.io/hexpm/v/univrse?color=informational)
![License](https://img.shields.io/github/license/libitx/univrse?color=informational)
![Build Status](https://img.shields.io/github/workflow/status/libitx/univrse/Elixir%20CI)

A universal schema for serializing data objects, secured with signatures and
encryption.

* **Serialising data** - Simple, binary-friendly data exchange using the Concise Binary Object Representation (CBOR) data format.
* **Authenticating data** - Protect integrity of data with digital signatures or message authentication code (MAC) algorithms.
* **Securing data** - Ensure confidentiality and integrity of data for one or multiple recipients, using standardised authenticated encryption algorithms.

## Sponsors

<p align="center">Supported by:</p>
<p align="center">
  <a href="https://coingeek.com" target="_blank" rel="noopener noreferrer">
    <img src="https://www.chronoslabs.net/img/badges/coingeek.png" width="180" alt="Coingeek">
  </a>
</p>

Your sponsorship will help us continue to release and maintain software that Bitcoin businesses and developers depend on.

#### 👉 [Sponsor Chronos Labs' open source work](https://www.chronoslabs.net/sponsor/)

## Installation

The package can be installed by adding `univrse` to your list of dependencies
in `mix.exs`.

```elixir
def deps do
  [
    {:univrse, "~> 0.1"}
  ]
end
```

## Usage

For full documentation, please refer to:

* [univrse.network docs](https://univrse.network/docs)
* [univrse API docs](https://hexdocs.pm/univrse)

### 1. Serialising data

Any arbitrary payload can be wrapped in a `t:Univrse.Envelope.t/0` structure,
and then encoded in one of three serialisation formats, using
`Univrse.Envelope.encode/2` and `Univrse.Envelope.to_script/2`

* `:cbor` - Concise CBOR-encoded binary value
* `:base64` - Compact Base64-url encoded string value
* `:script` - Encoded in a Bitcoin `OP_RETURN` script

```elixir
# Wrap any arbitrary data payload in an Envelope structure
iex> payload = "Hello world!"
iex> env = Univrse.wrap(payload, %{proto: "univrse.demo"})

# Encode the data in one of three serialisation formats
iex> env_cbor = Univrse.encode(env, :cbor)
iex> env_base64 = Univrse.encode(env, :base64)
iex> env_script = Univrse.Envelope.to_script(env)

# Decode the serialised data back into an Envelope structure
iex> {:ok, env2} = Univrse.decode(env_cbor)
iex> {:ok, env3} = Univrse.decode(env_base64)
iex> {:ok, env4} = Univrse.Envelope.parse_script(env_script)

# Compare payload
iex> env2.payload == payload and env3.payload == payload and env4.payload == payload
true
```

### 2. Using signatures

Digital signatures or message authentication code (MAC) algorithms can be used
to protect the integrity of an Envelope's data payload.

```elixir
# Generate keys
iex> alice_key = Univrse.Key.generate_key({:ec, :secp256k1})
iex> alice_pubkey = Univrse.Key.to_public(alice_key)
iex> app_secret = Univrse.Key.generate_key({:oct, 256})

# Sign and verify using a single key
iex> {:ok, env1} = "Hello world!"
...> |> Univrse.wrap(%{proto: "univrse.demo"})
...> |> Univrse.sign(alice_key, %{"alg" => "ES256K", "kid" => "alice"})

iex> Univrse.verify(env1, alice_pubkey)
true

# Sign and verify using multiple keys and algorithms
iex> {:ok, env2} = "Hello world!"
...> |> Univrse.wrap(%{proto: "univrse.demo"})
...> |> Univrse.sign([
...>      {alice_key, %{"alg" => "ES256K", "kid" => "alice"}},
...>      {app_secret, %{"alg" => "HS256", "kid" => "app"}}
...> ])

iex> Univrse.verify(env2, [alice_pubkey, app_secret])
true
```

### 3. Using encryption

Authenticated encryption algorithms may be used to ensure the confidentiality
of an Envelope's data payload for one or multiple recipients.

```elixir
# Generate keys
iex> bob_key = Univrse.Key.generate_key({:ec, :secp256k1})
iex> bob_pubkey = Univrse.Key.to_public(bob_key)
iex> charlie_key = Univrse.Key.generate_key({:ec, :secp256k1})
iex> charlie_pubkey = Univrse.Key.to_public(charlie_key)
iex> app_secret = Univrse.Key.generate_key({:oct, 256})

# Encrypt and decrypt data for a single recipient
iex> {:ok, env1} = "Hello world!"
...> |> Univrse.wrap(%{proto: "univrse.demo"})
...> |> Univrse.encrypt(bob_pubkey, %{"alg" => "ECDH-ES+A128GCM", "kid" => "bob"})

iex> {:ok, env1} = Univrse.decrypt(env1, bob_key)
iex> env1.payload
"Hello world!"

# Encrypt and decrypt data for multiple recipients using multiple algorithms
iex> {:ok, env2} = "Hello world!"
...> |> Univrse.wrap(%{proto: "univrse.demo"})
...> |> Univrse.encrypt([
...>      {app_secret, %{"alg" => "A256GCM"}},
...>      {bob_pubkey, %{"alg" => "ECDH-ES+A128GCM", "kid" => "bob"}},
...>      {charlie_pubkey, %{"alg" => "ECDH-ES+A128GCM", "kid" => "charlie"}}
...> ])

iex> {:ok, bob_env} = Univrse.Envelope.decrypt_at(env2, 1, bob_key)
iex> bob_env.payload
"Hello world!"

iex> {:ok, charlie_env} = Univrse.Envelope.decrypt_at(env2, 2, charlie_key)
iex> charlie_env.payload
"Hello world!"
```

## License

Univrse is open source and released under the [Apache-2 License](https://github.com/libitx/univrse/blob/master/LICENSE).

Copyright (c) 2021 Chronos Labs Ltd.