SDG8
SDG8

Reputation: 79

Why are characters in my RING-LWE Encryption being swapped?

I'm developing a Secure Chat Application using Ring-LWE for my cryptography and securities project using Java in a Client-Server environment. I have so far implemented the logic behind the key sharing along with the encryption and decryption, however characters are being swapped out. Here's the code and sample outputs I am recieving:

Client.java with the Ring-LWE code:

        class RingLWE {
            private final int n = 512;
            private final int q = 12289;
            private final int scalingFactor = q / 256; //48
    
            private int[] s;
    
            public RingLWE() {
                Random random = new Random();
                s = new int[n];
                for (int i = 0; i < n; i++) {
                    s[i] = random.nextInt(3) - 1; // Coefficients in {-1, 0, 1}
                }
            }
    
            // public key (a, b)
            public int[][] generatePublicKey() {
                Random random = new Random();
                int[] a = new int[n];
                int[] e = new int[n];
                int[] b = new int[n];
    
                // polynomial a
                for (int i = 0; i < n; i++) {
                    a[i] = random.nextInt(q);
                }
    
                // error polynomial e
                for (int i = 0; i < n; i++) {
                    e[i] = random.nextInt(3) - 1; // Coefficients in {-1, 0, 1}
                }
    
                // b = a * s + e mod q
                b = polyAdd(polyMul(a, s), e);
                for (int i = 0; i < n; i++) {
                    b[i] = modq(b[i]);
                }
    
                return new int[][]{a, b};
            }
    
            public int[] encryptByte(int message, int[] a, int[] b) {
                Random random = new Random();
    
                // polynomial r
                int[] r = new int[n];
                for (int i = 0; i < n; i++) {
                    r[i] = random.nextInt(3) - 1; // Coefficients in {-1, 0, 1}
                }
    
                // error polynomials e1 and e2
                int[] e1 = new int[n];
                int[] e2 = new int[n];
                for (int i = 0; i < n; i++) {
                    e1[i] = random.nextInt(3) - 1;
                    e2[i] = random.nextInt(3) - 1;
                }
    
                // u = a * r + e1 mod q
                int[] u = polyAdd(polyMul(a, r), e1);
                for (int i = 0; i < n; i++) {
                    u[i] = modq(u[i]);
                }
    
                int[] m = new int[n];
                m[0] = message;
    
                // v = b * r + e2 + m * scalingFactor mod q
                int[] scaledM = scalarMul(m, scalingFactor);
                int[] v = polyAdd(polyAdd(polyMul(b, r), e2), scaledM);
                for (int i = 0; i < n; i++) {
                    v[i] = modq(v[i]);
                }
    
                int[] ciphertext = new int[2 * n];
                System.arraycopy(u, 0, ciphertext, 0, n);
                System.arraycopy(v, 0, ciphertext, n, n);
    
                return ciphertext;
            }
    
            public int decryptByte(int[] ciphertext) {
                int[] u = new int[n];
                int[] v = new int[n];
                System.arraycopy(ciphertext, 0, u, 0, n);
                System.arraycopy(ciphertext, n, v, 0, n);
    
                // m' = v - u * s mod q
                int[] us = polyMul(u, s);
                int[] mPrime = polySub(v, us);
                for (int i = 0; i < n; i++) {
                    mPrime[i] = modq(mPrime[i]);
                }
    
                int decryptedMessage = (int) Math.round((double) mPrime[0] / scalingFactor);
                decryptedMessage = decryptedMessage % 256;
                if (decryptedMessage < 0) decryptedMessage += 256;
    
                return decryptedMessage;
            }
    
            // Polynomial multiplication modulo x^n + 1
            private int[] polyMul(int[] a, int[] b) {
                int[] result = new int[n];
                for (int i = 0; i < n; i++) {
                    long sum = 0;
                    for (int j = 0; j < n; j++) {
                        int index = (i - j) % n;
                        if (index < 0) index += n;
                        int sign = (((i - j) >= 0) ? 1 : -1);
                        sum += (long) sign * a[j] * b[index];
                    }
                    result[i] = modq((int) sum);
                }
                return result;
            }
    
            private int[] polyAdd(int[] a, int[] b) {
                int[] result = new int[n];
                for (int i = 0; i < n; i++) {
                    result[i] = modq(a[i] + b[i]);
                }
                return result;
            }
    
            private int[] polySub(int[] a, int[] b) {
                int[] result = new int[n];
                for (int i = 0; i < n; i++) {
                    result[i] = modq(a[i] - b[i]);
                }
                return result;
            }
            
            private int[] scalarMul(int[] a, int scalar) {
                int[] result = new int[n];
                for (int i = 0; i < n; i++) {
                    result[i] = modq(a[i] * scalar);
                }
                return result;
            }
    
            private int modq(int x) {
                int result = x % q;
                if (result < 0) result += q;
                return result;
            }
        }
    }

Output:

I have so far tried increasing the scalar factor and error coefficients, but that does not seem to fix it.

I'm aware Ring-LWE is a bad idea for real time voice and file encryption. This is only for project purposes.

Upvotes: 1

Views: 63

Answers (0)

Related Questions