File Coverage

blib/lib/Crypt/SSSS.pm
Criterion Covered Total %
statement 73 75 97.3
branch 12 18 66.6
condition 11 16 68.7
subroutine 7 7 100.0
pod 2 3 66.6
total 105 119 88.2


line stmt bran cond sub pod time code
1             package Crypt::SSSS;
2              
3 1     1   736 use strict;
  1         1  
  1         28  
4 1     1   5 use warnings;
  1         2  
  1         83  
5              
6             our $VERSION = 0.2;
7              
8             require Exporter;
9              
10             our @ISA = qw(Exporter);
11             our @EXPORT = qw(ssss_distribute ssss_reconstruct);
12              
13 1     1   829 use POSIX qw(ceil pow);
  1         7017  
  1         9  
14 1     1   2038 use Crypt::SSSS::Message;
  1         3  
  1         781  
15              
16             require Carp;
17              
18             sub ssss_distribute(%) {
19 4     4 1 1609 my (%data) = @_;
20              
21 4 50       16 my $message = $data{message} or Carp::croak 'Missed "message" argument';
22              
23 4 50       10 my $k = $data{k} or Carp::croak 'Missed "k" argument';
24 4   66     19 my $n = $data{n} || $k;
25              
26 4   50     12 my $p = $data{p} || 257;
27              
28 4         5 my $shares = {};
29              
30 4         13 for my $x (1 .. $n) {
31 16         49 $shares->{$x} = Crypt::SSSS::Message->new(p => $p);
32             }
33              
34 4         7 my $chunks;
35 4 50       14 if (my $ref = ref $message) {
36 0 0       0 Carp::croak qw/"message" has unsupported type "$ref"/
37             unless $ref eq 'Crypt::SSSS::Message';
38              
39 0         0 $chunks = $message->get_data;
40             }
41             else {
42 4   100     29 $chunks = [unpack (($data{pack_size} || 'C') . '*', $message)];
43             }
44 4         13 while (@$chunks) {
45 5         13 my @a = splice @$chunks, 0, $k;
46              
47 5         10 for my $x (1 .. $n) {
48              
49 20         31 my $res = 0;
50 20         36 for my $pow (0 .. $k - 1) {
51 68   50     1750 $res += ($a[$pow] || 0) * pow($x, $pow);
52              
53             }
54              
55             # print "$x → ", $res % $p, "\n";
56 20         151 $shares->{$x}->push_data($res % $p);
57             }
58             }
59              
60 4         17 $shares;
61             }
62              
63             sub ssss_reconstruct(%) {
64 4     4 1 16 my (%data) = @_;
65              
66 4         5 my $shares = $data{shares};
67 4   50     12 my $p = $data{p} || '257';
68              
69 4         16 my @xs = keys %$shares;
70 4         9 my $k = @xs;
71              
72 4         6 my %mdata;
73 4         7 foreach my $x (@xs) {
74             $mdata{$x} =
75 13         47 Crypt::SSSS::Message->build_from_binary($p, $shares->{$x})
76             ->get_data;
77             }
78              
79 4   66     14 my $size = $data{size} || @{(values %mdata)[0]};
80              
81 4         7 my $message = '';
82              
83 4   100     16 my $pack_size = $data{pack_size} || 'C';
84              
85 4         14 for (my $l = 0; $l < $size; $l++) {
86 5         8 my @fx = ();
87 5         9 for my $i (@xs) {
88              
89             # Plynom
90 16         26 my @pl = (1);
91              
92             # Divider
93 16         27 my $d = 1;
94 16         23 for my $j (@xs) {
95 56 100       120 if ($j != $i) {
96              
97             # Multiply polinoms
98 40         63 my @opl = @pl;
99 40         65 unshift @pl, 0;
100 40         96 for (my $i = 0; $i < @opl; $i++) {
101 79         203 $pl[$i] += -$j * $opl[$i];
102             }
103 40         82 $d *= $i - $j;
104             }
105             }
106 16 100       35 $d += $p if $d < 0;
107              
108 16         29 my ($m) = extended_gcb($d, $p);
109 16 100       37 $m += $p if $m < 0;
110              
111 16         37 while (@fx < @pl) {
112 16         36 push @fx, 0;
113             }
114              
115             # Add our polynom (multiplied by constant)
116 16         39 for (my $j = 0; $j < @pl; $j++) {
117 56         165 $fx[$j] += $m * $mdata{$i}->[$l] * $pl[$j];
118             }
119             }
120              
121 5         15 for (@fx) {
122 16         18 $_ %= $p;
123 16 50       37 $_ += $p if $_ < 0;
124             }
125              
126 5         12 for (my $i = 0; $i < $k; $i++) {
127 16         53 $message .= pack $pack_size, $fx[$i];
128             }
129             }
130              
131 4         37 $message;
132             }
133              
134             sub extended_gcb {
135 74     74 0 93 my ($a, $b) = @_;
136              
137 74 100       158 return (1, 0) if $b == 0;
138              
139 58         91 my $q = int($a / $b);
140 58         70 my $r = $a % $b;
141 58         112 my ($s, $t) = extended_gcb($b, $r);
142              
143 58         113 return ($t, $s - $q * $t);
144             }
145              
146             1;
147             __END__