I'm trying to program the McEliece cryptosystem, but I'm having trouble combining the binary vectors and linsolve section in the decryption step of the algorithm.
I'm expecting the array m to be equal to the message array x after decryption, but I'm getting the wrong result:
x =
1 1 1 1
ciphertext =
1 1 1 1 0 1 1
m =
1.2500 0.5000 0.5000 0.7500
Why does my decrypted result differ from my plain-text message?
Here is what I have so far:
clc;clear all;
n = 7;
k = 4; %Let C be an (n,k)-linear code
g = [ 1 0 0 0 1 1 0
0 1 0 0 1 0 1
0 0 1 0 0 1 1
0 0 0 1 1 1 1]; %Let G be a generator matrix for C.
s = [ 1 1 0 1
1 0 0 1
0 1 1 1
1 1 0 0]; %Alice selects a random (k x k) binary non-singular matrix S
p = [ 0 1 0 0 0 0 0
0 0 0 1 0 0 0
0 0 0 0 0 0 1
1 0 0 0 0 0 0
0 0 1 0 0 0 0
0 0 0 0 0 1 0
0 0 0 0 1 0 0]; %Alice selects a random (n x n) permutation matrix P.
% s , g and p is private key ( alice has a private key )
% g'=s*g*p is public key (alice compute the public key and send to Bob )
gg = s*g*p; %Alice computes the (n x k)matrix g'=s*g*p .
key = mod(gg,2); % public key
x = [ 1 1 1 1 ] %message
t = 1;
e = [ 0 0 0 0 1 0 0 ]; % the erorr
%%the Encryption (( Bob Encrypt the message x by using the public key) )
y = x*key;
y1=mod(y,2);
ciphertext=mod((y+e),2) % ciphertext is Encrypt the message x ( send the ciphertext to Alice)
%%the Decryption ((alice decrypt the ciphertext , the result must equal to the orginal message x ( by using the private key) ))
yy = ciphertext*inv(p);
ee = e*inv(p);
xsg = mod((yy-ee),2);
xs = linsolve(g',xsg');
m = mod((xs' * inv(s)),2) % m must equal to x .
More details on the McEliece cryptosystem can be found here:
http://www-math.ucdenver.edu/~wcherowi/courses/m5410/ctcmcel.html
I tried to implement this example given in the above link:
For an example we shall use the (7,4) Hamming code which corrects all
single errors. A generator matrix for this code is given by (note the
clever choice):
G = [1 0 0 0 1 1 0
0 1 0 0 1 0 1
0 0 1 0 0 1 1
0 0 0 1 1 1 1];
and Bob chooses the scrambler matrix
S = [1 1 0 1
1 0 0 1
0 1 1 1
1 1 0 0];
and the permutation matrix
P = [0 1 0 0 0 0 0
0 0 0 1 0 0 0
0 0 0 0 0 0 1
1 0 0 0 0 0 0
0 0 1 0 0 0 0
0 0 0 0 0 1 0
0 0 0 0 1 0 0];
Bob makes public the generator matrix
G' = SGP = [1 1 1 1 0 0 0
1 1 0 0 1 0 0
1 0 0 1 1 0 1
0 1 0 1 1 1 0];
If Alice wishes to send the message x = (1 1 0 1) to Bob, she first
constructs a weight 1 error vector, say e = (0 0 0 0 1 0 0) and
computes
y = xG' + e
= (0 1 1 0 0 1 0) + (0 0 0 0 1 0 0)
= (0 1 1 0 1 1 0)
which she then sends to Bob.
Upon receiving y, Bob first computes y' = yP^-1, where
P^-1 = [0 0 0 1 0 0 0
1 0 0 0 0 0 0
0 0 0 0 1 0 0
0 1 0 0 0 0 0
0 0 0 0 0 0 1
0 0 0 0 0 1 0
0 0 1 0 0 0 0];
obtaining y' = (1 0 0 0 1 1 1). Now Bob decodes y' by the fast
decoding algorithm (Hamming decoding in this example). The syndrome of
y' is (1 1 1 0)T, so the error occurs in position 7 (details
omitted). Bob now has the code word y'' = (1 0 0 0 1 1 0). Because
of the clever choice for G, Bob knows that xS = (1 0 0 0), and he
can now obtain x by multiplying by the matrix
S-1 = [1 1 0 1
1 1 0 0
0 1 1 1
1 0 0 1];
obtaining
x = (1 0 0 0)S^-1 = (1 1 0 1).
Really I just followed your tutorial link, it seems like you struggled at the end and stopped doing what was in the tutorial? The algorithm is detailed well enough to follow, as below.
The main issue you were having is that you didn't need linsolve at all. The key changes I've made come in the last block of the code - the decryption. Two main things:
Using the forward slash operator is better than using inv(). From the documentation for the back slash operator (equivalent for pre-multiplication):
x = A\b is computed differently than x = inv(A)*b and is recommended for solving systems of linear equations
Using information about how the generator matrix was formed, the algorithm becomes much easier, as noted in your linked tutorial.
[By writing] G in standard form [Ik A], xS would just be the first k positions of xSG
Corrected code with comments:
clc; clear all;
% McEliece Encryption / Decryption, source material for example:
% http://www-math.ucdenver.edu/~wcherowi/courses/m5410/ctcmcel.html
n = 7;
%Let C be an (n,k)-linear code
k = 4;
%Let G be a generator matrix for C.
G = [1 0 0 0 1 1 0
0 1 0 0 1 0 1
0 0 1 0 0 1 1
0 0 0 1 1 1 1];
%Alice selects a random (k x k) binary non-singular matrix S
S = [1 1 0 1
1 0 0 1
0 1 1 1
1 1 0 0];
%Alice selects a random (n x n) permutation matrix P.
P = [0 1 0 0 0 0 0
0 0 0 1 0 0 0
0 0 0 0 0 0 1
1 0 0 0 0 0 0
0 0 1 0 0 0 0
0 0 0 0 0 1 0
0 0 0 0 1 0 0];
% S, G and P are the private key (Alice has a private key)
% GG = S*G*P is public key (Alice computes the public key and sends it to Bob)
GG = S*G*P;
publickey = mod(GG,2); % public key
% --- public key sent from Alice to Bob --- %
% Bob wants to send a message, msg, so encrypts it using Alice's public key
msg = [1 1 0 1] % message
e = [0 0 0 0 1 0 0]; % the weight vector - treated as an error by Alice
% Encryption
y = msg*publickey;
% ciphertext is the encrypted message (send the ciphertext to Alice)
ciphertext = mod((y+e),2)
% --- message sent from Bob to Alice --- %
% Decryption (Alice decrypts the ciphertext by using the private key,
% the result must be equal to the orginal message
% Using a forward slash can be quicker and more accurate than inv()
YY = ciphertext/P;
ee = e/P;
xSG = mod((YY-ee),2);
% Because G was of the form [I_k, A], xS is just the first k positions of
% xSG, and no multiplication is needed. This can be found in source material.
xS = xSG(1:k);
decoded = mod(xS/S,2)
Output:
msg =
1 1 0 1
ciphertext =
0 1 1 0 1 1 0
decoded =
1 1 0 1
Nice example. Added error removal. Tested in Octave
% Further references
% https://www.avoggu.com/posts/an-efficient-algorithm-for-hamming-(74)-decoding-matlab-implementation/
% https://www.tutorialspoint.com/hamming-code-for-single-error-correction-double-error-detection
% https://en.wikipedia.org/wiki/Hamming(7,4)
% http://michael.dipperstein.com/hamming/index.html
n=7;
%% Individual message size
k=4;
%% Generator Matrix
%d1 d2 d3 d4 p1 p2 p3
G = [ 1, 0, 0, 0, 1, 1, 0;... %d1
0, 1, 0, 0, 1, 0, 1;... %d2
0, 0, 1, 0, 0, 1, 1;... %d3
0, 0, 0, 1, 1, 1, 1;]; %d4
%% Parity check
%d1 d2 d3 d4 p1 p2 p3
H = [ 1, 1, 0, 1, 1, 0, 0; %p1
1, 0, 1, 1, 0, 1, 0; %p2
0, 1, 1, 1, 0, 0, 1;];%p3
%% A random invertible scrambler binary random matrix
S=zeros(k);
while ( abs(cond(S)) > 10 )
S = rand(k) > 0.5;
endwhile
%% A random permutation matrix
P = eye(n) (:,randperm(n));
%% Public key
Gprime = mod(S*G*P,2);
%% message
message = [1,1,0,1]
%% error vector
error = [1,0,0,0,0,0,0] (1,randperm(n));
%% encrypted message
encrypted_message = mod(message*Gprime + error,2)
% Decryption
% Undo permutation
encrypted_message = mod(encrypted_message/P,2);
% Remove error
find_error = mod(H*encrypted_message',2);
%% Use a lookup table bit to flip
error_position_table=[5,6,1,7,2,3,4];
error_indicator = (find_error(1))*1 + ...
(find_error(2))*2 + ...
(find_error(3))*4;
if error_indicator > 0
encrypted_message(error_position_table(error_indicator)) +=1;
endif
xSG = mod(encrypted_message,2);
% Due to ordering of columns in G message is in first k columns
xS = xSG(1:k);
decrypted_message = mod(round(xS/S),2)
Related
I am new to Matlab and I need some help.
I want compute Parity Check Matrix and then to encode a codeword using Generator Matrix
My matrix is the following :
1 0 0 0 1 1 1
0 1 0 0 1 1 0
0 0 1 0 1 0 1
0 0 0 1 0 1 1
The codeword is 1 0 1 1.
My code in Matlab is as follow :
printf('Generator Matrix\n');
G = [
1 0 0 0 1 1 1;
0 1 0 0 1 1 0;
0 0 1 0 1 0 1;
0 0 0 1 0 1 1
]
[k,n] = size(G)
P = G(1:k,k+1:n)
PT = P'
printf('Parity Check Matrix\n');
H = cat(2,PT,eye( n-k ))
printf('Encode the following word : \n');
D = [1 0 1 1]
C = xor( G(1,:), G(3,:) , G(4,:) )
My problem is that I want to get dynamically the rows of G Matrix in order to make the xor operation.
Could you help me please ?
Thanks a lot
You only need matrix multiplication modulo 2:
C = mod(D*G, 2);
Alternatively, compute the sum of the rows of G indicated by D, modulo 2:
C = mod(sum(G(D==1,:), 1), 2);
I know the code below :
N = 5;
assert(N>1 && mod(N,2)==1);
A = zeros(N);
% diamond mask
N2 = fix(N/2);
[I,J] = meshgrid(-N2:N2);
mask = (abs(I) + abs(J)) == N2;
% fill with zeros
A(mask) = 1;
which transforms matrix A to this:
A=
0 0 1 0 0
0 1 0 1 0
1 0 0 0 1
0 1 0 1 0
0 0 1 0 0
But I want the diamond to be filled with 1.
What should I do?
Here's a vectorized approach using bsxfun -
Nh = (N+1)/2;
range_vec = [1:Nh Nh-1:-1:1];
out = bsxfun(#plus,range_vec(:),range_vec) > Nh
Sample runs -
1) N = 5 :
out =
0 0 1 0 0
0 1 1 1 0
1 1 1 1 1
0 1 1 1 0
0 0 1 0 0
2) N = 9 :
out =
0 0 0 0 1 0 0 0 0
0 0 0 1 1 1 0 0 0
0 0 1 1 1 1 1 0 0
0 1 1 1 1 1 1 1 0
1 1 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1 0
0 0 1 1 1 1 1 0 0
0 0 0 1 1 1 0 0 0
0 0 0 0 1 0 0 0 0
You can use tril and flip functions:
mat = tril(ones(N), round((N-1)/2)) - tril(ones(N), round((-N-1)/2));
out = mat & flip(mat)
Odd values of N:
% N = 5;
out =
0 0 1 0 0
0 1 1 1 0
1 1 1 1 1
0 1 1 1 0
0 0 1 0 0
Even values of N:
% N = 4;
out =
0 1 1 0
1 1 1 1
1 1 1 1
0 1 1 0
What you need is to return a 1 or a 0 based on the Manhattan distance from each array location to the center of your diamond
N = 5;
assert(N>1 && mod(N,2)==1);
A = false(N);
[m, n] = size(A); %dimensions of A
X = floor([m, n]/2); %floored division gives integer indices of center of array
x = X(1); y = X(2);
radius = m/2; %half the height gives the radius
for a = 1 : m
for b = 1 : n
A(a,b) = abs(a-x)+abs(b-y) <= radius; %test if manhatten distance <= radius
end
end
This naturally will need editing to suit your particular case... In particular, the center of your diamond can realistically be placed anywhere by modifying x, y, and the radius can be either smaller or larger than half the width of the array if you so choose.
Just add a for loop and fill all diagonals:
N = 5;
assert(N>1 && mod(N,2)==1);
A = zeros(N);
% diamond mask
N2 = fix(N/2);
[I,J] = meshgrid(-N2:N2);
for id = 0:N2
A((abs(I) + abs(J)) == id) = 1;
end
I have the following two matrices which are outputs of a procedure. The size of the matrices may change but both matrices will always be the same size: size(TwoHopMat_1) == size(Final_matrix)
Example:
TwoHopMat_1 =
0 0 0 0 1
0 0 1 1 0
0 1 0 1 0
0 1 1 0 0
1 0 0 0 0
Final_matrix =
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1
1 1 0 0 0
1 0 0 0 1
Now I need to shuffle the final_matrix such that i meet the following conditions after shuffling:
Every column should have a minimum of one 1s
If i have a 1 in a particular position of TwoHopMat_1 then that particular position should not have 1 after shuffling.
The conditions should work even if we give matrices of size 100x100.
first step: set one element of each column of the result matrix ,that is not 1 in Final_matrix ,to 1
second step: then remaining ones randomly inserted into positions of the result matrix that are not 1 in Final_matrix and are not 1 in the first step result
TwoHopMat_1=[...
0 0 0 0 1
0 0 1 1 0
0 1 0 1 0
0 1 1 0 0
1 0 0 0 0];
Final_matrix=[...
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1
1 1 0 0 0
1 0 0 0 1];
[row col] = size(Final_matrix);
result = zeros(row ,col);
%condition 1 & 2 :
notTwoHop = ~TwoHopMat_1;
s= sum(notTwoHop,1);
c= [0 cumsum(s(1:end - 1))];
f= find(notTwoHop);
r = floor(rand(1, col) .* s) + 1;
i = c + r;
result(f(i)) = 1;
%insert remaining ones randomly into the result
f= find(~(result | TwoHopMat_1));
i = randperm(numel(f), sum(Final_matrix(:))-col);
result(f(i)) =1
A possible solution:
function [result_matrix] = shuffle_matrix(TwoHopMat_1, Final_matrix)
% Condition number 2
ones_mat = ones(size(TwoHopMat_1));
temp_mat = abs(TwoHopMat_1 - ones_mat);
% Condition number 1
ones_to_remove = abs(sum(sum(temp_mat)) - sum(sum(Final_matrix)));
while ones_to_remove > 0
% Random matrix entry
i = floor((size(Final_matrix, 1) * rand())) + 1;
j = floor((size(Final_matrix, 2) * rand())) + 1;
if temp_mat(i,j) == 1
temp_mat(i,j) = 0;
ones_to_remove = ones_to_remove - 1;
end
end
result_matrix = temp_mat;
end
Note: this solution uses brute force.
In Matlab I have a vectors that looks like this:
0 0 1 1 0 0 0 1 1 0 0 0 0 1 1 1 0 0 0 0 1 0 1
What I want to do now is to count the number of 1 in this vector. Consecutive 1s count as 1. Additionally, I want also to calculate the average and median numbers of 0s between 1s. So for this example:
1s: 5
Median 0s: 3.5
Average 0s: 3
I solved that with a brute force method, that is investigate each element in a loop and check the previous as well as the next element. But I'm sure there has to be a solution that is way faster. Any idea?
Given the data in vector v,
v = [ 0 0 1 1 0 0 0 1 1 0 0 0 0 1 1 1 0 0 0 0 1 0 1 ]; % data
compute as follows:
w = [ 1 v 1 ]; % auxiliary vector
runs_zeros = find(diff(w)==1)-find(diff(w)==-1); % lenghts of runs of 0's
% Desired results:
number_ones = length(runs_zeros)-1+v(1)+v(end);
% For average and median, don't count first run if v(1) is 0,
% or last run if v(end) is 0:
average_runs_zeros = mean(runs_zeros(2-v(1):end-1+v(end)));
median_runs_zeros = median(runs_zeros(2-v(1):end-1+v(end)));
This is faster than #TryHard's solution because it doesn't require converting to strings
Okay, so this seems to be working
>> a=[0 0 1 1 0 0 0 1 1 0 0 0 0 1 1 1 0 0 0 0 1 0 1];
>> %Remove traling and leading zeros
>> y = a(find(a,1,'first'):find(a,1,'last'));
>> q = diff([0 a 0] == 1);
>> v = find(q == -1) - find(q == 1);
>> length(v) % Consecutive Ones
ans =
5
>> q = diff([0 ~y 0] == 1);
>> v = find(q == -1) - find(q == 1);
>> v
v =
3 4 4 1
>> median(v)
ans =
3.5000
>> mean(v)
ans =
3
You can do it as follows:
dat=[0 0 1 1 0 0 0 1 1 0 0 0 0 1 1 1 0 0 0 0 1 0 1];
str = regexprep(num2str(dat),' ','');
[n1 istart1 iend1] = regexp(str,'[1]+','match','start','end');
[n0 istart0 iend0] = regexp(str(min(istart1):max(iend1)),'[0]+','match','start','end');
% number of strings of `1`s
length(n1)
% property of intercalated strings of `0`s
median([iend0-istart0+1])
mean([iend0-istart0+1])
I have a matrix m = zeros(1000, 1000). Within this matrix I want to draw an estimate of the line which passes through 2 points from my matrix. Let's say x = [122 455]; and y = [500 500];.
How can I do this in Matlab? Are there any predefined functions to do this? I am using Matlab 2012b.
I'll denote the two endpoints as p1 and p2 because I'm planning to use x and y for something else. I'm also assuming that the first coordinate of p1 and p2 is x and the second is y. So here's a rather simple way to do it:
Obtain the equation of the line y = ax + b. In MATLAB, this can be done by:
x = p1(1):p2(1)
dx = p2(1) - p1(1);
dy = p2(2) - p1(2);
y = round((x - p1(1)) * dy / dx + p1(2));
Convert the values of x and y to indices of elements in the matrix, and set those elements to 1.
idx = sub2ind(size(m), y, x);
m(idx) = 1;
Example
Here's an example for a small 10-by-10 matrix:
%// This is our initial conditon
m = zeros(10);
p1 = [1, 4];
p2 = [5, 7];
%// Ensure the new x-dimension has the largest displacement
[max_delta, ix] = max(abs(p2 - p1));
iy = length(p1) - ix + 1;
%// Draw a line from p1 to p2 on matrix m
x = p1(ix):p2(ix);
y = round((x - p1(ix)) * (p2(iy) - p1(iy)) / (p2(ix) - p1(ix)) + p1(iy));
m(sub2ind(size(m), y, x)) = 1;
m = shiftdim(m, ix > iy); %// Transpose result if necessary
The result is:
m =
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0
0 0 1 1 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
Update: I have patched this algorithm to work when dy > dx by treating the dimension with the largest displacement as if it were the x-dimension, and then transposing the result if necessary.
Neither of the provided answers work for displacements in y greater than in x (dy > dx).
As pointed out, Bresenham's line algorithm is exactly meant for that.
The matlab file provided here works similarly than the examples provided in the other answers but covers all the use-cases.
To relate to the previously provided example, the script can be used like this:
% initial conditions
m = zeros(10);
p1 = [1, 4];
p2 = [5, 10];% note dy > dx
% use file provided on file exchange
[x y] = bresenham(p1(1),p1(2),p2(1),p2(2));
% replace entries in matrix m
m(sub2ind(size(m), y, x)) = 1;
result looks like this:
m =
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
For me (matlab R2013b) following line did not work, when p1(1)>p2(2) (":" can not count backwards):
x = p1(1):p2(1);
E.G.:
1:10
1 2 3 4 5 6 7 8 9 10
10:1
Empty matrix: 1-by-0
But it worked when I used linspac instead:
x = linspace(p1(1), p2(1), abs(p2(1)-p1(1))+1);