Compare commits

..

14 Commits
flow ... main

Author SHA1 Message Date
_
79b6a12e10 table
All checks were successful
Release to Production / build_and_release (push) Successful in 22s
2025-03-07 18:29:19 +00:00
_
d341e27591 fix: stuff
All checks were successful
Release to Production / build_and_release (push) Successful in 26s
2025-03-07 18:23:37 +00:00
_
27a557241d fix: warnings
All checks were successful
Release to Production / build_and_release (push) Successful in 23s
2025-03-07 18:21:33 +00:00
_
ce92669bc3 fix: sign flow
All checks were successful
Release to Production / build_and_release (push) Successful in 29s
2025-03-07 15:17:11 +00:00
_
5adfd853e7 chore: proof of code
All checks were successful
Release to Production / build_and_release (push) Successful in 23s
2025-03-07 14:57:38 +00:00
_
ecbcd9141f feat: docs
All checks were successful
Release to Production / build_and_release (push) Successful in 30s
2025-03-07 14:55:15 +00:00
_
30dcc722b1 fix: create
All checks were successful
Release to Production / build_and_release (push) Successful in 27s
2025-03-06 18:32:24 +00:00
_
32fbd5cddf typo
All checks were successful
Release to Production / build_and_release (push) Successful in 16s
2025-01-13 00:47:13 +00:00
_
ceb2425fe9 tidy up
All checks were successful
Release to Production / build_and_release (push) Successful in 17s
2025-01-13 00:46:49 +00:00
_
40fa68b587 comment about 21 chars
All checks were successful
Release to Production / build_and_release (push) Successful in 22s
2025-01-13 00:41:02 +00:00
_
e209cea19c removing entropy part as it didn't add anything
All checks were successful
Release to Production / build_and_release (push) Successful in 24s
2025-01-13 00:37:43 +00:00
_
f9be77ec7c updates
All checks were successful
Release to Production / build_and_release (push) Successful in 19s
2025-01-12 23:24:33 +00:00
_
ed7c15ab72 feat: email flow
All checks were successful
Release to Production / build_and_release (push) Successful in 24s
2025-01-12 22:48:06 +00:00
_
f9a197cbb7 fix: file types
All checks were successful
Release to Production / build_and_release (push) Successful in 19s
2024-12-24 14:37:17 +00:00
11 changed files with 495 additions and 18 deletions

View File

