diff --git a/.github/workflows/sync-repo.yml b/.github/workflows/sync-repo.yml new file mode 100644 index 0000000..6c2cdaf --- /dev/null +++ b/.github/workflows/sync-repo.yml @@ -0,0 +1,63 @@ +name: Sync main repo to deployed repo + +on: + push: + branches: [ main ] + +env: + ORIGINAL_REPO: github.com/DV-Lab/dvlab-document + DEPLOYED_REPO: github.com/tranhuyducseven/dvlab-document + USERNAME: tranhuyducseven + EMAIL: tranhuyducseven@gmail.com + +jobs: + sync: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + token: ${{ secrets.SUPER_TOKEN }} + - name: Clone repo + run : | + echo "Clone ${{ env.ORIGINAL_REPO }} && ${{ env.DEPLOYED_REPO }}" + git clone https://${{ secrets.SUPER_TOKEN }}@${{ env.ORIGINAL_REPO }}.git origin + git clone https://${{ secrets.SUPER_TOKEN }}@${{ env.DEPLOYED_REPO }}.git temp + + - name: Setup global config + run : | + + + - name: Copy files + run : | + echo "[LOG] Copying all origin files to temp" + + cp origin/**.**.js temp + cp origin/**.js temp + cp -r origin/blog temp + cp -r origin/docs temp + cp origin/package**.json temp + cp origin/README.md temp + cp -r origin/src temp + cp -r origin/static temp + cd temp + rm -rf .github + + - name: Push and commit + run : | + echo "[LOG] Setup global config" + git config --global user.email "${{ env.EMAIL }}" + git config --global user.name "${{ env.USERNAME }}-bot" + git remote set-url origin https://x-access-token:${{ secrets.SUPER_TOKEN }}@${{ env.DEPLOYED_REPO }} + cd temp + echo "[LOG] Git add and commit" + git add . + git commit -m "Synchronize from private repository - Triggered by Github Workflows" + echo "[LOG] Git push" + git push + + - name: Remove temp folder + run : | + rm -rf temp + rm -rf origin + ls -al + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..51ffe42 --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +# Dependencies +/node_modules + +# Production +/build + +# Generated files +.docusaurus +.cache-loader + +# Misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +.env \ No newline at end of file diff --git a/.obsidian/app.json b/.obsidian/app.json new file mode 100644 index 0000000..6abe4c1 --- /dev/null +++ b/.obsidian/app.json @@ -0,0 +1,3 @@ +{ + "alwaysUpdateLinks": true +} \ No newline at end of file diff --git a/.obsidian/appearance.json b/.obsidian/appearance.json new file mode 100644 index 0000000..21c46fc --- /dev/null +++ b/.obsidian/appearance.json @@ -0,0 +1,4 @@ +{ + "accentColor": "", + "theme": "moonstone" +} \ No newline at end of file diff --git a/.obsidian/core-plugins-migration.json b/.obsidian/core-plugins-migration.json new file mode 100644 index 0000000..5c13490 --- /dev/null +++ b/.obsidian/core-plugins-migration.json @@ -0,0 +1,29 @@ +{ + "file-explorer": true, + "global-search": true, + "switcher": true, + "graph": true, + "backlink": true, + "canvas": true, + "outgoing-link": true, + "tag-pane": true, + "page-preview": true, + "daily-notes": true, + "templates": true, + "note-composer": true, + "command-palette": true, + "slash-command": false, + "editor-status": true, + "bookmarks": true, + "markdown-importer": false, + "zk-prefixer": false, + "random-note": false, + "outline": true, + "word-count": true, + "slides": false, + "audio-recorder": false, + "workspaces": false, + "file-recovery": true, + "publish": false, + "sync": false +} \ No newline at end of file diff --git a/.obsidian/core-plugins.json b/.obsidian/core-plugins.json new file mode 100644 index 0000000..9405bfd --- /dev/null +++ b/.obsidian/core-plugins.json @@ -0,0 +1,20 @@ +[ + "file-explorer", + "global-search", + "switcher", + "graph", + "backlink", + "canvas", + "outgoing-link", + "tag-pane", + "page-preview", + "daily-notes", + "templates", + "note-composer", + "command-palette", + "editor-status", + "bookmarks", + "outline", + "word-count", + "file-recovery" +] \ No newline at end of file diff --git a/.obsidian/hotkeys.json b/.obsidian/hotkeys.json new file mode 100644 index 0000000..ab21988 --- /dev/null +++ b/.obsidian/hotkeys.json @@ -0,0 +1,66 @@ +{ + "workspace:goto-tab-1": [], + "workspace:goto-tab-2": [], + "workspace:goto-tab-3": [], + "workspace:goto-tab-4": [], + "workspace:goto-tab-5": [], + "workspace:goto-tab-6": [], + "workspace:goto-tab-7": [], + "workspace:goto-tab-8": [], + "editor:set-heading-1": [ + { + "modifiers": [ + "Mod" + ], + "key": "1" + } + ], + "editor:set-heading-2": [ + { + "modifiers": [ + "Mod" + ], + "key": "2" + } + ], + "editor:set-heading-3": [ + { + "modifiers": [ + "Mod" + ], + "key": "3" + } + ], + "editor:set-heading-4": [ + { + "modifiers": [ + "Mod" + ], + "key": "4" + } + ], + "editor:set-heading-5": [ + { + "modifiers": [ + "Mod" + ], + "key": "5" + } + ], + "editor:set-heading-6": [ + { + "modifiers": [ + "Mod" + ], + "key": "6" + } + ], + "editor:set-heading": [ + { + "modifiers": [ + "Mod" + ], + "key": "7" + } + ] +} \ No newline at end of file diff --git a/.obsidian/workspace.json b/.obsidian/workspace.json new file mode 100644 index 0000000..35313ff --- /dev/null +++ b/.obsidian/workspace.json @@ -0,0 +1,189 @@ +{ + "main": { + "id": "38abb5d6fb6f8fdc", + "type": "split", + "children": [ + { + "id": "8f981b92b8be1b75", + "type": "tabs", + "children": [ + { + "id": "e1a0919aa61aa36b", + "type": "leaf", + "state": { + "type": "empty", + "state": {} + } + } + ] + } + ], + "direction": "vertical" + }, + "left": { + "id": "768edfb3035fe433", + "type": "split", + "children": [ + { + "id": "c2a6e74d0d6b8ab0", + "type": "tabs", + "children": [ + { + "id": "8f47329d91681f09", + "type": "leaf", + "state": { + "type": "file-explorer", + "state": { + "sortOrder": "alphabetical" + } + } + }, + { + "id": "bc6969d17370cd4e", + "type": "leaf", + "state": { + "type": "search", + "state": { + "query": "", + "matchingCase": false, + "explainSearch": false, + "collapseAll": false, + "extraContext": false, + "sortOrder": "alphabetical" + } + } + }, + { + "id": "d859b0379d96f4f3", + "type": "leaf", + "state": { + "type": "bookmarks", + "state": {} + } + } + ] + } + ], + "direction": "horizontal", + "width": 300 + }, + "right": { + "id": "06cb587134c0ed4b", + "type": "split", + "children": [ + { + "id": "7f1dec20b2b93d3a", + "type": "tabs", + "children": [ + { + "id": "9304d6e4fca7e5b9", + "type": "leaf", + "state": { + "type": "backlink", + "state": { + "collapseAll": false, + "extraContext": false, + "sortOrder": "alphabetical", + "showSearch": false, + "searchQuery": "", + "backlinkCollapsed": false, + "unlinkedCollapsed": true + } + } + }, + { + "id": "0dfbb3aaf94e77d0", + "type": "leaf", + "state": { + "type": "outgoing-link", + "state": { + "linksCollapsed": false, + "unlinkedCollapsed": true + } + } + }, + { + "id": "923b66ed283092df", + "type": "leaf", + "state": { + "type": "tag", + "state": { + "sortOrder": "frequency", + "useHierarchy": true + } + } + }, + { + "id": "81d37de9f64c2fb9", + "type": "leaf", + "state": { + "type": "outline", + "state": {} + } + } + ] + } + ], + "direction": "horizontal", + "width": 300, + "collapsed": true + }, + "left-ribbon": { + "hiddenItems": { + "switcher:Open quick switcher": false, + "graph:Open graph view": false, + "canvas:Create new canvas": false, + "daily-notes:Open today's daily note": false, + "templates:Insert template": false, + "command-palette:Open command palette": false + } + }, + "active": "e1a0919aa61aa36b", + "lastOpenFiles": [ + "docs/overview.md", + "docs/cryptography-core/zksnark.png", + "docs/cryptography-core/zk.md", + "docs/cryptography-core/public_key.md", + "docs/cryptography-core/_category_.json", + "docs/cryptography-core/UC.png", + "docs/cryptography-core", + "docs/architecture/ZUNI-architecture.png", + "docs/architecture/vc.png", + "docs/architecture/solana.jpeg", + "docs/architecture/_category_.json", + "docs/architecture/4.solana blockchain.md", + "docs/architecture/3.system.md", + "docs/architecture/2.vc.md", + "docs/architecture/1.did.md", + "docs/literature_review/zkps-and-zk-snarks.md", + "docs/literature_review/introduction.md", + "docs/literature_review/decentralized-indentiy-and-dids.md", + "docs/literature_review/blockchain.md", + "docs/literature_review/_category_.json", + "docs/literature_review", + "docs/overview.md", + "docs/architecture/index.md", + "docs/architecture/3.solana blockchain.md", + "docs/architecture/3.system copy.md", + "docs/architecture/2.vc copy.md", + "docs/architecture/did copy.md", + "docs/architecture/did.md", + "docs/architecture/zksnark.png", + "docs/architecture/UC.png", + "docs/architecture", + "docs/architecture_asdf/zkps-and-zk-snarks.md", + "docs/architecture_asdf/introduction.md", + "docs/architecture_asdf/decentralized-indentiy-and-dids.md", + "docs/architecture_asdf/blockchain.md", + "docs/architecture_asdf/_category_.json", + "docs/architecture_asdf", + "docs/architecture_/_category_.json", + "docs/architecture/zkps-and-zk-snarks.md", + "docs/architecture/introduction.md", + "docs/architecture/decentralized-indentiy-and-dids.md", + "docs/architecture_/ZUNI-architecture.png", + "docs/architecture_/zksnark.png", + "docs/architecture_/vc.png", + "docs/architecture_" + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..aaba2fa --- /dev/null +++ b/README.md @@ -0,0 +1,41 @@ +# Website + +This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator. + +### Installation + +``` +$ yarn +``` + +### Local Development + +``` +$ yarn start +``` + +This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. + +### Build + +``` +$ yarn build +``` + +This command generates static content into the `build` directory and can be served using any static contents hosting service. + +### Deployment + +Using SSH: + +``` +$ USE_SSH=true yarn deploy +``` + +Not using SSH: + +``` +$ GIT_USER= yarn deploy +``` + +If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 0000000..e00595d --- /dev/null +++ b/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + presets: [require.resolve('@docusaurus/core/lib/babel/preset')], +}; diff --git a/blog/authors.yml b/blog/authors.yml new file mode 100644 index 0000000..1a33a10 --- /dev/null +++ b/blog/authors.yml @@ -0,0 +1,5 @@ +tranhuyducsven: + name: Tran Huy Duc + title: Blockchain developer + url: https://github.com/tranhuyducseven + image_url: https://github.com/tranhuyducseven.png diff --git a/blog/hello.md b/blog/hello.md new file mode 100644 index 0000000..2cc1e13 --- /dev/null +++ b/blog/hello.md @@ -0,0 +1,12 @@ +--- +slug: first-blog-post +title: Hello world +authors: + name: Tran Huy Duc + title: Blockchain developer + url: https://github.com/tranhuyducseven + image_url: https://github.com/tranhuyducseven.png +tags: [blockchain developer] +--- + +Hello world diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000..3148cd7 Binary files /dev/null and b/bun.lockb differ diff --git a/docs/architecture/1.did.md b/docs/architecture/1.did.md new file mode 100644 index 0000000..fce4def --- /dev/null +++ b/docs/architecture/1.did.md @@ -0,0 +1,19 @@ +--- +sidebar_position: 1 +--- + +# Decentralized Identifiers (DID) + +A **Decentralized Identifier (DID)** is a unique identifier that enables self-sovereign identity and allows individuals or entities to have control over their digital identity. In our ZUNI system, DIDs play a crucial role in establishing trust and enabling secure interactions between different stakeholders. Here's an overview of the key concepts related to DIDs: + +- **DID Subject**: Each entity within the system must create a Solana wallet (account) and associate it with a DID. The DID subject refers to the entity that possesses the DID. It represents a specific individual or entity within the system. Each DID Subject use one or multiple key pairs to create and manage DID. One DID Subject could creates multiple DIDs. + +- **DID Controller**: The DID controller is the entity authorized to make changes to the DID document associated with a particular DID subject. By default, the DID controller is set to the DID subject's wallet address within the Solana blockchain. + +- **Also Known As**: This property allows the DID subject to refer to other identifiers associated with their digital identity. These identifiers can be other DIDs or various types of URIs, such as a website or social media profile. + +- **Verification Methods**: Verification methods are used to authenticate and authorize interactions with the DID subject. They establish the trustworthiness of the subject's identity. Here verification methods refers to public keys of each DID used for different purposes below: + + - **Authentication**: The authentication property defines the methods or verification processes used to verify the subject's identity, enabling secure access to systems or services. + - **Assertion**: The assertion property allows the DID subject to express claims or statements. When verifying a Verifiable Credential (VC), the verifier can check if the signature satisfies the assertion methods defined by the issuer. This ensures that the VC's content is authentic and trustworthy. + - **Key Agreement**: Key agreement methods define how (which key pairs) entities can generate encryption material to securely transmit confidential information to the DID subject. This property enables secure communication and data exchange between stakeholders. diff --git a/docs/architecture/2.vc.md b/docs/architecture/2.vc.md new file mode 100644 index 0000000..a6ad833 --- /dev/null +++ b/docs/architecture/2.vc.md @@ -0,0 +1,16 @@ +--- +sidebar_position: 2 +--- + +# Verifiable Credentials (VCs) + +![vc.png](./vc.png) +Verifiable Credentials (VCs) are the core component of the ZUNI platform, enabling secure and trustworthy sharing and verification of information. VCs provide a standardized format based on W3C standard for expressing claims or statements about individuals or entities, allowing them to present and prove their credentials digitally, without losing privacy. Here's an overview of Verifiable Credentials and their key elements: + +- Each VC is issued, held, presented and verified by DIDs in the system. +- **Credential Content**: The content of a Verifiable Credential includes claims or statements about the holder's attributes, achievements, or qualifications, ... +- **Credential Metadata**: Metadata provides additional information about the Verifiable Credential itself, such as the issuer, issuance date, expiration date, and other relevant contextual information. This metadata enhances the trustworthiness and context of the credential, enabling verifiers to make informed decisions during the verification process. +- **Digital Signatures**: Verifiable Credentials are digitally signed by the issuer using cryptographic algorithms to ensure the integrity and authenticity of the credentials and it can be easily verified. Also, the content is private by default and no one except issuer and holder could open it. +- **Selective Disclosure**: Selective disclosure refers to the capability of the holder to present specific information from their VCs to verifiers. It enables privacy-preserving interactions by allowing the holder to share only the necessary information required for a specific verification request. The zero-knowledge proof cryptography utilized by ZUNI ensures that sensitive personal data is not disclosed during the verification process. + +By utilizing Verifiable Credentials within the ZUNI platform, organizations can issue tamper-resistant, digitally signed credentials that holders can securely manage and present for verification. This framework enhances data integrity, privacy, and trust between issuers, holders, and verifiers, enabling efficient and reliable credential verification processes. diff --git a/docs/architecture/3.system.md b/docs/architecture/3.system.md new file mode 100644 index 0000000..ad78324 --- /dev/null +++ b/docs/architecture/3.system.md @@ -0,0 +1,25 @@ +--- +sidebar_position: 3 +--- + +# System flow + +![ZUNI arch](./zuni-architecture.png) +As illustrated in figure above, the ZUNI incorporates several roles and components as further explained below: + +- The architecture diagram for verifying electronic certificates using ZKP and DID involves three main entities: issuers, verifiers, and holders. Additionally, a Verifiable Credentials Repository (VCR) is included in the architecture to handle tasks such as creating Solana wallets, registering DIDs, storing and anchoring the hash of issued VCs on the blockchain, and verifying identities and VC validity. + +- Every participant in the Zuni system must have at least one DID, which serves as a unique identifier for managing individual identities and their resources in the decentralized world. A person/organization can have multiple DIDs for different purposes, for example: education, entertainment, ... but all of these DIDs can refer to a private identity if the identity have credentials to prove that. + +- Issuers play a pivotal role in generating VCs and issuing them to relevant parties **(see 1a arrow)**. By default, the content of VCs is hidden from the public, ensuring visibility only to the issuer and the holder. This level of privacy is achieved through the use of public key encryption methods. Each e-certificate is associated with a unique DID, registered in the Verifiable Credential Registry. Furthermore, issuers store and anchor the hash of the issued VCs to facilitate efficient management and potential revocation if required **(see 1b arrow)**. + +- To indirectly prove that holders possess specific claims without revealing all the details of the verifiable credential, Zero-Knowledge cryptography schemes are employed. These schemes utilize a claim from a verifiable credential to derive a presented value, which is cryptographically asserted in such a way that verifiers can trust the value if they trust the issuer. The presented value represents the information that the verifier seeks to verify, along with certain public fields of the VC that enhance the verifier's confidence in the presentation of the VC **(see 2 arrow)**. These verification details are included in a **verification schema** which is built by the verifier and sent to the holders for them to submit their credentials. + +- For authentication, holders must provide comprehensive certificate information, submitted to the ZK engine as raw (decrypted) data. The ZK engine then utilizes this data to generate a Zero-Knowledge proof **(see arrow 3)**, providing evidence that the certificate is signed by the issuer without revealing any details about the signature or original data. Holders can then send the claim to the verifier **(see arrow 4)**, including the Zero-Knowledge proof and the specific information they intend to reveal (e.g., name and other non-sensitive fields). Finally, the verifier can verify the correctness of the claim using snark-based utility **(see arrow 5)**. Optionally, the verifier may choose to store verified VCs within their own database or on a decentralized platform. + +- Each participants can choose some set of DIDs in the network that they trust to efficiently filter out the irrelevant submissions to their verification schemas, for example: the goverment, world organizations, celebrities, ... We call this **trusted DID**. These trusted DIDs can form a web of trust system. + +- For efficiency, VCs are created based on **credential templates**. These templates can be created and used by anyone to issue credentials to others. There are some templates that can be the standard templates for popular credential types, such as KYC credential template, Driving license credential template, ... This template mechanism can help verifiers to easily pick the fields to set conditions and requirements. + - Also, we are forming a new concept of **template inheritance**, in which people could extends standard templates (common standards) to build their own custom templates, which is really useful in case some issuers want to have some custom fields but still comply with the common standards. This also help VC verification process more general and a verification schema can specify the common standard to verify common fields, no matter what exactly templates are used on VCs of submitters. + +- The Zuni system also implements the Trustless Relayer, supporting data storage and transfer between entities and processes within the system. The Trustless Relayer ensures that all private data is protected by cryptography protocols before being sent to or through it, preserving data privacy and preventing interference. Moreover, the Trustless Relayer enhances data availability and removes censorship by leveraging public decentralized data storage alternatives. \ No newline at end of file diff --git a/docs/architecture/4.solana blockchain.md b/docs/architecture/4.solana blockchain.md new file mode 100644 index 0000000..8ec1d3b --- /dev/null +++ b/docs/architecture/4.solana blockchain.md @@ -0,0 +1,17 @@ +--- +sidebar_position: 4 +--- + +# Solana Blockchain + +In the ZUNI system, each entity is required to create a Solana wallet (account) as a foundational component for their digital identity. The Solana wallet serves as the core account for managing decentralized identities (DIDs) and interacting with the Solana blockchain. Here's an overview of the Solana wallet's role within the system: + +
+ solana +
+ +- **Solana Wallet Creation**: Each entity must create a Solana wallet (account) to participate in the ZUNI system. ZUNI mobile supports this wallet creation seamlessly. The Solana wallet provides the necessary infrastructure for managing digital identities, issuing and holding verifiable credentials (VCs), and interacting with other stakeholders. +- Each time an entity perform an actions, others must use DID information stored on Solana blockchain to check the signatures on the data and verify their identity. The keys of DIDs are used to encrypt and decrypt data transfered between entities. +- **Verifiable Data Registry**: The Solana blockchain serves as the decentralized platform for storing verifiable data within the ZUNI system including DIDs and VC anchors, metadata, ... + +By utilizing the Solana blockchain and Solana wallets, ZUNI provides a secure and decentralized infrastructure for managing decentralized identities (DIDs), issuing and holding verifiable credentials (VCs), and facilitating trusted interactions between stakeholders in the system. \ No newline at end of file diff --git a/docs/architecture/UC.png b/docs/architecture/UC.png new file mode 100644 index 0000000..91d501a Binary files /dev/null and b/docs/architecture/UC.png differ diff --git a/docs/architecture/_category_.json b/docs/architecture/_category_.json new file mode 100644 index 0000000..6a701e1 --- /dev/null +++ b/docs/architecture/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "Architecture", + "position": 2, + "link": { + "type": "generated-index", + "description": "Welcome to the Architecture category page! 5 minutes to learn the most important ZUNI concepts." + } +} diff --git a/docs/architecture/vc.png b/docs/architecture/vc.png new file mode 100644 index 0000000..ba4d9ac Binary files /dev/null and b/docs/architecture/vc.png differ diff --git a/docs/architecture/zksnark.png b/docs/architecture/zksnark.png new file mode 100644 index 0000000..443a95e Binary files /dev/null and b/docs/architecture/zksnark.png differ diff --git a/docs/architecture/zuni-architecture.png b/docs/architecture/zuni-architecture.png new file mode 100644 index 0000000..e86c53a Binary files /dev/null and b/docs/architecture/zuni-architecture.png differ diff --git a/docs/cryptography-core/UC.png b/docs/cryptography-core/UC.png new file mode 100644 index 0000000..91d501a Binary files /dev/null and b/docs/cryptography-core/UC.png differ diff --git a/docs/cryptography-core/_category_.json b/docs/cryptography-core/_category_.json new file mode 100644 index 0000000..a40af8d --- /dev/null +++ b/docs/cryptography-core/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "Cryptography core", + "position": 2, + "link": { + "type": "generated-index", + "description": "5 minutes to learn the most important ZUNI cryptography core concepts." + } +} diff --git a/docs/cryptography-core/public_key.md b/docs/cryptography-core/public_key.md new file mode 100644 index 0000000..34400ac --- /dev/null +++ b/docs/cryptography-core/public_key.md @@ -0,0 +1,144 @@ +--- +sidebar_position: 1 +--- +# Public key cryptography + +We use mainly the curve secp256k1 for public-key cryptography, including digital signature and encryption. Here we present a simpler version of our cryptography protocol, the real protocol is quite similar but has some more fields to supports fully private proof verification. + +## 1. Credential format + +- A credential issued by an issuer must consist of the below fields: + - Public fields that would be revealed to the public and sent through the unsecured channel + - "issuer": issuer's DID + - "holder": holder's DID + - "type": an array of types of the credentials, e.g. ["RelationshipCredential", "Uni- + versityDegreeCredential"] + - "issuanceDate": the date that issue VC, format by ISO 8601 + - "expirationDate" (optional field): the date that VC expired format by ISO 8601 + - "encryptedData": encrypted private fields’ data using holder’s public key + - "signatureProof": The signature signed by the issuer, not ZK proof + - "type": "RsaSignature2018"/"EcdsaSecp256k1Signature2019"/..., + - "created": ISO 8601 date format + - "verificationMethod": verification method, corresponding to the signature sheme + - "proofPurpose": "assertionMethod"/"authentication"/..., + - "value": "pYw8XNi1..Cky6Ed=", **proof = sign(issuer, holder, public fields above)** + - "id": SHA256 hash of proof + - Private fields (only issuer and holder knows): + - "credentialSubject": a json containing content of the credential => all these private fields are encrypted under the field **encryptedData** +- Example: + +```json +{ + "id": "ebfeb1f712ebc6f1c276e12ec21klj23h4o937842iuwlehasdf", + "type": [ "UniversityDegreeCredential" ], + "issuer": "did:solana:17A3AAB832349DA...", + "holder": "did:solana:9DEf34AB8349DA...", + "issuanceDate": "2010-01-01T19:23:24Z", + "expirationDate": "2020-01-01T19:23:24Z", + "credentialSubject": { + "degree": { + "type": "BachelorDegree", + "name": "Bachelor of Science and Arts", + }, + "department": "FIT", + "class" : 2024 + }, + "encryptedData": "asdfnlaksh2l34hqq32987roaidshalskjdaslkdjf239862o34" + "proof": { + "type": "Ed25519Signature2020", + "created": "2022-02-25T14:58:43Z", + "verificationMethod": "Ed25519SignatureVerification2020", + "proofPurpose": "assertionMethod", + "proofValue": "z3zwi434j3HdZv3C3TJxBnwmmiBgrtzRjM2oeDtZyAEkDeNDBeB9Metc +vyB4ZZUvQswKqPdgk5cFSAnyJ3yjvButH" + } +} +``` + +## 2. User flow + +### 2.1 Issuer issues a credential + +- Step 1: Issuer fill credential's content +- Step 2: Issuer encrypt private fields with public key of holder to create a new field "encryptedData" + - **encryptedData = ECCEncryption(holder's public key)** // ECC + Diffie-Hellman method +- Step 3: Generate signature & id + - **proof = sign(signature_method, issuer, holder, encryptedData)** + - **id = sha256(proof.value)** +- Step 4: Send the credential (only public fields) to holder -> holder stores credential in local storage +- Step 5: Call the smart contract to create an anchor to the credential + + ```js + - credentials[id] = { + - issuer: askdfhlaksdf + - holder: lakhewjlkajsdfhasdf + - status: issued/revoked/disputed/... + } + ``` + +### 2.2 Verifier creates a schema + +Verifier chooses a schema template (e.g. UniversityDegreeCredentialSchema) or creates a new schema and then send to the holder or publish this schema to standardized process for VC verification. +The schema should be constructed with the format below: + +- "verifier": verifier's DID +- "checks": an array of check, each check corresponds to one specific credential, +which means a schema can be used to asserts multiple credentials. Each check in the array is a JSON object can be presented as below: + + ```js + : [, ] | + : (*) + + + : a comparison operator ($GT, $GTE, $LE, $LTE, $EQ, $NE), would scale to arbitrary expression later + + : the value of check + + : formatted as same as - which is a recursive check for sub fields of the current value + + (*): represent equality, (ongoing feature, we aim to build this like in ORM frameworks) + + ``` + +- "requests": ["index_of_credential_in_checks_field.requestField1", "index_of_credential_in_checks_field.requestField2", ...] => request holder to shows these fields + +- Example: + +```json +{ + "verifier": "did:solana:17AB8349DA...", + "checks":[ + { + "type": ["$EQ$", "UniversityDegreeCredential"] + "degree" : { + "type": ["$EQ", "BachelorDegree"], // based on the global standard + "name": ["$EQ", "Bachelor of Science and Arts"] + }, + "class": ["$GTE", 2023] // only allows guys graduate this year to apply into the job + }, + { + "type": ["$EQ", "NationalIdentificationCredential"] + "country": ["$EQ", "US"], + "nationality": ["$EQ", "US"], + "dateOfBirth": ["GTE", "2000-01-01T00:00:00Z"], // only allows guys born in 21'st century + } + ], + "requests": ["0.schoolName", "1.name"] // get name & school name +} +``` + +### 2.3 Holder submits credentials to a schema + +- Step 1: After getting the schema from the verifier, the holder chooses corresponding credentials that satisfy the checks and requests +- Step 2: Holder generates & encrypt the requested fields (using verifier public key) into **encryptedRequestedData** (**encryptedRequestedData = ECCEncrypt(verifier_pubic_key, requestedData))** +- Step 3: Holder generate ZK proof: **proof = generateProof(rawCredentials[], public rawSchema, public requestedData)** + - This function do the below checks: + - Check if credentials satisfy the schema + - Check if requestedData is the requested fields specified in rawSchema and taken from rawCredentials +- Step 4: Holder sends ZK proof + encryptedRequestedData to the verifier through public channel or in-secure private channel (like BE) + - **schema_submissions[schema_id][proof] = true/false** (true means the proof passes the verifier checks) +- Step 5 (Optional) : Holder submit an anchor of the proof to the verifying smart contract. + +### 2.4 Verifier verifies submission + +- Step 1: Verifier decrypt the requestedData: **requestedData = ECCDecrypt(verifier_private_key, encryptedRequestedData)** + +- Step 2: Verifier run the check: + - Verifier verifies ZK proof: **verify(proof, rawSchema, requestedData)** + - If the check passes, the verifier updates the status of this submission to diff --git a/docs/cryptography-core/zk.md b/docs/cryptography-core/zk.md new file mode 100644 index 0000000..903bd37 --- /dev/null +++ b/docs/cryptography-core/zk.md @@ -0,0 +1,80 @@ +--- +sidebar_position: 2 +--- +# ZK Core Protocol + +## Problem + +The challenge here is, we want to enable holder to submit VCs that satisfy checks and share the requested fields based on what are specified in the verification schema. The point is if we don't share the private fields, how can we prove that the fields satisfy checks? + +## Solution + +We did some thorough experiments and came up with a simple idea: Each credentials and verification schemas consist of single fields. We need to prove multiple comparisons of the form (credential_field_value, operator, schema_single_field_check_value). When generating a ZK proof, holder can supply these raw data into ZK engine and it will execute the comparison to check if the supplied credentials satisfy the schema. + +To ensure that holder supplies correct values (not omit or forge the schema checks), each VC and each schema has their own published field index list. The idea is: we give each field in a JSON object a distinct index, and then we put all these indexes into a Spare Merkle Tree to store the unique proof of inclusion of all the fields. Each VC and verification schema has their own field index SMT. The holder must supply the SMT roots into the ZK engine as public inputs. The verifier then just supply exact same roots of VCs and schema to verify the proof. This helps ensure the fields provided by holders are not faked ones and they satisfy all the single field checks in the schema. The issuers publish the SMT for the VCs they issue and the verifiers publish the SMT for the schemas they create. + +```typescript +export enum ProofPurpose { + ASSERTION = 'ASSERTION', + AUTHENTICATION = 'AUTHENTICATION', +} +export interface DataSignature { + type: string; + created: string; + proofPurpose: ProofPurpose; + value: string; + verificationMethod: string; +} +export interface FieldIndexInterface { + fieldName: string; + fieldIndex: number; +} +export interface CredentialInterface { + id: string; + types: string[]; + issuer: string; + issuerPublicKey: string; + holderPublicKey: string; + holder: string; + issuanceDate: string; + expirationDate?: string; + fieldIndexes: Array; + fieldMerkleRoot: string; + credentialSubject?: any; + encryptedData: string; + signatureProof: DataSignature

