ElGamal Cryptosystem

The ElGamal cryptosystem, as demonstrated in this Julia code example, is a fundamental component of many verifiable e-voting systems. This implementation showcases the core operations of the ElGamal encryption scheme, including key generation, encryption, and decryption and is implemented in a group agnostic way.

The example illustrates both scalar and vector cases of ElGamal encryption. It defines an ElGamalRow struct to represent encrypted messages, and implements functions for encryption (enc) and decryption (dec). The code demonstrates how to encrypt multiple messages simultaneously and how to work with tuples of group elements as well as vectors. By using Julia's multiple dispatch capabilities, the implementation provides a flexible and type-safe approach to handling different input types. The test cases at the end of the file are made using P-192 elliptic curve group verify the correctness of the encryption and decryption operations for both single-row and multi-row scenarios.

using Test
using CryptoGroups

struct ElGamalRow{G<:Group, N}
    a::NTuple{N, G}
    b::NTuple{N, G}
end

ElGamalRow(m::NTuple{N, G}) where {N, G<:Group} = convert(ElGamalRow{G, N}, m)
Base.convert(::Type{ElGamalRow{G, N}}, m::NTuple{N, G}) where {N, G <: Group} = ElGamalRow{G, N}(one.(m), m)

enc(g::G, pk::G, e::ElGamalRow{G, N}, r::NTuple{N, <:Integer}) where {N, G <: Group} =
    ElGamalRow(e.a .* g .^ r, e.b .* pk .^ r)

enc(g::G, pk::G, m::NTuple{N, G}, r::NTuple{N, <:Integer}) where {N, G <: Group} = enc(g, pk, ElGamalRow(m), r)

dec(e::ElGamalRow{G}, x::Integer) where G <: Group = e.b ./ e.a .^ x

# A scalar example with 3 row elements

g = @ECGroup{P_192}()

x = 42
pk = g^x

m = (g^2, g^3, g^4)

cyphertexts = enc(g, pk, m, (4, 5, 6))

plaintexts = dec(cyphertexts, x)

@test plaintexts == m #

# A vector case with 3 rows

mvec = NTuple{3, typeof(g)}[
    (g^2, g^3, g^4),
    (g^4, g^7, g^8),
    (g^3, g^9, g^2)
]

rvec = NTuple{3, Int}[
    (4, 5, 6),
    (4, 5, 6),
    (4, 5, 6)
]

cyphertexts_vec = ((m, r) -> enc(g, pk, m, r)).(mvec, rvec)

plaintexts_vec = dec.(cyphertexts_vec, x)

@test plaintexts_vec == mvec
Test Passed

This page was generated using Literate.jl.