pqcrypto
Post-Quantum Lemniscate-AGM Isogeny (LAI) Encryption
A multi-language reference implementation of the Lemniscate-AGM Isogeny (LAI) encryption scheme.
LAI is a promising post-quantum cryptosystem based on isogenies of elliptic curves over lemniscate lattices, offering conjectured resistance against quantum-capable adversaries.
Table of Contents
- Project Overview
- Mathematical Formulation
- Features
- Releases & Package Managers
4.1. Python (PyPI)
4.2. JavaScript (npm)
4.3. Ruby (RubyGems)
4.4. .NET (NuGet)
4.5. Java (Maven)
4.6. Rust (crates.io) - Usage Examples
5.1. Python
5.2. JavaScript
5.3. Ruby
5.4. .NET (C#)
5.5. Java
5.6. Rust - API Reference
- Testing
- Contributing & Development
- License
Project Overview
This library implements all core mathematical primitives and high-level APIs for LAI:
-
Hash-Based Seed Function
$$( H(x, y, s) = \mathrm{SHA256}\bigl(x,|,y,|,s\bigr) \bmod p )$$ -
Modular Square Root via Tonelli–Shanks (with fast branch if $$(p \equiv 3 \pmod 4)$$).
-
LAI Transformation
$$[ T\bigl((x,y),,s;,a,,p\bigr) ;=; \Bigl(, x' ;=; \tfrac{x + a + h}{2} \bmod p,;; y' ;=; \sqrt{x,y + h}\bmod p \Bigr) ] $$
where $$(h = H(x,y,s))$$.
-
Binary Exponentiation of $$(T)$$ to compute $$(T^k(P_0))$$ in $$(O(\log k)$$) time.
-
Key Generation, Encryption, and Decryption routines for integer messages $$(0 \le m < p)$$.
-
Bulk JSON Decryption: decrypt an entire JSON payload into raw bytes (e.g., to reconstruct a file or UTF-8 text).
All language‐specific wrappers expose identical API semantics under the hood. This makes pqcrypto ideal for cross-platform experiments, research, and educational purposes.
Mathematical Formulation
1. Hash-Based Seed Function
For $$(x, y, s \in \mathbb{Z}_p)$$, define:
$$ [ H(x, y, s) ;=; \mathrm{SHA256}\bigl(\text{bytes}(x),|,\text{bytes}(y),|,\text{bytes}(s)\bigr);\bmod;p, ] $$
where $$“(|)”$$ denotes concatenation of the big-endian byte representations.
2. Modular Square Root (Tonelli–Shanks)
Solve $$(z^2 \equiv a \pmod p) for prime (p)$$:
- If $$(p \equiv 3 \pmod 4)$$:
$$ [ z = a^{\frac{p+1}{4}} \bmod p. ] $$
- Otherwise: apply the general Tonelli–Shanks algorithm in $$(O(\log^2 p))$$ time.
3. LAI Transformation $$(T)$$
Given $$((x,y)\in\mathbb{F}_p^2)$$, parameter $$(a)$$, and seed index $$(s)$$, define
$$ \begin{cases} h = H(x,,y,,s),[6pt] x' = \dfrac{x + a + h}{2}\bmod p,[6pt] y' = \sqrt{x,y + h};\bmod p. \end{cases} $$
Thus $$(;T\bigl((x,y),s;a,p\bigr) = (,x',,y',))$$.
4. Binary Exponentiation of $$(T)$$
To compute $$(T^k(P_0))$$ efficiently:
function pow_T(P, k):
result ← P
base ← P
s ← 1
while k > 0:
if (k mod 2) == 1:
result ← T(result, s)
base ← T(base, s)
k ← k >> 1
s ← s + 1
return result
5. Algorithmic API
Key Generation
function keygen(p, a, P0):
k ← random integer in [1, p−1]
Q ← pow_T(P0, k)
return (k, Q)
Encryption
function encrypt(m, Q, p, a, P0):
r ← random integer in [1, p−1]
C1 ← pow_T(P0, r)
Sr ← pow_T(Q, r)
M ← (m mod p, 0)
C2 ← ((M.x + Sr.x) mod p, (M.y + Sr.y) mod p)
return (C1, C2)
Decryption
function decrypt(C1, C2, k, a, p):
S ← pow_T(C1, k)
M.x ← (C2.x − S.x) mod p
return M.x
Bulk Decryption (JSON)
function decryptAll(jsonPayload):
parse p, a, P0, k, blocks[]
for each block in blocks:
(x1,y1) = block.C1
(x2,y2) = block.C2
r = block.r
M_int = decrypt((x1,y1),(x2,y2),k,r,a,p)
convert M_int into fixed-length big-endian B-byte chunk
append to output byte buffer
return outputBuffer
Features
-
Pure Implementations (no native code)
- Python: only uses
hashlib,secrets(stdlib). - JavaScript: pure JS/BigInt.
- Ruby: pure Ruby +
openssl. - C#: uses
System.Numerics.BigInteger(no external C/C++). - Java: uses
java.math.BigInteger+ Jackson for JSON.
- Python: only uses
-
Mathematically Annotated
Every function corresponds exactly to the paper’s formulas. -
Modular Design
Separation of low‐level primitives (H,sqrt_mod,T) from high‐level API (keygen,encrypt,decrypt). -
General & Optimized
- Fast branch for $$(p\equiv3\pmod4)$$.
- Full Tonelli–Shanks fallback for any odd prime.
-
Bulk JSON Decryption
Produce or consume large ciphertext payloads (e.g., encrypted files, JavaScript code, JSON blobs). -
CI/CD Ready
- Python: auto‐publish to PyPI via GitHub Actions.
- JS: auto‐publish to npm.
- Ruby: auto‐publish to RubyGems.
- C#: auto‐publish to NuGet & GitHub Packages.
- Java: auto‐publish to GitHub Packages (Maven).
Releases & Package Managers
Python (PyPI)
JavaScript (npm)
Ruby (RubyGems)
.NET (NuGet)
Rust
Add to your Cargo.toml:
[]
= "0.1"
Or via Cargo CLI:
bash
Build:
-
Crates.io: https://crates.io/crates/laicrypto
-
Documentation: https://docs.rs/laicrypto
Java (Maven Central / GitHub Packages)
com.pelajaran.pqcrypto
laicrypto
0.1.0
Usage Examples
Below are minimal “hello, world”-style code snippets for each language wrapper.
Python
# 1. Setup parameters
= 10007
= 5
=
# 2. Generate keypair
, =
# 3. Encrypt integer m
= 2024
, =
# 4. Decrypt using private_k
=
assert ==
If you need to encrypt an entire text/file, convert it to integer blocks via
int.from_bytes(...), then call encrypt(...) on each block. See the
Python demo in this README for details.
JavaScripts
// Install: npm install pqlaicrypto
const = require;
const p = 10007n;
const a = 5n;
const P0 = ;
// 1. Generate keypair
const = ;
console.log;
console.log;
// 2. Encrypt a small integer
const m = 2024n;
const = ;
console.log;
// 3. Decrypt
const recovered = ;
console.log;
Use BigInt-aware file/block conversions to encrypt larger messages or files.
Ruby
# Install: gem install laicrypto
p = 10007
a = 5
= [1, 0]
# 1. Generate keypair
k, = LAI.keygen(p, a, P0)
puts
puts
# 2. Encrypt integer
message = 2024
C1, C2, r = LAI.encrypt(message, Q, k, p, a, P0)
puts
# 3. Decrypt
recovered = LAI.decrypt(C1, C2, k, r, a, p)
puts
Similar to Python, convert larger text to integer blocks using String#bytes
and Integer().
.NET (C#)
// Install via NuGet:
// <PackageReference Include="PQCrypto.Lai" Version="0.1.0" />
using System;
using System.Numerics;
using PQCrypto; // namespace containing LaiCrypto
class Demo {
static void Main(string[] args) {
// 1. Setup parameters
BigInteger p = 10007;
BigInteger a = 5;
LaiCrypto.Point P0 = new LaiCrypto.Point(1, 0);
// 2. Generate keypair
var kp = LaiCrypto.KeyGen(p, a, P0);
Console.WriteLine($"Private k: {kp.k}");
Console.WriteLine($"Public Q: ({kp.Q.x}, {kp.Q.y})");
// 3. Encrypt integer
BigInteger message = 2024;
var ct = LaiCrypto.Encrypt(message, kp.Q, p, a, P0);
Console.WriteLine($"C1: ({ct.C1.x}, {ct.C1.y}) C2: ({ct.C2.x}, {ct.C2.y}) r: {ct.r}");
// 4. Decrypt
BigInteger recovered = LaiCrypto.Decrypt(ct.C1, ct.C2, kp.k, ct.r, a, p);
Console.WriteLine($"Recovered: {recovered}");
if (recovered != message) throw new Exception("Decryption mismatch!");
}
}
To decrypt a JSON payload:
using System.IO;
using Newtonsoft.Json.Linq; // or System.Text.Json
var json = File.ReadAllText("ciphertext.json");
var jNode = JObject.Parse(json);
byte[] plaintextBytes = LaiCrypto.DecryptAll(jNode);
string plaintext = System.Text.Encoding.UTF8.GetString(plaintextBytes);
Java
<!-- In your pom.xml -->
com.pelajaran.pqcrypto
laicrypto
0.1.0
;
;
;
;
;
To decrypt a JSON payload in Java:
;
;
// ...
ObjectMapper mapper ;
JsonNode root ;
byte[] plaintextBytes ;
String plaintext ;
Rust
use LaiCryptoEngine;
API Reference
| Function | Description |
|---|---|
H(x: BigInt, y: BigInt, s: BigInt, p: BigInt) → BigInt |
SHA-256(x | y | s) mod p. |
sqrt_mod(a: BigInt, p: BigInt) → BigInt or null |
Compute $\sqrt{a} \bmod p$. Returns null if no root exists. |
T(point: (BigInt,BigInt), s: BigInt, a: BigInt, p: BigInt) → (BigInt,BigInt) |
One LAI transform step. |
pow_T(P, startS: BigInt, exp: BigInt, a: BigInt, p: BigInt) → (BigInt,BigInt) |
Compute $T^{\text{exp}}(P)$ by exponentiation by squaring. |
keygen(p: BigInt, a: BigInt, P0: (BigInt,BigInt)) → (k: BigInt, Q: (BigInt,BigInt)) |
Generate a random private key k and public point Q = Tᵏ(P₀). |
encrypt(m: BigInt, Q: (BigInt,BigInt), k: BigInt, p: BigInt, a: BigInt, P0: (BigInt,BigInt)) → (C1, C2, r) |
Encrypt integer m (< p) yielding C1, C2, and randomness r. |
decrypt(C1: (BigInt,BigInt), C2: (BigInt,BigInt), k: BigInt, r: BigInt, a: BigInt, p: BigInt) → BigInt |
Decrypt one block, returning the original integer m. |
decryptAll(jsonPayload) → byte[] |
Read entire JSON ciphertext payload (array of blocks) and return concatenated plaintext bytes. |
Testing
Each language wrapper includes its own test suite:
-
Python:
-
JavaScript:
-
Ruby:
-
.NET (C#):
-
Java (Maven):
Make sure all tests pass locally before opening a pull request.
Contributing & Development
-
Fork the repository
-
Create a feature branch
-
Implement changes
- Add or fix primitives/pseudo-code as needed.
- Add unit tests for any new functionality.
-
Run tests in all supported languages.
-
Commit & push, then open a pull request.
Please follow PEP 8 style in Python, StandardJS in JavaScript, Ruby Style Guide, C# coding conventions, and Java conventions. Include thorough documentation for any new API.
License
This project is licensed under the MIT License.