; +} +export interface SchemaInterface{ + id: string; + name: string; + verifier: string; + credentialChecks: Array>; + requestedFields: string[]; + signatureProof: DataSignature

; + issuanceDate: string; + verifierPublicKey: string; +} +``` + +In this manner, the verifier does not need to pass the raw values of credentials, SMT roots are enough, so the holder can hide the raw data of the credentials. + +In out previous experiments, we put multiple credentials and schemas into a single proof, but in this project, we build a new method to generate and verify proofs more efficiently: which is to build proof of single field checks separately, so we could generate proofs of single field validations concurrently, which boosts the speed of proof generation and verification. + +Here is the example public parameters of our circuits, there is no raw data of credentials needed, only the SMT roots is shared to the verifier: +```c++ +component main {public [credentialRoot, schemaCheckRoot, credentialFieldIndex, schemaCheckFieldIndex, schemaCheckFieldOperation ]} = VCFieldVerifier(4, 6); +``` +## Some benchmarks + +Currently, in the deployed version, we only support limited number of fields: +- Each credential should not have more than 32 fields to be safe +- Each schema can have unlimited credential check but each credential check should have no more than 32 field constraints to be safe +- The number of ZK constraints generated (for a single field validation) is around 16k which is small enough. Proof generation time is about 2 - 5 seconds and verification time is 1s. This is quite a good number that we have achieved. +- Our app allows holders to generate proof of credentials right on the mobile app (React Native). Actually the circom library does not work well on React Native since the ffjs library relies heavily on Wasm and it does not work on RN. We decided to use Webview to gen proof instead, this is good enough in terms of performance and UX. + +## Some problems and future goals + +- Experiment with some more lightweight primitives other than SMT to increase the number of fields supported and to boost the proof generation time down to less than 2s. The final goal is instant proof generation, maybe ZK is not the final solution to achieve that. +- Explore some delegated proof generation/verification approach. +- Building "Sign in with DID/VC" feature to replace traditional Oauth methods which lack of privacy and data-ownership for users. +- Since our DID and VC solution rely on blockchain and the data is spread across multiple platforms, we are aiming to build a general solution to help users to use DID and VC on every platforms, even on the internet without spending much time to learn about each platform. This for sure needs a lot of research and time to construct that form of general solution but we believe it is still possible using proofs of VCs/DIDs or proofs of data ownership. \ No newline at end of file diff --git a/docs/cryptography-core/zksnark.png b/docs/cryptography-core/zksnark.png new file mode 100644 index 0000000..443a95e Binary files /dev/null and b/docs/cryptography-core/zksnark.png differ diff --git a/docs/overview.md b/docs/overview.md new file mode 100644 index 0000000..3c01a1a --- /dev/null +++ b/docs/overview.md @@ -0,0 +1,37 @@ +--- +sidebar_position: 1 +--- + +# Overview + +**ZUNI** is an online platform that revolutionizes the issuance, submission, and verification of credentials in a decentralized manner using Blockchain, Zero-knowledge Proof Cryptography, and Decentralized Identity (DID). + +## Problem statement + +The traditional methods of issuing, submitting, and verifying credentials often involve manual processes, centralized authorities, and paper-based documents. This approach presents several challenges and limitations: + +1. **Forgery and Fraud:** Paper-based credentials are vulnerable to forgery and fraud, as they can be easily tampered with or replicated. +2. **Centralization:** Centralized authorities are responsible for managing and storing credentials, which can lead to a single point of failure, data breaches, or unauthorized access. +3. **Inefficiency:** Manual verification processes can be time-consuming, cumbersome, and prone to errors. They may require individuals to physically present their credentials, leading to inconvenience and delays. +4. **Lack of Privacy:** Traditional methods often require individuals to disclose sensitive personal information during the verification process, which can raise privacy concerns. + +## Our Solution + +**ZUNI** addresses these challenges by leveraging the following technologies: + +1. **Blockchain:** **ZUNI** utilizes a decentralized blockchain network to store credentials securely. The blockchain's immutability and tamper-resistant properties ensure the integrity of issued credentials, making them highly reliable and resistant to forgery. +2. **Zero-knowledge Proof Cryptography:** **ZUNI** employs zero-knowledge proof cryptography to enable credential verification without revealing sensitive information. With this approach, the platform allows a holder to prove the validity of a credential to a verifier without disclosing any additional personal data except for what are required, hence preserving the privacy of the individual. + +## Why ZUNI is better? + +1. **Security and Trust:** By leveraging blockchain technology, ZUNI enhances the security and trustworthiness of credentials. The decentralized nature of the blockchain ensures that credentials cannot be tampered with or manipulated, providing a robust and reliable system for verification. +2. **Data Privacy:** Zero-knowledge proof cryptography enables ZUNI to verify credentials without the need to disclose unnecessary personal information. This approach ensures that individuals can maintain their privacy while still proving the authenticity of their credentials. +3. **Efficiency and Convenience:** ZUNI streamlines the issuance and verification processes by eliminating the need for physical document handling. Individuals can issue and submit credentials online, reducing the time and effort required for verification. +4. **Digital Transformation:** ZUNI represents a significant step towards digitizing and modernizing the credentialing process. By adopting blockchain and zero-knowledge proof cryptography, ZUNI contributes to the digital transformation of various industries, such as education, healthcare, and finance. + +Overall, ZUNI's innovative use of blockchain and zero-knowledge proof cryptography addresses the limitations of traditional credentialing methods. It offers enhanced security, data privacy, efficiency, and contributes to the ongoing digital transformation of various sectors. + +## Getting Started + +- [Architecture](./category/architecture) +- [Cryptography core](./category/cryptography-core) diff --git a/docusaurus.config.js b/docusaurus.config.js new file mode 100644 index 0000000..3747ff4 --- /dev/null +++ b/docusaurus.config.js @@ -0,0 +1,148 @@ +// @ts-check +// Note: type annotations allow type checking and IDEs autocompletion + +const lightCodeTheme = require("prism-react-renderer/themes/github"); +const darkCodeTheme = require("prism-react-renderer/themes/dracula"); + +require("dotenv").config(); + +/** @type {import('@docusaurus/types').Config} */ +const config = { + // Environment variables + customFields: { + SUPABASE_API: process.env.SUPABASE_API, + SUPABASE_PUBLIC_KEY: process.env.SUPABASE_PUBLIC_KEY, + BASE_URL: process.env.BASE_URL, + USERS: process.env.USERS + }, + + title: "DV Lab", + tagline: "Building innovative privacy-preserving solutions for the decentralized world 🔎", + favicon: "/img/logo-circle.png", + + // Set the production url of your site here + url: "https://dvlab-document.vercel.app/", + // Set the // pathname under which your site is served + // For GitHub pages deployment, it is often '//' + baseUrl: "/", + + // GitHub pages deployment config. + // If you aren't using GitHub pages, you don't need these. + organizationName: "dvlab", // Usually your GitHub org/user name. + projectName: "document", // Usually your repo name. + + onBrokenLinks: "throw", + onBrokenMarkdownLinks: "warn", + + // Even if you don't use internalization, you can use this field to set useful + // metadata like html lang. For example, if your site is Chinese, you may want + // to replace "en" with "zh-Hans". + i18n: { + defaultLocale: "en", + locales: ["en"], + }, + + presets: [ + [ + "classic", + /** @type {import('@docusaurus/preset-classic').Options} */ + ({ + docs: { + sidebarPath: require.resolve("./sidebars.js"), + // Please change this to your repo. + // Remove this to remove the "edit this page" links. + editUrl: "https://github.com/DV-Lab/dvlab-document", + }, + blog: { + showReadingTime: true, + // Please change this to your repo. + // Remove this to remove the "edit this page" links. + editUrl: "https://github.com/DV-Lab/dvlab-document", + }, + theme: { + customCss: require.resolve("./src/css/custom.css"), + }, + }), + ], + ], + + themeConfig: + /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ + ({ + // Replace with your project's social card + image: "img/thumbnail.png", + navbar: { + title: "DV Laboratory", + logo: { + alt: "DV Laboratory", + src: "img/dv-lab-logo.png", + }, + items: [ + { + type: "docSidebar", + sidebarId: "tutorialSidebar", + position: "left", + label: "ZUNI", + }, + { to: "/blog", label: "Blog", position: "left" }, + { + href: "https://github.com/DV-Lab", + label: "GitHub", + position: "right", + }, + ], + }, + footer: { + style: "dark", + links: [ + { + title: "🌟 Highlight projects", + items: [ + { + label: "ZUNI", + to: "/docs/overview", + }, + ], + }, + { + title: "Contact", + items: [ + { + label: "Twitter @tranhuyducseven", + href: "https://twitter.com/tranhuyducseven", + }, + { + label: "Discord", + href: "https://discord.gg/ZA4QrA85", + }, + { + label: "Email dv.vn.labs@gmail.com", + href: "mailto:dv.vn.labs@gmail.com", + }, + ], + }, + { + title: "More", + items: [ + { + label: "Blog", + to: "/blog", + }, + { + label: "GitHub", + href: "https://github.com/DV-Lab", + }, + ], + }, + ], + copyright: `Copyright © ${new Date().getFullYear()} + DV Laboratory.`, + }, + prism: { + theme: lightCodeTheme, + darkTheme: darkCodeTheme, + }, + }), +}; + +module.exports = config; diff --git a/package.json b/package.json new file mode 100644 index 0000000..be7cde7 --- /dev/null +++ b/package.json @@ -0,0 +1,47 @@ +{ + "name": "dvlabs-document", + "version": "0.0.0", + "private": true, + "scripts": { + "docusaurus": "docusaurus", + "start": "docusaurus start", + "build": "docusaurus build", + "swizzle": "docusaurus swizzle", + "deploy": "docusaurus deploy", + "clear": "docusaurus clear", + "serve": "docusaurus serve", + "write-translations": "docusaurus write-translations", + "write-heading-ids": "docusaurus write-heading-ids" + }, + "dependencies": { + "@docusaurus/core": "2.4.1", + "@docusaurus/preset-classic": "2.4.1", + "@mdx-js/react": "^1.6.22", + "@supabase/supabase-js": "^2.25.0", + "clsx": "^1.2.1", + "prism-react-renderer": "^1.3.5", + "react": "^17.0.2", + "react-dom": "^17.0.2", + "react-markdown": "^8.0.7", + "remark-gfm": "^3.0.1" + }, + "devDependencies": { + "@docusaurus/module-type-aliases": "2.4.1", + "dotenv": "^16.3.1" + }, + "browserslist": { + "production": [ + ">0.5%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "engines": { + "node": ">=16.14" + } +} diff --git a/sidebars.js b/sidebars.js new file mode 100644 index 0000000..9ab54c2 --- /dev/null +++ b/sidebars.js @@ -0,0 +1,33 @@ +/** + * Creating a sidebar enables you to: + - create an ordered group of docs + - render a sidebar for each doc of that group + - provide next/previous navigation + + The sidebars can be generated from the filesystem, or explicitly defined here. + + Create as many sidebars as you want. + */ + +// @ts-check + +/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ +const sidebars = { + // By default, Docusaurus generates a sidebar from the docs folder structure + tutorialSidebar: [{type: 'autogenerated', dirName: '.'}], + + // But you can create a sidebar manually + /* + tutorialSidebar: [ + 'intro', + 'hello', + { + type: 'category', + label: 'Tutorial', + items: ['tutorial-basics/create-a-document'], + }, + ], + */ +}; + +module.exports = sidebars; diff --git a/src/components/AuthenticationHOC.jsx b/src/components/AuthenticationHOC.jsx new file mode 100644 index 0000000..e265478 --- /dev/null +++ b/src/components/AuthenticationHOC.jsx @@ -0,0 +1,128 @@ +import { useHistory } from "@docusaurus/router"; +import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; +import { createClient } from "@supabase/supabase-js"; +import React, { useCallback, useEffect, useState } from "react"; + +export function AuthenticationHOC({ children }) { + const { siteConfig } = useDocusaurusContext(); + const supabase = createClient( + siteConfig.customFields.SUPABASE_API, + siteConfig.customFields.SUPABASE_PUBLIC_KEY + ); + const history = useHistory(); + const [user, setUser] = useState(null); + const [check, setCheck] = useState(false); + const app = siteConfig.customFields.SUPABASE_API.split("//")[1].split(".")[0]; + useEffect(() => { + async function fetchUser() { + const appData = localStorage.getItem(`sb-${app}-auth-token`); + const accessToken = JSON.parse(appData)?.access_token; + if (accessToken) { + const { + error, + data: { user }, + } = await supabase.auth.getUser(accessToken); + if (error) { + alert("Please sign in!"); + return; + } + setUser(user); + } + } + + fetchUser(); + }, [setUser]); + + async function signInWithGithub() { + const { error } = await supabase.auth.signInWithOAuth({ + provider: "github", + options: { + redirectTo: `${siteConfig.customFields.BASE_URL}/improvement`, + }, + }); + + if (error) { + alert(error.message); + return; + } + } + const preCheck = useCallback(() => { + if (user) { + if ( + siteConfig.customFields.USERS.toString() + .split(",") + .includes(user.identities[0].identity_data.user_name) + ) { + setCheck(true); + history.replace("/improvement"); + return; + } + setCheck(false); + } + }, [setCheck, user, siteConfig]); + + useEffect(() => { + preCheck(); + }, [preCheck]); + if (!user) { + return ( +

+

Hello, please sign in!

+ +
+ ); + } + + return ( +
+ {check &&
{children}
} + {!check && ( +
+

You do not have right to access

+
+ )} +
+ ); +} diff --git a/src/components/HomepageFeatures/index.jsx b/src/components/HomepageFeatures/index.jsx new file mode 100644 index 0000000..a4cda28 --- /dev/null +++ b/src/components/HomepageFeatures/index.jsx @@ -0,0 +1,30 @@ +import React, { useEffect, useState } from "react"; +import styles from "./styles.module.css"; +import ReactMarkdown from "react-markdown"; +import remarkGfm from "remark-gfm"; + +export default function HomepageFeatures() { + const [dvLab, setDvLab] = useState(""); + + useEffect(() => { + async function fetchDvLab() { + try { + const response = await fetch("markdown/dv-lab.md"); + const content = await response.text(); + setDvLab(content); + } catch (error) { + console.error("Error fetching dvLab content:", error); + } + } + + fetchDvLab(); + }, []); + + return ( +
+
+ +
+
+ ); +} diff --git a/src/components/HomepageFeatures/styles.module.css b/src/components/HomepageFeatures/styles.module.css new file mode 100644 index 0000000..b248eb2 --- /dev/null +++ b/src/components/HomepageFeatures/styles.module.css @@ -0,0 +1,11 @@ +.features { + display: flex; + align-items: center; + padding: 2rem 0; + width: 100%; +} + +.featureSvg { + height: 200px; + width: 200px; +} diff --git a/src/css/custom.css b/src/css/custom.css new file mode 100644 index 0000000..96863cd --- /dev/null +++ b/src/css/custom.css @@ -0,0 +1,49 @@ +/** + * Any CSS included here will be global. The classic template + * bundles Infima by default. Infima is a CSS framework designed to + * work well for content-centric websites. + */ + +/* You can override the default Infima variables here. */ +:root { + --ifm-color-primary: #0d9488; + --ifm-color-primary-dark: #0d9488; + --ifm-color-primary-darker: #0d9488; + --ifm-color-primary-darkest: #0d9488; + --ifm-color-primary-light: #14b8a6; + --ifm-color-primary-lighter: #14b8a6; + --ifm-color-primary-lightest: #14b8a6; + --ifm-code-font-size: 95%; + --ifm-col-max-width: 100%!important; + --ifm-col-width: 100%!important; + --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); +} + +/* For readability concerns, you should choose a lighter palette in dark mode. */ +[data-theme='dark'] { + --ifm-color-primary: #25c2a0; + --ifm-color-primary-dark: #21af90; + --ifm-color-primary-darker: #1fa588; + --ifm-color-primary-darkest: #1a8870; + --ifm-color-primary-light: #29d5b0; + --ifm-color-primary-lighter: #32d8b4; + --ifm-color-primary-lightest: #4fddbf; + --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); +} + +/* .row > .col { + max-width: 80%!important; +} */ +/* .row > .docItemCol_node_modules-\@docusaurus-theme-classic-lib-theme-DocItem-Layout-styles-module{ + padding: 0; + margin: 0; + width: 100%; + margin-left: 0; + margin-right: 0; + margin-top: 0; + margin-bottom: 0; + padding-left: 0; + padding-right: 0; + padding-top: 0; + padding-bottom: 0; +} */ \ No newline at end of file diff --git a/src/pages/improvement/index.md b/src/pages/improvement/index.md new file mode 100644 index 0000000..d181ba3 --- /dev/null +++ b/src/pages/improvement/index.md @@ -0,0 +1,208 @@ +--- +title: Future directions +--- +[16/06/2023] + +## Not store VC in IPFS + +Privacy considerations -> Lost proofs +Hard to implement +Fee +Distributed system + +## Deep dive ZKP and [DID](https://www.w3.org/TR/did-core/#architecture-overview) + +## ZUNI UI on Solana + +1. Mobile (Main) + - Create new wallet/ Backup wallet (Sign up/Sign in) **using DID** + - Main screens: (4 icon on bottom bar) + - Credentials: + - Show detail + - DIDs (1 DID by default) + - QR + - Verification: (For only verifier) + - Show verification templates + - Show QR + - Show a list of verified applications of each form + - Verify Screens: Only showing when scanning **verifier QR.** + - Choose credential + - Choose field ⇒ actually the field is automatically ticked because the verifier specified it when creating the form + - Verification Status + - Sign in with DID Screen: Only showing when scanning **sign-in** **QR**. + - Form: Choose DID & authorize + - Popup form to confirm & sign txs when: + - issuer issues credentials + +2. Web (Support) + - Sign in with DID + - Show QR code + - Main Screens: (4 icon on sidebar) + - Detail info for DID (Create Public Credential on Blockchain) + - Register (Not exist) + - Show info (Existed) + - Create & **manage** credentials (For issuer) + - Create verification form from templates (For verifier) + - Add trusted DIDs (For verifier) + +## Change flows + +### 1. Credential format + +- A credential issued by an issuer must consist of the below fields: + - public fields => the fields that would be revealed to the public and sent through the unsecured channel + - "issuer": issuer's public key + - "holder": holder's public key + - "id": SHA256 hash of proof + - "@context": // in the first stage, there is no need to use this + - "**encryptedData**": encrypted private fields' data using holder's public key + - "proof": The signature signed by the issuer, not ZK proof + - "type": "RsaSignature2018"/"EcdsaSecp256k1Signature2019"/..., + - "created": ISO_date, + - "proofPurpose": "assertionMethod"/"authentication"/..., + - "value": "pYw8XNi1..Cky6Ed=", + - **proof = sign(issuer, holder, encryptedData)** + - "verificationMethod": verification method, corresponding to the signature sheme + - private fields: + - "type": an array of types of the credentials, e.g. ["RelationshipCredential", "UniversityDegreeCredential"] + - "issuanceDate": ISO date format, + - "expirationDate" : ISO date format, or not included if this field is ignored + - "credentialSubject": a json containing content of the credential + - => all these private fields are encrypted under the field: "encryptedData" +- Example: + + ```json + { + "id": "ebfeb1f712ebc6f1c276e12ec21klj23h4o937842iuwlehasdf", + "type": [ "UniversityDegreeCredential" ], + "issuer": "732oi4uh2klj34bb879wfgasiudasdf", + "holder": "bklajsdfh78236jhbasdkfj23897123", + "issuanceDate": "2010-01-01T19:23:24Z", + "expirationDate": "2020-01-01T19:23:24Z", + "credentialSubject": { + "degree": { + "type": "BachelorDegree", + "name": "Bachelor of Science and Arts", + }, + "department": "FIT", + "class" : 2024 + }, + "encryptedData": "asdfnlaksh2l34hqq32987roaidshalskjdaslkdjf239862o34" + "proof": { + "type": "Ed25519Signature2020", + "created": "2022-02-25T14:58:43Z", + "verificationMethod": "Ed25519SignatureVerification2020", + "proofPurpose": "assertionMethod", + "proofValue": "z3zwi434j3HdZv3C3TJxBnwmmiBgrtzRjM2oeDtZyAEkDeNDBeB9Metc + vyB4ZZUvQswKqPdgk5cFSAnyJ3yjvButH" + } + } + ``` + +### 2. User solana + +#### 2.1 Issuer issues a credential + +- Step 1: Issuer fill credential's content +- Step 2: Issuer encrypt private fields with public key of holder to create a new field "encryptedData" + - **encryptedData = ECCEncryption(holder's public key)** // ECC + Diffie-Hellman method +- Step 3: Generate signature & id + - **proof.value = sign(signature_method, issuer, holder, encryptedData)** + - **id = sha256(proof.value)** +- Step 4: Send the credential (only public fields) to holder -> holder stores credential in local storage +- Step 5: Call the smart contract to create an anchor to the credential + + ```ts + credentials[id]: { + issuer: string; + holder: string; + status: enum; + } = { + issuer: askdfhlaksdf + holder: lakhewjlkajsdfhasdf + status: issued/revoked/disputed/... + } + ``` + +#### 2.2 Verifier creates a schema + +- Verifier chooses a schema template (e.g. UniversityDegreeCredentialSchema) or creates a new schema and then send to the holder/publish this schema. The schema should be constructed with the format below: + + - "name": "Computer Science University Degree Check" + - "verifier": verifier's public key + - "checks": an array [] of check, each check corresponds to one specific credential, which means a schema can be used to asserts multiple credentials + - each check in the array is a json: + - "field": + - "operator" : value + - **operator** is a comparison operator (gt, gte, le, lte, eq) => would scale to arbitrary expression later + - "sub_field": { ... similar pattern } + - or just use "field": "value" to represent equality + - **the field "type" is a must-have check** + - "requests": ["index_of_credential_in_checks_field.requestField1", "index_of_credential_in_checks_field.requestField2", ...] => request holder to shows these fields + - "proof": The signature signed by the verifier, not ZK proof + - "type": "RsaSignature2018"/"EcdsaSecp256k1Signature2019"/..., + - "created": ISO_date, + - "proofPurpose": "assertionMethod"/"authentication"/..., + - "value": "pYw8XNi1..Cky6Ed=", + - **proof = sign(name, verifier, checks, requests)** using verifier's private key + - "verificationMethod": verification method, corresponding to the signature scheme + - **id = sha256(proof.value)** +- Example: + + ```json + { + "name": "Computer Science University Degree Check", + "verifier": "asdnfklj234o123498ssdfasdjfagsdf", + "checks":[ + { + "type": { + "eq" : "UniversityDegreeCredential" + }, + "degree" : { + "type": "BachelorDegree", // based on the global standard + "name": "Bachelor of Science and Arts" + }, + "class": { + "gte": "2023" // only allows guys graduate this year to apply into the job + } + }, + { + "type": { + "eq" : "NationalIdentificationCredential" + }, + "country": "VI", + "nationality": "VI", + "dateOfBirth": { + "gte": "2000-01-01T00:00:00Z", // only allows Vietnamse guys born in 21'st century + } + } + ], + "requests": ["0.schoolName", "1.name"] // get name & school name + } + ``` + +#### 2.3 Holder submits credentials to a schema + +- Step 1: After getting the schema from the verifier, the holder chooses corresponding credentials that satisfy the checks and requests +- Step 2: Holder generates & encrypt the requested fields (using verifier public key) into **encryptedRequestedData** (**encryptedRequestedData = ECCEncrypt(verifier_pubic_key, requestedData))** +- Step 3: Holder generate ZK proof: **proof = generateProof(rawCredentials[], public rawSchema, public requestedData)** + - This function do the below checks: + - Check if credentials satisfy the schema + - Check if requestedData is the requested fields specified in rawSchema and taken from rawCredentials +- Step 4: Holder sends proof + encryptedRequestedData to the verifier through public channel or in-secure private channel (like BE) + +- (Optional) Step 5: Holder submit an anchor of the proof to the verifier smart contract: + - **schema_submissions\[schema_id\]\[proof\] = true/false** (true means the proof passes the verifier checks) + +#### 2.4 Verifier verifies submission + +- Step 1: Verifier decrypt the requestedData: **requestedData = ECCDecrypt(verifier_private_key, encryptedRequestedData)** +- Step 2: Verifier run the check: + - verifier verifies proof: **verify(proof, rawSchema, requestedData)** + - if the check passes, the verifier updates the status of this submission to holder + +## Design new UI (contact designer) + +## Currently, writing ZK circuit for dynamic data using Rust + +## Current issues ??? diff --git a/src/pages/index.jsx b/src/pages/index.jsx new file mode 100644 index 0000000..27e1657 --- /dev/null +++ b/src/pages/index.jsx @@ -0,0 +1,41 @@ +import Link from "@docusaurus/Link"; +import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; +import HomepageFeatures from "@site/src/components/HomepageFeatures"; +import Layout from "@theme/Layout"; +import clsx from "clsx"; +import React from "react"; + +import styles from "./index.module.css"; + +function HomepageHeader() { + const { siteConfig } = useDocusaurusContext(); + return ( +
+
+

{siteConfig.title}

+

{siteConfig.tagline}

+
+ + ZUNI - Pioneering decentralized ID and verifiable credential system 🚀 + +
+
+
+ ); +} + +export default function Home() { + const { siteConfig } = useDocusaurusContext(); + + return ( + + +
+ +
+
+ ); +} diff --git a/src/pages/index.module.css b/src/pages/index.module.css new file mode 100644 index 0000000..9f71a5d --- /dev/null +++ b/src/pages/index.module.css @@ -0,0 +1,23 @@ +/** + * CSS files with the .module.css suffix will be treated as CSS modules + * and scoped locally. + */ + +.heroBanner { + padding: 4rem 0; + text-align: center; + position: relative; + overflow: hidden; +} + +@media screen and (max-width: 996px) { + .heroBanner { + padding: 2rem; + } +} + +.buttons { + display: flex; + align-items: center; + justify-content: center; +} diff --git a/src/theme/MDXPage/index.jsx b/src/theme/MDXPage/index.jsx new file mode 100644 index 0000000..41eb1e9 --- /dev/null +++ b/src/theme/MDXPage/index.jsx @@ -0,0 +1,13 @@ +import React from "react"; +import MDXPage from "@theme-original/MDXPage"; +import { AuthenticationHOC } from "../../components/AuthenticationHOC"; + +export default function MDXPageWrapper(props) { + return ( + <> + + + + + ); +} diff --git a/static/.nojekyll b/static/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/static/favicon.ico b/static/favicon.ico new file mode 100644 index 0000000..c01d54b Binary files /dev/null and b/static/favicon.ico differ diff --git a/static/img/docusaurus-social-card.jpg b/static/img/docusaurus-social-card.jpg new file mode 100644 index 0000000..ffcb448 Binary files /dev/null and b/static/img/docusaurus-social-card.jpg differ diff --git a/static/img/docusaurus.png b/static/img/docusaurus.png new file mode 100644 index 0000000..f458149 Binary files /dev/null and b/static/img/docusaurus.png differ diff --git a/static/img/dv-lab-logo.png b/static/img/dv-lab-logo.png new file mode 100644 index 0000000..9e421ad Binary files /dev/null and b/static/img/dv-lab-logo.png differ diff --git a/static/img/logo-circle.png b/static/img/logo-circle.png new file mode 100644 index 0000000..bd670d9 Binary files /dev/null and b/static/img/logo-circle.png differ diff --git a/static/img/logo-square.png b/static/img/logo-square.png new file mode 100644 index 0000000..4aa20a7 Binary files /dev/null and b/static/img/logo-square.png differ diff --git a/static/img/logo.svg b/static/img/logo.svg new file mode 100644 index 0000000..9db6d0d --- /dev/null +++ b/static/img/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/img/solana.jpeg b/static/img/solana.jpeg new file mode 100644 index 0000000..94c3a2b Binary files /dev/null and b/static/img/solana.jpeg differ diff --git a/static/img/thumbnail.png b/static/img/thumbnail.png new file mode 100644 index 0000000..d102eb6 Binary files /dev/null and b/static/img/thumbnail.png differ diff --git a/static/img/undraw_docusaurus_mountain.svg b/static/img/undraw_docusaurus_mountain.svg new file mode 100644 index 0000000..af961c4 --- /dev/null +++ b/static/img/undraw_docusaurus_mountain.svg @@ -0,0 +1,171 @@ + + Easy to Use + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/static/img/undraw_docusaurus_react.svg b/static/img/undraw_docusaurus_react.svg new file mode 100644 index 0000000..94b5cf0 --- /dev/null +++ b/static/img/undraw_docusaurus_react.svg @@ -0,0 +1,170 @@ + + Powered by React + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/static/img/undraw_docusaurus_tree.svg b/static/img/undraw_docusaurus_tree.svg new file mode 100644 index 0000000..d9161d3 --- /dev/null +++ b/static/img/undraw_docusaurus_tree.svg @@ -0,0 +1,40 @@ + + Focus on What Matters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/static/markdown/dv-lab.md b/static/markdown/dv-lab.md new file mode 100644 index 0000000..3c1eb7c --- /dev/null +++ b/static/markdown/dv-lab.md @@ -0,0 +1,15 @@ +## About Us + +Our team is made up of developers and researchers passionate about exploring the possibilities of decentralized technologies and building applications that can make a real impact on people's lives. + +## What We Do + +At our organization, we focus on researching and developing cutting-edge web3/blockchain, and privacy applications that can help bring about a more decentralized, transparent and privacy-preserving world. + +## Our Goals + +Our foremost objective is to develop cutting-edge solutions and applications that foster the widespread adoption of web3/blockchain technologies. We firmly believe in the transformative power of decentralized technologies to revolutionize industries and enhance the world we live in. We are striving to realize this vision by prioritizing privacy, security, and decentralization in all our endeavors. + +Our github: [https://github.com/DV-Lab/](https://github.com/DV-Lab/) + +We would love to hear from you! 🤟 \ No newline at end of file