Cryptography

This section is all about the cryptography used in Tusknet

AES Encryption Standard

Advanced Encryption Standard (AES) is a widely used symmetric encryption algorithm. It operates on fixed-size blocks of data (128-bit blocks) and supports key sizes of 128, 192, or 256 bits. AES is highly efficient and secure, making it a popular choice for encrypting sensitive data.

Key Features:

  1. Symmetric Encryption: Both encryption and decryption use the same key.

  2. Block Cipher: AES encrypts data in blocks of 128 bits.

  3. Operating Modes: AES supports several modes like CBC (Cipher Block Chaining), GCM (Galois/Counter Mode), etc., for flexibility in different applications.

  4. Security: AES-256 provides a high level of security due to its large key size.

Your AES Implementation:

The provided code uses AES-256-CBC, where:

  • Key (256 bits): Used for both encryption and decryption.

  • Initialization Vector (IV): A random value to ensure unique ciphertexts for identical plaintexts.

  • Encryption Process:

    • Input text is converted to bytes.

    • Encrypted using the cipher initialized with the key and IV.

    • Outputs the encrypted data and IV as hexadecimal strings.

  • Decryption Process:

    • Uses the encrypted data and IV to reconstruct the original plaintext.

AES Code Example:

const crypto = require('crypto');

const algorithm = 'aes-256-cbc';
const key = "mypasswith32chars>>AES_256_bytes"; // Symmetric key
const iv = crypto.randomBytes(16); // Initialization vector

function encrypt(text) {
    let cipher = crypto.createCipheriv(algorithm, Buffer.from(key), iv);
    let encrypted = cipher.update(text);
    encrypted = Buffer.concat([encrypted, cipher.final()]);
    return { iv: iv.toString('hex'), encryptedData: encrypted.toString('hex') };
}

function decrypt(text) {
    let iv = Buffer.from(text.iv, 'hex');
    let encryptedText = Buffer.from(text.encryptedData, 'hex');
    let decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(key), iv);
    let decrypted = decipher.update(encryptedText);
    decrypted = Buffer.concat([decrypted, cipher.final()]);
    return decrypted;
}

This AES encryption is applied to secure cost functions within your network.


Pedersen Commitments

The Pedersen Commitment scheme is a cryptographic protocol that allows a value to be "committed" while keeping it hidden. It is widely used in privacy-preserving systems due to its binding and hiding properties.

Properties:

  1. Binding: Once committed, the value cannot be changed without invalidating the commitment.

  2. Hiding: The committed value remains hidden until explicitly revealed.

  3. Homomorphic: Commitments can be added together to produce a commitment to the sum of their values.

How It Works:

  • Setup:

    • Two large prime numbers ppp and qqq are generated, where q∣(p−1)q \mid (p-1)q∣(p−1).

    • Two group elements ggg and hhh are chosen such that g,h∈Zq∗g, h \in \mathbb{Z}_q^*g,h∈Zq∗​.

  • Commitment: A value xxx is committed using: C=gx⋅hrmod  qC = g^x \cdot h^r \mod qC=gx⋅hrmodq where rrr is a random value.

  • Verification: To verify, the commitment CCC is checked against the disclosed xxx and rrr.

Your Pedersen Commitment Implementation:

  • Generates large primes ppp and qqq.

  • Randomly selects ggg, sss, and computes h=gsmod  qh = g^s \mod qh=gsmodq.

  • Provides functions for committing, verifying, and adding commitments.

Code Implementation:

import os
import sys
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import rsa

def generate_large_prime(bit_length):
    return rsa.generate_private_key(public_exponent=65537, key_size=bit_length, backend=default_backend()).private_numbers().p

class PedersonCommitment:
    def __init__(self, security=1024):
        self.p = generate_large_prime(security)
        self.q = generate_large_prime(security * 2)
        self.g = int.from_bytes(os.urandom(32), 'big') % self.q
        self.s = int.from_bytes(os.urandom(32), 'big') % self.q
        self.h = pow(self.g, self.s, self.q)

    def commit(self, x):
        r = int.from_bytes(os.urandom(32), 'big') % self.q
        c = (pow(self.g, x, self.q) * pow(self.h, r, self.q)) % self.q
        return c, r

    def verify(self, c, x, r):
        return c == (pow(self.g, x, self.q) * pow(self.h, r, self.q)) % self.q

    def add_commitments(self, c1, c2):
        return (c1 * c2) % self.q

System Overview

Byzantine Fault Tolerance:

The system employs Pedersen commitments to ensure that all nodes in the network agree on cost functions securely:

  1. Commitments: Each node commits to a cost using Pedersen commitments.

  2. Encryption: Cost values are encrypted using AES before aggregation.

  3. Aggregation: Committed values are aggregated to ensure correctness.

  4. Verification: Results can be verified to ensure Byzantine fault tolerance.

Workflow:

  1. Encrypt Cost:

    def encrypt_cost(cost):
        cost_int = int(cost)
        c, r = commitment.commit(cost_int)
        print(f"Salt: {r}")
        print(f"Encrypted Cost: {c}")
        return c, r
  2. Aggregate Commitments:

    def aggregate_commitments(commitments):
        result = 1
        for c in commitments:
            result = commitment.add_commitments(result, c)
        return result

This hybrid approach combines Pedersen commitments and AES encryption to secure cost functions and maintain fault tolerance in a distributed network.

Last updated