├── .idea └── .gitignore ├── LICENSE ├── README.md ├── assets ├── Core Components (JS).png ├── Elliptic Curve.png ├── HMAC.png ├── Purpose-1.png ├── Purpose-2.png ├── Schnorr's Protocol.png ├── Synergistic Operation.png ├── ZKP-HMAC-1.png ├── ZKP-HMAC-2.png ├── ZKP-HMAC-3.png ├── ZKP-HMAC-4.png ├── ZeroKnowledge (JS).png └── zk-Call Preview [JS].png ├── example1.mjs ├── example2.mjs ├── example3.mjs └── src ├── HMAC ├── algorithms │ └── base.mjs ├── core │ └── base.mjs ├── errors │ └── base.mjs ├── types │ └── base.mjs └── utils │ └── base.mjs ├── SeedGeneration ├── core │ └── base.mjs ├── errors │ └── base.mjs ├── types │ └── base.mjs └── utils │ └── base.mjs └── ZeroKnowledge ├── algorithms └── base.mjs ├── core └── base.mjs ├── errors └── base.mjs ├── models └── base.mjs ├── types └── base.mjs └── utils ├── convert.mjs ├── hashing.mjs └── serialization.mjs /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | MIT License 3 | 4 | Copyright (c) 2023 zk-Call & Digital Co. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | zk-Call Preview [JS] 3 |
4 |

zk-Call & Labs

