Unpacking a vector into an array of a certain bit width - system-verilog
Suppose I have a vector of bits. I'd like to convert it into an array of n bit values, where n is a variable (not a parameter). Can I achieve this using the streaming operators? I tried this (right now I'm just trying a value of 3, but eventually '3' should be variable):
module tb;
bit [51:0] vector = 'b111_110_101_100_011_010_001_000;
byte vector_byte[];
initial begin
$displayb(vector);
vector_byte = {<<3{vector}};
foreach(vector_byte[i])
$display("%0d = %0b", i, vector_byte[i]);
end
endmodule
What I was expecting was:
vector_byte = '{'b000, 'b001, 'b010 ... 'b111};
However, the output I got was:
# vsim -voptargs=+acc=npr
# run -all
# 00000000000000000000000000000000111110101100011010001000
# 0 = 101
# 1 = 111001
# 2 = 1110111
# 3 = 0
# 4 = 0
# 5 = 0
# 6 = 0
# exit
Am I just using the streaming operators wrong?
The streaming operators only work with contiguous streams. You need 5'b00000 inserted into each byte.
module tb;
bit [51:0] vector = 'b111_110_101_100_011_010_001_000;
int W = 3;
byte vector_byte[];
initial begin
vector_byte = new[$bits(vector)/3];
$displayb(vector);
foreach(vector_byte[i]) begin
vector_byte[i] = vector[i*W+:8] & (1<<W)-1; // mask W is in range 1-8
$display("%0d = %0b", i, vector_byte[i]);
end
end
endmodule
Related
SystemVerilog error in multiplexing channels : nonconstant index into instance array
I'm designing a module that accepts multiple channels and outputs one channel. Each channel consists of valid signal and data of some widths. If a channel has valid data, the module should output that channel. If multiple channels have valid data, the module should output one of them (in my case, channel with highest index) and rests are dropped. My simple implementation looks like this: module test1 #( parameter NUM_CHANNEL = 8, parameter DATA_WIDTH = 512 ) ( input logic [DATA_WIDTH - 1 : 0] data_in [NUM_CHANNEL], input logic valid_in [NUM_CHANNEL], output logic [DATA_WIDTH - 1 : 0] data_out, output logic valid_out ); always_comb begin valid_out = 0; for (int i = 0; i < NUM_CHANNEL; ++i) begin if (valid_in[i]) begin valid_out = 1; data_out = data_in[i]; end end end endmodule This works perfectly in both simulation and real circuit (FPGA). However, channel can be complex type so I used interface like this: interface channel #( parameter DATA_WIDTH = 512 ); logic valid; logic [DATA_WIDTH - 1 : 0] data; modport in ( input valid, input data ); modport out ( output valid, output data ); endinterface // sub_csr_if module test #( parameter NUM_CHANNEL = 8, parameter DATA_WIDTH = 512 ) ( channel.in in[NUM_CHANNEL], channel.out out ); always_comb begin out.valid = 0; for (int i = 0; i < NUM_CHANNEL; ++i) begin if (in[i].valid) begin out.valid = 1; out.data = in[i].data; end end end endmodule Then, this code gets Nonconstant index into instance array 'sub_port'. error in ModelSim, and i is not a constant error in Quartus. If I unroll the loop, it works but it becomes non-parametric code. (only works for fixed NUM_CHANNEL) Why the latter one does not work, while the first one works flawlessly?
An array of instances (module or interface) is not a true array type. As your error message indicates, you cannot select a particular instance with a variable index. With a true array, every element is identical. Because of the way parameterization, defparam, and port connections work, each instance element could have differences. The elaboration process essentially flattens all hierarchy before simulation begins. What you can do is use a generate construct to select your instance as follows ; module test #( parameter NUM_CHANNEL = 8, parameter DATA_WIDTH = 512 ) ( channel.in in[NUM_CHANNEL], channel.out out ); logic _valid[NUM_CHANNEL]; logic [DATA_WIDTH - 1 : 0] _data[NUM_CHANNEL]; for (genvar ii=0;ii<NUM_CHANNEL;ii++) begin assign _valid[ii] = in[ii].valid; assign _data[ii] = in[ii].data; end always_comb begin out.valid = 0; for (int i = 0; i < NUM_CHANNEL; ++i) begin if (_valid[i]) begin out.valid = 1; out.data = _data[i]; end end end endmodule
Extraction of data from DWT subband
I am attempting to extract data from a DWT subband. I am able to embed data correctly (I have followed it in the debugger),cal PSNR etc. PSNR rate seem very high 76.2?? however,I am having lot of trouble extracting data back!It is sometimes extracting the number 128?? Can anyone help or have any idea why this is? I would be very thankful.I have been working on this all day & having no luck!I am very curious to know?? Data Embedding: coverImage = imread('lena.bmp'); message = importdata('minutiaTest.txt'); %message = 'Bifurcations:'; [LL,LH,HL,HH] = dwt2(coverImage,'haar'); if size(message) > size(coverImage,1) * size(coverImage,2) error ('message too big to embed'); end bit_count = 0; steg_coeffs = [4, 4.75, 5.5, 6.25, 7]; for jj=1:size(message,2)+1 if jj > size(message,2) charbits = [0,0,0,0,0,0,0,0]; else charbits = dec2bin(message(jj),8)'; charbits = charbits(:)'-'0'; end for ii=1:8 bit_count = bit_count + 1; if charbits(ii) == 1 if HH(bit_count) <= 0 HH(bit_count) = steg_coeffs(randi(numel(steg_coeffs))); end else if HH(bit_count) >= 0 HH(bit_count) = -1 * steg_coeffs(randi(numel(steg_coeffs))); end end end end stego_image = idwt2(LL,LH,HL,HH,'haar'); imwrite(uint8(stego_image),'newStego.bmp'); Data Extraction: new_Stego = imread('newStego.bmp'); [LL,LH,HL,HH] = dwt2(new_Stego,'haar'); message = ''; msgbits = ''; for ii = 1:size(HH,1)*size(HH,2) if HH(ii) > 0 msgbits = strcat (msgbits, '1'); elseif HH(ii) < 0 msgbits = strcat (msgbits, '0'); else return; end if mod(ii,8) == 0 msgChar = bin2dec(msgbits); if msgChar == 0 break; end msgChar = char (msgChar); message = [message msgChar]; msgbits = ''; end end
The problem arises from reading your data with importdata. This command will load the data to an array. Since you have 39 lines and 2 columns (skipping any empty lines), its size will be 39 2. However, the program assumes that your message will be a string. For example, 'i am a string' has a size 1 13. This expectation of the program compared to the data you actually give it creates all sorts of problems. What you want is to read your data as a single string, where the number 230 is not one element, but 3 individual characters. Tabs and newlines will also be read in as well. To read your file: message = fileread('minutiaTest.txt'); After you extract your message, to save it to a file: fid = fopen('myFilename.txt','w'); fprintf(fid,message); fclose(fid);
MATLAB Execution Time Increasing
Here is my code. The intent is I have a Wireshark capture saved to a particularly formatted text file. The MATLAB code is supposed to go through the Packets, dissect them for different protocols, and then make tables based on those protocols. I currently have this programmed for ETHERNET/IP/UDP/MODBUS. In this case, it creates a column in MBTable each time it encounters a new register value, and each time it comes across a change to that register value, it updates the value in that line of the table. The first column of MBTable is time, the registers start with the second column. MBTable is preallocated to over 100,000 Rows (nol is very large), 10 columns before this code is executed. The actual data from a file I'm pulling into the table gets to about 10,000 rows and 4 columns and the code execution is so slow I have to stop it. The tic/toc value is calculated every 1000 rows and continues to increase exponentially with every iteration. It is a large loop, but I can't see where anything is growing in such a way that it would cause it to run slower with each iteration. All variables get initialized up top (left out to lessen amount of code. The variables eth, eth.ip, eth.ip.udp, and eth.ip.udp.modbus are all of type struct as is eth.header and eth.ip.header. WSID is a file ID from a .txt file opened earlier. MBTable = zeros(nol,10); tval = tic; while not(feof(WSID)) packline = packline + 1; fl = fl + 1; %Get the next line from the file MBLine = fgetl(WSID); %Make sure line is not blank or short if length(MBLine) >= 3 %Split the line into 1. Line no, 2. Data, 3. ASCII %MBAll = strsplit(MBLine,' '); %First line of new packet, if headers included if strcmp(MBLine(1:3),'No.') newpack = true; newtime = false; newdata = false; stoppack = false; packline = 1; end %If packet has headers, 2nd line contains timestamp if newpack Ordered = false; if packline == 2; newtime = true; %MBstrs = strsplit(MBAll{2},' '); packno = int32(str2double(MBLine(1:8))); t = str2double(MBLine(9:20)); et = t - lastt; if lastt > 0 && et > 0 L = L + 1; MBTable(L,1) = t; end %newpack = false; end if packline > 3 dataline = int16(str2double(MBLine(1:4))); packdata = strcat(packdata,MBLine(7:53)); end end else %if t >= st if packline > 3 stoppack = true; newpack = false; end if stoppack invalid = false; %eth = struct; eth.pack = packdata(~isspace(packdata)); eth.length = length(eth.pack); %Dissect the packet data eth.stbyte = 1; eth.ebyte = eth.length; eth.header.stbyte = 1; eth.header.ebyte = 28; %Ethernet Packet Data eth.header.pack = eth.pack(eth.stbyte:eth.stbyte+27); eth.header.dest = eth.header.pack(eth.header.stbyte:eth.header.stbyte + 11); eth.header.src = eth.header.pack(eth.header.stbyte + 12:eth.header.stbyte + 23); eth.typecode = eth.header.pack(eth.header.stbyte + 24:eth.header.ebyte); if strcmp(eth.typecode,'0800') eth.type = 'IP'; %eth.ip = struct; %IP Packet Data eth.ip.stbyte = eth.header.ebyte + 1; eth.ip.ver = eth.pack(eth.ip.stbyte); %IP Header length eth.ip.header.length = 4*int8(str2double(eth.pack(eth.ip.stbyte+1))); eth.ip.header.ebyte = eth.ip.stbyte + eth.ip.header.length - 1; %Differentiated Services Field eth.ip.DSF = eth.pack(eth.ip.stbyte + 2:eth.ip.stbyte + 3); %Total IP Packet Length eth.ip.length = hex2dec(eth.pack(eth.ip.stbyte+4:eth.ip.stbyte+7)); eth.ip.ebyte = eth.ip.stbyte + max(eth.ip.length,46) - 1; eth.ip.pack = eth.pack(eth.ip.stbyte:eth.ip.ebyte); eth.ip.ID = eth.pack(eth.ip.stbyte+8:eth.ip.stbyte+11); eth.ip.flags = eth.pack(eth.ip.stbyte+12:eth.ip.stbyte+13); eth.ip.fragoff = eth.pack(eth.ip.stbyte+14:eth.ip.stbyte+15); %Time to Live eth.ip.ttl = hex2dec(eth.pack(eth.ip.stbyte+16:eth.ip.stbyte+17)); eth.ip.typecode = eth.pack(eth.ip.stbyte+18:eth.ip.stbyte+19); eth.ip.checksum = eth.pack(eth.ip.stbyte+20:eth.ip.stbyte+23); %eth.ip.src = eth.pack(eth.ip.stbyte+24:eth.ip.stbyte+31); eth.ip.src = ... [num2str(hex2dec(eth.pack(eth.ip.stbyte+24:eth.ip.stbyte+25))),'.', ... num2str(hex2dec(eth.pack(eth.ip.stbyte+26:eth.ip.stbyte+27))),'.', ... num2str(hex2dec(eth.pack(eth.ip.stbyte+28:eth.ip.stbyte+29))),'.', ... num2str(hex2dec(eth.pack(eth.ip.stbyte+30:eth.ip.stbyte+31)))]; eth.ip.dest = ... [num2str(hex2dec(eth.pack(eth.ip.stbyte+32:eth.ip.stbyte+33))),'.', ... num2str(hex2dec(eth.pack(eth.ip.stbyte+34:eth.ip.stbyte+35))),'.', ... num2str(hex2dec(eth.pack(eth.ip.stbyte+36:eth.ip.stbyte+37))),'.', ... num2str(hex2dec(eth.pack(eth.ip.stbyte+38:eth.ip.stbyte+39)))]; if strcmp(eth.ip.typecode,'11') eth.ip.type = 'UDP'; eth.ip.udp.stbyte = eth.ip.stbyte + 40; eth.ip.udp.src = hex2dec(eth.pack(eth.ip.udp.stbyte:eth.ip.udp.stbyte + 3)); eth.ip.udp.dest = hex2dec(eth.pack(eth.ip.udp.stbyte+4:eth.ip.udp.stbyte+7)); eth.ip.udp.length = hex2dec(eth.pack(eth.ip.udp.stbyte+8:eth.ip.udp.stbyte+11)); eth.ip.udp.checksum = eth.pack(eth.ip.udp.stbyte+12:eth.ip.udp.stbyte+15); eth.ip.udp.protoID = eth.pack(eth.ip.udp.stbyte+20:eth.ip.udp.stbyte+23); if strcmp(eth.ip.udp.protoID,'0000') eth.ip.udp.proto = 'MODBUS'; %eth.ip.udp.modbus = struct; eth.ip.udp.modbus.stbyte = eth.ip.udp.stbyte+16; eth.ip.udp.modbus.transID = eth.pack(eth.ip.udp.modbus.stbyte:eth.ip.udp.modbus.stbyte+3); eth.ip.udp.modbus.protoID = eth.ip.udp.protoID; eth.ip.udp.modbus.length = int16(str2double(eth.pack(eth.ip.udp.modbus.stbyte + 8:eth.ip.udp.modbus.stbyte + 11))); eth.ip.udp.modbus.UID = eth.pack(eth.ip.udp.modbus.stbyte + 12:eth.ip.udp.modbus.stbyte + 13); eth.ip.udp.modbus.func = hex2dec(eth.pack(eth.ip.udp.modbus.stbyte + 14:eth.ip.udp.modbus.stbyte+15)); eth.ip.udp.modbus.register = eth.pack(eth.ip.udp.modbus.stbyte + 16: eth.ip.udp.modbus.stbyte+19); %Number of words to a register, or the number of registers eth.ip.udp.modbus.words = hex2dec(eth.pack(eth.ip.udp.modbus.stbyte+20:eth.ip.udp.modbus.stbyte+23)); eth.ip.udp.modbus.bytes = hex2dec(eth.pack(eth.ip.udp.modbus.stbyte+24:eth.ip.udp.modbus.stbyte+25)); eth.ip.udp.modbus.data = eth.pack(eth.ip.udp.modbus.stbyte + 26:eth.ip.udp.modbus.stbyte + 26 + 2*eth.ip.udp.modbus.bytes - 1); %If func 16 or 23, loop through data/registers and add to table if eth.ip.udp.modbus.func == 16 || eth.ip.udp.modbus.func == 23 stp = eth.ip.udp.modbus.bytes*2/eth.ip.udp.modbus.words; for n = 1:stp:eth.ip.udp.modbus.bytes*2; %Check for existence of register as a key? if ~isKey(MBMap,eth.ip.udp.modbus.register) MBCol = MBCol + 1; MBMap(eth.ip.udp.modbus.register) = MBCol; end MBTable(L,MBCol) = hex2dec(eth.ip.udp.modbus.data(n:n+stp-1)); eth.ip.udp.modbus.register = dec2hex(hex2dec(eth.ip.udp.modbus.register)+1); end lastt = t; end %If func 4, make sure it is the response, then put %data into table for register column elseif false %need code to handle serial to UDP conversion box else invalid = true; end else invalid = true; end else invalid = true; end if ~invalid end end %end end %Display Progress if int64(fl/1000)*1000 == fl for x = 1:length(mess); fprintf('\b'); end %fprintf('Lines parsed: %i',fl); mess = sprintf('Lines parsed: %i / %i',fl,nol); fprintf('%s',mess); %Check execution time - getting slower: %%{ ext = toc(tval); mess = sprintf('\nExecution Time: %f\n',ext); fprintf('%s',mess); %%} end end ext = toc - exst; Update: I updated my code above to remove the overloaded operators (disp and lt were replaced with mess and lastt) Was asked to use the profiler, so I limited to 2000 lines in the table (added && L >=2000 to the while loop) to limit the execution time, and here are the top results from the profiler: SGAS_Wireshark_Parser_v0p7_fulleth 1 57.110 s 9.714 s Strcat 9187 29.271 s 13.598 s Blanks 9187 15.673 s 15.673 s Uigetfile 1 12.226 s 0.009 s uitools\private\uigetputfile_helper 1 12.212 s 0.031 s FileChooser.FileChooser>FileChooser.show 1 12.085 s 0.006s ...er>FileChooser.showPeerAndBlockMATLAB 1 12.056 s 0.001s ...nChooser>FileOpenChooser.doShowDialog 1 12.049 s 12.049 s hex2dec 44924 2.944 s 2.702 s num2str 16336 1.139 s 0.550 s str2double 17356 1.025 s 1.025 s int2str 16336 0.589 s 0.589 s fgetl 17356 0.488 s 0.488 s dec2hex 6126 0.304 s 0.304 s fliplr 44924 0.242 s 0.242 s It appears to be strcat calls that are doing it. I only explicitly call strcat on one line. Are some of the other string manipulations I'm doing calling strcat indirectly? Each loop should be calling strcat the same number of times though, so I still don't understand why it takes longer and longer the more it runs... also, hex2dec is called a lot, but is not really affecting the time. But anyway, are there any other methods I can use the combine the strings?
Here is the issue: The string (an char array in MATLAB) packdata was being resized and reallocated over and over again. That's what was slowing down this code. I did the following steps: I eliminated the redundant variable packdata and now only use eth.pack. I preallocated eth.pack and a couple "helper variables" of known lengths by running blanks ONCE for each before the loop ever starts eth.pack = blanks(604); thisline = blanks(47); smline = blanks(32); (Note: 604 is the maximum possible size of packdata based on headers + MODBUS protocol) Then I created a pointer variable to point to the location of the last char written to packdata. pptr = 1; ... dataline = int16(str2double(MBLine(1:4))); thisline = MBLine(7:53); %Always 47 characters smline = [thisline(~isspace(thisline)),blanks(32-sum(~isspace(thisline)))]; %Always 32 Characters eth.pack(pptr:pptr+31) = smline; pptr = pptr + 32; The above was inside the 'if packline > 3' block in place of the 'packdata =' statement, then at the end of the 'if stoppack' block was the reset statement: pptr = 1; %Reset Pointer FYI, not surprisingly this brought out other flaws in my code which I've mostly fixed but still need to finish. Not a big issue now as this loop executes lightning fast with these changes. Thanks to Yvon for helping point me in the right direction. I kept thinking my huge table, MBTable was the issue... but it had nothing to do with it.
SystemVerilog array random seed of Shuffle function
I get the same output everytime I run the code below. module array_shuffle; integer data[10]; initial begin foreach (data[x]) begin data[x] = x; end $display("------------------------------\n"); $display("before shuffle, data contains:\n"); foreach (data[x]) begin $display("data[%0d] = %0d", x, data[x]); end data.shuffle(); $display("------------------------------\n"); $display("after shuffle, data contains:\n"); foreach (data[x]) begin $display("data[%0d] = %0d", x, data[x]); end end endmodule Output: ------------------------------ before shuffle, data contains: data[0] = 0 data[1] = 1 data[2] = 2 data[3] = 3 data[4] = 4 data[5] = 5 data[6] = 6 data[7] = 7 data[8] = 8 data[9] = 9 ------------------------------ after shuffle, data contains: data[0] = 8 data[1] = 6 data[2] = 7 data[3] = 9 data[4] = 5 data[5] = 0 data[6] = 1 data[7] = 4 data[8] = 2 data[9] = 3 Is there a way to seed the randomization of the shuffle function?
Shuffle returns the same result every time because you probably run the simulator with the same seed. This is the intended behavior, because when you run a simulation and find a bug, you want to be able to reproduce it, regardless of any design (and to some extent testbench) changes. To see a different output, try setting the seed on the simulator command line. For Incisive this is: irun -svseed 1 // sets the seed to 1 irun -svseed random // will set a random seed It's also possible to manipulate the seed of the random number generator using set_randstate, but I wouldn't mess with that.
Pure Lua implementation of md5
Is there a pure lua implementation of the md5 hashing algorithm? One that doesn't rely on any c or external libraries? There's javascript implementations that don't rely on c or anything, so it ought to be possible with lua. Thanks!
I combined the mentioned lua MD5 library that required bitlib and added in LuaBit to make it a pure lua implementation. As an additional benefit it's structured in such a way that it will work inside of the redis lua scripting environment. Please note that it is extremely slow compared to other non pure lua based implementations. --[[--------------- LuaBit v0.4 ------------------- a bitwise operation lib for lua. http://luaforge.net/projects/bit/ How to use: ------------------- bit.bnot(n) -- bitwise not (~n) bit.band(m, n) -- bitwise and (m & n) bit.bor(m, n) -- bitwise or (m | n) bit.bxor(m, n) -- bitwise xor (m ^ n) bit.brshift(n, bits) -- right shift (n >> bits) bit.blshift(n, bits) -- left shift (n << bits) bit.blogic_rshift(n, bits) -- logic right shift(zero fill >>>) Please note that bit.brshift and bit.blshift only support number within 32 bits. 2 utility functions are provided too: bit.tobits(n) -- convert n into a bit table(which is a 1/0 sequence) -- high bits first bit.tonumb(bit_tbl) -- convert a bit table into a number ------------------- Under the MIT license. copyright(c) 2006~2007 hanzhao (abrash_han#hotmail.com) --]]--------------- --do ------------------------ -- bit lib implementions local function check_int(n) -- checking not float if(n - math.floor(n) > 0) then error("trying to use bitwise operation on non-integer!") end end local function tbl_to_number(tbl) local n = #tbl local rslt = 0 local power = 1 for i = 1, n do rslt = rslt + tbl[i]*power power = power*2 end return rslt end local function expand(tbl_m, tbl_n) local big = {} local small = {} if(#tbl_m > #tbl_n) then big = tbl_m small = tbl_n else big = tbl_n small = tbl_m end -- expand small for i = #small + 1, #big do small[i] = 0 end end local to_bits = function () end local function bit_not(n) local tbl = to_bits(n) local size = math.max(#tbl, 32) for i = 1, size do if(tbl[i] == 1) then tbl[i] = 0 else tbl[i] = 1 end end return tbl_to_number(tbl) end to_bits = function (n) check_int(n) if(n < 0) then -- negative return to_bits(bit_not(math.abs(n)) + 1) end -- to bits table local tbl = {} local cnt = 1 while (n > 0) do local last = math.mod(n,2) if(last == 1) then tbl[cnt] = 1 else tbl[cnt] = 0 end n = (n-last)/2 cnt = cnt + 1 end return tbl end local function bit_or(m, n) local tbl_m = to_bits(m) local tbl_n = to_bits(n) expand(tbl_m, tbl_n) local tbl = {} local rslt = math.max(#tbl_m, #tbl_n) for i = 1, rslt do if(tbl_m[i]== 0 and tbl_n[i] == 0) then tbl[i] = 0 else tbl[i] = 1 end end return tbl_to_number(tbl) end local function bit_and(m, n) local tbl_m = to_bits(m) local tbl_n = to_bits(n) expand(tbl_m, tbl_n) local tbl = {} local rslt = math.max(#tbl_m, #tbl_n) for i = 1, rslt do if(tbl_m[i]== 0 or tbl_n[i] == 0) then tbl[i] = 0 else tbl[i] = 1 end end return tbl_to_number(tbl) end local function bit_xor(m, n) local tbl_m = to_bits(m) local tbl_n = to_bits(n) expand(tbl_m, tbl_n) local tbl = {} local rslt = math.max(#tbl_m, #tbl_n) for i = 1, rslt do if(tbl_m[i] ~= tbl_n[i]) then tbl[i] = 1 else tbl[i] = 0 end end --table.foreach(tbl, print) return tbl_to_number(tbl) end local function bit_rshift(n, bits) check_int(n) local high_bit = 0 if(n < 0) then -- negative n = bit_not(math.abs(n)) + 1 high_bit = 2147483648 -- 0x80000000 end for i=1, bits do n = n/2 n = bit_or(math.floor(n), high_bit) end return math.floor(n) end -- logic rightshift assures zero filling shift local function bit_logic_rshift(n, bits) check_int(n) if(n < 0) then -- negative n = bit_not(math.abs(n)) + 1 end for i=1, bits do n = n/2 end return math.floor(n) end local function bit_lshift(n, bits) check_int(n) if(n < 0) then -- negative n = bit_not(math.abs(n)) + 1 end for i=1, bits do n = n*2 end return bit_and(n, 4294967295) -- 0xFFFFFFFF end local function bit_xor2(m, n) local rhs = bit_or(bit_not(m), bit_not(n)) local lhs = bit_or(m, n) local rslt = bit_and(lhs, rhs) return rslt end -- An MD5 mplementation in Lua, requires bitlib (hacked to use LuaBit from above, ugh) -- 10/02/2001 jcw#equi4.com local md5={ff=tonumber('ffffffff',16),consts={}} string.gsub([[ d76aa478 e8c7b756 242070db c1bdceee f57c0faf 4787c62a a8304613 fd469501 698098d8 8b44f7af ffff5bb1 895cd7be 6b901122 fd987193 a679438e 49b40821 f61e2562 c040b340 265e5a51 e9b6c7aa d62f105d 02441453 d8a1e681 e7d3fbc8 21e1cde6 c33707d6 f4d50d87 455a14ed a9e3e905 fcefa3f8 676f02d9 8d2a4c8a fffa3942 8771f681 6d9d6122 fde5380c a4beea44 4bdecfa9 f6bb4b60 bebfbc70 289b7ec6 eaa127fa d4ef3085 04881d05 d9d4d039 e6db99e5 1fa27cf8 c4ac5665 f4292244 432aff97 ab9423a7 fc93a039 655b59c3 8f0ccc92 ffeff47d 85845dd1 6fa87e4f fe2ce6e0 a3014314 4e0811a1 f7537e82 bd3af235 2ad7d2bb eb86d391 67452301 efcdab89 98badcfe 10325476 ]],"(%w+)", function (s) table.insert(md5.consts, tonumber(s,16)) end) --67452301 efcdab89 98badcfe 10325476 ]],"(%w+)", function (s) tinsert(md5.consts,tonumber(s,16)) end) function md5.transform(A,B,C,D,X) local f=function (x,y,z) return bit_or(bit_and(x,y),bit_and(-x-1,z)) end local g=function (x,y,z) return bit_or(bit_and(x,z),bit_and(y,-z-1)) end local h=function (x,y,z) return bit_xor(x,bit_xor(y,z)) end local i=function (x,y,z) return bit_xor(y,bit_or(x,-z-1)) end local z=function (f,a,b,c,d,x,s,ac) a=bit_and(a+f(b,c,d)+x+ac,md5.ff) -- be *very* careful that left shift does not cause rounding! return bit_or(bit_lshift(bit_and(a,bit_rshift(md5.ff,s)),s),bit_rshift(a,32-s))+b end local a,b,c,d=A,B,C,D local t=md5.consts a=z(f,a,b,c,d,X[ 0], 7,t[ 1]) d=z(f,d,a,b,c,X[ 1],12,t[ 2]) c=z(f,c,d,a,b,X[ 2],17,t[ 3]) b=z(f,b,c,d,a,X[ 3],22,t[ 4]) a=z(f,a,b,c,d,X[ 4], 7,t[ 5]) d=z(f,d,a,b,c,X[ 5],12,t[ 6]) c=z(f,c,d,a,b,X[ 6],17,t[ 7]) b=z(f,b,c,d,a,X[ 7],22,t[ 8]) a=z(f,a,b,c,d,X[ 8], 7,t[ 9]) d=z(f,d,a,b,c,X[ 9],12,t[10]) c=z(f,c,d,a,b,X[10],17,t[11]) b=z(f,b,c,d,a,X[11],22,t[12]) a=z(f,a,b,c,d,X[12], 7,t[13]) d=z(f,d,a,b,c,X[13],12,t[14]) c=z(f,c,d,a,b,X[14],17,t[15]) b=z(f,b,c,d,a,X[15],22,t[16]) a=z(g,a,b,c,d,X[ 1], 5,t[17]) d=z(g,d,a,b,c,X[ 6], 9,t[18]) c=z(g,c,d,a,b,X[11],14,t[19]) b=z(g,b,c,d,a,X[ 0],20,t[20]) a=z(g,a,b,c,d,X[ 5], 5,t[21]) d=z(g,d,a,b,c,X[10], 9,t[22]) c=z(g,c,d,a,b,X[15],14,t[23]) b=z(g,b,c,d,a,X[ 4],20,t[24]) a=z(g,a,b,c,d,X[ 9], 5,t[25]) d=z(g,d,a,b,c,X[14], 9,t[26]) c=z(g,c,d,a,b,X[ 3],14,t[27]) b=z(g,b,c,d,a,X[ 8],20,t[28]) a=z(g,a,b,c,d,X[13], 5,t[29]) d=z(g,d,a,b,c,X[ 2], 9,t[30]) c=z(g,c,d,a,b,X[ 7],14,t[31]) b=z(g,b,c,d,a,X[12],20,t[32]) a=z(h,a,b,c,d,X[ 5], 4,t[33]) d=z(h,d,a,b,c,X[ 8],11,t[34]) c=z(h,c,d,a,b,X[11],16,t[35]) b=z(h,b,c,d,a,X[14],23,t[36]) a=z(h,a,b,c,d,X[ 1], 4,t[37]) d=z(h,d,a,b,c,X[ 4],11,t[38]) c=z(h,c,d,a,b,X[ 7],16,t[39]) b=z(h,b,c,d,a,X[10],23,t[40]) a=z(h,a,b,c,d,X[13], 4,t[41]) d=z(h,d,a,b,c,X[ 0],11,t[42]) c=z(h,c,d,a,b,X[ 3],16,t[43]) b=z(h,b,c,d,a,X[ 6],23,t[44]) a=z(h,a,b,c,d,X[ 9], 4,t[45]) d=z(h,d,a,b,c,X[12],11,t[46]) c=z(h,c,d,a,b,X[15],16,t[47]) b=z(h,b,c,d,a,X[ 2],23,t[48]) a=z(i,a,b,c,d,X[ 0], 6,t[49]) d=z(i,d,a,b,c,X[ 7],10,t[50]) c=z(i,c,d,a,b,X[14],15,t[51]) b=z(i,b,c,d,a,X[ 5],21,t[52]) a=z(i,a,b,c,d,X[12], 6,t[53]) d=z(i,d,a,b,c,X[ 3],10,t[54]) c=z(i,c,d,a,b,X[10],15,t[55]) b=z(i,b,c,d,a,X[ 1],21,t[56]) a=z(i,a,b,c,d,X[ 8], 6,t[57]) d=z(i,d,a,b,c,X[15],10,t[58]) c=z(i,c,d,a,b,X[ 6],15,t[59]) b=z(i,b,c,d,a,X[13],21,t[60]) a=z(i,a,b,c,d,X[ 4], 6,t[61]) d=z(i,d,a,b,c,X[11],10,t[62]) c=z(i,c,d,a,b,X[ 2],15,t[63]) b=z(i,b,c,d,a,X[ 9],21,t[64]) return A+a,B+b,C+c,D+d end -- convert little-endian 32-bit int to a 4-char string local function leIstr(i) local f=function (s) return string.char(bit_and(bit_rshift(i,s),255)) end return f(0)..f(8)..f(16)..f(24) end -- convert raw string to big-endian int local function beInt(s) local v=0 for i=1,string.len(s) do v=v*256+string.byte(s,i) end return v end -- convert raw string to little-endian int local function leInt(s) local v=0 for i=string.len(s),1,-1 do v=v*256+string.byte(s,i) end return v end -- cut up a string in little-endian ints of given size local function leStrCuts(s,...) local o,r=1,{} for i=1,#arg do table.insert(r,leInt(string.sub(s,o,o+arg[i]-1))) o=o+arg[i] end return r end function md5.Calc(s) local msgLen=string.len(s) local padLen=56- msgLen % 64 if msgLen % 64 > 56 then padLen=padLen+64 end if padLen==0 then padLen=64 end s=s..string.char(128)..string.rep(string.char(0),padLen-1) s=s..leIstr(8*msgLen)..leIstr(0) assert(string.len(s) % 64 ==0) local t=md5.consts local a,b,c,d=t[65],t[66],t[67],t[68] for i=1,string.len(s),64 do local X=leStrCuts(string.sub(s,i,i+63),4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4) assert(#X==16) X[0]=table.remove(X,1) -- zero based! a,b,c,d=md5.transform(a,b,c,d,X) end local swap=function (w) return beInt(leIstr(w)) end return string.format("%08x%08x%08x%08x",swap(a),swap(b),swap(c),swap(d)) end return md5.Calc("asdf"); -- 912ec803b2ce49e4a541068d495ab570 It is available in this gist.
http://equi4.com/md5/md5calc.lua but that still requires a lib.
There's an old one here but it requires bitlib.
I've refined #Adam Baldwin's solution and made a library that calculates md5 sums in pure Lua, with no external dependencies and no C: https://github.com/kikito/md5.lua Summary of changes: Implemented two functions on the interface, md5.sum and md5.sumhex, that work exactly like their counterparts in the Kepler library, but are implemented in Lua alone. Added a small test suite with using busted. Removed some unused functions Avoided re-creation of anonymous functions when it was not needed Simplified the creation of the constants, and made them private Spacing and naming changes. For now I don't need md5.crypt and md5.decrypt, so I have not implemented those. But I will accept pull requests :)