C Programming Assignment - LFSR,
Permutation, and Algorithm
M. Ayush Reddy
22XV1M6705
1. Implement a configurable 8-bit LFSR with XOR feedback.
Input:
- Initial state = 0xB2, tap positions = bits 7, 5, 4, 3 (zero-indexed from left)
Task:
- Generate 20 states of the LFSR and store the sequence in an array. Analyze if
the sequence repeats.
LFSR (Linear Feedback Shift Register) produces pseudo-random sequences
through XOR of tap bits. The sequence will repeat eventually depending on
the tap configuration and initial seed.
2. Design a 4-round Feistel cipher using user-defined keys and
permutations.
Input:
- Plaintext = 8 bits, Keys = {0x3, 0x5, 0x7, 0x2}, Permutation = [2, 0, 3, 1, 6,
4, 7, 5]
Task:
- Implement 4 Feistel rounds using XOR and permutation. Show the final
ciphertext.
Feistel cipher splits data into two halves and executes multiple rounds. Each
round executes a round function, permutation, and XOR, producing encrypted
data after all rounds.
3. Simulate a bit-level permutation box (P-box).
Input:
- Input bits = 0b10110100, Permutation = [7, 6, 0, 2, 5, 4, 3, 1]
Task:
- Apply the permutation and output the transformed binary.
A P-Box is responsible for performing a fixed bit permutation on the input,
which helps enhance diffusion in cryptographic algorithms.
4. Develop a reversible permutation function and its inverse.
Input:
- Permutation = [3, 0, 2, 1]
Task:
- Apply this permutation to a 4-bit input and also implement the inverse
permutation to restore the original.
A permutation rearranges bits or elements; an inverse permutation reverses
the original
5. Implement an LFSR-based pseudo-random number generator.
Input:
- Seed = 0xA3, taps = [7, 5]
Task:
- Generate 10 pseudo-random bytes using LFSR and store them in an array.
Print as hex.
A PRNG based on LFSR produces pseudo-random bytes by repeatedly shifting
and implementing tap XOR logic.
6. Simulate a cipher mode: Stream XOR encryption using LFSR keystream.
Input:
- Plaintext = "CRYPTO", LFSR state = 0xE7
Task:
- Generate keystream using LFSR (8 bits per char) and encrypt the string
using XOR. Show encrypted text in hex.
A keystream is produced using an LFSR and XORed with the plaintext to
generate encrypte outputs.
7. Perform permutation on nibbles of a 16-bit word.
Input:
- Word = 0xABCD, Nibble permutation = [3, 1, 2, 0]
Task:
- Split into 4 nibbles, permute, and recombine into a new 16-bit word.
A 16-bit word is divided into 4 nibbles, rearranged with a permutation, and
formed back to a new word.
8. Simulate parallel LFSRs (2 registers) for keystream generation.
Input:
- LFSR1 = 0xF0, taps1 = [7, 4], LFSR2 = 0x3C, taps2 = [5, 2]
Task:
- XOR outputs of both LFSRs to generate 16 keystream bits.
Two LFSRs produce bits in parallel; their outputs are XORed to produce a
secure
9. Apply permutation to rows of a 4x4 matrix (image pixels simulation).
Input:
- 4x4 matrix of bytes, Row permutation = [2, 0, 3, 1]
Task:
- Rearrange rows using permutation and display the matrix.
Rows of matrices are permuted with a permutation index array to mimic
image row scrambling.
10. Implement a block permutation cipher.
Input:
- Plaintext = "ABCDEFGH", Block size = 4, Block permutation = [2, 0, 3, 1]
Task:
- Divide plaintext into 2 blocks, permute each block, and output the encrypted
message.
Text is broken into blocks and characters are permuted within each block
according to an permutation.
11. Implement a function to perform ROL and ROR operations and verify their
inverse relationship.
Inputs:
- X = 0x1234, rotate by 4
Task:
- Perform ROL(X, 4) followed by ROR(result, 4)
- Confirm if the original value is recovered.
This exercise confirms that a right rotate (ROR) with the same amount
followed by a left rotate (ROL) restores the original value.
12. Write a function to perform modular addition on two arrays of 5 elements
each.
Inputs:
- A[] = {0x1111, 0x2222, 0x3333, 0x4444, 0x5555}
- B[] = {0xAAAA, 0xBBBB, 0xCCCC, 0xDDDD, 0xEEEE}
Task:
- Perform (A[i] + B[i]) mod 2^16 and print results.
This operation sums every element of two arrays modulo 2^16 to avoid
overflow and wrap-around values.
13. Simulate a 2-round ARX block with custom rotations.
Inputs:
- X = 0x1357, Y = 0x2468, ROL = 7, ROR = 3
Task:
- Perform 2 ARX rounds, print outputs after each round.
Executes two ARX rounds with given rotate values and outputs results after
each round.
14. Perform ARX with user-defined round keys.
Inputs:
- X = 0xAAAA, Y = 0xBBBB
- K1 = 0x1111, K2 = 0x2222
Task:
- R1: ARX(X, Y ^ K1)
- R2: ARX(result, Y ^ K2)
Performs ARX (Addition, Rotate, XOR) rounds with keys blended into the Y
operand for every round.
15. Write a function that performs ARX on 32-bit values with user-defined shift
values.
Inputs:
- X = 0xCAFEBABE, Y = 0xDEADBEEF, ROL = 10, ROR = 8
Task:
- Perform ARX operation and print result.
Merges add-rotate-xor operations for 32-bit values with user-specified shift
values for secure transformation.
16. Compare ARX output for small vs large rotation values.
Inputs:
- X = 0x0F0F, Y = 0xF0F0
Task:
- Case A: ROL = 1, ROR = 2
- Case B: ROL = 12, ROR = 13
- Compare outputs.
Verifies the impact of small and large rotate values in ARX and measures their
output difference.
17. Encrypt a 4-element array using repeated ARX rounds.
Inputs:
- plaintext[] = {0x1234, 0x5678, 0x9ABC, 0xDEF0}
- key = 0x1A2B, ROL = 3, ROR = 2
Task:
- Apply 3 ARX rounds per element, print final encrypted array.
Encrypts every array element using 3 iterations of ARX operations with
constant key and shift values.
18. Design a round function that combines ARX with masking.
Inputs:
- X = 0x5A5A, Y = 0xA5A5, Mask = 0x0F0F
Task:
- Perform: (ROL(X, 4) + ROR(Y, 4)) ^ Mask
A special round function that blends ARX logic with bit masking to improve
cryptographic diffusion.
19. Create a menu-driven ARX tool.
Inputs:
- User provides: X, Y, choice of operation (ROL, ROR, Add, ARX), and shift
values
Task:
- Perform selected operation using switch-case.
Interactive ARX tool enables user to select and perform ROL, ROR, Add, or
ARX operations.
20. Perform differential analysis of ARX.
Inputs:
- X1 = 0xAAAA, Y1 = 0x5555
- X2 = X1 ^ 0x0001, Y2 = Y1 ^ 0x0001
Task:
- Compute ARX(X1, Y1) and ARX(X2, Y2), compare outputs.
Examines the influence of a 1-bit input variation on ARX output to determine
cryptographic sensitivity.
1. 8-bit LFSR with XOR Feedback
#include <stdio.h>
int main() {
unsigned char state = 0xB2, seq[20]; int i;
for(i = 0; i < 20; i++) {
seq[i] = state;
unsigned char bit = ((state >> 7) ^ (state >> 5) ^ (state >> 4) ^ (state
>> 3)) & 1;
state = (state << 1) | bit;
}
for(i = 0; i < 20; i++) printf("%02X ", seq[i]);
}
2. 4-round Feistel Cipher
#include <stdio.h>
unsigned char permute(unsigned char b) {
int p[8] = {2,0,3,1,6,4,7,5}, i, out = 0;
for(i=0;i<8;i++) out |= ((b >> (7 - p[i])) & 1) << (7 - i);
return out;
}
int main() {
unsigned char L=0xF0, R=0x0C, keys[4]={0x3,0x5,0x7,0x2}, t;
for(int i=0;i<4;i++) {
t = permute(R ^ keys[i]);
t ^= L;
L = R;
R = t;
}
printf("Cipher: %02X%02X\n", L, R);
}
3. Bit-level Permutation
#include <stdio.h>
int main() {
unsigned char in = 0b10110100, out = 0, p[8] = {7,6,0,2,5,4,3,1};
for(int i=0;i<8;i++) out |= ((in >> (7 - p[i])) & 1) << (7 - i);
printf("Output: %02X\n", out);
}
4. Reversible Permutation
#include <stdio.h>
int main() {
int in=0b1101, p[4]={3,0,2,1}, ip[4]; int out=0, rev=0;
for(int i=0;i<4;i++) out |= ((in >> (3 - p[i])) & 1) << (3 - i);
for(int i=0;i<4;i++) ip[p[i]] = i;
for(int i=0;i<4;i++) rev |= ((out >> (3 - ip[i])) & 1) << (3 - i);
printf("Out: %X, Inverse: %X\n", out, rev);
}
5. LFSR-based PRNG
#include <stdio.h>
int main() {5. LFSR-based PRNG
unsigned char state = 0xA3, rnd[10]; int i;
for(i=0;i<10;i++) {
rnd[i] = state;
unsigned char bit = ((state >> 7) ^ (state >> 5)) & 1;
state = (state << 1) | bit;
}
for(i=0;i<10;i++) printf("%02X ", rnd[i]);
}
6. Stream XOR Encryption using LFSR
#include <stdio.h>
int main() {
char* pt = "CRYPTO"; unsigned char ks = 0xE7, ct[6];
for(int i=0;i<6;i++) {
ct[i] = pt[i] ^ ks;
unsigned char bit = ((ks>>7) ^ (ks>>5)) & 1;
ks = (ks << 1) | bit;
}
for(int i=0;i<6;i++) printf("%02X ", ct[i]);
}
7. Nibble Permutation
#include <stdio.h>
int main() {
unsigned short word = 0xABCD, n[4], out=0, p[4]={3,1,2,0};
for(int i=0;i<4;i++) n[i] = (word >> ((3-i)*4)) & 0xF;
for(int i=0;i<4;i++) out |= n[p[i]] << ((3-i)*4);
printf("Output: %04X\n", out);
}
8. Parallel LFSRs
#include <stdio.h>
int main() {
unsigned char l1=0xF0, l2=0x3C, ks=0; int i;
for(i=0;i<16;i++) {
ks <<= 1;
ks |= ((l1>>7) ^ (l2>>7)) & 1;
l1 = (l1 << 1) | (((l1>>7) ^ (l1>>4)) & 1);
l2 = (l2 << 1) | (((l2>>5) ^ (l2>>2)) & 1);
}
printf("Keystream: %04X\n", ks);
}
9. Row Permutation of 4x4 Matrix
#include <stdio.h>
int main() {
int m[4][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}},
p[4]={2,0,3,1}, r[4][4];
for(int i=0;i<4;i++) for(int j=0;j<4;j++) r[i][j]=m[p[i]][j];
for(int i=0;i<4;i++,printf("\n")) for(int j=0;j<4;j++) printf("%2d ", r[i][j]);
}
10. Block Permutation Cipher
#include <stdio.h>
int main() {
char pt[] = "ABCDEFGH", ct[9]; int p[4]={2,0,3,1};
for(int i=0;i<8;i+=4)
for(int j=0;j<4;j++) ct[i+j] = pt[i+p[j]];
ct[8]='\0';
printf("Cipher: %s\n", ct);
}
11. ROL and ROR Operations (Inverse Check)
#include <stdio.h>
unsigned short rol(unsigned short x, int n) {
return (x << n) | (x >> (16 - n));
}
unsigned short ror(unsigned short x, int n) {
return (x >> n) | (x << (16 - n));
}
int main() {
unsigned short x = 0x1234;
unsigned short result = ror(rol(x, 4), 4);
printf("Restored: %04X\n", result);
}
12. Modular Addition of Two Arrays
#include <stdio.h>
int main() {
unsigned short A[] = {0x1111, 0x2222, 0x3333, 0x4444, 0x5555};
unsigned short B[] = {0xAAAA, 0xBBBB, 0xCCCC, 0xDDDD, 0xEEEE};
for (int i = 0; i < 5; i++) printf("%04X ", (A[i] + B[i]) & 0xFFFF);
}
13. Simulate 2-round ARX Block
#include <stdio.h>
unsigned short rol(unsigned short x, int n) { return (x << n) | (x >> (16 -
n)); }
unsigned short ror(unsigned short x, int n) { return (x >> n) | (x << (16 -
n)); }
int main() {
unsigned short x = 0x1357, y = 0x2468;
x = rol((x + y) & 0xFFFF, 7); printf("Round 1: %04X\n", x);
x = ror((x + y) & 0xFFFF, 3); printf("Round 2: %04X\n", x);
}
14. ARX with User-defined Keys
#include <stdio.h>
unsigned short rol(unsigned short x, int n) { return (x << n) | (x >> (16 -
n)); }
int main() {
unsigned short x = 0xAAAA, y = 0xBBBB, k1 = 0x1111, k2 = 0x2222;
x = rol((x + (y ^ k1)) & 0xFFFF, 4); printf("R1: %04X\n", x);
x = rol((x + (y ^ k2)) & 0xFFFF, 4); printf("R2: %04X\n", x);
}
15. ARX on 32-bit with Custom Shifts
#include <stdio.h>
unsigned short rol(unsigned short x, int n) { return (x << n) | (x >> (16 -
n)); }
int main() {
unsigned short x = 0xAAAA, y = 0xBBBB, k1 = 0x1111, k2 = 0x2222;
x = rol((x + (y ^ k1)) & 0xFFFF, 4); printf("R1: %04X\n", x);
x = rol((x + (y ^ k2)) & 0xFFFF, 4); printf("R2: %04X\n", x);
}
15. ARX on 32-bit with Custom Shifts
#include <stdio.h>
unsigned int rol(unsigned int x, int n) { return (x << n) | (x >> (32 - n)); }
unsigned int ror(unsigned int x, int n) { return (x >> n) | (x << (32 - n)); }
int main() {
unsigned int x = 0xCAFEBABE, y = 0xDEADBEEF;
unsigned int z = (rol(x, 10) + ror(y, 8)) ^ 0xFFFFFFFF;
printf("Result: %08X\n", z);
}
16. ARX Small vs Large Rotation Comparison
#include <stdio.h>
unsigned short rol(unsigned short x, int n) { return (x << n) | (x >> (16 -
n)); }
unsigned short ror(unsigned short x, int n) { return (x >> n) | (x << (16 -
n)); }
int main() {
unsigned short x = 0x0F0F, y = 0xF0F0;
unsigned short a = (rol(x, 1) + ror(y, 2)) & 0xFFFF;
unsigned short b = (rol(x, 12) + ror(y, 13)) & 0xFFFF;
printf("Small: %04X, Large: %04X\n", a, b);
}
17. Encrypt Array with ARX Rounds
#include <stdio.h>
unsigned short rol(unsigned short x, int n) { return (x << n) | (x >> (16 -
n)); }
unsigned short ror(unsigned short x, int n) { return (x >> n) | (x << (16 -
n)); }
int main() {
unsigned short p[] = {0x1234, 0x5678, 0x9ABC, 0xDEF0}, k = 0x1A2B;
for(int i=0;i<4;i++) {
p[i] = rol((p[i]+k)&0xFFFF, 3);
p[i] = ror((p[i]+k)&0xFFFF, 2);
p[i] = rol((p[i]+k)&0xFFFF, 3);
printf("%04X ", p[i]);
}
}
18. Round Function with ARX and Masking
#include <stdio.h>
unsigned short rol(unsigned short x, int n) { return (x << n) | (x >> (16 -
n)); }
unsigned short ror(unsigned short x, int n) { return (x >> n) | (x << (16 -
n)); }
int main() {
unsigned short x = 0x5A5A, y = 0xA5A5, m = 0x0F0F;
unsigned short result = (rol(x, 4) + ror(y, 4)) ^
unsigned short x = 0x5A5A, y = 0xA5A5, m = 0x0m;
printf("Masked: %04X\n", result);
}
19. Menu-Driven ARX Tool
#include <stdio.h>
unsigned short rol(unsigned short x, int n) { return (x << n) | (x >> (16 -
n)); }
unsigned short ror(unsigned short x, int n) { return (x >> n) | (x << (16 -
n)); }
int main() {
unsigned short x, y; int op, s;
printf("Enter X, Y, operation (1-ROL,2-ROR,3-ADD,4-ARX), shift: ");
scanf("%hx %hx %d %d", &x, &y, &op, &s);
if(op==1) printf("%04X\n", rol(x, s));
else if(op==2) printf("%04X\n", ror(x, s));
else if(op==3) printf("%04X\n", (x+y)&0xFFFF);
else if(op==4) printf("%04X\n", rol((x+y)&0xFFFF, s)^y);
}
20. Differential ARX Analysis
#include <stdio.h>
unsigned short rol(unsigned short x, int n) { return (x << n) | (x >> (16 -
n)); }
int main() {
unsigned short x1 = 0xAAAA, y1 = 0x5555;
unsigned short x2 = x1 ^ 0x0001, y2 = y1 ^ 0x0001;
unsigned short r1 = rol((x1 + y1) & 0xFFFF, 4);
unsigned short r2 = rol((x2 + y2) & 0xFFFF, 4);
printf("Diff: %04X\n", r1 ^ r2);
}