├── .idea ├── .DS_Store └── .gitignore ├── LICENSE ├── README.md ├── assets ├── Core Components (C++).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 └── zk-Call Preview [C++].png ├── example1.cpp ├── example2.cpp ├── example3.cpp └── src ├── HMAC ├── algorithms │ ├── base.cpp │ └── base.h ├── core │ ├── base.cpp │ └── base.h ├── errors │ ├── base.cpp │ └── base.h ├── types │ ├── base.cpp │ └── base.h └── utils │ ├── base.cpp │ └── base.h ├── SeedGeneration ├── core │ ├── base.cpp │ └── base.h ├── errors │ ├── base.cpp │ └── base.h ├── types │ ├── base.cpp │ └── base.h └── utils │ ├── base.cpp │ └── base.h └── ZeroKnowledge ├── algorithms ├── base.cpp └── base.h ├── core ├── base.cpp └── base.h ├── errors ├── base.cpp └── base.h ├── models ├── base.cpp └── base.h ├── types ├── curve │ ├── base.cpp │ └── base.h └── point │ ├── base.cpp │ └── base.h └── utils ├── base.cpp └── base.h /.idea/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-cpp/77c9d20971f7d8eaac22a81db90696ccc0efb845/.idea/.DS_Store -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml -------------------------------------------------------------------------------- /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 [C++] 3 |
4 |

zk-Call & Labs

