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

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