Data update

This commit is contained in:
Ingy döt Net 2025-06-11 20:16:52 -04:00
parent 72eb4943cb
commit 4d5544505c
2347 changed files with 62432 additions and 16731 deletions

View file

@ -0,0 +1,269 @@
const readline = require('readline');
// Enum-like object for Playfair options
const playfairOption = {
NO_Q: 0,
I_EQUALS_J: 1,
};
// Represents the Playfair cipher state and methods
class Playfair {
constructor(keyword, pfo) {
this.keyword = keyword;
this.pfo = pfo; // playfairOption
this.table = Array(5).fill(null).map(() => Array(5).fill('')); // 5x5 table
}
// Initializes the 5x5 Playfair table based on the keyword and option
init() {
const used = Array(26).fill(false); // Track used letters
if (this.pfo === playfairOption.NO_Q) {
used['Q'.charCodeAt(0) - 65] = true; // Q is used/omitted
} else {
used['J'.charCodeAt(0) - 65] = true; // J is used/replaced by I
}
const alphabet = this.keyword.toUpperCase() + "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
let row = 0;
let col = 0;
for (const char of alphabet) {
const charCode = char.charCodeAt(0);
// Check if it's a letter A-Z
if (charCode >= 'A'.charCodeAt(0) && charCode <= 'Z'.charCodeAt(0)) {
const charIndex = charCode - 65; // 0-25 index
// Handle J if I_EQUALS_J option is selected
let charToUse = char;
let indexToUse = charIndex;
if (char === 'J' && this.pfo === playfairOption.I_EQUALS_J) {
charToUse = 'I';
indexToUse = 'I'.charCodeAt(0) - 65;
}
// Skip Q if NO_Q option is selected
if (charToUse === 'Q' && this.pfo === playfairOption.NO_Q) {
continue;
}
if (!used[indexToUse]) {
this.table[row][col] = charToUse;
used[indexToUse] = true;
col++;
if (col === 5) {
row++;
if (row === 5) {
break; // Table filled
}
col = 0;
}
}
}
}
}
// Prepares the plaintext: uppercase, removes non-letters,
// handles Q/J based on option, inserts X between duplicate letters,
// pads with X/Z if length is odd.
getCleanText(plainText) {
plainText = plainText.toUpperCase();
const cleanChars = [];
let prevChar = ''; // Use '' to indicate no previous character
for (let i = 0; i < plainText.length; i++) {
let currentChar = plainText[i];
const charCode = currentChar.charCodeAt(0);
// Skip non-letters
if (charCode < 'A'.charCodeAt(0) || charCode > 'Z'.charCodeAt(0)) {
continue;
}
// Handle J if I_EQUALS_J option is specified, replace J with I
if (currentChar === 'J' && this.pfo === playfairOption.I_EQUALS_J) {
currentChar = 'I';
}
// Skip Q if NO_Q option is specified (already handled in init, but good here too)
if (currentChar === 'Q' && this.pfo === playfairOption.NO_Q) {
continue;
}
// Insert 'X' between duplicate consecutive letters
// Only compare if prevChar is set (not the very first character)
if (prevChar !== '' && currentChar === prevChar) {
cleanChars.push('X');
}
cleanChars.push(currentChar);
prevChar = currentChar; // Store the character *after* potential X insertion
}
// If length is odd, add a padding character
if (cleanChars.length % 2 === 1) {
// Add 'X' unless the last letter is 'X', then add 'Z'
if (cleanChars[cleanChars.length - 1] !== 'X') {
cleanChars.push('X');
} else {
cleanChars.push('Z');
}
}
return cleanChars.join('');
}
// Finds the row and column of a character in the table
findChar(char) {
for (let i = 0; i < 5; i++) {
for (let j = 0; j < 5; j++) {
if (this.table[i][j] === char) {
return [i, j]; // Return [row, col]
}
}
}
return [-1, -1]; // Should not happen if getCleanText is correct
}
// Encodes plaintext using the Playfair cipher
encode(plainText) {
const cleanText = this.getCleanText(plainText);
const cipherChars = [];
for (let i = 0; i < cleanText.length; i += 2) {
const char1 = cleanText[i];
const char2 = cleanText[i + 1]; // cleanText length is always even
const [row1, col1] = this.findChar(char1);
const [row2, col2] = this.findChar(char2);
let encodedChar1, encodedChar2;
if (row1 === row2) { // Same row
encodedChar1 = this.table[row1][(col1 + 1) % 5];
encodedChar2 = this.table[row2][(col2 + 1) % 5];
} else if (col1 === col2) { // Same column
encodedChar1 = this.table[(row1 + 1) % 5][col1];
encodedChar2 = this.table[(row2 + 1) % 5][col2];
} else { // Different row and column (rectangle)
encodedChar1 = this.table[row1][col2];
encodedChar2 = this.table[row2][col1];
}
cipherChars.push(encodedChar1);
cipherChars.push(encodedChar2);
// Add space after each digram, matching Go's output format
if (i + 2 < cleanText.length) {
cipherChars.push(' ');
}
}
return cipherChars.join('');
}
// Decodes ciphertext using the Playfair cipher
decode(cipherText) {
// The Go code processes the ciphertext including spaces,
// stepping by 3. We'll do the same by stripping spaces first
// and then processing in pairs. This is conceptually simpler in JS.
// Or, we can replicate the Go loop that steps by 3. Let's replicate for exact match.
const decodedChars = [];
const l = cipherText.length;
for (let i = 0; i < l; i += 3) { // Step by 3 due to spaces in encoded text
const char1 = cipherText[i];
const char2 = cipherText[i + 1];
// cipherText[i+2] will be a space, which findChar will correctly not find (-1, -1)
// But the Go code explicitly finds the *bytes* at i and i+1. Let's stick to that.
// Ensure we only process valid character pairs
if (!char1 || !char2 || char1 === ' ' || char2 === ' ') {
// This shouldn't happen with the i+=3 loop structure if the input
// format from encode is followed, but good to be safe.
continue;
}
const [row1, col1] = this.findChar(char1);
const [row2, col2] = this.findChar(char2);
let decodedChar1, decodedChar2;
// Decoding rules are the reverse of encoding
if (row1 === row2) { // Same row
// Shift left: (col - 1 + 5) % 5
decodedChar1 = this.table[row1][(col1 + 4) % 5];
decodedChar2 = this.table[row2][(col2 + 4) % 5];
} else if (col1 === col2) { // Same column
// Shift up: (row - 1 + 5) % 5
decodedChar1 = this.table[(row1 + 4) % 5][col1];
decodedChar2 = this.table[(row2 + 4) % 5][col2];
} else { // Different row and column (rectangle)
decodedChar1 = this.table[row1][col2];
decodedChar2 = this.table[row2][col1];
}
decodedChars.push(decodedChar1);
decodedChars.push(decodedChar2);
// Add space after each digram in decoded text, matching Go's output format
if (i + 3 < l) { // Check if there's more content after the current digram+space
decodedChars.push(' ');
}
}
return decodedChars.join('');
}
// Prints the 5x5 table to the console
printTable() {
console.log("The table to be used is :\n");
for (let i = 0; i < 5; i++) {
console.log(this.table[i].join(' ')); // Join row elements with space
}
console.log(); // Add a blank line for spacing
}
}
// Main execution function using async/await for readline
async function main() {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const question = (query) => new Promise((resolve) => rl.question(query, resolve));
try {
const keyword = await question("Enter Playfair keyword : ");
let ignoreQ = '';
while (ignoreQ !== "y" && ignoreQ !== "n") {
ignoreQ = (await question("Ignore Q when building table y/n : ")).toLowerCase();
}
const pfo = (ignoreQ === "y") ? playfairOption.NO_Q : playfairOption.I_EQUALS_J;
const pf = new Playfair(keyword, pfo);
pf.init();
pf.printTable();
const plainText = await question("\nEnter plain text : ");
const encodedText = pf.encode(plainText);
console.log("\nEncoded text is :", encodedText);
// The Go code decodes the encoded text *including* the spaces it added.
// Pass the encoded text as is to the decode function.
const decodedText = pf.decode(encodedText);
console.log("Decoded text is :", decodedText);
} finally {
rl.close(); // Close the readline interface
}
}
// Execute the main function
main();

