@antigane/encryption
Version:
encryption with Lattice-based Cryptography
114 lines (113 loc) • 3.21 kB
JavaScript
// src/index.ts
var AntiganeEncryption = class {
m;
n;
q;
A;
s;
e;
constructor(m, n, q = 2053) {
this.m = m;
this.n = n;
this.q = q;
this.A = [];
this.s = [];
this.e = [];
}
mod(x, q) {
let result = x % q;
return result >= 0 ? result : result + q;
}
getSecureRandom(max) {
const array = new Uint32Array(1);
crypto.getRandomValues(array);
return this.mod(array[0], max);
}
defineA() {
this.A = Array(this.n).fill(0).map(
() => Array(this.m).fill(0).map(() => this.getSecureRandom(this.q))
);
}
defineE() {
this.e = Array(this.m).fill(0).map(() => this.mod(this.getSecureRandom(10), this.q));
}
async generateHash(message) {
const encoder = new TextEncoder();
const data = encoder.encode(message);
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray.map((byte) => this.mod(byte, this.q));
}
async sVector(password) {
const hashValues = await this.generateHash(password);
this.s = hashValues.slice(0, this.n);
while (this.s.length < this.n) {
this.s.push(this.s[this.s.length % hashValues.length]);
}
}
calculateB() {
let tempAS = Array(this.A.length).fill(null).map(() => Array(this.A[0].length).fill(0));
for (let i = 0; i < this.A.length; i++) {
for (let j = 0; j < this.A[0].length; j++) {
tempAS[i][j] = this.mod(this.s[i] * this.A[i][j], this.q);
}
}
let result = Array(this.m).fill(0);
for (let i = 0; i < this.m; i++) {
for (let j = 0; j < this.n; j++) {
result[i] = this.mod(result[i] + tempAS[j][i], this.q);
}
}
return result.map((val, idx) => this.mod(val + this.e[idx], this.q));
}
async encrypt(msg, password, encryptParams) {
await this.sVector(password);
if (encryptParams) {
this.A = encryptParams.A;
this.e = encryptParams.E;
} else {
this.defineA();
this.defineE();
}
const ascii = Array.from(msg).map(
(char) => this.mod(char.charCodeAt(0), this.q)
);
const b = this.calculateB();
const cyphertext = ascii.map(
(val, idx) => this.mod(val + b[idx % b.length], this.q)
);
return {
data: this.arrayToBase64(cyphertext),
params: {
A: this.A,
E: this.e,
q: this.q
}
};
}
async decrypt(encryptedData, password) {
await this.sVector(password);
this.A = encryptedData.params.A;
this.e = encryptedData.params.E;
this.q = encryptedData.params.q;
const fromBase64 = this.base64ToArray(encryptedData.data);
const b = this.calculateB();
const decrypted = fromBase64.map(
(val, idx) => this.mod(val - b[idx % b.length], this.q)
);
return String.fromCharCode(...decrypted);
}
arrayToBase64(arr) {
return Buffer.from(JSON.stringify(arr)).toString("base64");
}
base64ToArray(base64) {
return JSON.parse(Buffer.from(base64, "base64").toString());
}
};
var createEncryptionService = (m = 128, n = 64, q = 2053) => {
return new AntiganeEncryption(m, n, q);
};
export {
AntiganeEncryption,
createEncryptionService
};