zqlu 0.3.0

zqlu is a convenient text-based format for public keys
Documentation
# zqlu

zqlu is a text-based format for public keys designed to be efficient and convenient. 
A key looks something like this: `zq.luAAhI0TjjRFd5K5vfy4hig23m7bppmotzOLVIkwFnPMfVWDp`

Public key cryptography algorithms based on elliptic curves have many advantages, one of them
being small key sizes. However, that benefit is not fully taken advantage of using common
key encoding methods such as OpenSSH or PEM.

Features
* Compact representation
* Using only copy-and-paste friendly characters
* Relatively easy to visually confirm the format of a key
* A checksum is added, so a corrupted key can be detected

## Credits and prior art

The design of zqlu was influenced by the [nkey](https://github.com/nats-io/nkeys) format. Thank you
for the inspiration!

## Naming

I picked zqlu because I had the idea to use a very short domain name for the magic value
at the beginning of each key. It would be unique, and if you encounter a key somewhere without
context, you can use the first five bytes as a web address and get more information about the format.
It turned out that zq.lu was available for registration, so that determined the name.

## Format

zqlu is a text-based format that encodes keys into the upper and lower case alphanumeric characters, 
numbers 0 through 9, and the period character "." as defined in the Basic Latin chart in the Unicode 
standard.

Each key consists of three parts:

* The identifier string `zq.lu`
* The key type character
* The binary key data in a key-specific encoding, concatenated with a crc16 checksum and encoded 
  with Base62

Every key starts with the string `zq.lu` identifying the format. 

The next character holds information about the type of key, or "Key Algorithm" in using the 
terminology of the ssh specifications. The table below maps keys to their equivalent SSH key.

```
A   ssh-ed25519
B   ssh-rsa, 2048-bit modulus with exponent 65537
C   ecdsa-sha2-nistp256 with odd y value
D   ecdsa-sha2-nistp256 with even y value
E   ecdsa-sha2-nistp384 with odd y value
F   ecdsa-sha2-nistp384 with even y value
G   ecdsa-sha2-nistp521 with odd y value
H   ecdsa-sha2-nistp521 with even y value
I   ssh-rsa, 3072-bit modulus with exponent 65537
J   ssh-rsa, 4096-bit modulus with exponent 65537
K   ssh-rsa, exotic parameters
L-W reserved for future use
X   extended header
Y-Z reserved for future use
```

The different variations belonging to the ECDSA family of keys map to two different 
compressed y values as described in the elliptic curve point compression scheme 
in SEC 1 Section 2.3.3.

The RSA key types `B`, `I`, and `J` are compact encodings for common RSA public keys
using the Fermat F4 public exponent 65537, or `2**16 + 1`. Their key data is the
unsigned big-endian modulus encoded in exactly 256, 384, or 512 octets, respectively.
The fixed-length modulus MUST match the modulus size implied by the key type character.

The RSA key type `K` is reserved for RSA public keys that do not fit the compact
`B`, `I`, or `J` profiles. Its key data is a sequence of two length-value fields: the
public exponent followed by the modulus. Each value is encoded as an unsigned
big-endian integer using the minimum number of octets needed to represent it, with no
leading zero octets. Each length is encoded as an unsigned base-128 variable-length
integer: the low seven bits of each octet carry data, the high bit is set when another
length octet follows, and the least significant seven-bit group is encoded first. This
is the same integer representation used by Protocol Buffers varints.

The extended header value is a mechanism for future extensibility, where the value X indicates
that an extended header to be defined at a later date is prepended to the key data. 

### Checksum

The crd16 checksum is calculated over the first 6 characters of the key converted to bytes
using the US-ASCII character set, followed by the key bits. Once calculated, the checksum is
appended to the key data in network byte order. The specific algorithm we use is CRC-16/IBM-STLC 
as specified in RFC 1662, so the string `123456789` should produce the value `0x906e`

Please note that this checksum algorithm will work the same even for future 
versions of this format. 

### Base62 encoding

The alphabet used for base62 encoding the binary key data uses an alphabet containing the
numbers 0-9 followed by the upper case letters A-Z and lower case letters a-z.

When encoding binary data as Base62, the key data plus checksum is treated as a big-endian
integer. This means that leading zero bytes would normally be lost. To preserve them, each
leading zero byte is encoded as a leading `0` character in the Base62 output, followed by the
Base62 encoding of the remaining bytes.

This follows the same general approach as the [Base58 encoding draft](https://datatracker.ietf.org/doc/html/draft-msporny-base58),
which preserves leading zero bytes using a dedicated leading character. In Base58 that
character is `1`, because `1` is the zero-valued digit in the Bitcoin Base58 alphabet. In
zqlu Base62, the corresponding character is `0`, because the alphabet begins with `0`.

### White space

ASCII whitespace and newline characters are ignored in the key, which means that a key 
can be stored in a multiline string, or even indented to match some formatting if put 
in for example a YAML file.

## Rust usage

If you already parse SSH public keys with `ssh_key::PublicKey::from_openssh()`, the smallest
change is to switch those call sites to `zqlu::parse()`:

```rust
let public_key = zqlu::parse(input)?;
```

This returns `ssh_key::PublicKey` and accepts standard OpenSSH public key text, a `zqlu`
key, or a PEM/SPKI public key such as what OpenSSL emits from `openssl ec -pubout` or
`openssl pkey -pubout`.


## License

This project is licensed under either of:

- MIT
- Apache-2.0

at your option.