View file

@ -0,0 +1,225 @@
use std::io::{self, Write};
struct Playfair {
txt: String,
m: [[char; 5]; 5],
}
impl Playfair {
fn new() -> Self {
Playfair {
txt: String::new(),
m: [[' '; 5]; 5],
}
}
fn do_it(&mut self, k: &str, t: &str, ij: bool, e: bool) {
self.create_grid(k, ij);
self.get_text_ready(t, ij, e);
if e {
self.process(1);
} else {
self.process(-1);
}
self.display();
}
fn process(&mut self, dir: i32) {
let mut ntxt = String::new();
let mut chars = self.txt.chars().collect::<Vec<char>>();
let mut i = 0;
while i < chars.len() {
if i + 1 >= chars.len() {
break;
}
let mut a = 0;
let mut b = 0;
let mut c = 0;
let mut d = 0;
if self.get_char_pos(chars[i], &mut a, &mut b) &&
self.get_char_pos(chars[i+1], &mut c, &mut d) {
if a == c {
ntxt.push(self.get_char(a, b + dir));
ntxt.push(self.get_char(c, d + dir));
} else if b == d {
ntxt.push(self.get_char(a + dir, b));
ntxt.push(self.get_char(c + dir, d));
} else {
ntxt.push(self.get_char(c, b));
ntxt.push(self.get_char(a, d));
}
}
i += 2;
}
self.txt = ntxt;
}
fn display(&self) {
println!("\n\n OUTPUT:\n=========");
let chars = self.txt.chars().collect::<Vec<char>>();
let mut cnt = 0;
let mut i = 0;
while i < chars.len() {
if i + 1 < chars.len() {
print!("{}{} ", chars[i], chars[i+1]);
i += 2;
cnt += 1;
if cnt >= 26 {
println!();
cnt = 0;
}
} else {
print!("{}", chars[i]);
i += 1;
}
}
println!("\n");
}
fn get_char(&self, a: i32, b: i32) -> char {
let row = ((b + 5) % 5) as usize;
let col = ((a + 5) % 5) as usize;
self.m[row][col]
}
fn get_char_pos(&self, l: char, a: &mut i32, b: &mut i32) -> bool {
for y in 0..5 {
for x in 0..5 {
if self.m[y][x] == l {
*a = x as i32;
*b = y as i32;
return true;
}
}
}
false
}
fn get_text_ready(&mut self, t: &str, ij: bool, e: bool) {
self.txt.clear();
for c in t.chars() {
let c_upper = c.to_ascii_uppercase();
if c_upper < 'A' || c_upper > 'Z' {
continue;
}
if c_upper == 'J' && ij {
self.txt.push('I');
} else if c_upper == 'Q' && !ij {
continue;
} else {
self.txt.push(c_upper);
}
}
if e {
let mut ntxt = String::new();
let chars = self.txt.chars().collect::<Vec<char>>();
let len = chars.len();
let mut x = 0;
while x < len {
ntxt.push(chars[x]);
if x + 1 < len {
if chars[x] == chars[x + 1] {
ntxt.push('X');
}
ntxt.push(chars[x + 1]);
}
x += 2;
}
self.txt = ntxt;
}
if self.txt.len() % 2 == 1 {
self.txt.push('X');
}
}
fn create_grid(&mut self, k: &str, ij: bool) {
let mut key = k.to_string();
if key.is_empty() {
key = "KEYWORD".to_string();
}
key.push_str("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
let mut nk = String::new();
for c in key.chars() {
let c_upper = c.to_ascii_uppercase();
if c_upper < 'A' || c_upper > 'Z' {
continue;
}
if (c_upper == 'J' && ij) || (c_upper == 'Q' && !ij) {
continue;
}
if !nk.contains(c_upper) {
nk.push(c_upper);
}
}
let mut idx = 0;
for y in 0..5 {
for x in 0..5 {
if idx < nk.len() {
self.m[y][x] = nk.chars().nth(idx).unwrap();
idx += 1;
}
}
}
}
}
fn main() -> io::Result<()> {
let mut input = String::new();
print!("(E)ncode or (D)ecode? ");
io::stdout().flush()?;
io::stdin().read_line(&mut input)?;
let e = input.trim().to_lowercase().starts_with('e');
input.clear();
print!("Enter a en/decryption key: ");
io::stdout().flush()?;
io::stdin().read_line(&mut input)?;
let key = input.trim().to_string();
input.clear();
print!("I <-> J (Y/N): ");
io::stdout().flush()?;
io::stdin().read_line(&mut input)?;
let ij = input.trim().to_lowercase().starts_with('y');
input.clear();
print!("Enter the text: ");
io::stdout().flush()?;
io::stdin().read_line(&mut input)?;
let txt = input.trim().to_string();
let mut pf = Playfair::new();
pf.do_it(&key, &txt, ij, e);
println!("Press Enter to continue...");
input.clear();
io::stdin().read_line(&mut input)?;
Ok(())
}