File Coverage

blib/lib/Encode/Base32/GMP.pm
Criterion Covered Total %
statement 19 21 90.4
branch n/a
condition n/a
subroutine 7 7 100.0
pod n/a
total 26 28 92.8


line stmt bran cond sub pod time code
1             package Encode::Base32::GMP;
2 3     3   169277 use strict;
  3         7  
  3         118  
3 3     3   17 use warnings;
  3         7  
  3         84  
4 3     3   82 use 5.008_009;
  3         24  
  3         222  
5             our $VERSION = '0.02';
6              
7 3     3   17 use base qw(Exporter);
  3         7  
  3         186  
8             our @EXPORT = qw(encode_base32 decode_base32);
9             our @EXPORT_OK = qw(base32_from_to md5_base32);
10              
11 3     3   434 use Carp;
  3         6  
  3         276  
12 3     3   17 use Digest::MD5 qw(md5_hex);
  3         6  
  3         183  
13 3     3   1429 use Math::GMPz qw(Rmpz_get_str);
  0            
  0            
14             use Scalar::Util qw(blessed);
15              
16             sub encode_base32 {
17             my ($int, $alphabet, $len) = @_;
18              
19             my $base32 = blessed($int) && $int->isa('Math::GMPz') ?
20             Rmpz_get_str($int, 32) :
21             Rmpz_get_str(Math::GMPz->new($int), 32);
22              
23             if ($len && $len =~ m|\A[0-9]+\Z|) {
24             $base32 = sprintf("%0${len}s",$base32);
25             }
26              
27             $alphabet && lc $alphabet eq 'gmp' ?
28             uc($base32) :
29             base32_from_to($base32,'gmp',$alphabet||'crockford');
30             }
31              
32             sub decode_base32 {
33             my ($base32, $alphabet) = @_;
34              
35             unless ($alphabet && lc $alphabet eq 'gmp') {
36             $base32 = base32_from_to($base32,$alphabet||'crockford','gmp');
37             }
38              
39             Math::GMPz->new($base32, 32);
40             }
41              
42             sub base32_from_to {
43             my ($base32, $from_alphabet, $to_alphabet) = @_;
44              
45             my $alphabets = {
46             crockford => '0123456789ABCDEFGHJKMNPQRSTVWXYZ',
47             rfc4648 => 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567',
48             zbase32 => 'YBNDRFG8EJKMCPQXOT1UWISZA345H769',
49             base32hex => '0123456789ABCDEFGHIJKLMNOPQRSTUV',
50             gmp => '0123456789ABCDEFGHIJKLMNOPQRSTUV',
51             };
52              
53             $from_alphabet = lc($from_alphabet||'crockford');
54             $to_alphabet = lc($to_alphabet ||'crockford');
55             $from_alphabet = 'gmp' if $from_alphabet eq 'base32hex';
56             $to_alphabet = 'gmp' if $to_alphabet eq 'base32hex';
57             $base32 = uc($base32);
58              
59             if ($from_alphabet eq 'crockford') {
60             $base32 =~ y|O|0|;
61             $base32 =~ y|IL|11|;
62             } elsif ($from_alphabet eq 'rfc4648') {
63             $base32 =~ y|0|O|;
64             $base32 =~ y|1|L|;
65             }
66              
67             my $from_digits = $alphabets->{$from_alphabet}
68             or croak("Encode::Base32::GMP::from_to called with invalid from_alphabet [$from_alphabet]");
69             my $to_digits = $alphabets->{$to_alphabet}
70             or croak("Encode::Base32::GMP::from_to called with invalid to_alphabet [$to_alphabet]");
71              
72             if ($from_alphabet ne $to_alphabet) {
73             if ($from_alphabet eq 'gmp') {
74             if ($to_alphabet eq 'crockford') {
75             $base32 =~ y|0123456789ABCDEFGHIJKLMNOPQRSTUV|0123456789ABCDEFGHJKMNPQRSTVWXYZ|;
76             } elsif ($to_alphabet eq 'rfc4648' ) {
77             $base32 =~ y|0123456789ABCDEFGHIJKLMNOPQRSTUV|ABCDEFGHIJKLMNOPQRSTUVWXYZ234567|;
78             } elsif ($to_alphabet eq 'zbase32') {
79             $base32 =~ y|0123456789ABCDEFGHIJKLMNOPQRSTUV|YBNDRFG8EJKMCPQXOT1UWISZA345H769|;
80             }
81             } elsif ($from_alphabet eq 'crockford') {
82             if ($to_alphabet eq 'gmp') {
83             $base32 =~ y|0123456789ABCDEFGHJKMNPQRSTVWXYZ|0123456789ABCDEFGHIJKLMNOPQRSTUV|;
84             } elsif ($to_alphabet eq 'rfc4648' ) {
85             $base32 =~ y|0123456789ABCDEFGHJKMNPQRSTVWXYZ|ABCDEFGHIJKLMNOPQRSTUVWXYZ234567|;
86             } elsif ($to_alphabet eq 'zbase32') {
87             $base32 =~ y|0123456789ABCDEFGHJKMNPQRSTVWXYZ|YBNDRFG8EJKMCPQXOT1UWISZA345H769|;
88             }
89             } elsif ($from_alphabet eq 'rfc4648') {
90             if ($to_alphabet eq 'gmp') {
91             $base32 =~ y|ABCDEFGHIJKLMNOPQRSTUVWXYZ234567|0123456789ABCDEFGHIJKLMNOPQRSTUV|;
92             } elsif ($to_alphabet eq 'crockford' ) {
93             $base32 =~ y|ABCDEFGHIJKLMNOPQRSTUVWXYZ234567|0123456789ABCDEFGHJKMNPQRSTVWXYZ|;
94             } elsif ($to_alphabet eq 'zbase32') {
95             $base32 =~ y|ABCDEFGHIJKLMNOPQRSTUVWXYZ234567|YBNDRFG8EJKMCPQXOT1UWISZA345H769|;
96             }
97             } else {
98             if ($to_alphabet eq 'gmp') {
99             $base32 =~ y|YBNDRFG8EJKMCPQXOT1UWISZA345H769|0123456789ABCDEFGHIJKLMNOPQRSTUV|;
100             } elsif ($to_alphabet eq 'crockford' ) {
101             $base32 =~ y|YBNDRFG8EJKMCPQXOT1UWISZA345H769|0123456789ABCDEFGHJKMNPQRSTVWXYZ|;
102             } elsif ($to_alphabet eq 'rfc4648') {
103             $base32 =~ y|YBNDRFG8EJKMCPQXOT1UWISZA345H769|ABCDEFGHIJKLMNOPQRSTUVWXYZ234567|;
104             }
105             }
106             }
107              
108             return $base32;
109             }
110              
111             sub md5_base32 {
112             encode_base32('0x'.md5_hex(shift), shift, 26);
113             }
114              
115             1;
116              
117             # ABSTRACT: High speed Base32 encoding using GMP with BigInt and MD5 support
118              
119             =head1 NAME
120              
121             Encode::Base32::GMP - High speed Base32 encoding using GMP with BigInt and MD5 support
122              
123             =head1 SYNOPSIS
124              
125             use Encode::Base32::GMP;
126              
127             # Encode Int as Base32
128             encode_base32(12345); # => C1S string
129             encode_base32('0x3039'); # => C1S string
130             encode_base32(Math::GMPz->new('0x3039')); # => C1S string
131              
132             # Encode Int as Base32 using GMP alphabet
133             encode_base32(12345,'rfc4648'); # => MBZ string
134             encode_base32(12345,'zbase32'); # => CB3 string
135             encode_base32(12345,'base32hex'); # => C1P string
136             encode_base32(12345,'gmp'); # => C1P string
137              
138             # Decode Base32 as Math::GMPz Int
139             decode_base32('C1S'); # => 12345 Math::GMPz object
140             int decode_base32('C1S'); # => 12345 integer
141              
142             # Decode Base32 as Math::GMPz Int using normaliztion (built-in)
143             decode_base32('c1s'); # => 12345 Math::GMPz object
144             decode_base32('cis'); # => 12345 Math::GMPz object
145              
146             # Decode Base32 as Math::GMPz Int using GMP alphabet
147             decode_base32('MBZ','rfc4648'); # => 12345 Math::GMPz object
148             decode_base32('CB3','zbase32'); # => 12345 Math::GMPz object
149              
150             # MD5 Base32 Digest
151             md5_base32('foo@bar.com'); # => 7KNPJ0BKM91DQR41099QNH5P58
152              
153             # Convert between alphabets, e.g. Crockford and RFC-4648
154             base32_from_to('0123456789ABCDEFGHJKMNPQRSTVWXYZ','crockford','rfc4648');
155             # => ABCDEFGHIJKLMNOPQRSTUVWXYZ234567
156             base32_from_to('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567','rfc4648','zbase32');
157             # => YBNDRFG8EJKMCPQXOT1UWISZA345H769
158              
159             =head1 DESCRIPTION
160              
161             Encode::Base32::GMP is a numerical Base32 encoder/decoder implementation using
162             the GNU Multiple Precision Arithmetic Library (GMP) with transcoding between
163             Crockford, RFC 4648, z-base-32, and Base32hex / GMP implementations. The
164             Crockford alphabet is the default and used when no alphabet is provided.
165             Crockford was selected as the default because it extends hexadecimal more
166             naturally than other alphabets and it is easier to distinguish visually.
167              
168             crockford: [0123456789ABCDEFGHJKMNPQRSTVWXYZ]
169             rfc4648: [ABCDEFGHIJKLMNOPQRSTUVWXYZ234567]
170             zbase32: [YBNDRFG8EJKMCPQXOT1UWISZA345H769]
171             base32hex: [0123456789ABCDEFGHIJKLMNOPQRSTUV]
172             gmp: [0123456789ABCDEFGHIJKLMNOPQRSTUV]
173              
174             The encode_base32, decode_base32 and md5_base32 methods support an alphabet
175             parameter which can be set to the supported alphabets to indicate the value
176             to be encoded or decoded:
177              
178             [qw/crockford rfc4648 base32hex zbase32 gmp/]
179              
180             This module functions similarly to L with Base32 being
181             ideal for case-insensitive encoding and Base58 being ideal for case-sensitive
182             encoding.
183              
184             =head1 FUNCTIONS
185              
186             =head2 encode_base32 ( $number [, $alphabet ] )
187              
188             This routine encodes a $number in Base32. $number can be a Math::GMPz object
189             or a binary, octal, decimal or hexidecimal number. Binary, octal and hexidecimal
190             string literals must be prefixed with 0[Bb]/0/0[Xx] respectively. The resulting
191             Base32 encoded number is provided in upper case per Crockford and RFC-4648
192             definitions. The Crockford alphabet is used unless $alphabet is set.
193              
194             =head2 decode_base32( $base32 [, $alphabet ] )
195              
196             This routine decodes a Base32 value and returns a Math::GMPz object. Use int
197             on the return value to convert the Math::GMPz object to an integer. The input
198             can be upper or lower case. Crockford and RFC-4648 inputs are normalized
199             exchanging the set [01ilo] as necessary. The Crockford alphabet is used unless
200             $alphabet is set.
201              
202             =head2 base32_from_to( $base32, $from_alphabet, $to_alphabet )
203              
204             This routine encodes a Base32 string from one encoding to another encoding.
205             The input can be upper or lower case. Crockford and RFC-4648 inputs are
206             normalized exchanging the set [01ilo] as necessary. The resulting Base32
207             encoded number is provided in upper case per Crockford and RFC-4648
208             definitions. This routing is not exported by default.
209              
210             =head2 md5_base32( $data [, $alphabet ] )
211              
212             This routine returns a MD5 digest in Base32. This routine is not exported
213             by default.
214              
215             =head1 NOTE
216              
217             This module is designed to encode and decode numbers. As such, it is backward
218             compatible with L while also adding BigInt support.
219              
220             While this module can be used to transcode other Base32 encodings, this
221             module is not designed to encode and decode binary strings, for which
222             L, L, and L can
223             be used. These modules also result in different and longer encodings for
224             numbers which is not desirable when encoding digests and other uids.
225              
226             =head1 SEE ALSO
227              
228             Crockford Base32 Encoding Definition: L
229              
230             RFC 4648 Definition: L
231              
232             z-base-32 Definition: L
233              
234             GMP: L
235              
236             L, L, L, L
237              
238             =head1 AUTHOR
239              
240             John Wang , L
241              
242             =head1 COPYRIGHT
243              
244             Copyright 2013 by John Wang .
245              
246             This software is released under the MIT license cited below.
247              
248             =head2 COPYRIGHT AND LICENSE (The MIT License)
249              
250             Permission is hereby granted, free of charge, to any person obtaining
251             a copy of this software and associated documentation files (the
252             "Software"), to deal in the Software without restriction, including
253             without limitation the rights to use, copy, modify, merge, publish,
254             distribute, sublicense, and/or sell copies of the Software, and to
255             permit persons to whom the Software is furnished to do so, subject to
256             the following conditions:
257              
258             The above copyright notice and this permission notice shall be
259             included in all copies or substantial portions of the Software.
260              
261             THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
262             EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
263             MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
264             NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
265             LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
266             OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
267             WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
268              
269             =cut