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