5 | 6 |
7 | "Zero-Knowledge" Proof Implementation with HMAC Communication in JavaScript 8 |
9 |
10 |
11 | Experimental 12 |
13 |
14 | 15 | Built by zk-Call :) 16 | 17 |
18 |
19 | 20 | # Table of Contents 21 | - [Credits](#credits) 22 | - [Purpose](#purpose) 23 | - [How it Works](#how-it-works) 24 | - [API](#api) 25 | - [Example Usage](#example-usage) 26 |
27 | 28 | # Credits 29 | 30 | This repository hosts a refined implementation of [**Schnorr's Protocol**](https://en.wikipedia.org/wiki/Schnorr_signature), innovatively incorporating a state seed for enhanced security measures. While the underlying proofs may appear intricate, I aim to elucidate their functionality to the best of my ability. However, for a deeper understanding, I encourage referencing the seminal research papers underpinning this implementation, as they offer comprehensive insights. 31 | 32 | --- 33 | 34 | ![Detailed Schematic Overview of Schnorr's Protocol (Example)](assets/Schnorr's%20Protocol.png) 35 |
36 |
37 | 38 | **For further exploration:** 39 | 40 | [**Elliptic Curve Based "Zero-Knowledge" Proofs and Their Applicability on Resource Constrained Devices by Ioannis Chatzigiannakis, Apostolos Pyrgelis, Paul G. Spirakis, and Yannis C. Stamatiou**](https://arxiv.org/pdf/1107.1626.pdf) 41 | 42 | --- 43 | 44 | ![Detailed Schematic Overview of Elliptic Curves (Example)](assets/Elliptic%20Curve.png) 45 |
46 | 47 | Additionally, this repository delves into the concepts of **"Zero-Knowledge" Proofs (ZKPs)** and **Hash-based Message Authentication Codes (HMACs)**. **ZKPs** are cryptographic protocols that allow one party **(the prover)** to prove to another party **(the verifier)** that a given statement is true, without revealing any additional information beyond the validity of the statement itself. This property is particularly valuable for preserving privacy while establishing trust. 48 |
49 | 50 | On the other hand, **HMACs** are a type of cryptographic hash function used for message authentication. They involve a cryptographic hash function **(such as SHA-256)** and a secret cryptographic key. **HMACs** provide a way to verify both the data integrity and the authenticity of a message, ensuring that it has not been altered or tampered with during transmission and that it indeed originates from the purported sender. 51 |
52 |
53 | 54 | # Purpose 55 | 56 | In today's rapidly evolving IT and application development landscape, **"Zero-Knowledge" Proofs (ZKPs)** emerge as a pivotal paradigm for authentication security. Their capacity to affirm the validity of a claim, such as proving possession of a secret password — without revealing any sensitive information about the claim itself, such as passwords or hashes, revolutionizes the assurance of secure **AAA operations** (**authentication**, **authorization**, and **accounting**). 57 | 58 | --- 59 | 60 | ![The Purpose of our Repositories and The Overall Technology](assets/Purpose-1.png) 61 |
62 | 63 | **zk-Call & Labs** represents an implementation of a [**Non-Interactive "Zero-Knowledge" Proof**](https://en.wikipedia.org/wiki/Non-interactive_zero-knowledge_proof) **(NIZKP)** protocol tailored specifically for validating text-based secrets. This framework proves invaluable for safeguarding passwords and other authentication mechanisms, ensuring robust security measures without compromising privacy. Additionally, the integration of **HMAC (Hash-Based Message Authentication Code)** further fortifies the authentication process, enhancing data integrity and thwarting potential security breaches. 64 |
65 |
66 | 67 | # How It Works 68 | 69 | The authentication protocol employed in this system operates based on two fundamental concepts: 70 | **"Zero-Knowledge" Proofs (ZKPs)** and **Hash-Based Message Authentication Code (HMAC)**. Let's delve into each of these components and understand how they synergize to ensure secure authentication in messaging applications. 71 |
72 | 73 | "Zero-Knowledge" Proofs (ZKPs) 74 | --- 75 | 76 | 77 | #### **"Zero-Knowledge" Proofs (ZKPs):** 78 | **ZKPs** form the bedrock of privacy-preserving authentication mechanisms. These proofs allow one party **(the prover)** to demonstrate the validity of a claim to another party **(the verifier)** without revealing any additional information beyond the claim's validity. In essence, **ZKPs** enable authentication without the need for the prover to disclose sensitive data, such as passwords or cryptographic keys. 79 | 80 | --- 81 | 82 | ![Detailed Schematic Overview of "Zero-Knowledge" Technology (1)](assets/ZKP-HMAC-1.png) 83 | ![Detailed Schematic Overview of "Zero-Knowledge" Technology (2)](assets/ZKP-HMAC-2.png) 84 | ![Detailed Schematic Overview of "Zero-Knowledge" Technology (3)](assets/ZKP-HMAC-3.png) 85 | ![Detailed Schematic Overview of "Zero-Knowledge" Technology (4)](assets/ZKP-HMAC-4.png) 86 |
87 | 88 | 89 | #### **Application in Authentication:** 90 | In the context of messaging applications, **ZKPs** play a pivotal role in verifying a user's identity without the need to transmit explicit credentials over the network. Instead, users can generate cryptographic proofs attesting to their identity or possession of certain credentials without exposing those credentials themselves. This ensures that sensitive information remains confidential during the authentication process, bolstering security and privacy. 91 |
92 |
93 | 94 | 95 | Hash-Based Message Authentication Code (HMAC) 96 | --- 97 | 98 | #### **Hash-Based Message Authentication Code (HMAC):** 99 | **HMAC** provides a robust mechanism for verifying the integrity and authenticity of messages exchanged between parties. It involves the use of a cryptographic hash function in conjunction with a secret key to generate a unique code **(the HMAC)** for each message. This code serves as a digital signature, allowing the recipient to verify that the message has not been tampered with or altered during transmission. 100 | 101 | --- 102 | 103 | ![Detailed Schematic Overview of HMAC Encryption](assets/HMAC.png) 104 | 105 | 106 | #### **Application in Authentication:** 107 | In messaging applications, **HMAC** can be employed to authenticate message senders and ensure the integrity of communication channels. By appending an **HMAC** to each message using a shared secret key, both the sender and recipient can validate the message's authenticity upon receipt. Any unauthorized modifications to the message would result in a mismatch between the **computed HMAC** and the **received HMAC**, thereby alerting the recipient to potential tampering. 108 |
109 |
110 | 111 | Synergistic Operation 112 | --- 113 | When combined, **"Zero-Knowledge" Proofs** and **HMAC** create a formidable framework for secure authentication in messaging applications. **ZKPs** facilitate identity verification without divulging sensitive information, while **HMAC** ensures the integrity and authenticity of messages exchanged between parties. Together, these mechanisms uphold the confidentiality, integrity, and authenticity of communication channels, safeguarding users' privacy and security in the digital realm. 114 | 115 | --- 116 | 117 | ![The Advantages of Synergy between "Zero-Knowledge" Proof and HMAC](assets/Synergistic%20Operation.png) 118 |
119 |
120 | 121 | # API 122 | 123 | The **`"Zero-Knowledge"`** JavaScript API is meant to be simple and intuitive:
124 | 125 | 126 | ## Core Components 127 | The **`Core Components`** are key for establishing a secure and efficient framework for cryptographic protocols; streamlining the creation and validation of **"Zero-Knowledge" Proofs (ZKPs)**. They enhance anonymous, data-safe proof validations. 128 | 129 | ![Detailed Schematic Overview of Core Components](assets/Core%20Components%20(JS).png) 130 | 131 | --- 132 | 133 | #### ZeroKnowledge.models.ZeroKnowledgeParams 134 | The parameters **used to initialize the "Zero-Knowledge"** crypto system. 135 | 136 | class ZeroKnowledgeParams(NamedTuple): 137 | """ 138 | Parameters used to construct a Zero-Knowledge Proof state, utilizing an elliptic curve and a random salt 139 | """ 140 | algorithm: str # Hashing algorithm name 141 | curve: str # Standard Elliptic Curve name to use 142 | s: int # Random salt for the state 143 | 144 | #### ZeroKnowledge.models.ZeroKnowledgeSignature 145 | A **cryptographic "Zero-Knowledge"** signature that can be used to verify future messages. 146 | 147 | class ZeroKnowledgeSignature(NamedTuple): 148 | """ 149 | Cryptographic public signature designed to verify future messages 150 | """ 151 | params: ZeroKnowledgeParams # Reference ZeroKnowledge Parameters 152 | signature: int # The public key derived from your original secret 153 | 154 | 155 | #### ZeroKnowledge.models.ZeroKnowledgeProof 156 | A **cryptographic proof** that can be verified against a signature. 157 | 158 | class ZeroKnowledgeProof(NamedTuple): 159 | """ 160 | Non-deterministic cryptographic Zero-Knowledge Proof designed to confirm that the 161 | private key creating the proof matches the key used to generate the signature 162 | """ 163 | params: ZeroKnowledgeParams # Reference ZeroKnowledge Parameters 164 | c: int # The hash of the signed data and random point, R 165 | m: int # The offset from the secret `r` (`R=r*g`) from c * Hash(secret) 166 | 167 | 168 | #### ZeroKnowledge.models.ZeroKnowledgeData 169 | **Wrapper** that contains **a proof and the necessary data** to validate the proof against a signature. 170 | 171 | class ZeroKnowledgeData(NamedTuple): 172 | """ 173 | Wrapper designed to hold data along with its corresponding signed proof 174 | """ 175 | data: Union[str, bytes, int] 176 | proof: ZeroKnowledgeProof 177 | 178 | --- 179 | 180 | ## ZeroKnowledge 181 | The **`ZeroKnowledge`** class is the central component of **`ZeroKnowledge`** and its state (defined by **`ZeroKnowledgeParams`**) should be inherently known to both the **Client (Prover)** and **Server (Verifier)**. 182 | 183 | ![Comprehensive Visual Guide to ZeroKnowledge Framework](assets/ZeroKnowledge%20(JS).png) 184 | 185 | --- 186 | 187 | #### Instance Methods 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 207 | 208 | 209 | 210 | 211 | 212 | 213 |
MethodParamsRolePurpose
create_signaturesecret: Union[str, bytes]ProverCreate a cryptographic signature derived from the value secret to be generated during initial registration and stored for subsequent challenge proofs.
signsecret: Union[str, bytes]
data: Union[str, bytes, int]
ProverCreate a ZeroKnowledgeData object using the secret and any additional data. 206 |
verifychallenge: Union[ZeroKnowledgeData, ZeroKnowledgeProof]
signature: ZeroKnowledgeSignature
data: Optional[Union[str, bytes, int]]
VerifierVerify the user-provided challenge against the stored signature and randomly generated token to verify the validity of the challenge.
214 | 215 | --- 216 | 217 | # Example Usage 218 | TODO: Include **`Example Usage`** 219 | 220 | ## Example 1 221 | 222 | import {HMACClient} from './src/HMAC/core/base.mjs'; 223 | import {SeedGenerator} from './src/SeedGeneration/core/base.mjs'; 224 | 225 | // DEBUG constant used for enabling/disabling debugging messages 226 | const DEBUG = true; 227 | 228 | // Function to print messages with specific formatting if DEBUG is enabled 229 | function printMsg(who, message) { 230 | if (DEBUG) { 231 | console.log(`[${who}] ${message}\n`); 232 | } 233 | } 234 | 235 | // The main function of the script 236 | function main() { 237 | // Generating a client seed using a SeedGenerator instance 238 | const client_seed = new SeedGenerator("job").generate(); 239 | 240 | // Creating an HMAC client instance for the client using sha256 algorithm and the generated seed 241 | const client_hmac = new HMACClient("sha256", client_seed, 1); 242 | 243 | // Creating an HMAC server instance for the server using sha256 algorithm and the same generated seed 244 | const serverhmac = new HMACClient("sha256", client_seed, 1); 245 | 246 | // Checking if the encrypted message from client and server matches 247 | if (client_hmac.encrypt_message('') === serverhmac.encrypt_message('')) { 248 | // Defining a message to be sent from client to server 249 | const client_message = 'hello'; 250 | 251 | // Encrypting the client message in chunks using the client HMAC instance 252 | const client_encrypted_message_for_server = client_hmac.encrypt_message_by_chunks(client_message) 253 | 254 | // Printing a message indicating that client has sent an encrypted message 255 | printMsg('client', 'sent has encrypted message') 256 | 257 | // Decrypting the message received from client by the server using server HMAC instance 258 | const server_decrypted_message = serverhmac.decrypt_message_by_chunks(client_encrypted_message_for_server) 259 | // Printing a message indicating that server has decrypted the message 260 | printMsg('server', 'server has decrypt message') 261 | 262 | // Encrypting the decrypted message by the server 263 | const server_response = serverhmac.encrypt_message(server_decrypted_message) 264 | // Printing a message indicating that server has encrypted the message 265 | printMsg('server', 'server has encrypted message') 266 | 267 | // Checking if the encrypted message from client matches the server's response 268 | if (client_hmac.encrypt_message(client_message) === server_response) { 269 | // Printing a message indicating that server has successfully read the message from client 270 | printMsg('client', 'server has read message') 271 | } 272 | } 273 | } 274 | 275 | // Calling the main function to start the script execution 276 | main() 277 | 278 | --- 279 | 280 | ## Example 2 281 | 282 | // Importing necessary modules 283 | import { ZeroKnowledge } from "./src/ZeroKnowledge/core/base.mjs"; // Importing ZeroKnowledge class 284 | import { ZeroKnowledgeData } from "./src/ZeroKnowledge/models/base.mjs"; // Importing ZeroKnowledgeData class 285 | 286 | // DEBUG constant used for enabling/disabling debugging messages 287 | const DEBUG = true; 288 | 289 | // Function to print messages with specific formatting if DEBUG is enabled 290 | function printMsg(who, message) { 291 | if (DEBUG) { 292 | console.log(`[${who}] ${message}\n`); // Print formatted message 293 | } 294 | } 295 | 296 | // The main function of the script 297 | function main() { 298 | // Generating a client seed using a SeedGenerator instance 299 | const server_password = "SecretServerPassword"; // Define server password 300 | 301 | // Creating ZeroKnowledge instances for server and client 302 | const server_object = ZeroKnowledge.new("secp256k1", "sha3_256"); // Initialize server ZeroKnowledge instance 303 | const client_object = ZeroKnowledge.new("secp256k1", "sha3_256"); // Initialize client ZeroKnowledge instance 304 | 305 | // Creating signatures for server and client 306 | const server_signature = server_object.create_signature(server_password); // Generate server signature 307 | printMsg("Server", `Server signature: ${server_signature}`); // Print server signature 308 | const idenity = 'John'; // Define client identity 309 | const client_sig = client_object.create_signature(idenity); // Generate client signature 310 | printMsg("Client", `Client signature: ${client_sig}`); // Print client signature 311 | 312 | // Signing and generating token for server and client 313 | const server_token = server_object.sign(server_password, client_object.token()); // Sign and generate token for server 314 | printMsg("Server", `Server token: ${server_token}`); // Print server token 315 | const client_proof = client_object.sign(idenity, server_token.data); // Sign token data for client 316 | printMsg("Client", `Client proof: ${client_proof}`); // Print client proof 317 | 318 | // Creating ZeroKnowledgeData instance for token verification 319 | const token_veif = new ZeroKnowledgeData(client_proof.data, client_proof.proof); 320 | 321 | // Verifying the token against server signature 322 | const server_verif = server_object.verify(token_veif, server_signature); // Verify token against server signature 323 | printMsg("Server", `Server verification: ${server_verif}`); // Print server verification 324 | } 325 | 326 | // Calling the main function to start the script execution 327 | main(); 328 | 329 | --- 330 | 331 | ## Example 3 332 | 333 | // Importing necessary modules 334 | import {ZeroKnowledge} from "./src/ZeroKnowledge/core/base.mjs"; // Importing ZeroKnowledge class 335 | import {ZeroKnowledgeData} from "./src/ZeroKnowledge/models/base.mjs"; 336 | import {SeedGenerator} from "./src/SeedGeneration/core/base.mjs"; 337 | import {HMACClient} from "./src/HMAC/core/base.mjs"; // Importing ZeroKnowledgeData class 338 | 339 | // DEBUG constant used for enabling/disabling debugging messages 340 | const DEBUG = true; 341 | 342 | // Function to print messages with specific formatting if DEBUG is enabled 343 | function printMsg(who, message) { 344 | if (DEBUG) { 345 | console.log(`[${who}] ${message}\n`); // Print formatted message 346 | } 347 | } 348 | 349 | // The main function of the script 350 | function main() { 351 | // Generating a client seed using a SeedGenerator instance 352 | const server_password = "SecretServerPassword"; // Define server password 353 | 354 | // Creating ZeroKnowledge instances for server and client 355 | const server_object = ZeroKnowledge.new("secp256k1", "sha3_256"); // Initialize server ZeroKnowledge instance 356 | const client_object = ZeroKnowledge.new("secp256k1", "sha3_256"); // Initialize client ZeroKnowledge instance 357 | 358 | // Creating signatures for server and client 359 | const server_signature = server_object.create_signature(server_password); // Generate server signature 360 | printMsg("Server", `Server signature: ${server_signature}`); // Print server signature 361 | const idenity = 'John'; // Define client identity 362 | const client_sig = client_object.create_signature(idenity); // Generate client signature 363 | printMsg("Client", `Client signature: ${client_sig}`); // Print client signature 364 | 365 | // Signing and generating token for server and client 366 | const server_token = server_object.sign(server_password, client_object.token()); // Sign and generate token for server 367 | printMsg("Server", `Server token: ${server_token}`); // Print server token 368 | const client_proof = client_object.sign(idenity, server_token.data); // Sign token data for client 369 | printMsg("Client", `Client proof: ${client_proof}`); // Print client proof 370 | 371 | // Creating ZeroKnowledgeData instance for token verification 372 | const token_veif = new ZeroKnowledgeData(client_proof.data, client_proof.proof); 373 | 374 | // Verifying the token against server signature 375 | const server_verif = server_object.verify(token_veif, server_signature); // Verify token against server signature 376 | printMsg("Server", `Server verification: ${server_verif}`); // Print server verification 377 | if (server_verif) { 378 | // Generating a client seed using a SeedGenerator instance 379 | const client_seed = new SeedGenerator("job").generate(); 380 | 381 | // Creating an HMAC client instance for the client using sha256 algorithm and the generated seed 382 | const client_hmac = new HMACClient("sha256", client_seed, 1); 383 | 384 | // Creating an HMAC server instance for the server using sha256 algorithm and the same generated seed 385 | const serverhmac = new HMACClient("sha256", client_seed, 1); 386 | 387 | // Checking if the encrypted message from client and server matches 388 | if (client_hmac.encrypt_message('') === serverhmac.encrypt_message('')) { 389 | // Defining a message to be sent from client to server 390 | const client_message = 'hello'; 391 | 392 | // Encrypting the client message in chunks using the client HMAC instance 393 | const client_encrypted_message_for_server = client_hmac.encrypt_message_by_chunks(client_message) 394 | 395 | // Printing a message indicating that client has sent an encrypted message 396 | printMsg('client', 'sent has encrypted message') 397 | 398 | // Decrypting the message received from client by the server using server HMAC instance 399 | const server_decrypted_message = serverhmac.decrypt_message_by_chunks(client_encrypted_message_for_server) 400 | // Printing a message indicating that server has decrypted the message 401 | printMsg('server', 'server has decrypt message') 402 | 403 | // Encrypting the decrypted message by the server 404 | const server_response = serverhmac.encrypt_message(server_decrypted_message) 405 | // Printing a message indicating that server has encrypted the message 406 | printMsg('server', 'server has encrypted message') 407 | 408 | // Checking if the encrypted message from client matches the server's response 409 | if (client_hmac.encrypt_message(client_message) === server_response) { 410 | // Printing a message indicating that server has successfully read the message from client 411 | printMsg('client', 'server has read message') 412 | } 413 | } 414 | } 415 | } 416 | 417 | // Calling the main function to start the script execution 418 | main(); 419 | -------------------------------------------------------------------------------- /assets/Core Components (JS).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-js/82482346efc872ffa08367cadb401d64afc830b6/assets/Core Components (JS).png -------------------------------------------------------------------------------- /assets/Elliptic Curve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-js/82482346efc872ffa08367cadb401d64afc830b6/assets/Elliptic Curve.png -------------------------------------------------------------------------------- /assets/HMAC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-js/82482346efc872ffa08367cadb401d64afc830b6/assets/HMAC.png -------------------------------------------------------------------------------- /assets/Purpose-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-js/82482346efc872ffa08367cadb401d64afc830b6/assets/Purpose-1.png -------------------------------------------------------------------------------- /assets/Purpose-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-js/82482346efc872ffa08367cadb401d64afc830b6/assets/Purpose-2.png -------------------------------------------------------------------------------- /assets/Schnorr's Protocol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-js/82482346efc872ffa08367cadb401d64afc830b6/assets/Schnorr's Protocol.png -------------------------------------------------------------------------------- /assets/Synergistic Operation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-js/82482346efc872ffa08367cadb401d64afc830b6/assets/Synergistic Operation.png -------------------------------------------------------------------------------- /assets/ZKP-HMAC-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-js/82482346efc872ffa08367cadb401d64afc830b6/assets/ZKP-HMAC-1.png -------------------------------------------------------------------------------- /assets/ZKP-HMAC-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-js/82482346efc872ffa08367cadb401d64afc830b6/assets/ZKP-HMAC-2.png -------------------------------------------------------------------------------- /assets/ZKP-HMAC-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-js/82482346efc872ffa08367cadb401d64afc830b6/assets/ZKP-HMAC-3.png -------------------------------------------------------------------------------- /assets/ZKP-HMAC-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-js/82482346efc872ffa08367cadb401d64afc830b6/assets/ZKP-HMAC-4.png -------------------------------------------------------------------------------- /assets/ZeroKnowledge (JS).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-js/82482346efc872ffa08367cadb401d64afc830b6/assets/ZeroKnowledge (JS).png -------------------------------------------------------------------------------- /assets/zk-Call Preview [JS].png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-js/82482346efc872ffa08367cadb401d64afc830b6/assets/zk-Call Preview [JS].png -------------------------------------------------------------------------------- /example1.mjs: -------------------------------------------------------------------------------- 1 | import {HMACClient} from './src/HMAC/core/base.mjs'; 2 | import {SeedGenerator} from './src/SeedGeneration/core/base.mjs'; 3 | 4 | // DEBUG constant used for enabling/disabling debugging messages 5 | const DEBUG = true; 6 | 7 | // Function to print messages with specific formatting if DEBUG is enabled 8 | function printMsg(who, message) { 9 | if (DEBUG) { 10 | console.log(`[${who}] ${message}\n`); 11 | } 12 | } 13 | 14 | // The main function of the script 15 | function main() { 16 | // Generating a client seed using a SeedGenerator instance 17 | const client_seed = new SeedGenerator("job").generate(); 18 | 19 | // Creating an HMAC client instance for the client using sha256 algorithm and the generated seed 20 | const client_hmac = new HMACClient("sha256", client_seed, 1); 21 | 22 | // Creating an HMAC server instance for the server using sha256 algorithm and the same generated seed 23 | const serverhmac = new HMACClient("sha256", client_seed, 1); 24 | 25 | // Checking if the encrypted message from client and server matches 26 | if (client_hmac.encrypt_message('') === serverhmac.encrypt_message('')) { 27 | // Defining a message to be sent from client to server 28 | const client_message = 'hello'; 29 | 30 | // Encrypting the client message in chunks using the client HMAC instance 31 | const client_encrypted_message_for_server = client_hmac.encrypt_message_by_chunks(client_message) 32 | 33 | // Printing a message indicating that client has sent an encrypted message 34 | printMsg('client', 'sent has encrypted message') 35 | 36 | // Decrypting the message received from client by the server using server HMAC instance 37 | const server_decrypted_message = serverhmac.decrypt_message_by_chunks(client_encrypted_message_for_server) 38 | // Printing a message indicating that server has decrypted the message 39 | printMsg('server', 'server has decrypt message') 40 | 41 | // Encrypting the decrypted message by the server 42 | const server_response = serverhmac.encrypt_message(server_decrypted_message) 43 | // Printing a message indicating that server has encrypted the message 44 | printMsg('server', 'server has encrypted message') 45 | 46 | // Checking if the encrypted message from client matches the server's response 47 | if (client_hmac.encrypt_message(client_message) === server_response) { 48 | // Printing a message indicating that server has successfully read the message from client 49 | printMsg('client', 'server has read message') 50 | } 51 | } 52 | } 53 | 54 | // Calling the main function to start the script execution 55 | main() 56 | -------------------------------------------------------------------------------- /example2.mjs: -------------------------------------------------------------------------------- 1 | // Importing necessary modules 2 | import { ZeroKnowledge } from "./src/ZeroKnowledge/core/base.mjs"; // Importing ZeroKnowledge class 3 | import { ZeroKnowledgeData } from "./src/ZeroKnowledge/models/base.mjs"; // Importing ZeroKnowledgeData class 4 | 5 | // DEBUG constant used for enabling/disabling debugging messages 6 | const DEBUG = true; 7 | 8 | // Function to print messages with specific formatting if DEBUG is enabled 9 | function printMsg(who, message) { 10 | if (DEBUG) { 11 | console.log(`[${who}] ${message}\n`); // Print formatted message 12 | } 13 | } 14 | 15 | // The main function of the script 16 | function main() { 17 | // Generating a client seed using a SeedGenerator instance 18 | const server_password = "SecretServerPassword"; // Define server password 19 | 20 | // Creating ZeroKnowledge instances for server and client 21 | const server_object = ZeroKnowledge.new("secp256k1", "sha3_256"); // Initialize server ZeroKnowledge instance 22 | const client_object = ZeroKnowledge.new("secp256k1", "sha3_256"); // Initialize client ZeroKnowledge instance 23 | 24 | // Creating signatures for server and client 25 | const server_signature = server_object.create_signature(server_password); // Generate server signature 26 | printMsg("Server", `Server signature: ${server_signature}`); // Print server signature 27 | const idenity = 'John'; // Define client identity 28 | const client_sig = client_object.create_signature(idenity); // Generate client signature 29 | printMsg("Client", `Client signature: ${client_sig}`); // Print client signature 30 | 31 | // Signing and generating token for server and client 32 | const server_token = server_object.sign(server_password, client_object.token()); // Sign and generate token for server 33 | printMsg("Server", `Server token: ${server_token}`); // Print server token 34 | const client_proof = client_object.sign(idenity, server_token.data); // Sign token data for client 35 | printMsg("Client", `Client proof: ${client_proof}`); // Print client proof 36 | 37 | // Creating ZeroKnowledgeData instance for token verification 38 | const token_veif = new ZeroKnowledgeData(client_proof.data, client_proof.proof); 39 | 40 | // Verifying the token against server signature 41 | const server_verif = server_object.verify(token_veif, server_signature); // Verify token against server signature 42 | printMsg("Server", `Server verification: ${server_verif}`); // Print server verification 43 | } 44 | 45 | // Calling the main function to start the script execution 46 | main(); 47 | -------------------------------------------------------------------------------- /example3.mjs: -------------------------------------------------------------------------------- 1 | // Importing necessary modules 2 | import {ZeroKnowledge} from "./src/ZeroKnowledge/core/base.mjs"; // Importing ZeroKnowledge class 3 | import {ZeroKnowledgeData} from "./src/ZeroKnowledge/models/base.mjs"; 4 | import {SeedGenerator} from "./src/SeedGeneration/core/base.mjs"; 5 | import {HMACClient} from "./src/HMAC/core/base.mjs"; // Importing ZeroKnowledgeData class 6 | 7 | // DEBUG constant used for enabling/disabling debugging messages 8 | const DEBUG = true; 9 | 10 | // Function to print messages with specific formatting if DEBUG is enabled 11 | function printMsg(who, message) { 12 | if (DEBUG) { 13 | console.log(`[${who}] ${message}\n`); // Print formatted message 14 | } 15 | } 16 | 17 | // The main function of the script 18 | function main() { 19 | // Generating a client seed using a SeedGenerator instance 20 | const server_password = "SecretServerPassword"; // Define server password 21 | 22 | // Creating ZeroKnowledge instances for server and client 23 | const server_object = ZeroKnowledge.new("secp256k1", "sha3_256"); // Initialize server ZeroKnowledge instance 24 | const client_object = ZeroKnowledge.new("secp256k1", "sha3_256"); // Initialize client ZeroKnowledge instance 25 | 26 | // Creating signatures for server and client 27 | const server_signature = server_object.create_signature(server_password); // Generate server signature 28 | printMsg("Server", `Server signature: ${server_signature}`); // Print server signature 29 | const idenity = 'John'; // Define client identity 30 | const client_sig = client_object.create_signature(idenity); // Generate client signature 31 | printMsg("Client", `Client signature: ${client_sig}`); // Print client signature 32 | 33 | // Signing and generating token for server and client 34 | const server_token = server_object.sign(server_password, client_object.token()); // Sign and generate token for server 35 | printMsg("Server", `Server token: ${server_token}`); // Print server token 36 | const client_proof = client_object.sign(idenity, server_token.data); // Sign token data for client 37 | printMsg("Client", `Client proof: ${client_proof}`); // Print client proof 38 | 39 | // Creating ZeroKnowledgeData instance for token verification 40 | const token_veif = new ZeroKnowledgeData(client_proof.data, client_proof.proof); 41 | 42 | // Verifying the token against server signature 43 | const server_verif = server_object.verify(token_veif, server_signature); // Verify token against server signature 44 | printMsg("Server", `Server verification: ${server_verif}`); // Print server verification 45 | if (server_verif) { 46 | // Generating a client seed using a SeedGenerator instance 47 | const client_seed = new SeedGenerator("job").generate(); 48 | 49 | // Creating an HMAC client instance for the client using sha256 algorithm and the generated seed 50 | const client_hmac = new HMACClient("sha256", client_seed, 1); 51 | 52 | // Creating an HMAC server instance for the server using sha256 algorithm and the same generated seed 53 | const serverhmac = new HMACClient("sha256", client_seed, 1); 54 | 55 | // Checking if the encrypted message from client and server matches 56 | if (client_hmac.encrypt_message('') === serverhmac.encrypt_message('')) { 57 | // Defining a message to be sent from client to server 58 | const client_message = 'hello'; 59 | 60 | // Encrypting the client message in chunks using the client HMAC instance 61 | const client_encrypted_message_for_server = client_hmac.encrypt_message_by_chunks(client_message) 62 | 63 | // Printing a message indicating that client has sent an encrypted message 64 | printMsg('client', 'sent has encrypted message') 65 | 66 | // Decrypting the message received from client by the server using server HMAC instance 67 | const server_decrypted_message = serverhmac.decrypt_message_by_chunks(client_encrypted_message_for_server) 68 | // Printing a message indicating that server has decrypted the message 69 | printMsg('server', 'server has decrypt message') 70 | 71 | // Encrypting the decrypted message by the server 72 | const server_response = serverhmac.encrypt_message(server_decrypted_message) 73 | // Printing a message indicating that server has encrypted the message 74 | printMsg('server', 'server has encrypted message') 75 | 76 | // Checking if the encrypted message from client matches the server's response 77 | if (client_hmac.encrypt_message(client_message) === server_response) { 78 | // Printing a message indicating that server has successfully read the message from client 79 | printMsg('client', 'server has read message') 80 | } 81 | } 82 | } 83 | } 84 | 85 | // Calling the main function to start the script execution 86 | main(); 87 | -------------------------------------------------------------------------------- /src/HMAC/algorithms/base.mjs: -------------------------------------------------------------------------------- 1 | export const Hash_type_and_len = { 2 | "sha3-224": 56, // SHA3-224 algorithm has a digest length of 56 bytes 3 | "sha256": 64 // SHA-256 algorithm has a digest length of 64 bytes 4 | }; 5 | -------------------------------------------------------------------------------- /src/HMAC/core/base.mjs: -------------------------------------------------------------------------------- 1 | import * as crypto from 'crypto'; // Import the crypto module for cryptographic operations 2 | import * as itertools from 'itertools'; // Import the itertools module for iterating over combinations 3 | import * as string from 'string'; // Import the string module for string operations (e.g., Python-like operations) 4 | import { Hash_type_and_len } from '../algorithms/base.mjs'; // Import the Hash_type_and_len constant from the base module 5 | 6 | class HMACClient { 7 | constructor(algorithm = 'sha3-256', secret = Buffer.from(''), symbol_count = 1) { 8 | // Constructor for the HMACClient class with default parameters 9 | this._algorithm = algorithm; // Set the HMAC algorithm 10 | this._secret = secret; // Set the secret key for HMAC 11 | this._decrypt_dict = {}; // Initialize a dictionary to store decrypted values 12 | this._symbol_count = symbol_count; // Set the number of symbols per chunk 13 | this.init_decrypt_dict(); // Initialize the decrypt dictionary 14 | } 15 | 16 | // Initialize the decrypt dictionary with combinations of characters 17 | init_decrypt_dict() { 18 | const lowercaseLetters = 'abcdefghijklmnopqrstuvwxyz'; // Define lowercase letters 19 | const uppercaseLetters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; // Define uppercase letters 20 | const digits = '0123456789'; // Define digits 21 | const punctuation = `!"#$%&'()*+,-./:;<=>?@[\\]^_\`{|}~`; // Define punctuation characters 22 | 23 | const all_chars = lowercaseLetters + uppercaseLetters + digits + punctuation; // Combine all characters 24 | const combinations = this.generateCombinations(all_chars, this._symbol_count); // Generate combinations 25 | 26 | // Generate combinations and encrypt them to create the decrypt dictionary 27 | for (const comb of combinations) { 28 | const value = comb.join(''); // Concatenate characters to form a value 29 | const key = this.encrypt_message(value); // Encrypt the value to get a key 30 | this._decrypt_dict[key] = value; // Store the key-value pair in the decrypt dictionary 31 | } 32 | } 33 | 34 | // Generate combinations of characters 35 | generateCombinations(characters, length) { 36 | const combinations = []; // Initialize an array to store combinations 37 | 38 | function generate(prefix, remainingLength) { 39 | if (remainingLength === 0) { // If remaining length is 0, add the prefix to combinations 40 | combinations.push(prefix); 41 | } else { 42 | for (const char of characters) { // Iterate over characters 43 | generate(prefix.concat(char), remainingLength - 1); // Recursively generate combinations 44 | } 45 | } 46 | } 47 | 48 | generate([], length); // Start with an empty prefix and full length 49 | return combinations; // Return the generated combinations 50 | } 51 | 52 | // Encrypt message by dividing it into chunks and encrypting each chunk 53 | encrypt_message_by_chunks(message) { 54 | let encrypted_message = ''; // Initialize a variable to store the encrypted message 55 | for (let i = 0; i < message.length; i += this._symbol_count) { // Iterate over the message in chunks 56 | const chunk = message.slice(i, i + this._symbol_count); // Get a chunk of the message 57 | encrypted_message += this.encrypt_message(chunk); // Encrypt the chunk and append to the encrypted message 58 | } 59 | return encrypted_message; // Return the encrypted message 60 | } 61 | 62 | // Encrypt message using HMAC 63 | encrypt_message(message) { 64 | return crypto.createHMAC(this._algorithm, this._secret) // Create an HMAC object 65 | .update(Buffer.from(message, 'utf-8')) // Update the HMAC with the message 66 | .digest('hex'); // Compute the digest and return it as a hexadecimal string 67 | } 68 | 69 | // Encrypt message and return the digest 70 | encrypt_message_digest(message) { 71 | return crypto.createHMAC(this._algorithm, this._secret) // Create an HMAC object 72 | .update(Buffer.from(message, 'utf-8')) // Update the HMAC with the message 73 | .digest(); // Compute the digest and return it 74 | } 75 | 76 | // Decrypt message by dividing it into chunks and decrypting each chunk 77 | decrypt_message_by_chunks(message, chunk = null) { 78 | let msg_raw = ''; // Initialize a variable to store the raw message 79 | const chank = chunk || Hash_type_and_len[this._algorithm]; // Get the chunk size 80 | if (message.length % this._symbol_count === 0) { // Check if the message length is divisible by symbol count 81 | for (let i = 0; i < message.length; i += chank) { // Iterate over the message in chunks 82 | const chunk = message.slice(i, i + chank); // Get a chunk of the message 83 | msg_raw += this.decrypt_message(chunk); // Decrypt the chunk and append to the raw message 84 | } 85 | return msg_raw; // Return the raw message 86 | } else { 87 | throw new Error(`The algorithm ${this._algorithm} is invalid`); // Throw an error for an invalid algorithm 88 | } 89 | } 90 | 91 | // Decrypt message using the decrypt dictionary 92 | decrypt_message(message) { 93 | const val = this._decrypt_dict[message]; // Get the value from the decrypt dictionary 94 | if (val) { // If the value exists 95 | return val; // Return the decrypted message 96 | } else { 97 | throw new Error(`The algorithm ${this._algorithm} is invalid`); // Throw an error for an invalid algorithm 98 | } 99 | } 100 | } 101 | 102 | export { HMACClient }; // Export the HMACClient class for usage in other modules 103 | -------------------------------------------------------------------------------- /src/HMAC/errors/base.mjs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-js/82482346efc872ffa08367cadb401d64afc830b6/src/HMAC/errors/base.mjs -------------------------------------------------------------------------------- /src/HMAC/types/base.mjs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-js/82482346efc872ffa08367cadb401d64afc830b6/src/HMAC/types/base.mjs -------------------------------------------------------------------------------- /src/HMAC/utils/base.mjs: -------------------------------------------------------------------------------- 1 | // Function to convert data to bytes representation 2 | function to_bytes(data, encoding = "utf-8") { 3 | // Check if the data is a string 4 | if (typeof data === 'string') { 5 | // If it's a string, convert it to bytes using the specified encoding 6 | return Buffer.from(data, encoding); 7 | } 8 | // If data is not a string, return it as is 9 | return data; 10 | } 11 | 12 | // Function to convert data to string representation 13 | function to_str(data, encoding = "utf-8") { 14 | // Check if the data is a buffer 15 | if (Buffer.isBuffer(data)) { 16 | // If it's a buffer, convert it to a string using the specified encoding 17 | return data.toString(encoding); 18 | } 19 | // If data is not a buffer, return it as is 20 | return data; 21 | } 22 | 23 | // Export the functions for usage in other modules 24 | export { to_bytes, to_str }; 25 | -------------------------------------------------------------------------------- /src/SeedGeneration/core/base.mjs: -------------------------------------------------------------------------------- 1 | import * as secrets from 'secrets'; // Import secrets module for cryptographic operations 2 | import * as crypto from 'crypto'; // Import crypto module for cryptographic operations 3 | import { get_random_int, hash_digest } from '../utils/base.mjs'; // Import helper functions from base module 4 | 5 | export class SeedGenerator { 6 | constructor(phrase) { 7 | this._phrase = phrase; // Initialize SeedGenerator with a phrase 8 | } 9 | 10 | _hash(length) { 11 | // Private method to generate a hash 12 | // Example: generate secure random bytes using crypto module 13 | const randomBytes = crypto.randomBytes(64); // Generate 64 random bytes securely 14 | const combinated_bytes = Buffer.concat([randomBytes, Buffer.from(this._phrase)]); // Concatenate random bytes and phrase 15 | return hash_digest(combinated_bytes); // Return the hash of the combined bytes 16 | } 17 | 18 | generate() { 19 | // Public method to generate a seed 20 | return this._hash(get_random_int()); // Generate a hash using a random length 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/SeedGeneration/errors/base.mjs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-js/82482346efc872ffa08367cadb401d64afc830b6/src/SeedGeneration/errors/base.mjs -------------------------------------------------------------------------------- /src/SeedGeneration/types/base.mjs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-js/82482346efc872ffa08367cadb401d64afc830b6/src/SeedGeneration/types/base.mjs -------------------------------------------------------------------------------- /src/SeedGeneration/utils/base.mjs: -------------------------------------------------------------------------------- 1 | import { createHash } from 'crypto'; // Import createHash function from the crypto module 2 | 3 | // Function to generate a random integer 4 | function get_random_int() { 5 | const random_int = Math.floor(Math.random() * Math.pow(2, 20)); // Generate a random integer in the range [0, 2^20) 6 | return random_int; // Return the generated random integer 7 | } 8 | 9 | // Function to compute the hash digest of the combined bytes 10 | function hash_digest(combined_bytes) { 11 | const hash = createHash('sha256'); // Create a hash object using SHA-256 algorithm 12 | hash.update(combined_bytes); // Update the hash with the combined bytes 13 | return hash.digest(); // Return the digest (hash value) of the combined bytes 14 | } 15 | 16 | // Export the functions for usage in other modules 17 | export { get_random_int, hash_digest }; 18 | -------------------------------------------------------------------------------- /src/ZeroKnowledge/algorithms/base.mjs: -------------------------------------------------------------------------------- 1 | // Importing hashlib is not straightforward in JavaScript. 2 | // For the purpose of this translation, we'll skip the hashlib part. 3 | 4 | // Create an object containing the supported hash functions 5 | export const HashTypes = { 6 | md5: "md5", 7 | sha1: "sha1", 8 | sha224: "sha224", 9 | sha256: "sha256", 10 | sha512: "sha512", 11 | sha3_224: "sha3-224", 12 | sha3_256: "sha3-256", 13 | sha3_384: "sha3-384", 14 | sha3_512: "sha3-512", 15 | blake2b: "blake2b", 16 | blake2s: "blake2s" 17 | }; 18 | 19 | // Register new JWT algorithms with supported hashlib algorithms 20 | const algorithms = { 21 | HS3_224: "sha3-224", 22 | HS3_256: "sha3-256", 23 | HS3_384: "sha3-384", 24 | HS3_512: "sha3-512", 25 | HB2S: "blake2s", 26 | HB2B: "blake2b" 27 | }; 28 | 29 | // In JavaScript/Node.js, you might not have a direct equivalent of "register_algorithm" from the jwt library. 30 | // You would typically create a map of algorithms to hash functions, but handling JWTs typically requires 31 | // a specific library that provides this functionality. 32 | // Below is a simple representation of how you might handle this: 33 | 34 | // Map of algorithm names to hash functions 35 | const hashFunctions = {}; 36 | 37 | // Function to register algorithm with its hash function 38 | function registerAlgorithm(algorithm, hashFunction) { 39 | hashFunctions[algorithm] = hashFunction; 40 | } 41 | 42 | // Register each algorithm with its hash function 43 | for (const [algorithm, hashName] of Object.entries(algorithms)) { 44 | registerAlgorithm(algorithm, HashTypes[hashName]); 45 | } 46 | 47 | // Usage example 48 | -------------------------------------------------------------------------------- /src/ZeroKnowledge/core/base.mjs: -------------------------------------------------------------------------------- 1 | import {ZeroKnowledgeData, ZeroKnowledgeParams, ZeroKnowledgeProof, ZeroKnowledgeSignature} from '../models/base.mjs'; // Import necessary models 2 | import * as jwt from 'jsonwebtoken'; // Import jwt module for JSON Web Token operations 3 | import {bytes_to_int, int_to_bytes, to_bytes, to_str} from '../utils/convert.mjs'; // Import utility functions 4 | import {curve_by_name, hash_numeric, mod} from '../utils/hashing.mjs'; // Import utility functions 5 | import {dump_object} from '../utils/serialization.mjs'; // Import utility functions 6 | import {randomBytes} from 'crypto'; // Import randomBytes function from the crypto module 7 | 8 | 9 | export class ZeroKnowledge { 10 | /** 11 | * Class implementing zero-knowledge authentication scheme. 12 | */ 13 | constructor(params, secret = null, algorithm = "HB2S", issuer = "zk-call") { 14 | /** 15 | * Initialize the curve with the given parameters 16 | */ 17 | this._obj_curve = curve_by_name(params.curve); // Retrieve the curve object 18 | if (!this._obj_curve) { 19 | throw new Error(`The curve '${params.curve}' is invalid`); 20 | } 21 | this._params = params; // Store the parameters 22 | 23 | this._bits = this._obj_curve.curve.p.bitLength(); // Get the number of bits for the curve 24 | this._secret = secret; // Store the secret key 25 | this._algorithm = algorithm; // Store the algorithm for JWT 26 | this._issuer = issuer; // Store the issuer name for JWT 27 | } 28 | 29 | generate_jwt(signature, exp = td(seconds = 10)) { 30 | /** 31 | * Generate a JSON Web Token (JWT) using the provided signature and expiration time. 32 | */ 33 | if (this._secret) { 34 | 35 | const now = new Date().toISOString(); // Get the current UTC time 36 | return to_str(jwt.encode({ // Encode the JWT payload 37 | "signature": dump_object(signature), // Dump the signature object 38 | "iat": now, 39 | "nbf": now, 40 | "exp": new Date(new Date().getTime() + exp * 1000).toISOString(), 41 | "iss": this._issuer, // Set JWT claims 42 | }, this._secret, algorithm = this._algorithm)); // Encode JWT using secret key 43 | } 44 | } 45 | 46 | verify_jwt(tok) { 47 | /** 48 | * Verify a JSON Web Token (JWT) and return decoded data if valid. 49 | */ 50 | if (this._secret) { 51 | try { 52 | return jwt.decode(to_str(tok), this._secret, iss = this._issuer, algorithms = [this._algorithm]); 53 | } catch (e) { 54 | console.error(e); 55 | } 56 | } 57 | } 58 | 59 | get params() { 60 | /** 61 | * Get zero-knowledge parameters. 62 | */ 63 | return this._params; 64 | } 65 | 66 | get salt() { 67 | /** 68 | * Get salt used in the authentication. 69 | */ 70 | return this._params.salt; 71 | } 72 | 73 | get curve() { 74 | /** 75 | * Get the elliptic curve used for cryptography. 76 | */ 77 | return this._obj_curve; 78 | } 79 | 80 | static new(curve_name = "Ed25519", hash_alg = "blake2b", jwt_secret = null, jwt_alg = "HB2B", salt_size = 16) { 81 | /** 82 | * Create a new instance of "Zero-Knowledge" with specified parameters. 83 | */ 84 | const curve = curve_by_name(curve_name); // Get the curve object 85 | 86 | if (!curve) { 87 | throw new Error("Invalid Curve Name"); // Raise error for invalid curve name 88 | } 89 | let zkx = new ZeroKnowledgeParams({ // Initialize "Zero-Knowledge"Params object 90 | algorithm: hash_alg, // Set hashing algorithm 91 | curve: curve_name, // Set elliptic curve name 92 | salt: randomBytes(salt_size), // Generate salt 93 | }) 94 | 95 | return new ZeroKnowledge 96 | (new ZeroKnowledgeParams( // Return a new instance of "Zero-Knowledge" 97 | hash_alg, // Set hashing algorithm 98 | curve_name, // Set elliptic curve name 99 | randomBytes(salt_size), // Generate salt 100 | ), jwt_secret, // Set JWT secret 101 | jwt_alg // Set JWT algorithm 102 | ); 103 | } 104 | 105 | _to_point(value) { 106 | /** 107 | * Convert a value to a point on the elliptic curve. 108 | */ 109 | 110 | const bytes = to_bytes(value instanceof ZeroKnowledgeSignature ? value.signature : value); 111 | try { 112 | // Adjust isOdd as needed 113 | return this.curve.curve.pointFromX(bytes, /*isOdd=*/ true); 114 | } catch (error) { 115 | console.error("Error constructing point from x-coordinate:", error); 116 | // Handle the error or return null/undefined if appropriate 117 | return null; 118 | } 119 | } 120 | 121 | token() { 122 | /** 123 | * Generate a random token. 124 | */ 125 | return randomBytes(this._bits + 7 >> 3); 126 | } 127 | 128 | hash(...values) { 129 | /** 130 | * Hash the values provided modulo the curve order 131 | */ 132 | return mod(hash_numeric(...values.filter(v => v !== null), this.salt, this.params.algorithm), this.curve.curve.n); 133 | } 134 | 135 | create_signature(secret) { 136 | /** 137 | * Create a signature object using the provided secret key. 138 | */ 139 | 140 | let signaturePoint = this.curve.curve.g.mul(this.hash(secret)); 141 | 142 | let signatureBytes = to_bytes(signaturePoint); 143 | 144 | 145 | return new ZeroKnowledgeSignature({ 146 | params: this.params, 147 | signature: signatureBytes, 148 | }); 149 | } 150 | 151 | create_proof(secret, data = null) { 152 | const key = this.hash(secret); // Compute hash of the secret key 153 | const bytesNeeded = Math.ceil(Math.log2(this.curve.curve.n) / 8); // Calculate bytes needed for the curve order 154 | const randomBytes1 = randomBytes(bytesNeeded); // Generate random bytes 155 | const r = bytes_to_int(randomBytes1); // Convert random bytes to integer 156 | const R = this.curve.curve.g.mul(BigInt(r)); // Compute a point on the curve 157 | const c = this.hash(data, R); // Compute hash of the data and R 158 | const m = mod(r - c * key, this.curve.curve.n); // Compute m 159 | 160 | return new ZeroKnowledgeProof( 161 | this.params, 162 | int_to_bytes(c), 163 | int_to_bytes(m) 164 | ); 165 | } 166 | 167 | sign(secret, data) { 168 | /** 169 | * Sign the provided data using the secret key. 170 | */ 171 | 172 | 173 | data = to_str(data); // Convert data to string 174 | 175 | 176 | 177 | return new ZeroKnowledgeData( // Create a "Zero-Knowledge"Data object 178 | data, 179 | this.create_proof(secret, data) // Create proof for the data 180 | ); 181 | } 182 | 183 | static signature_is_valid(signature) { 184 | /** 185 | * Check if the signature is valid. 186 | */ 187 | try { 188 | const zk = new ZeroKnowledge(signature.params); // Create "Zero-Knowledge" object 189 | return zk.curve.curve.validate(zk._to_point(signature)); // Check if the signature is valid 190 | } catch (error) { 191 | console.error(error); 192 | return false; 193 | } 194 | } 195 | 196 | verify(challenge, signature, data = "") { 197 | /** 198 | * Verify the authenticity of the provided challenge data against the given signature. 199 | */ 200 | 201 | 202 | let proof=challenge.proof; 203 | 204 | data = challenge.data ; 205 | 206 | const c = bytes_to_int(proof.c); // Convert proof.c to an integer 207 | const p = this.curve.curve.g.mul(bytes_to_int(proof.m)).add(this._to_point(signature).mul(c)); 208 | return c === this.hash(data, p); // Compare c with hash of data and point 209 | } 210 | 211 | login(login_data) { 212 | /** 213 | * Perform a login using the provided login data. 214 | */ 215 | const data = this.verify_jwt(login_data.data); // Verify JWT token from login data 216 | return data && this.verify( // Check if data is valid and verify the login 217 | login_data, 218 | ZeroKnowledgeSignature.from_json(data.get("signature")) // Convert JSON signature to "Zero-Knowledge" Signature object 219 | ); 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /src/ZeroKnowledge/errors/base.mjs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-js/82482346efc872ffa08367cadb401d64afc830b6/src/ZeroKnowledge/errors/base.mjs -------------------------------------------------------------------------------- /src/ZeroKnowledge/models/base.mjs: -------------------------------------------------------------------------------- 1 | // Importing necessary modules 2 | 3 | // Define ZeroKnowledgeParams class 4 | class ZeroKnowledgeParams { 5 | /** 6 | * Parameters used to construct a "Zero-Knowledge" instance using a hashing scheme, 7 | * a standard elliptic curve name, and a random salt 8 | */ 9 | constructor(algorithm, curve, salt) { 10 | this.algorithm = algorithm; // Hashing algorithm name 11 | this.curve = curve; // Standard Elliptic Curve name to use 12 | this.salt = salt; // Random salt for the state 13 | } 14 | 15 | to_json() { 16 | // Convert parameters to JSON format 17 | return JSON.stringify({ 18 | algorithm: this.algorithm, 19 | curve: this.curve, 20 | salt: this.salt 21 | }); 22 | } 23 | 24 | static from_json(json) { 25 | // Convert JSON string to ZeroKnowledgeParams object 26 | const obj = JSON.parse(json); 27 | return new ZeroKnowledgeParams(obj.algorithm, obj.curve, obj.salt); 28 | } 29 | } 30 | 31 | // Define ZeroKnowledgeSignature class 32 | class ZeroKnowledgeSignature { 33 | /** 34 | * Cryptographic public signature used to verify future messages 35 | */ 36 | constructor(params, signature) { 37 | this.params = params; // Reference "Zero-Knowledge" Parameters 38 | this.signature = signature; // The public key derived from your original secret 39 | } 40 | 41 | to_json() { 42 | // Convert signature object to JSON format 43 | return JSON.stringify({ 44 | params: this.params.to_json(), 45 | signature: this.signature, 46 | }); 47 | } 48 | 49 | static from_json(json) { 50 | // Convert JSON string to ZeroKnowledgeSignature object 51 | const obj = JSON.parse(json); 52 | return new ZeroKnowledgeSignature(obj.params.from_json(), obj.signature); 53 | } 54 | } 55 | 56 | // Define ZeroKnowledgeProof class 57 | class ZeroKnowledgeProof { 58 | /** 59 | * Cryptographic proof that can be verified to ensure the private key used to create 60 | * the proof is the same key used to generate the signature 61 | */ 62 | constructor(params, c, m) { 63 | this.params = params; // Reference "Zero-Knowledge" Parameters 64 | this.c = c; // The hash of the signed data and random point, R 65 | this.m = m; // The offset from the secret `r` (`R=r*g`) from c * Hash(secret) 66 | } 67 | 68 | to_json() { 69 | // Convert proof object to JSON format 70 | return JSON.stringify({ 71 | params: this.params.to_json(), 72 | c: this.c, 73 | m: this.m, 74 | }); 75 | } 76 | 77 | static from_json(json) { 78 | // Convert JSON string to ZeroKnowledgeProof object 79 | const obj = JSON.parse(json); 80 | return new ZeroKnowledgeProof(obj.params.from_json(), obj.c, obj.m); 81 | } 82 | } 83 | 84 | // Define ZeroKnowledgeData class 85 | class ZeroKnowledgeData { 86 | /** 87 | * Wrapper to contain data and a signed proof using the data 88 | */ 89 | constructor(data, proof) { 90 | this.data = data; // Signed data 91 | this.proof = proof; // ZeroKnowledgeProof instance 92 | } 93 | 94 | static from_json(json) { 95 | // Convert JSON string to ZeroKnowledgeData object 96 | const obj = JSON.parse(json); 97 | return new ZeroKnowledgeData(obj.data, obj.proof.from_json()); 98 | } 99 | 100 | to_json() { 101 | // Convert ZeroKnowledgeData object to JSON format 102 | return JSON.stringify({ 103 | data: this.data, 104 | proof: this.proof.to_json(), 105 | }); 106 | } 107 | } 108 | 109 | // Exporting classes for usage 110 | export {ZeroKnowledgeParams, ZeroKnowledgeSignature, ZeroKnowledgeProof, ZeroKnowledgeData}; 111 | -------------------------------------------------------------------------------- /src/ZeroKnowledge/types/base.mjs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-js/82482346efc872ffa08367cadb401d64afc830b6/src/ZeroKnowledge/types/base.mjs -------------------------------------------------------------------------------- /src/ZeroKnowledge/utils/convert.mjs: -------------------------------------------------------------------------------- 1 | // Convert any value to an integer from its big endian bytes representation 2 | function bytes_to_int(value) { 3 | return parseInt(Buffer.from(value).toString('hex'), 16); 4 | } 5 | 6 | // Convert an integer value to bytes in big endian representation 7 | function int_to_bytes(value) { 8 | const hex = value.toString(16); // Convert integer to hexadecimal string 9 | // Create a buffer from the hexadecimal string, ensuring even length by padding with zeros if necessary 10 | return Buffer.from(hex.padStart(hex.length + (hex.length % 2), '0'), 'hex'); 11 | } 12 | 13 | // Encode data in base64 format, optionally strip padding 14 | function data_to_b64_str(data, strip=true) { 15 | const base64 = Buffer.from(data).toString('base64'); // Convert data to base64 16 | return strip ? base64.replace(/=+$/, '') : base64; // Optionally strip padding from base64 string 17 | } 18 | 19 | // Decode base64 data to bytes, append padding if necessary 20 | function b64d(data, pad=true) { 21 | return Buffer.from(data + (pad ? '==='.slice((data.length + 3) % 4) : ''), 'base64'); // Decode base64 data 22 | } 23 | 24 | // Convert data to its bytes representation 25 | function to_bytes(data, encoding="utf-8", errors="replace") { 26 | // If data is a string, convert it to bytes using the specified encoding 27 | if (typeof data === 'string') { 28 | return Buffer.from(data, encoding); 29 | } 30 | // If data is an integer, convert it to bytes using int_to_bytes function 31 | if (Number.isInteger(data)) { 32 | return int_to_bytes(data); 33 | } 34 | // Handle other types accordingly 35 | } 36 | 37 | // Convert data to its string representation 38 | function to_str(data, encoding="utf-8", errors="replace") { 39 | // If data is already a string, return it unchanged 40 | if (typeof data === 'string') { 41 | return data; 42 | } 43 | // If data is a Buffer, convert it to a string using the specified encoding 44 | if (data instanceof Buffer) { 45 | return data.toString(encoding, errors); 46 | } 47 | // If data is an integer, convert it to a string 48 | if (Number.isInteger(data)) { 49 | return data.toString(); 50 | } 51 | // Handle other types accordingly 52 | } 53 | 54 | // Export all functions for usage in other modules 55 | export { bytes_to_int, int_to_bytes, data_to_b64_str, b64d, to_bytes, to_str }; 56 | -------------------------------------------------------------------------------- /src/ZeroKnowledge/utils/hashing.mjs: -------------------------------------------------------------------------------- 1 | import {HashTypes} from '../algorithms/base.mjs'; // Import HashTypes from base module 2 | import {bytes_to_int, to_bytes} from './convert.mjs'; // Import bytes_to_int and to_bytes functions from convert module 3 | import EC from "elliptic"; // Import elliptic curve library 4 | import pkg from 'js-sha3'; // Import js-sha3 package for SHA3 hashing 5 | const {sha3_256} = pkg; // Destructure sha3_256 function from js-sha3 package 6 | 7 | // Function to get curve by name, case-insensitive 8 | function curve_by_name(name) { 9 | let curv1 = new EC.ec(name); // Create a new instance of the elliptic curve 10 | return new EC.ec(name); 11 | } 12 | 13 | // Function to compute a mod b, accounting for positive/negative numbers 14 | function mod(a, b) { 15 | return ((a % b) + b) % b; // Compute a mod b, considering positive/negative numbers 16 | } 17 | 18 | // Function to convert provided values to bytes and return the hash digest in bytes 19 | function hash_data(...values) { 20 | const algorithm = "sha3-256"; // Default algorithm 21 | const HashTypes = { // Define supported hash algorithms 22 | "sha3-256": (data) => sha3_256(data, { outputLength: 256 }) // Define function for SHA3-256 hash 23 | }; 24 | 25 | if (!(algorithm in HashTypes)) { // Check if the hash algorithm is supported 26 | throw new Error(`Hash algorithm '${algorithm}' is not supported`); 27 | } 28 | 29 | // Convert each value to bytes and concatenate them 30 | const bytesValues = values.map(value => { 31 | if (typeof value === 'string') { 32 | return Buffer.from(value); 33 | } else if (Buffer.isBuffer(value)) { 34 | return value; 35 | } else if (typeof value === 'number') { 36 | return Buffer.from(value.toString()); 37 | } else if (typeof value === 'object' && value.encode !== undefined) { 38 | return Buffer.from(value.encode()); 39 | } else { 40 | throw new Error(`Unsupported value type: ${typeof value}`); 41 | } 42 | }); 43 | 44 | const concatenatedBytes = Buffer.concat(bytesValues); // Concatenate bytes 45 | 46 | // Compute hash of concatenated values 47 | return HashTypes[algorithm](concatenatedBytes); // Return hash digest 48 | } 49 | 50 | // Function to compute the cryptographic hash of provided values and return the digest in integer form 51 | function hash_numeric(...values) { 52 | const algorithm = "sha3_256"; // Default algorithm 53 | const hashDigest = hash_data(...values, algorithm); // Compute hash digest 54 | return bytes_to_int(hashDigest); // Convert hash digest to integer form 55 | } 56 | 57 | export {curve_by_name, mod, hash_data, hash_numeric}; // Export functions for usage in other modules 58 | -------------------------------------------------------------------------------- /src/ZeroKnowledge/utils/serialization.mjs: -------------------------------------------------------------------------------- 1 | // Function to dump a JSON Dataclass to compressed JSON 2 | function dump_object(dc) { 3 | // The function takes a JSON Dataclass (dc) as input and returns the compressed JSON representation 4 | return JSON.stringify(dc, (key, value) => (value !== null && typeof value === 'object' ? value : undefined), ","); 5 | // JSON.stringify() method is used to serialize the JSON Dataclass 6 | // It accepts a replacer function as the second argument to control the serialization process 7 | // In this replacer function: 8 | // - If the value is not null and is of type object, it returns the value (i.e., includes it in the serialized output) 9 | // - Otherwise, it returns undefined (i.e., excludes it from the serialized output) 10 | // The third argument ',' specifies the separator between JSON elements (e.g., key-value pairs) 11 | } 12 | 13 | export {dump_object}; // Export the dump_object function for usage in other modules 14 | --------------------------------------------------------------------------------