Primarily associated with **GSM mobile communication security**, it contains a collection of input-output pairs. Each entry typically includes an **initialization key**, a **frame number** (or public input), and the corresponding **expected keystream output**.
Its purpose is to allow developers and researchers to **verify the correctness** of their A5 cipher implementations. By comparing their generated keystreams against these known good examples, they can ensure their code accurately reflects the A5 algorithm. This is vital for **interoperability** and maintaining the **security integrity** of systems relying on A5 encryption.
A5/1 Circuit, expressed in Verilog
The following is equivalent to the purported A5/1
pedagogical C earlier published.
For non-commercial, non-governmental use only.
It comes with a testbench and sample output.
/*
a5.v
Purported A5/1 circuit, expressed in Verilog.
13 May 99
David Honig
Derived from Briceno, Goldberg, Wagner's Pedagogical C Code
of May 99.
To load key: assert Startloading, load data starting on next clock,
bitwise (1 delay + 64 key + 22 frame clocks).
Then wait for Doneloading to be asserted (100 more clocks). Then
harvest your bits.
A testbench and sample output is appended as comments.
This synthesizes to about 150 LCs and runs at 80 Mhz on
the smaller Altera CPLDs e.g., 10K30.
*/
module a5(Clk, Reset_n,
Bitout,
Keybit,
Startloading,
Doneloading);
input Clk, Reset_n;
output Bitout; // output keystream
reg Bitout;
input Keybit; // input keybits 64 + 22
input Startloading; // initial keyload
output Doneloading; // signal done of keyloading
reg Doneloading;
// internal state; lsb is leftmost
reg [18:0] lfsr_1;
reg [21:0] lfsr_2;
reg [22:0] lfsr_3;
reg [1:0] State; // FSM control
reg [6:0] Counter; // for counting steps
reg [2:0] Phase; // for sequencing phases
wire hi_1, hi_2, hi_3;
assign hi_1 = lfsr_1[18];
assign hi_2 = lfsr_2[21];
assign hi_3 = lfsr_3[22];
wire mid1, mid2, mid3;
assign mid1=lfsr_1[8];
assign mid2=lfsr_2[10];
assign mid3=lfsr_3[10];
wire maj;
assign maj=majority(mid1, mid2, mid3);
wire newbit1, newbit2, newbit3;
assign newbit1= ( lfsr_1[13] ^ lfsr_1[16] ^ lfsr_1[17] ^ lfsr_1[18] );
assign newbit2= ( lfsr_2[20] ^ lfsr_2[21] ) ;
assign newbit3= ( lfsr_3[7] ^ lfsr_3[20] ^ lfsr_3[21] ^ lfsr_3[22] );
parameter IDLE=0;
parameter KEYING=1;
parameter RUNNING=2;
always @(posedge Clk or negedge Reset_n) begin
if (!Reset_n) begin: resetting
$display("a5 reset");
Doneloading <=0;
Bitout <=0;
{lfsr_1, lfsr_2, lfsr_3} <= 64'h 0;
{State, Counter, Phase} <=0;
end // reset
else begin
case (State)
IDLE: begin: reset_but_no_key
if (Startloading) begin: startloadingkey
// $display("Loading key starts at %0d ", $time);
State <= KEYING;
{lfsr_1, lfsr_2, lfsr_3} <= 64'h 0;
Phase <=0; Counter<=0;
end // if
end // idle
KEYING: begin
case (Phase)
0: begin: load64andclock
clockallwithkey;
// $display("Loading key bit %0b %0d at %0d %0x", Keybit, Counter, $time, lfsr_1);
if (Counter==63) begin
Counter <=0;
Phase <= Phase +1;
$display(" ");
end
else Counter <=Counter+1;
end
1: begin: load22andclock
// $display("Loading frame bit %0b at %0d %0d %0x", Keybit, Counter, $time, lfsr_1);
clockallwithkey;
if (Counter==21) begin
Counter <=0;
Phase <= Phase +1;
end
else Counter <=Counter+1;
end
2: begin: clock100
majclock;
if (Counter ==100) begin
$display("Done keying, now running %0d\n", $time);
State <= RUNNING;
end
else Counter <= Counter+1;
end
endcase // Phase
end // keying
RUNNING: begin
Doneloading <=1; // when done loading
Bitout <= hi_1 ^ hi_2 ^ hi_3;
majclock;
end // running
endcase // State
end // else not resetting
end // always
function majority;
input a,b,c;
begin
case({a,b,c}) // synopsys parallel_case
3'b 000: majority=0;
3'b 001: majority=0;
3'b 010: majority=0;
3'b 011: majority=1;
3'b 100: majority=0;
3'b 101: majority=1;
3'b 110: majority=1;
3'b 111: majority=1;
endcase
end
endfunction
task clock1;
begin
lfsr_1 <= ( lfsr_1 << 1 ) | newbit1;
end
endtask
task clock2;
begin
lfsr_2 <= (lfsr_2 << 1) | newbit2;
end
endtask
task clock3;
begin
lfsr_3 <= (lfsr_3 << 1) | newbit3;
end
endtask
task clockall;
begin
clock1;
clock2;
clock3;
end
endtask
task clockallwithkey;
begin
lfsr_1 <= ( lfsr_1 << 1 ) | newbit1 ^ Keybit;
lfsr_2 <= ( lfsr_2 << 1 ) | newbit2 ^ Keybit;
lfsr_3 <= ( lfsr_3 << 1 ) | newbit3 ^ Keybit;
end
endtask
task majclock;
begin
if (mid1 == maj) clock1;
if (mid2 == maj) clock2;
if (mid3 == maj) clock3;
end
endtask
endmodule
/**************** CUT HERE FOR TESTBENCH test_a5.v **************************
module test_a5;
reg Clk, Reset_n;
wire Bitout; // output keystream
reg Keybit; // input keybits 64 + 22
reg Startloading; // initial keyload
wire Doneloading; // signal done of keyloading
reg [0:7] key [7:0];
reg [22:0] frame;
a5 dut(Clk, Reset_n,
Bitout,
Keybit,
Startloading,
Doneloading);
always @(Clk) #5 Clk <= ~Clk;
integer i,j;
initial begin
#5
key[0]= 8'h 12;
key[1]= 8'h 23;
key[2]= 8'h 45;
key[3]= 8'h 67;
key[4]= 8'h 89;
key[5]= 8'h AB;
key[6]= 8'h CD;
key[7]= 8'h EF;
frame <= 22'h 134;
Clk <=0;
Reset_n <=1;
Startloading <=0;
Keybit <=0;
#10 Reset_n <=0;
#10 Reset_n <=1;
// key setup
#100
Startloading <=1; $display("Starting to key %0d", $time);
for (i=0; i<8; i=i+1) begin
for (j=0; j<8; j=j+1) begin
#10 Startloading <=0;
Keybit <= key[i] >> j;
end // j
end // i
for (i=0; i<22; i=i+1) begin
#10 Keybit <= frame[i];
end
wait(Doneloading); $display("Done keying %0d", $time);
$write("\nBits out: \n");
repeat (32) #10 $write("%b", Bitout);
$display("\nknown good=\n%b", 32'h 534EAA58);
#1000 $display("\nSim done."); $finish;
end // init
endmodule
************************* END OF TESTBENCH ************************************/
/**** SAMPLE OUTPUT
a5 reset
a5 reset
Starting to key 125
Done keying, now running 2000
Done keying 2010
Bits out:
01010011010011101010101001011000
known good=
01010011010011101010101001011000
Sim done.
*********/
// eof