docs.sigit.io/technical.md
zver 220ad4e5a5
All checks were successful
Release to Production / build_and_release (push) Successful in 27s
fix: stuff
2024-07-06 16:04:44 +01:00

103 lines
5.1 KiB
Markdown

# Document Signing
A proposal for signing documents in a secure and private way. Implemented by https://sigit.io
## Agreement
A signing round may occur for one or more documents, and involve one or more counterparties. This collection of documents, counterparties, and associated metadata constitutes a single "Agreement".
It is possible to complete an Agreement offline, or online without any external observer knowing that a counterparty was involved in an Agreement.
## Roles
When it comes to signing documents, the following roles (counterparties) are relevant:
* Creator - uploads the files, defines the remaining counterparties and signing order
* Signer - validates previous signatures and adds their own
* Viewer - has ability to view the Agreement
## Privacy
It should not be possible for observers to know the members or contents of an Agreement. This is achieved by using ephemeral keys for each counterparty, and encrypting all documents (before uploading to blossom) and metadata (before uploading to relays).
## Creation Process
The files themselves are zipped, and this `files.zip` file is then encrypted and uploaded to Blossom.
The Creator prepares an Agreement by creating and signing (but NOT publishing) a `Kind 938` event. The content field contains an object with the following information:
* `title` (string)
* `signers` (array) - list of npubs which can sign the Agreement
* `viewers` (array) - list of npubs which can view the Agreement
* `filehashes` (array) - series of objects containing the file name and file hash
* `zipUrl` (string) - the location of the encrypted zip file (blossom server)
* `markConfig` (object) - the template by which counterparties will make [Annotations](/#annotations) in any PDFs
This object is formed as follows:
```json
{
"signers":["npub1nqulz...","npub1d0csynr..."],
"viewers":["npub1viewr.."],
"fileHashes":[{
"name":"d51fe683-4c37-40b-b63c-d503387b0b75.png",
"hash":"8c4f41e76be536a4d6cc180cf1a6014fa0bacbb6cc5e7a1e12dde41f8f5158a8"
}],
"title": "our amazing agreement",
"zipUrl":"https://blossom.one/asdfafafaer23wsdf343fff4343fs"
}
```
Once the creator has signed, the `meta.json` file will contain the `createObject` (above) and a `keys` object that contains the decryption key for the zip file, NIP-44 encrypted to each counterparty.
```json
{
"createSignature": "{\n \"kind\": 938,\n \"content\": \"{\\\"signers\\\":[\\\"npub1d0csynr..\\\",\\\"npub1nqulz..\\\"],\\\"viewers\\\":[\\\"npub1viewr..\\\"]...}\",\n \"created_at\": 1716564780,\n \"tags\": [],\n \"pubkey\": \"6bf1024...\",\n \"id\": \"...\",\n \"sig\": \"...\"\n}",
"keys": {"npub1nqulz...":"ENCRYPTD","npub1d0csynr...":"ENCRYPTD","npub1viewr..":"ENCRYPTD"},
"docSignatures": {
}
}
```
This `meta.json` file is now sealed (using unsigned `Kind 938` to differentiate from DMs and speed up decryptions) and gift wrapped (with some PoW) per NIP-59, for each recipient, and the gift wrap is broadcast to each recipients relays.
`Kind 4 DMs` (from an ephemeral key) may optionally be broadcast, with a link to the signing application.
## Signing Process
Before signing, the client should first verify the signature from the create event, ensure the create event has a timestamp in the past, download / decrypt the `files.zip` from the `zipUrl`, and verify the hashes of each document.
A `Kind 938` event can now be signed that contains an object with the following attributes:
* `prevSig` (string) - the signature of the previous `Kind 938` event (mandatory)
* `marks` (object) - any pdf annotations, as described in the Annotations section
After signing, the `meta.json` can now be updated, eg as follows:
```json
{
"createSignature": "{\n \"kind\": 938,\n \"content\": \"{\\\"signers\\\":[\\\"npub1d0csynr..\\\",\\\"npub1nqulz..\\\"],\\\"viewers\\\":[\\\"npub1viewr..\\\"]...}\",\n \"created_at\": 1716564780,\n \"tags\": [],\n \"pubkey\": \"6bf1024...\",\n \"id\": \"...\",\n \"sig\": \"...\"\n}",
"keys": {"npub1nqulz...":"ENCRYPTD","npub1d0csynr...":"ENCRYPTD","npub1viewr..":"ENCRYPTD"},
"docSignatures": {
"npub1d0csynrrxcynkcedktdzrdj6gnras2psg48mf46kxjazs8skrjgq9uzhlq": "{\n \"kind\": 938,\n \"content\": \"{\\\"prevSig\\\":\\\"a76fdd0..",
"npub1nqulzcxcj0d2uesusstgupl5du8pa96xl6uy8xndweeckjkn964qjs23sn": "{\n \"kind\": 938,\n \"content\": \"{\\\"prevSig\\\":\\\"585c134.."
},
}
```
After each signature, this file is sealed using `Kind 938` and gift wrapped to each counterparty.
## Storing App Data
App data (list of all sigits) is stored as an encrypted file on Blossom. The file also contains a list of 'processed' `id`'s from `Kind 1059` events (to avoid having to continually decrypt when logging in, as well as enabling notifications).
A `Kind 30078` is also created, which contains a link to the blossom server, and an ephemeral key pair that can be used to sign the blossom requests. The user should be shown this `npub` so they can whitelist it on their blossom server.
NIP-78 requires a d-tag to provide some application context. To avoid revealing metadata, the d tag will be the first 32 chars of the encrypted result of the string "938" plus the users npub.