@ -2,4 +2,19 @@
SIGit is an open source, encrypted document signing tool. Users can Create, Sign and Verify documents individually or in groups. SIGit is an open source, encrypted document signing tool. Users can Create, Sign and Verify documents individually or in groups.
## Kind Numbers
The baseline for our kind numbers is 1603 - because [BIP-39 word 1603](https://github.com/bitcoin/bips/blob/master/bip-0039/english.txt#L1603) is "SIGN".
Kind numbers therefore as follows:
|Kind| Title|Signer|Storage|
|---|---|---|---|
|160300| Create event|creator|encrypted zip on blossom|
|160301|Keys event|ephemeral key|Relay|
|1603|Sign event| signer| encrypted zip on blossom
|14|chat event|unsigned|gitwrap event| on relay

View File

@ -1,6 +1,5 @@
- [Create](/create.md) * [Create Flow](/create.md)
- [Sign](/sign.md) * [Sign Flow](/sign.md)
- [Verify](/verify.md) * [Email Flow](/emailflow.md)
- [Offline Flow](/offline.md) * [Offline Flow](/offline.md)
- [Technical Notes](/technical.md) * [Technical Notes](/technical.md)
- [Techical Flow](/flow.md)

116
approach.md Normal file
View File

@ -0,0 +1,116 @@
# SIGit
## Flow
- Create Event
- Sign Event
- COMPLETE EVENT
---
sigit is made up of:
- pointers, notifications, components (events)
- files (encrypted blobs)
- all events are private (giftwrapped)
## Create Event Component - kind X1
Signer should display:
```
You are signing an Agreement template for the following npubs:
- npub1
- npub2
Ensure this event is sourced from a trusted SIGit instance.
```
- Signed by Creator
- NOT published by default
- fileData{}
- counterpartyData{}
- markData{}
This data is all stored inside the X1 blob
Verifications take place on all the elements in X2 (todo: list them)
---
## File pointer
Signer should say: "You are verifying that the following files exist:"
And list the full urls (blossom url + hash)
- signed by sender
- NOT PUBLISHED by default
- points to encrypted blossom blob (BB)
```json
{"content":"",
"kind": XX, --tbd
"tags"[
["filehash","$(hash)"],
["blossomUrls","url1","blossom2"], --optional
["engine": "SIGIT"]
]
}
```
---
## Encrypted Blob from XX
Contains:
- Create Event
- Files
- OTS?
## Creation flow
```mermaid
sequenceDiagram
autoNumber
actor u as Creator
participant s as SIGit Website
participant b as Blossom Server
participant r as Relay
u->>s: Signs NIP-98 <br> AUTH event
Note over s: Prepare SIGit <br> pack (docs, marks,<br>counterparties)
u->>s: Signs <br>CREATE event
Note over s: ZIP and ENCRYPT <br> SIGit pack
s->>b: Upload to Blossom
u->>s: Signs POINTER event
Note over s: Gift wrap pointer <br>+ decryption key
s->>r: <br>DM each counterparty
```
## Sign flow
```mermaid
sequenceDiagram
autoNumber
actor u as Signer
participant s as SIGit Website
participant b as Blossom Server
participant r as Relay
u->>s: Signs NIP-98 <br> AUTH event
r->>s: Fetch NIP-17 DMs
Note over s: Prepare SIGit <br> pack (docs, marks,<br>counterparties)
u->>s: Signs <br>CREATE event
Note over s: ZIP and ENCRYPT <br> SIGit pack
s->>b: Upload to Blossom
u->>s: Signs POINTER event
Note over s: Gift wrap pointer <br>+ decryption key
s->>r: <br>DM each counterparty
```

147
create.md
View File

@ -1 +1,148 @@
# Create # Create
## Nostr Event
This event is designed to provide clarity (when signing) about the agreement being created. It is NOT published to a relay - instead, it is saved in an encrypted zip.
```json
{
"kind": 160300,
"content": "You are creating an Agreement between the following npubs:\n- npub1\n- npub2\n\nEnsure this event is sourced from a trusted SIGit instance.",
"created_at": 1716564780,
"id": "...",
"sig": "...",
"pubkey": "pubkey of CREATOR",
"tags":[
["signers","npub1d0csynr..","npub1nqulz.."],
["viewers","npub1viewer1"], // optional tag, only if there are viewers
["files","hash1:name1.csv","hash2:name2.pdf"], // extension determines the file type. Order determines index.
["meta","hash1"] // the hash of the meta.json file
]
}
```
## Encrypted Zip File
This file contains the following:
- "files" folder - the unmarked files, using original filenames (to make them easy to open)
- "events" folder - contains the create Event and OTS request event
- meta.json file - contains the marks information
## Keys
The keys.json looks like this:
```json
{
"kind": 160301,
"content": "",
"created_at": 1716564780,
"id": "...",
"sig": "",
"pubkey": "random pubkey",
"tags":[
["filehash",<optional list of blossom servers>],
["array of decryption keys", "encrypted to each recipient"]
]
}
```
## Online Communication
Once the zip file is created, encrypted, and uploaded to the blossom server(s) - the decryption key and file location(s) must be sent to each counterparty. This is done using a regular NIP-17 Chat Message.
The rumor would be the same for all recipients:
```json
{
"id": "<usual hash>",
  "pubkey": "<sender-pubkey>",
"created_at": "<current-time>",
  "kind": 14,
  "tags": [
    ["p", "<receiver-1-pubkey>", "<relay-url>"],
    ["p", "<receiver-2-pubkey>", "<relay-url>"],
    ["e", "<kind-14-id>", "<relay-url>", "reply"] // if this is a reply
["subject", "<conversation-title>"],
    // by including tags from the kind 160301 we avoid an additional lookup in SIGit
["filehash",<optional list of blossom servers>],
["array of decryption keys", "encrypted to each recipient"]
  ],
  "content": "A new SIGit has been created - please visit your preferred instance or click https://sigit.io/find/$(idOfKind160301)",
}
```
## Online Flow
* Create & sign kind 160300
* Zip this along with files and meta.json
* Push zip to blossom
* Publish kind 160301 with decryption keys
* Send DM with link to above (manual flow) and keys (automatic flow)
```mermaid
sequenceDiagram
autoNumber
actor u as Creator
participant b as browser
participant r as Relay
participant bl as Blossom
u->>b: Upload files
u->>b: Define marks & <br>counterparties
u->>b: Sign Kind 160300
Note over b: 160300 + files <br>+ meta.json<br> = encrypted zip
b->>bl: Upload encrypted zip
Note over b: Create kind 160301 event<br>with ephemeral key
b->>r: publish 160301<br> to relay
Note over b: Create NIP-17 DM<br> with link to SIGit<br> & 160301 npub
u->>b: Sign NIP-17<br> notification / DM<br> for each receiver
b->>r: send DM to <br>each counterparty
```
## Offline Communication
For offline, the encrypted zip PLUS the Kind 160301 are zipped together and downloaded.
```mermaid
sequenceDiagram
autoNumber
actor u as Creator
participant b as browser
u->>b: Upload files
u->>b: Define marks & <br>counterparties
u->>b: Sign Kind 160300
Note over b: Encrypted Zip =<br>Kind 160300 <br>+ files <br>+ meta.json
Note over b: Kind 160301 = <br> decryption key<br>+ location
Note over b: Final Zip =<br> Encrypted Zip<br> + Kind 160301
b->>u: Download Zip
```

135
emailflow.md Normal file
View File

@ -0,0 +1,135 @@
# Email Flow
In creating an email flow that maintains PRIVACY and SECURITY whilst also being convenient to use, the following principles are observed:
- Keypair must be generated client-side
- Keypair must be protected by a strong password
- It must be possible to change the password
- It must be possible to work offline
- Network traffic must not contain identifying metadata
All of the above are achieved using a high level signup flow as follows:
1. User provides email and long (min 21 chars) password
2. These are used to encrypt a locally generated keypair
3. Email address, Public Key and encrypted backup are sent to the server
4. Email address is validated
5. Account is activated
The password is only used to encrypt/decrypt the local backup and is never stored or sent outside of the browser
When performing a regular login, the flow is:
1. Validate the email
2. Provide the encrypted keypair for the user to unlock
When performing a password reset:
1. Change the pasword locally
2. Re-encrypt the keypair using the new password
3. Send the new backup to the server
All key signing / encryption operations happen on client side using [private class properties](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_properties).
## SIGNUP FLOW
```mermaid
sequenceDiagram
autoNumber
actor U as SIGit User
participant W as SIGit Website
participant D as Server
Participant DB
Note over W,D: All comms encrypted with throwaway <br>(ephemeral) client keys and a <br>.well-known server key
U->>W: Click SIGNUP
U->>W: Provide Email and Complex Password
Note over W: Validate Email<br>Ensure Complex Password<br>(Min 21 chars)
Note right of U: User is warned that they CANNOT<br>RESET PASSWORD, should USE <br>PASSWORD MANAGER etc
Note over W: Nostr Keypair Generated <br> & Encrypted inside a <br> PRIVATE method,<br>with COMPLEX password.<br> Password variable is not <br>stored, sent or printed <br> anywhere. <br>Any sensitive variables <br>are immediately destroyed.
W->>D: Request account activation
Note right of W: Event uses PoW and<br> encrypts PUBKEY, EMAIL,<br> and the encrypted BACKUP<br> to the dvm@sigit.io pubkey<br> using the ephemeral key
Note over D: Verify PoW, <br>event.created_at,<br>event.id
D -x DB: Check if email exists
Note over D: If email already exists, and <br>user.last_seen <> null then <br>send user to LOGIN.<br><br>If email exists and last_seen<br> is null, then DELETE the <br>current entry.<br><br> Otherwise#58;
D->>DB: Create DB entries
Note over DB: USER insert#58;<br>#128274;user.id=uid()<br>user.pubkey=lowcase($PUBKEY)<br>user.email=lowcase($EMAIL)<br>user.last_seen=null<br>user.created_at=now()<br>user.bkp=$BACKUP
Note over DB: SESSION insert#58;<br>#128274;session.pubkey="ephemeral pubkey"<br>session.email_code=INT (6 digits)<br>session.user_id=user.id<br>session.created_at=now()
D->>U: Send session.email_code via email
D->>W: Account created
Note left of D: Payload is the user.id and/or<br> an encrypted (and detailed)<br> error message
Note over W: Verify DVM pubkey, <br> event.created_at,<br>event.id
W->>U: Tell user to check email and<br>to open it in the <br> SAME BROWSER SESSION
Note over W: Screen to accept the 6 digits <br> is already displayed<br>(mobile optimised if relevant)
U->>W: User opens link or enters the code
W->>D: Verify Account
Note right of W: Event uses PoW and <br>encrypts both user_id <br>and email_code<br> to DVM pubkey
D -x DB: Check email_code where <br>session pk=event pk
D->>DB: If email_code matches, <br>update USER table where<br> session.user_id=user.id
Note over DB: USER update#58;<br>user.last_seen=now()
D->>W: Account activated
Note left of D: Payload is an empty string or<br> an encrypted (and detailed)<br> error message
Note over W: Verify DVM pubkey, <br> event.created_at,<br>event.id
W->>U: User is automatically logged in
Note over W: Ephemeral key is destroyed<br>Default relay list is broadcast<br> using actual user pubkey
```
----
## Demo day proof of code
---
```
sequenceDiagram
autoNumber
actor U as SIGit User
participant W as SIGit Website
participant D as Server
Participant DB
Note over W,D: All comms encrypted with throwaway <br>(ephemeral) client keys and a <br>.well-known server key
U->>W: Click SIGNUP
U->>W: Provide Email and Complex Password
Note over W: Validate Email<br>Ensure Complex Password<br>(Min 21 chars)
Note right of U: User is warned that they CANNOT<br>RESET PASSWORD, should USE <br>PASSWORD MANAGER etc
Note over W: Nostr Keypair Generated <br> & Encrypted inside a <br> PRIVATE method,<br>with COMPLEX password.<br> Password variable is not <br>stored, sent or printed <br> anywhere. <br>Any sensitive variables <br>are immediately destroyed.
W->>D: Request account activation
Note right of W: Event uses PoW and<br> encrypts PUBKEY, EMAIL,<br> and the encrypted BACKUP<br> to the dvm@sigit.io pubkey<br> using the ephemeral key
Note over D: Verify PoW, <br>event.created_at,<br>event.id
D -x DB: Check if email exists
Note over D: If email already exists, and <br>user.last_seen <> null then <br>send user to LOGIN.<br><br>If email exists and last_seen<br> is null, then DELETE the <br>current entry.<br><br> Otherwise#58;
D->>DB: Create DB entries
Note over DB: USER insert#58;<br>#128274;user.id=uid()<br>user.pubkey=lowcase($PUBKEY)<br>user.email=lowcase($EMAIL)<br>user.last_seen=null<br>user.created_at=now()<br>user.bkp=$BACKUP
Note over DB: SESSION insert#58;<br>#128274;session.pubkey="ephemeral pubkey"<br>session.email_code=INT (6 digits)<br>session.user_id=user.id<br>session.created_at=now()
D->>U: Send session.email_code via email
D->>W: Account created
Note left of D: Payload is the user.id and/or<br> an encrypted (and detailed)<br> error message
Note over W: Verify DVM pubkey, <br> event.created_at,<br>event.id
W->>U: Tell user to check email and<br>to open it in the <br> SAME BROWSER SESSION
Note over W: Screen to accept the 6 digits <br> is already displayed<br>(mobile optimised if relevant)
U->>W: User opens link or enters the code
W->>D: Verify Account
Note right of W: Event uses PoW and <br>encrypts both user_id <br>and email_code<br> to DVM pubkey
D -x DB: Check email_code where <br>session pk=event pk
D->>DB: If email_code matches, <br>update USER table where<br> session.user_id=user.id
Note over DB: USER update#58;<br>user.last_seen=now()
D->>W: Account activated
Note left of D: Payload is an empty string or<br> an encrypted (and detailed)<br> error message
Note over W: Verify DVM pubkey, <br> event.created_at,<br>event.id
W->>U: User is automatically logged in
Note over W: Ephemeral key is destroyed<br>Default relay list is broadcast<br> using actual user pubkey
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 80 KiB

View File

@ -1,5 +0,0 @@
# Techical Flow (WIP)
Full sigit techical flow is visible on the diagram below:
![](static/sigit-flow.drawio.png)

View File

@ -15,9 +15,9 @@
<body> <body>
<nav> <nav>
<a href="#/Create">Create</a> <a href="#/create">Create</a>
<a href="#/Sign">Sign</a> <a href="#/sign">Sign</a>
<a href="#/Verify">Verify</a> <a href="#/verify">Verify</a>
</nav> </nav>
<div id="app">SIGit Documentation is loading...</div> <div id="app">SIGit Documentation is loading...</div>
<script> <script>
@ -45,7 +45,12 @@
--> -->
<script src="static/assets/js/docsify.js"></script> <script src="static/assets/js/docsify.js"></script>
<script src="static/assets/js/search.min.js"></script> <script src="static/assets/js/search.min.js"></script>
<script type="module">
import mermaid from "https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs";
mermaid.initialize({ startOnLoad: true });
window.mermaid = mermaid;
</script>
<script src="//unpkg.com/docsify-mermaid@2.0.1/dist/docsify-mermaid.js"></script>
</body> </body>
</html> </html>

54
sign.md
View File

@ -1 +1,55 @@
# Sign # Sign
SIGits can be signed in any order.
## Nostr Event
This event is designed to provide clarity (when signing) about the agreement being created. It is NOT published to a relay - instead, it is saved in an encrypted zip.
```json
{
"kind": 1603,
"content": "You are signing an Agreement Template for the following npubs:\n- npub1\n- npub2\n\nEnsure this event is sourced from a trusted SIGit instance.",
"created_at": 1716564780,
"id": "...",
"sig": "...",
"pubkey": "pubkey of SIGNER",
"tags":[
["prevsig","xxx"], // sig of kind 160300 (create) event
["meta","hash1"] // the hash of the meta.json file
]
}
```
## Encrypted Zip File
This file contains the following:
- "marked" folder (offline only) - containing marked pdfs
- "files" folder (offline only) - containing original pdfs
- "events" folder:
* Sign Event (1603)
* Create event (160300), for verification
* OTS request event
* OTS response event(s)
- meta.json file - contains the marks information
## Keys
The keys.json looks like this:
```json
{
"kind": 160301,
"content": "",
"created_at": 1716564780,
"id": "...",
"sig": "",
"pubkey": "random pubkey",
"tags":[
["filehash",<optional list of blossom servers>],
["array of decryption keys", "encrypted to each recipient"]
]
}
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 247 KiB

View File

@ -1,4 +1,5 @@
# DEPRECATED - NEW FLOW IN PROCESS
# WARNING - BREAKING CHANGES (v1 upcoming)
# Document Signing # Document Signing
A proposal for signing documents in a secure and private way. Implemented by https://sigit.io A proposal for signing documents in a secure and private way. Implemented by https://sigit.io
@ -100,3 +101,13 @@ A `Kind 30078` is also created, which contains a link to the blossom server, and
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. 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.
## File Types
All data is stored either on the relay(s) or on the blossome server(s). File types include the following:
* App Metadata Event - the kind 30078 (NIP-78) that lives on the relay
* App Data Object - the encrypted JSON file that lives on the blossom server
* Sigit Data Object - the encrypted meta.json file that lives on blossom
* Sigit Files Zip - the encrypted zip file with all the unchanged files, that lives on blossom
* Sigit Notification Event - the NIP-17 nostr event that lives on the relay