5 | 6 |
7 | "Zero-Knowledge" Proof Implementation with HMAC Communication in C++ 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 **`"HMAC_Client"`** С++ API is meant to be simple and intuitive: 124 | 125 | ## Core Components 126 | The **`Core Components`** streamline secure **Message Encryption** and **Decryption**, supporting both **Chunk** and **Character-Level** processing for enhanced data protection. 127 | 128 | ![Detailed Schematic Overview of Core Components](assets/Core%20Components%20(C++).png) 129 | 130 | --- 131 | 132 | #### HMAC_Client.encrypt_message_by_chunks 133 | Method to **encrypt a message** by processing it in **chunks**. 134 | 135 | std::string encrypt_message_by_chunks(const std::string& message); 136 | 137 | message: string # The message to be encrypted, processed in chunks 138 | 139 | #### HMAC_Client.encrypt_message 140 | Method to **encrypt a message** by a **chars**. 141 | 142 | std::string encrypt_message(const std::string& message); 143 | 144 | message: string # The message to be encrypted, processed in characters 145 | 146 | #### HMAC_Client.decrypt_message_by_chunks 147 | Method to **decrypt a message** by processing it in **chunks**. 148 | 149 | std::string decrypt_message_by_chunks(const std::string& message); 150 | 151 | message: string # The message to be decrypted, processed in chunks 152 | 153 | #### HMAC_Client.decrypt_message 154 | Method to **decrypt a message** by processing it in **chars**. 155 | 156 | std::string encrypt_message(const std::string& message); 157 | 158 | message: string # The message to be decrypted, processed in characters 159 | 160 | --- 161 | 162 | # Example Usage 163 | TODO: Include **`Example Usage`** 164 | 165 | ## Example 1 166 | 167 | #include // Include the input/output stream standard header 168 | #include // Include the thread standard header 169 | #include // Include the queue standard header 170 | #include // Include the string standard header 171 | #include "src/HMAC/core/base.h" // Include the header file for HMAC_Client functionality 172 | #include "src/SeedGeneration/core/base.h" // Include the header file for SeedGenerator functionality 173 | 174 | constexpr bool DEBUG = true; // Define a constexpr boolean variable DEBUG with value true 175 | 176 | void print_msg(const std::string &who, const std::string &message) { // Define a function to print messages 177 | if (DEBUG) { // Check if debugging is enabled 178 | std::cout << "[" << who << "] " << message << std::endl; // Print the message with source identifier 179 | } 180 | } 181 | 182 | bool check_if_queue_empty(std::queue &socket) { // Define a function to check if a queue is empty 183 | while (true) { // Infinite loop 184 | if (!socket.empty()) { // Check if the queue is not empty 185 | return true; // Return true if the queue is not empty 186 | } 187 | } 188 | } 189 | 190 | std::string get_content_from_socket(std::queue &socket) { // Define a function to get content from a socket (queue) 191 | if (check_if_queue_empty(socket)) { // Check if the queue is not empty 192 | std::string val = socket.front(); // Get the front element of the queue 193 | socket.pop(); // Remove the front element from the queue 194 | return val; // Return the retrieved value 195 | } 196 | } 197 | 198 | void client(std::queue &client_socket, std::queue &server_socket) { // Define the client function 199 | // Generating the main seed 200 | SeedGenerator seed_generator("job"); // Create an instance of SeedGenerator 201 | std::vector main_seed = seed_generator.generate(); // Generate the main seed 202 | 203 | // Creating an instance of HMAC_Client for encrypting messages 204 | print_msg("client", "first"); 205 | HMAC_Client obj("sha256", main_seed, 1); // Create an instance of HMAC_Client 206 | 207 | // Sending the main seed to the server 208 | server_socket.emplace(main_seed.begin(), main_seed.end()); // Convert the main seed vector to a string and send it to the server 209 | print_msg("client", "after obj"); 210 | 211 | // Checking if the server has successfully received the seed 212 | if (get_content_from_socket(client_socket) == obj.encrypt_message("")) { // Check if the server received the seed 213 | print_msg("client", "after if"); 214 | 215 | // If successful, send a message to the server 216 | std::string message = "hello"; // Define the message to be sent 217 | server_socket.push(obj.encrypt_message_by_chunks(message)); // Encrypt and send the message to the server 218 | print_msg("client", "client sent message " + message); 219 | 220 | // Checking if the server has successfully decrypted the message 221 | if (get_content_from_socket(client_socket) == obj.encrypt_message(message)) { // Check if the server decrypted the message 222 | print_msg("client", "server has decrypted message"); 223 | } 224 | } 225 | } 226 | 227 | void server(std::queue &server_socket, std::queue &client_socket) { // Define the server function 228 | // Receiving the main seed from the client 229 | std::string main_seed = get_content_from_socket(server_socket); // Receive the main seed from the client 230 | 231 | // Creating an instance of HMAC_Client for encrypting messages 232 | HMAC_Client obj("sha256", std::vector(main_seed.begin(), main_seed.end()), 1); // Create an instance of HMAC_Client 233 | 234 | // Sending an empty message to the client as acknowledgment 235 | client_socket.push(obj.encrypt_message("")); // Encrypt and send an empty message to the client as acknowledgment 236 | 237 | // Receiving the encrypted message from the client 238 | std::string msg = get_content_from_socket(server_socket); // Receive the encrypted message from the client 239 | print_msg("server", "message encrypted: " + msg); 240 | 241 | // Decrypting the message 242 | print_msg("server", "before decrypt "); 243 | std::string msg_raw = obj.decrypt_message_by_chunks(msg); // Decrypt the received message 244 | print_msg("server", "message raw: " + msg_raw); 245 | 246 | // Sending the encrypted message back to the client 247 | client_socket.push(obj.encrypt_message(msg_raw)); // Encrypt and send the decrypted message back to the client 248 | } 249 | 250 | int main() { // Main function 251 | std::queue client_socket, server_socket; // Create queues for client and server sockets 252 | std::thread client_thread(client, std::ref(client_socket), std::ref(server_socket)); // Create a thread for the client function 253 | std::thread server_thread(server, std::ref(server_socket), std::ref(client_socket)); // Create a thread for the server function 254 | 255 | // Joining the threads to wait for their completion 256 | client_thread.join(); // Wait for the client thread to finish 257 | server_thread.join(); // Wait for the server thread to finish 258 | 259 | return 0; // Return 0 to indicate successful execution 260 | } 261 | 262 | --- 263 | 264 | ## Example 2 265 | 266 | #include "src/ZeroKnowledge/core/base.h" // Include the header file for ZeroKnowledge class 267 | 268 | int main() { // Main function 269 | // Creating a ZeroKnowledge object for the client with specified curve and hash algorithm 270 | ZeroKnowledge clientObject = ZeroKnowledge::createNew("secp256k1", "sha3_256"); 271 | 272 | // Creating a ZeroKnowledge object for the server with specified curve and hash algorithm 273 | ZeroKnowledge serverObject = ZeroKnowledge::createNew("secp384r1", "sha3_512"); 274 | 275 | // Setting the server password 276 | std::string serverPassword = "SecretServerPassword"; 277 | 278 | // Creating a signature for the server password 279 | ZeroKnowledgeSignature serverSignature = serverObject.createSignature(serverPassword); 280 | 281 | // Creating a signature for the client identity 282 | std::string identity = "John"; 283 | ZeroKnowledgeSignature clientSignature = clientObject.createSignature(identity); 284 | std::cout<<"before\n"; 285 | 286 | // Generating a token signed by the server for the client 287 | std::cout< // Include the input/output stream standard header 320 | #include // Include the thread standard header 321 | #include // Include the queue standard header 322 | #include // Include the string standard header 323 | 324 | constexpr bool DEBUG = true; // Define a constexpr boolean variable DEBUG with value true 325 | 326 | void print_msg(const std::string &who, const std::string &message) { // Define a function to print messages 327 | if (DEBUG) { // Check if debugging is enabled 328 | std::cout << "[" << who << "] " << message << std::endl; // Print the message with source identifier 329 | } 330 | } 331 | 332 | bool check_if_queue_empty(std::queue &socket) { // Define a function to check if a queue is empty 333 | while (true) { // Infinite loop 334 | if (!socket.empty()) { // Check if the queue is not empty 335 | return true; // Return true if the queue is not empty 336 | } 337 | } 338 | } 339 | 340 | std::string get_content_from_socket(std::queue &socket) { // Define a function to get content from a socket (queue) 341 | if (check_if_queue_empty(socket)) { // Check if the queue is not empty 342 | std::string val = socket.front(); // Get the front element of the queue 343 | socket.pop(); // Remove the front element from the queue 344 | return val; // Return the retrieved value 345 | } 346 | } 347 | 348 | void client(std::queue &client_socket, std::queue &server_socket) { // Define the client function 349 | // Generating the main seed 350 | SeedGenerator seed_generator("job"); // Create an instance of SeedGenerator 351 | std::vector main_seed = seed_generator.generate(); // Generate the main seed 352 | 353 | // Creating an instance of HMAC_Client for encrypting messages 354 | print_msg("client", "first"); 355 | HMAC_Client obj("sha256", main_seed, 1); // Create an instance of HMAC_Client 356 | 357 | // Sending the main seed to the server 358 | server_socket.emplace(main_seed.begin(), main_seed.end()); // Convert the main seed vector to a string and send it to the server 359 | print_msg("client", "after obj"); 360 | 361 | // Checking if the server has successfully received the seed 362 | if (get_content_from_socket(client_socket) == obj.encrypt_message("")) { // Check if the server received the seed 363 | print_msg("client", "after if"); 364 | 365 | // If successful, send a message to the server 366 | std::string message = "hello"; // Define the message to be sent 367 | server_socket.push(obj.encrypt_message_by_chunks(message)); // Encrypt and send the message to the server 368 | print_msg("client", "client sent message " + message); 369 | 370 | // Checking if the server has successfully decrypted the message 371 | if (get_content_from_socket(client_socket) == obj.encrypt_message(message)) { // Check if the server decrypted the message 372 | print_msg("client", "server has decrypted message"); 373 | } 374 | } 375 | } 376 | 377 | void server(std::queue &server_socket, std::queue &client_socket) { // Define the server function 378 | // Receiving the main seed from the client 379 | std::string main_seed = get_content_from_socket(server_socket); // Receive the main seed from the client 380 | 381 | // Creating an instance of HMAC_Client for encrypting messages 382 | HMAC_Client obj("sha256", std::vector(main_seed.begin(), main_seed.end()), 1); // Create an instance of HMAC_Client 383 | 384 | // Sending an empty message to the client as acknowledgment 385 | client_socket.push(obj.encrypt_message("")); // Encrypt and send an empty message to the client as acknowledgment 386 | 387 | // Receiving the encrypted message from the client 388 | std::string msg = get_content_from_socket(server_socket); // Receive the encrypted message from the client 389 | print_msg("server", "message encrypted: " + msg); 390 | 391 | // Decrypting the message 392 | print_msg("server", "before decrypt "); 393 | std::string msg_raw = obj.decrypt_message_by_chunks(msg); // Decrypt the received message 394 | print_msg("server", "message raw: " + msg_raw); 395 | 396 | // Sending the encrypted message back to the client 397 | client_socket.push(obj.encrypt_message(msg_raw)); // Encrypt and send the decrypted message back to the client 398 | } 399 | 400 | void init_talking() { // Define a function to initialize client-server communication 401 | std::queue client_socket, server_socket; // Create queues for client and server sockets 402 | std::thread client_thread(client, std::ref(client_socket), std::ref(server_socket)); // Create a thread for the client function 403 | std::thread server_thread(server, std::ref(server_socket), std::ref(client_socket)); // Create a thread for the server function 404 | 405 | // Joining the threads to wait for their completion 406 | client_thread.join(); // Wait for the client thread to finish 407 | server_thread.join(); // Wait for the server thread to finish 408 | } 409 | 410 | int main() { // Main function 411 | 412 | // Creating a ZeroKnowledge object for the client with specified curve and hash algorithm 413 | ZeroKnowledge clientObject = ZeroKnowledge::createNew("secp256k1", "sha3_256"); 414 | 415 | // Creating a ZeroKnowledge object for the server with specified curve and hash algorithm 416 | ZeroKnowledge serverObject = ZeroKnowledge::createNew("secp384r1", "sha3_512"); 417 | 418 | // Setting the server password 419 | std::string serverPassword = "SecretServerPassword"; 420 | 421 | // Creating a signature for the server password 422 | ZeroKnowledgeSignature serverSignature = serverObject.createSignature(serverPassword); 423 | 424 | // Creating a signature for the client identity 425 | std::string identity = "John"; 426 | ZeroKnowledgeSignature clientSignature = clientObject.createSignature(identity); 427 | std::cout << "before\n"; 428 | 429 | // Generating a token signed by the server for the client 430 | std::cout << clientObject.token() << "\n"; 431 | 432 | ZeroKnowledgeData token = serverObject.sign(serverPassword, clientObject.token()); 433 | std::cout << "after\n"; 434 | 435 | // Generating proof using client identity and token 436 | ZeroKnowledgeData proof = clientObject.sign(identity, token.data); 437 | 438 | // Verifying the received proof 439 | bool serverVerification = serverObject.verify(token, serverSignature); 440 | if (!serverVerification) { // Check if server verification failed 441 | std::cout << "Server verification failed" << std::endl; // Print error message 442 | } else { // If server verification succeeded 443 | // Otherwise, verify the proof using client signature 444 | bool clientVerification = clientObject.verify(token, clientSignature, proof.proof); 445 | if (!clientVerification) { // Check if client verification failed 446 | std::cout << "Client verification failed" << std::endl; // Print error message 447 | } else { // If client verification succeeded 448 | std::cout << "Authentication successful" << std::endl; // Print success message 449 | init_talking(); // Initialize client-server communication 450 | 451 | } 452 | } 453 | 454 | return 0; // Return 0 to indicate successful execution 455 | } 456 | -------------------------------------------------------------------------------- /assets/Core Components (C++).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-cpp/77c9d20971f7d8eaac22a81db90696ccc0efb845/assets/Core Components (C++).png -------------------------------------------------------------------------------- /assets/Elliptic Curve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-cpp/77c9d20971f7d8eaac22a81db90696ccc0efb845/assets/Elliptic Curve.png -------------------------------------------------------------------------------- /assets/HMAC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-cpp/77c9d20971f7d8eaac22a81db90696ccc0efb845/assets/HMAC.png -------------------------------------------------------------------------------- /assets/Purpose-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-cpp/77c9d20971f7d8eaac22a81db90696ccc0efb845/assets/Purpose-1.png -------------------------------------------------------------------------------- /assets/Purpose-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-cpp/77c9d20971f7d8eaac22a81db90696ccc0efb845/assets/Purpose-2.png -------------------------------------------------------------------------------- /assets/Schnorr's Protocol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-cpp/77c9d20971f7d8eaac22a81db90696ccc0efb845/assets/Schnorr's Protocol.png -------------------------------------------------------------------------------- /assets/Synergistic Operation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-cpp/77c9d20971f7d8eaac22a81db90696ccc0efb845/assets/Synergistic Operation.png -------------------------------------------------------------------------------- /assets/ZKP-HMAC-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-cpp/77c9d20971f7d8eaac22a81db90696ccc0efb845/assets/ZKP-HMAC-1.png -------------------------------------------------------------------------------- /assets/ZKP-HMAC-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-cpp/77c9d20971f7d8eaac22a81db90696ccc0efb845/assets/ZKP-HMAC-2.png -------------------------------------------------------------------------------- /assets/ZKP-HMAC-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-cpp/77c9d20971f7d8eaac22a81db90696ccc0efb845/assets/ZKP-HMAC-3.png -------------------------------------------------------------------------------- /assets/ZKP-HMAC-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-cpp/77c9d20971f7d8eaac22a81db90696ccc0efb845/assets/ZKP-HMAC-4.png -------------------------------------------------------------------------------- /assets/zk-Call Preview [C++].png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zk-Call/zkp-hmac-communication-cpp/77c9d20971f7d8eaac22a81db90696ccc0efb845/assets/zk-Call Preview [C++].png -------------------------------------------------------------------------------- /example1.cpp: -------------------------------------------------------------------------------- 1 | #include // Include the input/output stream standard header 2 | #include // Include the thread standard header 3 | #include // Include the queue standard header 4 | #include // Include the string standard header 5 | #include "src/Hmac/core/base.h" // Include the header file for HMAC_Client functionality 6 | #include "src/SeedGeneration/core/base.h" // Include the header file for SeedGenerator functionality 7 | 8 | constexpr bool DEBUG = true; // Define a constexpr boolean variable DEBUG with value true 9 | 10 | void print_msg(const std::string &who, const std::string &message) { // Define a function to print messages 11 | if (DEBUG) { // Check if debugging is enabled 12 | std::cout << "[" << who << "] " << message << std::endl; // Print the message with source identifier 13 | } 14 | } 15 | 16 | bool check_if_queue_empty(std::queue &socket) { // Define a function to check if a queue is empty 17 | while (true) { // Infinite loop 18 | if (!socket.empty()) { // Check if the queue is not empty 19 | return true; // Return true if the queue is not empty 20 | } 21 | } 22 | } 23 | 24 | std::string get_content_from_socket(std::queue &socket) { // Define a function to get content from a socket (queue) 25 | if (check_if_queue_empty(socket)) { // Check if the queue is not empty 26 | std::string val = socket.front(); // Get the front element of the queue 27 | socket.pop(); // Remove the front element from the queue 28 | return val; // Return the retrieved value 29 | } 30 | } 31 | 32 | void client(std::queue &client_socket, std::queue &server_socket) { // Define the client function 33 | // Generating the main seed 34 | SeedGenerator seed_generator("job"); // Create an instance of SeedGenerator 35 | std::vector main_seed = seed_generator.generate(); // Generate the main seed 36 | 37 | // Creating an instance of HMAC_Client for encrypting messages 38 | print_msg("client", "first"); 39 | HMAC_Client obj("sha256", main_seed, 1); // Create an instance of HMAC_Client 40 | 41 | // Sending the main seed to the server 42 | server_socket.emplace(main_seed.begin(), main_seed.end()); // Convert the main seed vector to a string and send it to the server 43 | print_msg("client", "after obj"); 44 | 45 | // Checking if the server has successfully received the seed 46 | if (get_content_from_socket(client_socket) == obj.encrypt_message("")) { // Check if the server received the seed 47 | print_msg("client", "after if"); 48 | 49 | // If successful, send a message to the server 50 | std::string message = "hello"; // Define the message to be sent 51 | server_socket.push(obj.encrypt_message_by_chunks(message)); // Encrypt and send the message to the server 52 | print_msg("client", "client sent message " + message); 53 | 54 | // Checking if the server has successfully decrypted the message 55 | if (get_content_from_socket(client_socket) == obj.encrypt_message(message)) { // Check if the server decrypted the message 56 | print_msg("client", "server has decrypted message"); 57 | } 58 | } 59 | } 60 | 61 | void server(std::queue &server_socket, std::queue &client_socket) { // Define the server function 62 | // Receiving the main seed from the client 63 | std::string main_seed = get_content_from_socket(server_socket); // Receive the main seed from the client 64 | 65 | // Creating an instance of HMAC_Client for encrypting messages 66 | HMAC_Client obj("sha256", std::vector(main_seed.begin(), main_seed.end()), 1); // Create an instance of HMAC_Client 67 | 68 | // Sending an empty message to the client as acknowledgment 69 | client_socket.push(obj.encrypt_message("")); // Encrypt and send an empty message to the client as acknowledgment 70 | 71 | // Receiving the encrypted message from the client 72 | std::string msg = get_content_from_socket(server_socket); // Receive the encrypted message from the client 73 | print_msg("server", "message encrypted: " + msg); 74 | 75 | // Decrypting the message 76 | print_msg("server", "before decrypt "); 77 | std::string msg_raw = obj.decrypt_message_by_chunks(msg); // Decrypt the received message 78 | print_msg("server", "message raw: " + msg_raw); 79 | 80 | // Sending the encrypted message back to the client 81 | client_socket.push(obj.encrypt_message(msg_raw)); // Encrypt and send the decrypted message back to the client 82 | } 83 | 84 | int main() { // Main function 85 | std::queue client_socket, server_socket; // Create queues for client and server sockets 86 | std::thread client_thread(client, std::ref(client_socket), std::ref(server_socket)); // Create a thread for the client function 87 | std::thread server_thread(server, std::ref(server_socket), std::ref(client_socket)); // Create a thread for the server function 88 | 89 | // Joining the threads to wait for their completion 90 | client_thread.join(); // Wait for the client thread to finish 91 | server_thread.join(); // Wait for the server thread to finish 92 | 93 | return 0; // Return 0 to indicate successful execution 94 | } 95 | -------------------------------------------------------------------------------- /example2.cpp: -------------------------------------------------------------------------------- 1 | #include "src/ZeroKnowledge/core/base.h" // Include the header file for ZeroKnowledge class 2 | 3 | int main() { // Main function 4 | // Creating a ZeroKnowledge object for the client with specified curve and hash algorithm 5 | ZeroKnowledge clientObject = ZeroKnowledge::createNew("secp256k1", "sha3_256"); 6 | 7 | // Creating a ZeroKnowledge object for the server with specified curve and hash algorithm 8 | ZeroKnowledge serverObject = ZeroKnowledge::createNew("secp384r1", "sha3_512"); 9 | 10 | // Setting the server password 11 | std::string serverPassword = "SecretServerPassword"; 12 | 13 | // Creating a signature for the server password 14 | ZeroKnowledgeSignature serverSignature = serverObject.createSignature(serverPassword); 15 | 16 | // Creating a signature for the client identity 17 | std::string identity = "John"; 18 | ZeroKnowledgeSignature clientSignature = clientObject.createSignature(identity); 19 | std::cout<<"before\n"; 20 | 21 | // Generating a token signed by the server for the client 22 | std::cout< // Include the input/output stream standard header 5 | #include // Include the thread standard header 6 | #include // Include the queue standard header 7 | #include // Include the string standard header 8 | 9 | constexpr bool DEBUG = true; // Define a constexpr boolean variable DEBUG with value true 10 | 11 | void print_msg(const std::string &who, const std::string &message) { // Define a function to print messages 12 | if (DEBUG) { // Check if debugging is enabled 13 | std::cout << "[" << who << "] " << message << std::endl; // Print the message with source identifier 14 | } 15 | } 16 | 17 | bool check_if_queue_empty(std::queue &socket) { // Define a function to check if a queue is empty 18 | while (true) { // Infinite loop 19 | if (!socket.empty()) { // Check if the queue is not empty 20 | return true; // Return true if the queue is not empty 21 | } 22 | } 23 | } 24 | 25 | std::string get_content_from_socket(std::queue &socket) { // Define a function to get content from a socket (queue) 26 | if (check_if_queue_empty(socket)) { // Check if the queue is not empty 27 | std::string val = socket.front(); // Get the front element of the queue 28 | socket.pop(); // Remove the front element from the queue 29 | return val; // Return the retrieved value 30 | } 31 | } 32 | 33 | void client(std::queue &client_socket, std::queue &server_socket) { // Define the client function 34 | // Generating the main seed 35 | SeedGenerator seed_generator("job"); // Create an instance of SeedGenerator 36 | std::vector main_seed = seed_generator.generate(); // Generate the main seed 37 | 38 | // Creating an instance of HMAC_Client for encrypting messages 39 | print_msg("client", "first"); 40 | HMAC_Client obj("sha256", main_seed, 1); // Create an instance of HMAC_Client 41 | 42 | // Sending the main seed to the server 43 | server_socket.emplace(main_seed.begin(), main_seed.end()); // Convert the main seed vector to a string and send it to the server 44 | print_msg("client", "after obj"); 45 | 46 | // Checking if the server has successfully received the seed 47 | if (get_content_from_socket(client_socket) == obj.encrypt_message("")) { // Check if the server received the seed 48 | print_msg("client", "after if"); 49 | 50 | // If successful, send a message to the server 51 | std::string message = "hello"; // Define the message to be sent 52 | server_socket.push(obj.encrypt_message_by_chunks(message)); // Encrypt and send the message to the server 53 | print_msg("client", "client sent message " + message); 54 | 55 | // Checking if the server has successfully decrypted the message 56 | if (get_content_from_socket(client_socket) == obj.encrypt_message(message)) { // Check if the server decrypted the message 57 | print_msg("client", "server has decrypted message"); 58 | } 59 | } 60 | } 61 | 62 | void server(std::queue &server_socket, std::queue &client_socket) { // Define the server function 63 | // Receiving the main seed from the client 64 | std::string main_seed = get_content_from_socket(server_socket); // Receive the main seed from the client 65 | 66 | // Creating an instance of HMAC_Client for encrypting messages 67 | HMAC_Client obj("sha256", std::vector(main_seed.begin(), main_seed.end()), 1); // Create an instance of HMAC_Client 68 | 69 | // Sending an empty message to the client as acknowledgment 70 | client_socket.push(obj.encrypt_message("")); // Encrypt and send an empty message to the client as acknowledgment 71 | 72 | // Receiving the encrypted message from the client 73 | std::string msg = get_content_from_socket(server_socket); // Receive the encrypted message from the client 74 | print_msg("server", "message encrypted: " + msg); 75 | 76 | // Decrypting the message 77 | print_msg("server", "before decrypt "); 78 | std::string msg_raw = obj.decrypt_message_by_chunks(msg); // Decrypt the received message 79 | print_msg("server", "message raw: " + msg_raw); 80 | 81 | // Sending the encrypted message back to the client 82 | client_socket.push(obj.encrypt_message(msg_raw)); // Encrypt and send the decrypted message back to the client 83 | } 84 | 85 | void init_talking() { // Define a function to initialize client-server communication 86 | std::queue client_socket, server_socket; // Create queues for client and server sockets 87 | std::thread client_thread(client, std::ref(client_socket), std::ref(server_socket)); // Create a thread for the client function 88 | std::thread server_thread(server, std::ref(server_socket), std::ref(client_socket)); // Create a thread for the server function 89 | 90 | // Joining the threads to wait for their completion 91 | client_thread.join(); // Wait for the client thread to finish 92 | server_thread.join(); // Wait for the server thread to finish 93 | } 94 | 95 | int main() { // Main function 96 | 97 | // Creating a ZeroKnowledge object for the client with specified curve and hash algorithm 98 | ZeroKnowledge clientObject = ZeroKnowledge::createNew("secp256k1", "sha3_256"); 99 | 100 | // Creating a ZeroKnowledge object for the server with specified curve and hash algorithm 101 | ZeroKnowledge serverObject = ZeroKnowledge::createNew("secp384r1", "sha3_512"); 102 | 103 | // Setting the server password 104 | std::string serverPassword = "SecretServerPassword"; 105 | 106 | // Creating a signature for the server password 107 | ZeroKnowledgeSignature serverSignature = serverObject.createSignature(serverPassword); 108 | 109 | // Creating a signature for the client identity 110 | std::string identity = "John"; 111 | ZeroKnowledgeSignature clientSignature = clientObject.createSignature(identity); 112 | std::cout << "before\n"; 113 | 114 | // Generating a token signed by the server for the client 115 | std::cout << clientObject.token() << "\n"; 116 | 117 | ZeroKnowledgeData token = serverObject.sign(serverPassword, clientObject.token()); 118 | std::cout << "after\n"; 119 | 120 | // Generating proof using client identity and token 121 | ZeroKnowledgeData proof = clientObject.sign(identity, token.data); 122 | 123 | // Verifying the received proof 124 | bool serverVerification = serverObject.verify(token, serverSignature); 125 | if (!serverVerification) { // Check if server verification failed 126 | std::cout << "Server verification failed" << std::endl; // Print error message 127 | } else { // If server verification succeeded 128 | // Otherwise, verify the proof using client signature 129 | bool clientVerification = clientObject.verify(token, clientSignature, proof.proof); 130 | if (!clientVerification) { // Check if client verification failed 131 | std::cout << "Client verification failed" << std::endl; // Print error message 132 | } else { // If client verification succeeded 133 | std::cout << "Authentication successful" << std::endl; // Print success message 134 | init_talking(); // Initialize client-server communication 135 | 136 | } 137 | } 138 | 139 | return 0; // Return 0 to indicate successful execution 140 | } -------------------------------------------------------------------------------- /src/HMAC/algorithms/base.cpp: -------------------------------------------------------------------------------- 1 | #include "base.h" 2 | 3 | // Function definition for Hash_type_and_len() 4 | std::map Hash_type_and_len() { 5 | // Create a map object to store hash types and their corresponding lengths 6 | std::map obj; 7 | 8 | // Assign hash types and their lengths to the map 9 | obj["sha3_224"] = 56; // SHA-3 224-bit hash length 10 | obj["sha256"] = 64; // SHA-256 hash length 11 | 12 | // Return the populated map 13 | return obj; 14 | } 15 | -------------------------------------------------------------------------------- /src/HMAC/algorithms/base.h: -------------------------------------------------------------------------------- 1 | #ifndef HMAC_ALGORITHMS_BASE_H 2 | // Preprocessor directive to ensure that this header file is included only once during compilation 3 | 4 | #define HMAC_ALGORITHMS_BASE_H 5 | // Definition of the header guard macro to prevent multiple inclusions of the header file 6 | 7 | #include // Include the header file for the map container 8 | #include // Include the header file for string utilities 9 | #include // Include the header file for input/output stream objects 10 | 11 | // Function declaration for Hash_type_and_len() 12 | std::map Hash_type_and_len(); 13 | 14 | #endif //HMAC_ALGORITHMS_BASE_H 15 | // End of the header guard macro definition and the end of the header file 16 | -------------------------------------------------------------------------------- /src/HMAC/core/base.cpp: -------------------------------------------------------------------------------- 1 | #include "base.h" // Include the header file for the HMAC_Client class 2 | 3 | // Constructor definition for HMAC_Client class 4 | HMAC_Client::HMAC_Client(std::string algorithm, const std::vector& secret, int symbol_count) : 5 | _algorithm(std::move(algorithm)), _secret(secret), _symbol_count(symbol_count) { 6 | init_decrypt_dict(); // Initialize the decryption dictionary 7 | } 8 | 9 | // Method to initialize the decryption dictionary 10 | void HMAC_Client::init_decrypt_dict() { 11 | std::string all_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"; 12 | 13 | // Iterate through all characters 14 | for (char c : all_chars) { 15 | std::string key = encrypt_message(std::string(1, c)); // Encrypt the character (convert char to string) 16 | _decrypt_dict[key] = std::string(1, c); // Map the encrypted character to its original form 17 | } 18 | } 19 | 20 | // Method to encrypt a message by processing it in chunks 21 | std::string HMAC_Client::encrypt_message_by_chunks(const std::string& message) { 22 | std::string encrypted_message; 23 | // Process the message in chunks 24 | for (size_t i = 0; i < message.length(); i += _symbol_count) { 25 | std::string chunk = message.substr(i, _symbol_count); // Extract a chunk of the message 26 | encrypted_message += encrypt_message(chunk); // Encrypt the chunk and append it to the encrypted message 27 | } 28 | return encrypted_message; // Return the encrypted message 29 | } 30 | 31 | // Method to encrypt a message 32 | std::string HMAC_Client::encrypt_message(const std::string& message) { 33 | unsigned char digest[EVP_MAX_MD_SIZE]; // Buffer to store the digest 34 | unsigned int digest_len; // Length of the digest 35 | 36 | // Compute the HMAC digest using SHA-256 algorithm 37 | HMAC(EVP_sha256(), _secret.data(), _secret.size(), reinterpret_cast(message.c_str()), 38 | message.length(), digest, &digest_len); 39 | 40 | // Convert the digest to a hexadecimal string 41 | std::stringstream ss; 42 | ss << std::hex << std::setfill('0'); 43 | for (unsigned int i = 0; i < digest_len; ++i) { 44 | ss << std::setw(2) << static_cast(digest[i]); 45 | } 46 | 47 | return ss.str(); // Return the hexadecimal string representing the digest 48 | } 49 | 50 | // Method to decrypt a message by processing it in chunks 51 | std::string HMAC_Client::decrypt_message_by_chunks(const std::string& message) { 52 | std::string msg_raw; // Variable to store the raw message 53 | int chunk_len = Hash_type_and_len()["sha256"]; // Get the length of a single chunk 54 | 55 | // Check if the message length is divisible by the chunk length 56 | if (message.length() % chunk_len == 0) { 57 | // Process the message in chunks 58 | for (size_t i = 0; i < message.length(); i += chunk_len) { 59 | std::string chunk = message.substr(i, chunk_len); // Extract a chunk of the message 60 | msg_raw += decrypt_message(chunk); // Decrypt the chunk and append it to the raw message 61 | } 62 | return msg_raw; // Return the raw message 63 | } else { 64 | // If the message length is not divisible by the chunk length, throw an exception 65 | throw std::invalid_argument("The algorithm is invalid: " + _algorithm); 66 | } 67 | } 68 | 69 | // Method to decrypt a message 70 | std::string HMAC_Client::decrypt_message(const std::string& message) { 71 | auto it = _decrypt_dict.find(message); // Find the encrypted message in the decryption dictionary 72 | if (it != _decrypt_dict.end()) { 73 | return it->second; // Return the corresponding original message if found 74 | } else { 75 | // If the encrypted message is not found in the decryption dictionary, throw an exception 76 | throw std::invalid_argument("The algorithm is invalid: " + _algorithm); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/HMAC/core/base.h: -------------------------------------------------------------------------------- 1 | #ifndef HMAC_CORE_BASE_H 2 | // Preprocessor directive to ensure that this header file is included only once during compilation 3 | 4 | #define HMAC_CORE_BASE_H 5 | // Definition of the header guard macro to prevent multiple inclusions of the header file 6 | 7 | #include // Include the header file for string utilities 8 | #include // Include the header file for vector containers 9 | #include // Include the header file for map containers 10 | #include // Include the header file for HMAC related functions 11 | #include // Include the header file for algorithms 12 | #include // Include the header file for standard exception objects 13 | #include // Include the header file for OpenSSL's EVP functions 14 | #include // Include the header file for input/output manipulators 15 | #include // Include the header file for string streams 16 | #include "../algorithms/base.h" // Include the header file for base algorithms 17 | 18 | // Class declaration for HMAC_Client 19 | class HMAC_Client { 20 | private: 21 | std::string _algorithm; // Member variable to store the HMAC algorithm 22 | std::vector _secret; // Member variable to store the secret key 23 | std::map _decrypt_dict; // Member variable to store decryption dictionary 24 | int _symbol_count; // Member variable to store symbol count 25 | 26 | public: 27 | // Constructor for HMAC_Client class 28 | HMAC_Client(std::string algorithm = "sha256", const std::vector& secret = {}, int symbol_count = 1); 29 | 30 | // Method to initialize the decryption dictionary 31 | void init_decrypt_dict(); 32 | 33 | // Method to encrypt a message by processing it in chunks 34 | std::string encrypt_message_by_chunks(const std::string& message); 35 | 36 | // Method to encrypt a message 37 | std::string encrypt_message(const std::string& message); 38 | 39 | // Method to decrypt a message by processing it in chunks 40 | std::string decrypt_message_by_chunks(const std::string& message); 41 | 42 | // Method to decrypt a message 43 | std::string decrypt_message(const std::string& message); 44 | }; 45 | 46 | #endif //HMAC_CORE_BASE_H 47 | // End of the header guard macro definition and the end of the header file 48 | -------------------------------------------------------------------------------- /src/HMAC/errors/base.cpp: -------------------------------------------------------------------------------- 1 | #include "base.h" 2 | 3 | -------------------------------------------------------------------------------- /src/HMAC/errors/base.h: -------------------------------------------------------------------------------- 1 | #ifndef HMAC_ERRORS_BASE_H 2 | #define HMAC_ERRORS_BASE_H 3 | 4 | #endif //HMAC_ERRORS_BASE_H 5 | -------------------------------------------------------------------------------- /src/HMAC/types/base.cpp: -------------------------------------------------------------------------------- 1 | #include "base.h" 2 | 3 | -------------------------------------------------------------------------------- /src/HMAC/types/base.h: -------------------------------------------------------------------------------- 1 | #ifndef HMAC_TYPES_BASE_H 2 | #define HMAC_TYPES_BASE_H 3 | 4 | #endif //HMAC_TYPES_BASE_H 5 | -------------------------------------------------------------------------------- /src/HMAC/utils/base.cpp: -------------------------------------------------------------------------------- 1 | #include "base.h" // Include the header file "base.h" 2 | 3 | template // Definition of a template function, taking a typename T as a parameter 4 | std::string to_str(const T& data, const std::string& encoding) { // Definition of the function to_str, which converts data to a string using the specified encoding 5 | if constexpr (std::is_same_v) { // Conditional compilation based on whether T is std::string 6 | return data; // Return the input data directly if it's already a string 7 | } else if constexpr (std::is_same_v>) { // Conditional compilation based on whether T is std::vector 8 | return std::string(data.begin(), data.end()); // Return a string constructed from the vector of unsigned chars 9 | } else if constexpr (std::is_same_v) { // Conditional compilation based on whether T is const char* 10 | return std::string(data); // Return a string constructed from the C-style string 11 | } else if constexpr (std::is_same_v) { // Conditional compilation based on whether T is const unsigned char* 12 | return std::string(reinterpret_cast(data)); // Return a string constructed from the pointer to unsigned chars, cast to a const char* 13 | } else if constexpr (std::is_integral_v) { // Conditional compilation based on whether T is an integral type 14 | return std::to_string(data); // Return a string representation of the integral value 15 | } else if constexpr (std::is_floating_point_v) { // Conditional compilation based on whether T is a floating-point type 16 | return std::to_string(data); // Return a string representation of the floating-point value 17 | } else if constexpr (std::is_same_v) { // Conditional compilation based on whether T is bool 18 | return data ? "true" : "false"; // Return "true" or "false" depending on the boolean value 19 | } else { 20 | static_assert(std::is_same_v, "Unsupported type for to_str()"); // If none of the above conditions match, trigger a static assertion indicating unsupported type for to_str() 21 | } 22 | } 23 | 24 | template // Definition of a template function, taking a typename T as a parameter 25 | std::vector to_bytes(const T& data, const std::string& encoding) { // Definition of the function to_bytes, which converts data to a vector of unsigned chars using the specified encoding 26 | if constexpr (std::is_same_v) { // Conditional compilation based on whether T is std::string 27 | return std::vector(data.begin(), data.end()); // Return a vector of unsigned chars constructed from the string 28 | } else if constexpr (std::is_same_v) { // Conditional compilation based on whether T is const char* 29 | return std::vector(data, data + strlen(data)); // Return a vector of unsigned chars constructed from the C-style string 30 | } else if constexpr (std::is_same_v) { // Conditional compilation based on whether T is const unsigned char* 31 | return std::vector(data, data + strlen(reinterpret_cast(data))); // Return a vector of unsigned chars constructed from the pointer to unsigned chars, cast to a const char* 32 | } else if constexpr (std::is_integral_v) { // Conditional compilation based on whether T is an integral type 33 | std::string str = std::to_string(data); // Convert the integral value to a string 34 | return std::vector(str.begin(), str.end()); // Return a vector of unsigned chars constructed from the string 35 | } else if constexpr (std::is_floating_point_v) { // Conditional compilation based on whether T is a floating-point type 36 | std::string str = std::to_string(data); // Convert the floating-point value to a string 37 | return std::vector(str.begin(), str.end()); // Return a vector of unsigned chars constructed from the string 38 | } else if constexpr (std::is_same_v) { // Conditional compilation based on whether T is bool 39 | std::string str = data ? "true" : "false"; // Convert the boolean value to a string 40 | return std::vector(str.begin(), str.end()); // Return a vector of unsigned chars constructed from the string 41 | } else { 42 | static_assert(std::is_same_v, "Unsupported type for to_bytes()"); // If none of the above conditions match, trigger a static assertion indicating unsupported type for to_bytes() 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/HMAC/utils/base.h: -------------------------------------------------------------------------------- 1 | #ifndef HMAC_UTILS_BASE_H // Preprocessor directive: ifndef checks if the identifier HMAC_UTILS_BASE_H has not been defined before 2 | #define HMAC_UTILS_BASE_H // Preprocessor directive: defines the identifier HMAC_UTILS_BASE_H 3 | 4 | #include // Include the string standard header 5 | #include // Include the vector standard header 6 | #include // Include the cstring standard header (for C-style string manipulation) 7 | 8 | template // Declaration of a template function, taking a typename T as a parameter 9 | std::string to_str(const T& data, const std::string& encoding = "utf-8"); // Declaration of a function named to_str that converts data to a string using the specified encoding (default is utf-8) 10 | 11 | template // Declaration of a template function, taking a typename T as a parameter 12 | std::vector to_bytes(const T& data, const std::string& encoding = "utf-8"); // Declaration of a function named to_bytes that converts data to a vector of unsigned chars using the specified encoding (default is utf-8) 13 | 14 | #endif //HMAC_UTILS_BASE_H // End of the ifndef directive, comments that this is the end of the ifndef block 15 | -------------------------------------------------------------------------------- /src/SeedGeneration/core/base.cpp: -------------------------------------------------------------------------------- 1 | #include "base.h" // Assuming hash_digest() and get_random_int() functions are implemented in utils.h 2 | 3 | // Constructor definition for SeedGenerator class 4 | SeedGenerator::SeedGenerator(const std::string &phrase) : _phrase(phrase) {} 5 | // Constructor initializes the _phrase member variable with the provided phrase 6 | 7 | // Method to generate a hash 8 | std::vector SeedGenerator::_hash(int length) { 9 | // Create a vector to store combined bytes 10 | std::vector combined_bytes(length + _phrase.size()); 11 | 12 | // Secure random generation 13 | std::random_device rd; 14 | std::mt19937 gen(rd()); // Mersenne Twister pseudo-random generator engine 15 | std::uniform_int_distribution dist(0, 255); // Distribution for random bytes 16 | 17 | // Fill the vector with random bytes 18 | for (int i = 0; i < length; ++i) { 19 | combined_bytes[i] = dist(gen); // Generate random byte and store in vector 20 | } 21 | 22 | // Append phrase bytes to the end of the vector 23 | std::copy(_phrase.begin(), _phrase.end(), combined_bytes.begin() + length); 24 | 25 | // Hash the combined bytes using hash_digest() function 26 | return hash_digest(combined_bytes); 27 | } 28 | 29 | // Method to generate a seed 30 | std::vector SeedGenerator::generate() { 31 | // Call the _hash method with a random length obtained from get_random_int() function 32 | return _hash(get_random_int()); 33 | } 34 | -------------------------------------------------------------------------------- /src/SeedGeneration/core/base.h: -------------------------------------------------------------------------------- 1 | #ifndef SEEDGENERATION_CORE_BASE_H 2 | // Preprocessor directive to ensure that this header file is included only once during compilation 3 | 4 | #define SEEDGENERATION_CORE_BASE_H 5 | // Definition of the header guard macro to prevent multiple inclusions of the header file 6 | 7 | #include // String utilities 8 | #include // Random number generation 9 | #include "../utils/base.h" // Including header file for utility functions 10 | 11 | // Declaration of the SeedGenerator class 12 | class SeedGenerator { 13 | public: 14 | // Constructor for SeedGenerator class 15 | SeedGenerator(const std::string& phrase); 16 | 17 | // Method to generate a seed 18 | std::vector generate(); 19 | 20 | private: 21 | std::string _phrase; // Member variable to store the phrase 22 | std::vector _hash(int length); // Method to generate a hash 23 | }; 24 | 25 | #endif //SEEDGENERATION_CORE_BASE_H 26 | // End of the header guard macro definition and the end of the header file 27 | -------------------------------------------------------------------------------- /src/SeedGeneration/errors/base.cpp: -------------------------------------------------------------------------------- 1 | #include "base.h" 2 | 3 | -------------------------------------------------------------------------------- /src/SeedGeneration/errors/base.h: -------------------------------------------------------------------------------- 1 | #ifndef SEEDGENERATION_ERRORS_BASE_H 2 | #define SEEDGENERATION_ERRORS_BASE_H 3 | 4 | #endif //SEEDGENERATION_ERRORS_BASE_H 5 | -------------------------------------------------------------------------------- /src/SeedGeneration/types/base.cpp: -------------------------------------------------------------------------------- 1 | #include "base.h" 2 | 3 | -------------------------------------------------------------------------------- /src/SeedGeneration/types/base.h: -------------------------------------------------------------------------------- 1 | #ifndef SEEDGENERATION_TYPES_BASE_H 2 | #define SEEDGENERATION_TYPES_BASE_H 3 | 4 | #endif //SEEDGENERATION_TYPES_BASE_H 5 | -------------------------------------------------------------------------------- /src/SeedGeneration/utils/base.cpp: -------------------------------------------------------------------------------- 1 | #include "base.h" 2 | 3 | // Function to generate a random integer 4 | int get_random_int() { 5 | std::random_device rd; // Obtain a random seed from the operating system's random device 6 | std::mt19937 gen(rd()); // Initialize the Mersenne Twister pseudo-random number generator with the obtained seed 7 | std::uniform_int_distribution dist(0, (1 << 20) - 1); // Define a uniform distribution over the range [0, 2^20) 8 | return dist(gen); // Generate a random integer within the defined range and return it 9 | } 10 | 11 | // Function to compute the SHA-256 hash digest 12 | std::vector hash_digest(const std::vector &combined_bytes) { 13 | std::vector hash(SHA256_DIGEST_LENGTH); // Initialize a vector to store the hash digest 14 | 15 | SHA256_CTX sha256; // Declare a SHA-256 context structure 16 | SHA256_Init(&sha256); // Initialize the SHA-256 context 17 | SHA256_Update(&sha256, combined_bytes.data(), combined_bytes.size()); // Update the SHA-256 context with the input data 18 | SHA256_Final(hash.data(), &sha256); // Finalize the hashing process and store the hash digest in the vector 19 | 20 | return hash; // Return the computed hash digest 21 | } 22 | -------------------------------------------------------------------------------- /src/SeedGeneration/utils/base.h: -------------------------------------------------------------------------------- 1 | #ifndef SEEDGENERATION_UTILS_BASE_H 2 | // Preprocessor directive to ensure that this header file is included only once during compilation 3 | 4 | #define SEEDGENERATION_UTILS_BASE_H 5 | // Definition of the header guard macro to prevent multiple inclusions of the header file 6 | 7 | #include // Include the header file for random number generation 8 | #include // Include the header file for vector containers 9 | #include // OpenSSL header for SHA hashing 10 | 11 | // Function declaration to get a random integer 12 | int get_random_int(); 13 | 14 | // Function declaration to compute the hash digest of a vector of unsigned characters 15 | std::vector hash_digest(const std::vector &combined_bytes); 16 | 17 | #endif //SEEDGENERATION_UTILS_BASE_H 18 | // End of the header guard macro definition and the end of the header file 19 | -------------------------------------------------------------------------------- /src/ZeroKnowledge/algorithms/base.cpp: -------------------------------------------------------------------------------- 1 | #include "base.h" 2 | // Including the header file that declares the hash function 3 | 4 | // Function definition for hashing a string using SHA-3 algorithm 5 | uint64_t hash(const std::string &value) { 6 | // Calculate SHA-3 hash 7 | unsigned char hashOutput[SHA512_DIGEST_LENGTH]; // Buffer to store hash output 8 | SHA512_CTX ctx; // SHA-512 context structure 9 | SHA512_Init(&ctx); // Initialize SHA-512 context 10 | SHA512_Update(&ctx, value.c_str(), value.length()); // Update context with input data 11 | SHA512_Final(hashOutput, &ctx); // Finalize hashing and store the result in hashOutput 12 | 13 | // Convert the hash output to uint64_t 14 | uint64_t hashValue = 0; // Variable to store final hash value 15 | for (size_t i = 0; i < SHA512_DIGEST_LENGTH && i < sizeof(hashValue); ++i) { 16 | // Combine bytes from hashOutput into hashValue 17 | hashValue |= (static_cast(hashOutput[i]) << (8 * i)); 18 | } 19 | 20 | return hashValue; // Return the final hash value 21 | } 22 | -------------------------------------------------------------------------------- /src/ZeroKnowledge/algorithms/base.h: -------------------------------------------------------------------------------- 1 | #ifndef ZEROKNOWLEDGE_ALGORITHMS_BASE_H 2 | // Preprocessor directive to ensure that this header file is included only once during compilation 3 | 4 | #define ZEROKNOWLEDGE_ALGORITHMS_BASE_H 5 | // Definition of the header guard macro to prevent multiple inclusions of the header file 6 | 7 | #include // Input/output stream objects 8 | #include // Integer types with exact widths 9 | #include // OpenSSL library for SHA hash functions 10 | 11 | // Function declaration for hashing a string 12 | uint64_t hash(const std::string &value); 13 | // Declaration of the hash function to compute the hash of a string 14 | 15 | #endif //ZEROKNOWLEDGE_ALGORITHMS_BASE_H 16 | // End of the header guard macro definition and the end of the header file 17 | -------------------------------------------------------------------------------- /src/ZeroKnowledge/core/base.cpp: -------------------------------------------------------------------------------- 1 | #include "base.h" 2 | 3 | // Constructor for the ZeroKnowledge class 4 | ZeroKnowledge::ZeroKnowledge(const ZeroKnowledgeParams ¶ms, const string &sec, const string &alg, const string &iss) 5 | : params(params), secret(sec), algorithm(alg), issuer(iss), obj_curve(params.curve) { 6 | // Initialize ZeroKnowledge object with provided parameters: 7 | // - params: ZeroKnowledgeParams object containing curve, salt, and algorithm information 8 | // - sec: Secret key for cryptographic operations 9 | // - alg: Algorithm used for cryptographic operations 10 | // - iss: Issuer of tokens 11 | // Also initialize obj_curve with the curve specified in params. 12 | } 13 | 14 | // Static method to create a new instance of ZeroKnowledge 15 | ZeroKnowledge ZeroKnowledge::createNew(const string &curveName, const string &hashAlg, 16 | const string &jwtSecret, const string &jwtAlg, 17 | int saltSize) { 18 | // Create a new instance of ZeroKnowledge with specified parameters: 19 | // - curveName: Name of the elliptic curve to use 20 | // - hashAlg: Algorithm for hashing 21 | // - jwtSecret: Secret key for JWT operations 22 | // - jwtAlg: Algorithm for JWT operations 23 | // - saltSize: Size of the salt to generate 24 | // The ZeroKnowledgeParams object contains curve, salt, and algorithm information. 25 | // Return the created ZeroKnowledge object. 26 | 27 | // Create ZeroKnowledgeParams object with specified parameters 28 | ZeroKnowledgeParams params; 29 | params.curve = curveName; 30 | params.salt = generateSalt(saltSize); // Generate a salt 31 | params.algorithm = hashAlg; // Set hash algorithm 32 | 33 | // Return new ZeroKnowledge object initialized with provided parameters 34 | return ZeroKnowledge(params, jwtSecret, jwtAlg, "zk-call"); 35 | } 36 | 37 | // Method to generate a random salt 38 | std::string ZeroKnowledge::generateSalt(int size) { 39 | // Generate random bytes to create a salt of the specified size 40 | std::random_device rd; // Seed for random number generator 41 | std::mt19937 gen(rd()); // Mersenne Twister random number engine 42 | std::uniform_int_distribution dis(0, 255); // Uniform distribution for byte values 43 | 44 | // Generate random salt string of specified size 45 | std::string salt(size, '\0'); // Initialize string with null characters of size 'size' 46 | for (auto &byte: salt) { 47 | byte = dis(gen); // Assign random byte value to each character in the salt string 48 | } 49 | 50 | // Return the generated salt 51 | return salt; 52 | } 53 | 54 | // Method to generate a random token 55 | std::string ZeroKnowledge::token() { 56 | // Generate a random token using cryptographic secure random bytes 57 | std::random_device rd; // Seed for random number generator 58 | std::mt19937 gen(rd()); // Mersenne Twister random number engine 59 | std::uniform_int_distribution dis(0, 255); // Uniform distribution for byte values 60 | 61 | // Calculate the number of bytes required for the token based on curve degree 62 | size_t numBytes = (obj_curve.getDegree() + 7) >> 3; // Right shift by 3 (divide by 8) 63 | 64 | // Generate random token string of appropriate size 65 | std::string token(numBytes, '\0'); // Initialize string with null characters of appropriate size 66 | for (auto &byte: token) { 67 | byte = dis(gen); // Assign random byte value to each character in the token string 68 | } 69 | 70 | // Return the generated token 71 | return token; 72 | } 73 | 74 | 75 | // Function to hash a string with a point on the elliptic curve 76 | uint64_t ZeroKnowledge::hash_with_point(const std::string &value, const Point &R) { 77 | // Convert the point R to its uncompressed coordinates 78 | BIGNUM *x = BN_new(); // Allocate memory for x-coordinate 79 | BIGNUM *y = BN_new(); // Allocate memory for y-coordinate 80 | EC_POINT_get_affine_coordinates_GFp(obj_curve.getGroup(), R.get(), x, y, 81 | nullptr); // Get affine coordinates of point R 82 | 83 | // Convert the coordinates to bytes 84 | unsigned char *x_bytes = new unsigned char[BN_num_bytes(x)]; // Allocate memory for x-coordinate bytes 85 | unsigned char *y_bytes = new unsigned char[BN_num_bytes(y)]; // Allocate memory for y-coordinate bytes 86 | BN_bn2bin(x, x_bytes); // Convert x-coordinate to bytes 87 | BN_bn2bin(y, y_bytes); // Convert y-coordinate to bytes 88 | 89 | // Calculate SHA-3 hash including both value and the point R coordinates 90 | SHA512_CTX ctx; // Create SHA-512 context structure 91 | SHA512_Init(&ctx); // Initialize SHA-512 context 92 | SHA512_Update(&ctx, value.c_str(), value.length()); // Update context with value string 93 | SHA512_Update(&ctx, x_bytes, BN_num_bytes(x)); // Update context with x-coordinate bytes 94 | SHA512_Update(&ctx, y_bytes, BN_num_bytes(y)); // Update context with y-coordinate bytes 95 | unsigned char hashOutput[SHA512_DIGEST_LENGTH]; // Buffer to store hash output 96 | SHA512_Final(hashOutput, &ctx); // Finalize hashing and store result in hashOutput 97 | 98 | // Convert the hash output to uint64_t 99 | uint64_t hashValue = 0; // Variable to store final hash value 100 | for (size_t i = 0; i < SHA512_DIGEST_LENGTH && i < sizeof(hashValue); ++i) { 101 | // Combine bytes from hashOutput into hashValue 102 | hashValue |= (static_cast(hashOutput[i]) << (8 * i)); 103 | } 104 | 105 | // Perform modulo with the curve order 106 | BIGNUM *bnOrder = BN_new(); // Allocate memory for curve order 107 | EC_GROUP_get_order(obj_curve.getGroup(), bnOrder, nullptr); // Get order of the elliptic curve group 108 | 109 | // Compute the modulus using arithmetic operations 110 | uint64_t curveOrder = bignum_to_u int64(bnOrder); // Convert curve order to uint64_t 111 | hashValue %= curveOrder; // Perform modulo operation with curve order 112 | 113 | // Free allocated memory 114 | delete[] x_bytes; // Free memory allocated for x-coordinate bytes 115 | delete[] y_bytes; // Free memory allocated for y-coordinate bytes 116 | BN_free(x); // Free memory allocated for x-coordinate BIGNUM 117 | BN_free(y); // Free memory allocated for y-coordinate BIGNUM 118 | BN_free(bnOrder); // Free memory allocated for curve order BIGNUM 119 | 120 | // Return the final hash value 121 | return hashValue; 122 | } 123 | 124 | // Function to generate a JWT (JSON Web Token) with expiration time 125 | string ZeroKnowledge::generateJWT(const ZeroKnowledgeSignature &signature, int expSeconds) { 126 | // Calculate expiration time by adding specified seconds to current system time 127 | auto expTime = std::chrono::system_clock::now() + std::chrono::seconds(expSeconds); 128 | 129 | // Create JWT payload with expiration time 130 | auto token = jwt::create() 131 | .set_issuer(this->issuer) // Set the "iss" (issuer) claim 132 | .set_expires_at(expTime) // Set the expiration time 133 | .sign(jwt::algorithm::hs256{signature.signature}); // Sign the JWT using the provided signature 134 | 135 | // Return the generated JWT 136 | return token; 137 | } 138 | 139 | // Function to verify a JWT (JSON Web Token) 140 | bool ZeroKnowledge::verifyJWT(const string &token, const ZeroKnowledgeSignature &signature) { 141 | try { 142 | // Decode the JWT 143 | auto decoded_token = jwt::decode(token); 144 | 145 | // Verify the JWT using the provided signature and issuer 146 | jwt::verify() 147 | .allow_algorithm(jwt::algorithm::hs256{signature.signature}) // Allow the HS256 algorithm 148 | .with_issuer(this->issuer) // Verify the "iss" (issuer) claim 149 | .verify(decoded_token); // Verify the JWT 150 | 151 | // Verification succeeded 152 | return true; 153 | } catch (const std::exception &e) { 154 | // Verification failed 155 | return false; 156 | } 157 | } 158 | 159 | // Function to verify a challenge with a signature and optional data 160 | bool ZeroKnowledge::verify(const ZeroKnowledgeData &challenge, const ZeroKnowledgeSignature &signature, 161 | const std::variant &data) { 162 | if (std::holds_alternative(data)) { // Check if the data is a proof 163 | auto proof = std::get(data); // Extract proof data 164 | // Compute the point 165 | EC_POINT *p = EC_POINT_new(obj_curve.getGroup()); // Create a new EC_POINT object 166 | BIGNUM *m = BN_bin2bn(reinterpret_cast(proof.m.data()), proof.m.size(), 167 | nullptr); // Convert proof.m to BIGNUM 168 | BIGNUM *c = BN_bin2bn(reinterpret_cast(proof.c.data()), proof.c.size(), 169 | nullptr); // Convert proof.c to BIGNUM 170 | EC_POINT_mul(obj_curve.getGroup(), p, m, obj_curve.getGenerator(), c, 171 | nullptr); // Compute EC_POINT multiplication 172 | 173 | // Compare computed_c with hash of challenge data and point 174 | uint64_t computed_c = hash( 175 | challenge.data + proof.m); // Calculate hash of challenge data concatenated with proof.m 176 | BN_free(m); // Free memory allocated for m 177 | BN_free(c); // Free memory allocated for c 178 | EC_POINT_free(p); // Free memory allocated for p 179 | 180 | // Return true if computed_c matches proof.c 181 | return computed_c == bytes_to_int(proof.c); 182 | } else if (std::holds_alternative(data)) { // Check if the data is a string 183 | auto data_str = std::get(data); // Extract data as string 184 | return verify(challenge, signature, data_str); // Recursive call with string data 185 | } else { 186 | // Throw an exception for invalid data type provided 187 | throw std::invalid_argument("Invalid data type provided"); 188 | } 189 | } 190 | 191 | // Function to perform login using ZeroKnowledgeData 192 | bool ZeroKnowledge::login(const ZeroKnowledgeData &login_data) { 193 | if (!login_data.data.empty()) { // Check if login data is not empty 194 | // Deserialize the signature from login_data.data 195 | ZeroKnowledgeSignature signature = ZeroKnowledgeSignature::deserializeSignatureFromJson(login_data.data); 196 | 197 | // Verify JWT using verifyJWT function and return result 198 | return verifyJWT(login_data.data, signature); 199 | } else { 200 | return false; // Return false if login data is empty 201 | } 202 | } 203 | 204 | 205 | // Function to convert variant types to a Point on the elliptic curve 206 | Point ZeroKnowledge::to_point(const std::variant> &value) { 207 | std::string bytes; // Variable to store bytes representation of the value 208 | if (std::holds_alternative(value)) { // Check if the value is of type int 209 | int intValue = std::get(value); // Get the integer value 210 | bytes = std::to_string(intValue); // Convert the integer to string 211 | } else if (std::holds_alternative(value)) { // Check if the value is of type string 212 | bytes = std::get(value); // Get the string value 213 | } else if (std::holds_alternative>(value)) { // Check if the value is of type vector 214 | const std::vector &byte_data = std::get>(value); // Get the byte data 215 | bytes = std::string(byte_data.begin(), byte_data.end()); // Convert byte data to string 216 | } else { 217 | // Throw an exception for invalid type provided 218 | throw std::invalid_argument("Invalid type for value"); 219 | } 220 | 221 | // Convert the string to BIGNUM 222 | BIGNUM *x = BN_new(); // Allocate memory for BIGNUM 223 | BN_bin2bn(reinterpret_cast(bytes.data()), bytes.size(), x); // Convert bytes to BIGNUM 224 | 225 | // Create a new EC_POINT 226 | EC_POINT *point = EC_POINT_new(obj_curve.getGroup()); // Allocate memory for EC_POINT 227 | 228 | // Set the affine coordinates 229 | if (!EC_POINT_set_affine_coordinates_GFp(obj_curve.getGroup(), point, x, nullptr, nullptr)) { 230 | // Error handling in case setting affine coordinates fails 231 | BN_free(x); // Free memory allocated for BIGNUM 232 | EC_POINT_free(point); // Free memory allocated for EC_POINT 233 | throw std::runtime_error("Failed to set affine coordinates"); 234 | } 235 | 236 | // Check if the point is on the curve 237 | if (!obj_curve.is_on_curve(point)) { 238 | // Error handling in case point is not on the curve 239 | BN_free(x); // Free memory allocated for BIGNUM 240 | EC_POINT_free(point); // Free memory allocated for EC_POINT 241 | throw std::runtime_error("The point is not on the curve"); 242 | } 243 | 244 | // Free the allocated memory for x 245 | BN_free(x); 246 | 247 | // Return the Point object 248 | return Point(point); 249 | } 250 | 251 | // Function to convert BIGNUM to uint64_t 252 | uint64_t ZeroKnowledge::bignum_to_uint64(const BIGNUM *bn) { 253 | // Convert the big integer to a string representation 254 | char *str = BN_bn2hex(bn); // Convert BIGNUM to hexadecimal string 255 | if (!str) { 256 | throw std::runtime_error("Failed to convert BIGNUM to string"); // Throw an exception if conversion fails 257 | } 258 | 259 | // Convert the hexadecimal string to uint64_t 260 | uint64_t result = strtoull(str, nullptr, 16); // Convert hexadecimal string to uint64_t 261 | 262 | // Free the memory allocated by BN_bn2hex 263 | OPENSSL_free(str); // Free memory allocated for hexadecimal string 264 | 265 | return result; // Return the result 266 | } 267 | 268 | 269 | // Method to create a ZeroKnowledgeProof 270 | ZeroKnowledgeProof ZeroKnowledge::create_proof(const std::string &secret, 271 | const std::variant> &data) { 272 | // Compute hash of the secret key 273 | uint64_t key = hash(secret); // Compute hash of the secret key 274 | 275 | // Convert the value to a string 276 | std::string str_data; // Variable to store the converted data as string 277 | if (std::holds_alternative(data)) { // Check if the data is of type int 278 | str_data = std::to_string(std::get(data)); // Convert int data to string 279 | } else if (std::holds_alternative(data)) { // Check if the data is of type string 280 | str_data = std::get(data); // Get string data 281 | } else if (std::holds_alternative>(data)) { // Check if the data is of type vector 282 | const auto &byte_data = std::get>(data); // Get byte data 283 | str_data = std::string(byte_data.begin(), byte_data.end()); // Convert byte data to string 284 | } else { 285 | // Throw an exception for invalid type provided 286 | throw std::invalid_argument("Invalid type for data"); 287 | } 288 | 289 | // Convert the value to a point on the curve 290 | Point R = this->to_point(data); // Convert the value to a point on the curve 291 | 292 | // Compute hash with the point 293 | uint64_t c = this->hash_with_point(str_data, R); // Compute hash with the point 294 | 295 | // Generate a random integer 296 | std::random_device rd; // Create a random device 297 | std::mt19937 gen(rd()); // Initialize the Mersenne Twister engine with random seed 298 | const BIGNUM *curve_order_bignum = obj_curve.getOrder(); // Get the curve order 299 | uint64_t curve_order = bignum_to_uint64(curve_order_bignum); // Convert curve order to uint64_t 300 | std::uniform_int_distribution dis(0, curve_order); // Create uniform distribution over the curve order 301 | uint64_t r = dis(gen); // Generate a random integer 302 | 303 | // Compute m 304 | uint64_t m = mod(r - (c * key), curve_order); // Compute m 305 | 306 | // Return the proof object 307 | return ZeroKnowledgeProof{params, int_to_bytes(c), int_to_bytes(m)}; // Return the generated ZeroKnowledgeProof 308 | } 309 | 310 | 311 | 312 | // Method to create a signature for given data 313 | ZeroKnowledgeSignature ZeroKnowledge::createSignature(const std::string &data) { 314 | // For demonstration purposes, let's assume the signature is a hash of the data 315 | // You should replace this with your actual signature generation logic 316 | // Here, we'll use SHA-256 hash as the signature 317 | unsigned char hashOutput[SHA256_DIGEST_LENGTH]; // Array to store the hash output 318 | SHA256_CTX ctx; // SHA256 context 319 | SHA256_Init(&ctx); // Initialize SHA256 context 320 | SHA256_Update(&ctx, data.c_str(), data.length()); // Update SHA256 context with data 321 | SHA256_Final(hashOutput, &ctx); // Finalize SHA256 context and compute hash 322 | 323 | // Convert the hash to a hexadecimal string 324 | stringstream ss; // String stream to construct hexadecimal string 325 | for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i) { // Loop through hash output bytes 326 | ss << hex << setw(2) << setfill('0') << static_cast(hashOutput[i]); // Append each byte as hexadecimal to stringstream 327 | } 328 | string signature = ss.str(); // Convert stringstream to string 329 | 330 | // Create a ZeroKnowledgeSignature object with the generated signature 331 | return ZeroKnowledgeSignature{signature}; // Return the generated ZeroKnowledgeSignature 332 | } 333 | 334 | // Method to sign data with given secret 335 | ZeroKnowledgeData ZeroKnowledge::sign(const std::string &secret, const std::variant> &data) { 336 | std::string str_data; // String to store converted data 337 | std::visit([&str_data](const auto &value) { // Visit the variant type 338 | using T = std::decay_t; // Get the type of value 339 | if constexpr (std::is_same_v) { // Check if the type is int 340 | str_data = std::to_string(value); // Convert int to string 341 | } else if constexpr (std::is_same_v) { // Check if the type is string 342 | str_data = value; // No conversion needed for std::string 343 | } else if constexpr (std::is_same_v>) { // Check if the type is vector 344 | str_data = std::string(value.begin(), value.end()); // Convert std::vector to string 345 | } 346 | }, data); // Perform the visitation on data 347 | 348 | return ZeroKnowledgeData{ // Create a ZeroKnowledgeData object 349 | .data = str_data, // Set the data field 350 | .proof = create_proof(secret, str_data) // Create proof for the data 351 | }; 352 | } 353 | 354 | 355 | -------------------------------------------------------------------------------- /src/ZeroKnowledge/core/base.h: -------------------------------------------------------------------------------- 1 | #ifndef ZEROKNOWLEDGE_CORE_BASE_H 2 | // Preprocessor directive to ensure that this header file is included only once during compilation 3 | 4 | #define ZEROKNOWLEDGE_CORE_BASE_H 5 | // Definition of the header guard macro to prevent multiple inclusions of the header file 6 | 7 | #include // Time utilities 8 | #include // Integer types with exact widths 9 | #include // String utilities 10 | #include // Standard exception objects 11 | #include // Random number generation 12 | #include // Input/output stream objects 13 | #include // Type-safe union alternative 14 | #include // JWT library for JSON Web Tokens 15 | #include // OpenSSL library for Elliptic Curve Cryptography 16 | #include // Object identifiers for EC curves 17 | #include // ECDSA functions 18 | #include // PEM file format functions 19 | #include // High-level cryptographic functions 20 | #include // Error handling functions 21 | #include // Random number generation functions 22 | #include // OpenSSL header for SHA-3 hashing 23 | #include // JSON library 24 | 25 | // Forward declaration of classes from other files 26 | #include "../models/base.h" 27 | #include "../utils//base.h" 28 | #include "../algorithms/base.h" 29 | #include "../types/curve/base.h" 30 | #include "../types/point/base.h" 31 | 32 | // Alias for JSON namespace 33 | using json = nlohmann::json; 34 | // Using directive to avoid writing nlohmann::json:: prefix 35 | 36 | // Class definition for ZeroKnowledge 37 | class ZeroKnowledge { 38 | // Declaration of the ZeroKnowledge class 39 | private: 40 | std::string secret; // Secret key for cryptographic operations 41 | std::string algorithm; // Algorithm used for cryptographic operations 42 | std::string issuer; // Issuer of tokens 43 | ZeroKnowledgeParams params; // Parameters for zero-knowledge protocols 44 | Curve obj_curve; // Object representing the elliptic curve 45 | 46 | public: 47 | // Constructor for ZeroKnowledge class 48 | ZeroKnowledge(const ZeroKnowledgeParams ¶ms, const std::string &sec, const std::string &alg, const std::string &iss); 49 | // Declaration of the constructor 50 | 51 | // Static method to create a new instance of ZeroKnowledge 52 | static ZeroKnowledge createNew(const std::string &curveName = "Ed25519", const std::string &hashAlg = "blake2b", const std::string &jwtSecret = "", const std::string &jwtAlg = "HB2B", int saltSize = 16); 53 | // Declaration of a static method to create a new instance of ZeroKnowledge 54 | 55 | // Method to generate a JWT token 56 | std::string token(); 57 | // Declaration of a method to generate a JWT token 58 | 59 | // Method to generate a random salt 60 | static std::string generateSalt(int size); 61 | // Declaration of a static method to generate a random salt 62 | 63 | // Method to hash a string with a point 64 | uint64_t hash_with_point(const std::string &value, const Point &R); 65 | // Declaration of a method to hash a string with a point 66 | 67 | // Method to generate a JWT token 68 | std::string generateJWT(const ZeroKnowledgeSignature &signature, int expSeconds = 10); 69 | // Declaration of a method to generate a JWT token 70 | 71 | // Method to verify a JWT token 72 | bool verifyJWT(const std::string &token, const ZeroKnowledgeSignature &signature); 73 | // Declaration of a method to verify a JWT token 74 | 75 | // Method to verify a zero-knowledge proof 76 | bool verify(const ZeroKnowledgeData &challenge, const ZeroKnowledgeSignature &signature, const std::variant &data = ""); 77 | // Declaration of a method to verify a zero-knowledge proof 78 | 79 | // Method to perform login using zero-knowledge authentication 80 | bool login(const ZeroKnowledgeData &login_data); 81 | // Declaration of a method to perform login using zero-knowledge authentication 82 | 83 | // Method to convert a variant value to a point 84 | Point to_point(const std::variant> &value); 85 | // Declaration of a method to convert a variant value to a point 86 | 87 | // Method to convert a BIGNUM value to uint64_t 88 | uint64_t bignum_to_uint64(const BIGNUM* bn); 89 | // Declaration of a method to convert a BIGNUM value to uint64_t 90 | 91 | // Method to create a zero-knowledge proof 92 | ZeroKnowledgeProof create_proof(const std::string &secret, const std::variant> &data); 93 | // Declaration of a method to create a zero-knowledge proof 94 | 95 | // Method to create a digital signature 96 | ZeroKnowledgeSignature createSignature(const std::string &data); 97 | // Declaration of a method to create a digital signature 98 | 99 | // Method to sign data using zero-knowledge authentication 100 | ZeroKnowledgeData sign(const std::string &secret, const std::variant> &data); 101 | // Declaration of a method to sign data using zero-knowledge authentication 102 | }; 103 | 104 | #endif // ZEROKNOWLEDGE_CORE_BASE_H 105 | // End of the header guard macro definition and the end of the header file 106 | -------------------------------------------------------------------------------- /src/ZeroKnowledge/errors/base.cpp: -------------------------------------------------------------------------------- 1 | #include "base.h" 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/ZeroKnowledge/errors/base.h: -------------------------------------------------------------------------------- 1 | #ifndef ZEROKNOWLEDGE_ERRORS_BASE_H 2 | #define ZEROKNOWLEDGE_ERRORS_BASE_H 3 | 4 | #endif //ZEROKNOWLEDGE_ERRORS_BASE_H 5 | -------------------------------------------------------------------------------- /src/ZeroKnowledge/models/base.cpp: -------------------------------------------------------------------------------- 1 | #include "base.h" 2 | // Including the header file for the ZeroKnowledgeSignature class 3 | 4 | ZeroKnowledgeSignature ZeroKnowledgeSignature::deserializeSignatureFromJson(const std::string &json_data) { 5 | // Parsing the input JSON data 6 | auto parsed_json = json::parse(json_data); 7 | 8 | // Creating a ZeroKnowledgeSignature object 9 | ZeroKnowledgeSignature signature; 10 | 11 | // Assuming the JSON structure contains params and signature fields 12 | // Assigning values from the parsed JSON to the signature object 13 | signature.params.curve = parsed_json["params"]["curve"]; 14 | signature.params.salt = parsed_json["params"]["salt"]; 15 | signature.params.algorithm = parsed_json["params"]["algorithm"]; 16 | signature.signature = parsed_json["signature"]; 17 | 18 | // Returning the deserialized signature object 19 | return signature; 20 | } 21 | -------------------------------------------------------------------------------- /src/ZeroKnowledge/models/base.h: -------------------------------------------------------------------------------- 1 | #ifndef ZEROKNOWLEDGE_MODELS_BASE_H 2 | // Preprocessor directive to ensure that this header file is included only once during compilation 3 | 4 | #define ZEROKNOWLEDGE_MODELS_BASE_H 5 | // Definition of the header guard macro to prevent multiple inclusions of the header file 6 | 7 | #include 8 | // Include the JSON library 9 | 10 | using namespace std; 11 | using json = nlohmann::json; 12 | // Using directives to avoid writing std:: and nlohmann::json:: prefixes 13 | 14 | class ZeroKnowledgeParams { 15 | // Declaration of the ZeroKnowledgeParams class 16 | public: 17 | std::string curve; 18 | // Member variable to store the name of the elliptic curve 19 | std::string salt; 20 | // Member variable to store the salt value 21 | std::string algorithm; 22 | // Member variable to store the algorithm name 23 | }; 24 | 25 | class ZeroKnowledgeSignature { 26 | // Declaration of the ZeroKnowledgeSignature class 27 | public: 28 | ZeroKnowledgeParams params; 29 | // Member variable of type ZeroKnowledgeParams to store parameters 30 | std::string signature; 31 | // Member variable to store the signature 32 | 33 | // Static method to deserialize JSON data into ZeroKnowledgeSignature object 34 | static ZeroKnowledgeSignature deserializeSignatureFromJson(const std::string &json_data); 35 | // Declaration of a static method to deserialize JSON data into a ZeroKnowledgeSignature object 36 | }; 37 | 38 | class ZeroKnowledgeProof { 39 | // Declaration of the ZeroKnowledgeProof class 40 | public: 41 | ZeroKnowledgeParams params; 42 | // Member variable of type ZeroKnowledgeParams to store parameters 43 | std::string c; 44 | // Member variable to store a value 'c' 45 | std::string m; 46 | // Member variable to store a value 'm' 47 | }; 48 | 49 | class ZeroKnowledgeData { 50 | // Declaration of the ZeroKnowledgeData class 51 | public: 52 | std::string data; 53 | // Member variable to store data 54 | ZeroKnowledgeProof proof; 55 | // Member variable of type ZeroKnowledgeProof to store a proof 56 | }; 57 | 58 | #endif //ZEROKNOWLEDGE_MODELS_BASE_H 59 | // End of the header guard macro definition and the end of the header file 60 | -------------------------------------------------------------------------------- /src/ZeroKnowledge/types/curve/base.cpp: -------------------------------------------------------------------------------- 1 | #include "base.h" 2 | // Including the header file for the Curve class 3 | 4 | Curve::Curve(const std::string &curveName) { 5 | group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curveName.c_str())); 6 | // Creating a new elliptic curve group based on the given curve name 7 | if (!group) { 8 | throw std::invalid_argument("Invalid curve name"); 9 | } 10 | // Checking if the curve creation was successful, throwing an exception if not 11 | 12 | generator = EC_GROUP_get0_generator(group); 13 | // Getting the generator point of the elliptic curve group 14 | order = EC_GROUP_get0_order(group); 15 | // Getting the order of the elliptic curve group 16 | if (!generator || !order) { 17 | EC_GROUP_free(group); 18 | // Freeing the allocated memory for the group if either the generator or order retrieval fails 19 | throw std::runtime_error("Failed to retrieve curve generator or order"); 20 | } 21 | // Checking if the generator or order retrieval failed, throwing an exception if so 22 | } 23 | 24 | Curve::~Curve() { 25 | EC_GROUP_free(group); 26 | // Freeing the allocated memory for the elliptic curve group upon object destruction 27 | } 28 | 29 | EC_GROUP *Curve::getGroup() const { 30 | return group; 31 | // Returning the elliptic curve group pointer 32 | } 33 | 34 | bool Curve::is_on_curve(const EC_POINT *P) const { 35 | if (!group || !P) { 36 | throw std::invalid_argument("Invalid group or point"); 37 | } 38 | // Checking if the group or point is invalid, throwing an exception if so 39 | 40 | EC_KEY *key = EC_KEY_new(); 41 | // Creating a new elliptic curve key structure 42 | EC_KEY_set_group(key, group); 43 | // Setting the group for the key 44 | EC_KEY_set_public_key(key, P); 45 | // Setting the public key for the key 46 | int result = EC_POINT_is_on_curve(group, P, nullptr); 47 | // Checking if the given point lies on the curve 48 | EC_KEY_free(key); 49 | // Freeing the allocated memory for the key 50 | 51 | return result == 1; 52 | // Returning true if the point lies on the curve, otherwise false 53 | } 54 | 55 | const EC_POINT *Curve::getGenerator() const { 56 | return generator; 57 | // Returning the generator point of the curve 58 | } 59 | 60 | const BIGNUM *Curve::getOrder() const { 61 | return order; 62 | // Returning the order of the curve 63 | } 64 | 65 | int Curve::getDegree() const { 66 | return EC_GROUP_get_degree(group); 67 | // Returning the degree of the curve 68 | } 69 | -------------------------------------------------------------------------------- /src/ZeroKnowledge/types/curve/base.h: -------------------------------------------------------------------------------- 1 | #ifndef ZEROKNOWLEDGE_TYPES_CURVE_BASE_H 2 | // Preprocessor directive to ensure that this header file is included only once during compilation 3 | 4 | #define ZEROKNOWLEDGE_TYPES_CURVE_BASE_H 5 | // Definition of the header guard macro to prevent multiple inclusions of the header file 6 | 7 | #include 8 | // Including the OpenSSL library header file for elliptic curve operations 9 | 10 | #include 11 | // Including the OpenSSL library header file for object definitions 12 | 13 | #include 14 | // Including the standard input/output stream library for console I/O operations 15 | 16 | #include 17 | // Including the OpenSSL library header file for object-related operations 18 | 19 | class Curve { 20 | // Declaration of a class named Curve 21 | private: 22 | EC_GROUP *group; 23 | // Declaration of a pointer to an elliptic curve group structure 24 | const EC_POINT *generator; 25 | // Declaration of a pointer to a constant elliptic curve point structure representing the generator point 26 | const BIGNUM *order; 27 | // Declaration of a pointer to a constant BIGNUM structure representing the order of the elliptic curve group 28 | 29 | public: 30 | Curve(const std::string &curveName); 31 | // Declaration of the constructor for the Curve class, which takes a reference to a constant string as a parameter 32 | ~Curve(); 33 | // Declaration of the destructor for the Curve class 34 | EC_GROUP *getGroup() const; 35 | // Declaration of a method to get the elliptic curve group 36 | bool is_on_curve(const EC_POINT *P) const; 37 | // Declaration of a method to check if a given point lies on the curve 38 | const EC_POINT *getGenerator() const; 39 | // Declaration of a method to get the generator point of the curve 40 | const BIGNUM *getOrder() const; 41 | // Declaration of a method to get the order of the curve 42 | int getDegree() const; 43 | // Declaration of a method to get the degree of the curve 44 | // Add other necessary methods 45 | }; 46 | 47 | #endif // ZEROKNOWLEDGE_TYPES_CURVE_BASE_H 48 | // End of the header guard macro definition and the end of the header file 49 | -------------------------------------------------------------------------------- /src/ZeroKnowledge/types/point/base.cpp: -------------------------------------------------------------------------------- 1 | #include "base.h" 2 | // Including the header file for the Point class 3 | 4 | // Constructor definition for the Point class 5 | Point::Point(EC_POINT *p) : point(p) {} 6 | // Initializing the private member 'point' with the given EC_POINT pointer 'p' in the constructor 7 | 8 | // Destructor definition for the Point class 9 | Point::~Point() { 10 | EC_POINT_free(point); 11 | // Freeing the memory associated with the EC_POINT object when the Point object is destroyed 12 | } 13 | 14 | // Getter function definition to retrieve the EC_POINT pointer 15 | EC_POINT *Point::get() const { 16 | return point; 17 | // Returning the stored EC_POINT pointer 18 | } 19 | -------------------------------------------------------------------------------- /src/ZeroKnowledge/types/point/base.h: -------------------------------------------------------------------------------- 1 | #ifndef ZEROKNOWLEDGE_TYPES_POINT_BASE_H 2 | // Preprocessor directive to ensure that this header file is included only once during compilation 3 | 4 | #define ZEROKNOWLEDGE_TYPES_POINT_BASE_H 5 | // Definition of the header guard macro to prevent multiple inclusions of the header file 6 | 7 | #include 8 | // Including the OpenSSL library header file for elliptic curve operations 9 | 10 | // Declaration of the Point class 11 | class Point { 12 | // Declaration of a class named Point 13 | private: 14 | EC_POINT *point; 15 | // Declaration of a pointer to an elliptic curve point structure as a private member 16 | 17 | public: 18 | // Constructor to initialize the Point object with an EC_POINT pointer 19 | Point(EC_POINT *p); 20 | // Declaration of the constructor for the Point class, which takes an EC_POINT pointer as a parameter 21 | 22 | // Destructor to release resources associated with the Point object 23 | ~Point(); 24 | // Declaration of the destructor for the Point class 25 | 26 | // Getter function to retrieve the EC_POINT pointer 27 | EC_POINT *get() const; 28 | // Declaration of a method to get the EC_POINT pointer 29 | }; 30 | 31 | #endif // ZEROKNOWLEDGE_TYPES_POINT_BASE_H 32 | // End of the header guard macro definition and the end of the header file 33 | -------------------------------------------------------------------------------- /src/ZeroKnowledge/utils/base.cpp: -------------------------------------------------------------------------------- 1 | #include "base.h" 2 | // Including the header file 3 | 4 | 5 | // Function to convert a string of bytes to an unsigned 64-bit integer 6 | uint64_t bytes_to_int(const std::string &bytes) { 7 | // Initialize the result to zero 8 | uint64_t result = 0; 9 | // Iterate over each byte in the input string 10 | for (size_t i = 0; i < bytes.size(); ++i) { 11 | // Extract each byte, convert it to an unsigned char, then shift it to the appropriate position 12 | // Combine the bytes using bitwise OR to form the resulting unsigned integer 13 | result |= (static_cast(static_cast(bytes[i])) << (8 * i)); 14 | } 15 | // Return the resulting unsigned integer 16 | return result; 17 | } 18 | 19 | // Function to perform modulo operation on two unsigned 64-bit integers 20 | uint64_t mod(uint64_t a, uint64_t b) { 21 | // Compute the positive modulo result and ensure it is within the range [0, b) 22 | return (a % b + b) % b; 23 | } 24 | 25 | // Function to convert an unsigned 64-bit integer to a string of bytes 26 | std::string int_to_bytes(uint64_t value) { 27 | std::string result; 28 | // Extract each byte from the input value and append it to the result string 29 | while (value > 0) { 30 | // Extract the least significant byte using bitwise AND with 0xFF and convert it to char 31 | result.push_back(static_cast(value & 0xFF)); 32 | // Shift right by 8 bits to process the next byte 33 | value >>= 8; 34 | } 35 | // Return the resulting string of bytes 36 | return result; 37 | } 38 | -------------------------------------------------------------------------------- /src/ZeroKnowledge/utils/base.h: -------------------------------------------------------------------------------- 1 | #ifndef ZEROKNOWLEDGE_UTILS_BASE_H 2 | // Preprocessor directive to ensure that this header file is included only once during compilation 3 | 4 | #define ZEROKNOWLEDGE_UTILS_BASE_H 5 | // Definition of the header guard macro to prevent multiple inclusions of the header file 6 | 7 | #include // Standard I/O streams 8 | #include // Standard integer types 9 | 10 | // Function declaration to convert a string of bytes to an unsigned 64-bit integer 11 | uint64_t bytes_to_int(const std::string &bytes); 12 | 13 | // Function declaration to perform modulo operation on two unsigned 64-bit integers 14 | uint64_t mod(uint64_t a, uint64_t b); 15 | 16 | // Function declaration to convert an unsigned 64-bit integer to a string of bytes 17 | std::string int_to_bytes(uint64_t value); 18 | 19 | #endif //ZEROKNOWLEDGE_UTILS_BASE_H 20 | // End of the header guard macro definition and the end of the header file 21 | --------------------------------------------------------------------------------