Intrigued by Tied and Entangled, Quantum fun., thought I might try playing with the simulation
of quantum key distribution in Perl. Purely theoretical stuff unless you have
"quantum channel" to transmit your data (which usually means a
channel, such as fiber optic, that can transmit photons). Nonetheless the
theoretical insight still offers some practical inspiration.
Real Quick Rundown
Consider the following Perl script (the entire modules are enclosed at the end of this writing).
use strict;
use warnings;
use QKey qw/ randseq quantumencode analyze ynseq bobkey alicekey /;
# Alice
my @randseq = randseq(43);
my @quantumencode = quantumencode(@randseq);
# Bob
my @analyze = analyze(@quantumencode);
my @ynseq = ynseq(@analyze);
my @bobkey = bobkey(@analyze);
# Alice
my @alicekey = alicekey(\@ynseq, \@randseq);
print "@bobkey\n";
print "@alicekey\n";
__END__
0 1 1 1 0 1 0 0 0
0 1 1 1 0 1 0 0 0
Alice wants to share an encryption key with Bob. The data transmission
channels are always being listened to by eavesdroppers. Alice will need to send Bob some data first. Upon receiving those data and based on them, Bob generates a key and sends Alice back some pertaining information such that she can generate a key same as his.
Alice first generates a sequence of 43 random bits (0 or 1) with randseq(43), or however long. Then she quantum-encodes the bits into quantum states with quantumencode(@randseq) (in real life this would correspond to, for example, polarized photons). After that, she will transmit the quantum states (or quantum bits) via a quantum channel (such as fiber optic) to Bob.
Quantum encoding has at least two anti-hacking advantages:
-
If an eavesdropper "looks" into the quantum states, the states collapse (a quantum mechanics' law). It renders useless to Bob. He can't generate key. The eavesdropper gains nothing.
-
If the eavesdropper just "analyzes" the states, it could disturb the transmission with high probability (not simulated in the Perl code) and cause Bob and hence Alice errors when generating their keys. They can't transmit secret messages if their keys are broken. The eavedropper again gains nothing. Besides, such errors can be mathematically and statistically detected to determine if it's due to normal noise in the channel or outside interference.
Bob "analyzes" the quantum-encoded bits with analyze(@quantumencode). Without explaining the details, the "analysis" process is basically equivalent to randomly select a subset from Alice's quantum bits and therefore the corresponding original bits, with the result @bobkey = bobkey(@analyze). Bob will mark the positions from which he selects his bits with ynseq(@analyze) as a Y/N sequence. Bob will then send the Y/N sequence to Alice via regular channel.
Alice then uses the Y/N sequence to locate the subset from her original random bits to produce her key, which will be identical to Bob's.
Notice, what being sent via public channels are quantum bits by Alice through quantum channel and Y/N sequence by Bob through regular channel. It is highly unlikely for an eavesdropper to be able to replicate a key based on the quantum bits and the Y/N sequence alone.
It's partly because quantum bits don't correspond to the original bits deterministically but probabilistically (a quantum's law). There're also two additional randomizations occur during Bob's "analysis;" one by design, another by nature (quantum mechanics).
The design part is that Bob has an "analyzer" corresponding to bit 0 and another to bit 1. Bob selects one of the two analyzers randomly when analyzing each quantum bit sent by Alice.
If the bit 0 analyzer happens to analyze a quantum bit corresponding to bit 0 from Alice's original random bits, there will be 50/50 chances the analyzer will declare a match, due to quantum's law, and put a corresponding Y in the Y/N sequence. Same with bit 1 matches. If not a match, both analyzers will declare N with probability one.
Hence, in a way, the multiple randomizations that occur naturally and artificially during the key distribution process make it very hard to hack.
References
Preskill, John. Lecture
Notes for Physics 229: Quantum Information and Computation. Caltech, 1998.
Roychowdhury, Vwani P. "Tutorial on Quantum Computing: Lecture 1." Institute
for Pure and Applied Mathematics, UCLA.
Code Appendix
QKey.pm
package QKey;
use strict;
use Exporter;
use Math::MatrixReal;
use QStuff qw(entangle);
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(randseq quantumencode analyze ynseq bobkey aliceke
+y %ms);
our %ms; # seq of measurements used
sub randseq { map{int rand(2)} 1..($_[0]) } # Alice
sub quantumencode { # Alice
map { $_ ? entangle(1/sqrt(2), 0, 1/sqrt(2), 1) : entangle(1, 0,
+0, 1) } @_
}
# measurements(@quantumEncode): seq of measurements gonna use
sub _measurements { # Bob
my $ms = {};
$ms->{ms} = [ entangle(1/sqrt(2), 0, -1/sqrt(2), 1), entangle(0, 0
+, 1, 1) ];
$ms->{seq} = [ map{int rand(2)} 0..$#_ ];
return $ms;
}
# analyze(@quantumEncode): return measurement results
sub analyze { # Bob
%ms = %{_measurements(@_)};
map{ $_[$_]->proj($ms{ms}[$ms{seq}[$_]]) } 0..$#_;
}
# ynseq(@analyze): return y/n seq of "results"
sub ynseq { # Bob
map{ $_->cmpquanta($ms{ms}[0]) or $_->cmpquanta($ms{ms}[1]) ?
+1 : 0 } @_;
}
# bobkey(@analyze)
sub bobkey { # Bob
my @key;
for (@_) {
push(@key, 0) if $_->cmpquanta($ms{ms}[0]);
push(@key, 1) if $_->cmpquanta($ms{ms}[1]);
}
return @key;
}
# alicekey(\@ynseq, \@randseq)
sub alicekey { # Alice
my @key;
for(0..$#{$_[0]}){ push(@key, ${$_[1]}[$_]) if ${$_[0]}[$_] }
return @key;
}
1;
QStuff.pm
package QStuff;
use strict;
use Exporter;
use Math::MatrixReal;
use Quantum::Entanglement;
our @ISA = qw/Quantum::Entanglement Exporter/;
our @EXPORT_OK = qw/entangle/;
sub entangle {bless Quantum::Entanglement::entangle(@_)}
# args($entangle) returns values passed to entangle()
sub args { map {@{$_}} @{${$_[0]->[0]}} }
# $entange->probs returns probs only
sub probs {
my @ar = args(shift);
return map {@ar[$_*2]} 0..(int($#ar/2));
}
# $entange->states return states only
sub states {
my @ar = args(shift);
return map {@ar[$_*2+1]} 0..(int($#ar/2));
}
# $a->cmpquanta($b) sees if 2 quanta the same
sub cmpquanta {
return 0 unless $_[0]->cmpstates($_[1]);
my @probs0 = $_[0]->probs;
my @probs1 = $_[1]->probs;
for(0..$#probs0){return 0 unless abs($probs0[$_] - $probs1[$_]) <
+0.000001}
return 1;
}
# $a->cmpstates($b) sees if $a & $b have the same state space
sub cmpstates {
my @a = $_[0]->states;
my @b = $_[1]->states;
return 0 if $#a != $#b;
for (0..$#a) {return 0 if $a[$_] != $b[$_]};
return 1;
}
# project $a onto the subspace of $b
sub proj {
my ($a, $b) = @_;
# checking states compatability to be implemented
my @bstates = $b->states;
my ($I, $prob, $Pb, $measure, $norm, $measure);
$b = Math::MatrixReal->new_from_cols([[$b->probs]]);
$a = Math::MatrixReal->new_from_cols([[$a->probs]]);
$I = Math::MatrixReal->new_diag( [1, 1] );
$prob = (~$a * $b * ~$b * $a)->element(1,1);
$Pb = rand(1) < $prob ? $b * ~$b : ($I - $b * ~$b ); # quantum thi
+ng
$measure = $Pb * $a;
$norm = sqrt((~($measure) * $measure)->element(1,1));
$measure = $Pb * $a * (1/$norm);
bless QStuff::entangle(
map {$measure->element($_+1, 1) => $bstates[$_]} 0..$#bstates
);
}
1;
test_QStuff.pl
use strict;
use warnings;
use QStuff qw/entangle/;
my $a0 = entangle(1, 0, 0, 1);
my $a1 = entangle(1/sqrt(2), 0, 1/sqrt(2), 1);
my $b0 = entangle(1/sqrt(2), 0, -1/sqrt(2), 1);
my $b1 = entangle(0, 0, 1, 1);
print "proj\n";
print $a0->proj($b0)->show_states;
print $a1->proj($b1)->show_states;
print $a0->proj($b1)->show_states;
print $a1->proj($b0)->show_states;
print "\n\n";
exit;
print "cmpquanta\n";
print $a1->cmpquanta($b0) . "\n";
print $a1->cmpquanta($b1) . "\n";
print $a1->cmpquanta($a1) . "\n";
print $b1->cmpquanta($a0) . "\n";
print "\n\n";
print "cmpstates\n";
print $a1->cmpstates($b0) . "\n";
print $a1->cmpstates($b1) . "\n";
print $a1->cmpstates($a1) . "\n";
print $b1->cmpstates($a0) . "\n";
print "\n\n";
print "states\n";
print "@{[$a0->states]}\n";
print "@{[$a1->states]}\n";
print "@{[$b0->states]}\n";
print "@{[$b1->states]}\n";
print "\n\n";
print "probs\n";
print "@{[$a0->probs]}\n";
print "@{[$a1->probs]}\n";
print "@{[$b0->probs]}\n";
print "@{[$b1->probs]}\n";
print "\n\n";
print "args\n";
print "@{[$a0->args]}\n";
print "@{[$a1->args]}\n";
print "@{[$b0->args]}\n";
print "@{[$b1->args]}\n";