···11+## Multiformats
22+33+A really, really bare-bones implementation of the Multiformat protocol as found on https://multiformats.io/
44+55+Consider this entire package experimental, things **will** break.
66+77+## Github is not the primary repository
88+99+If you're reading this on Github, keep in mind that this package is not developed here; the only code that lives here is the main branch, put here to allow others to access it easier. Development takes place on my personal Gitlab instance, which should also explain the `.gitlab-ci.yml` file ;)
+49
lib/Multiformats.pm
···88# this package exists purely as a little placeholder for various abstracts and versions; as well as some
99# of the documentation
10101111+=pod
1212+1313+=head1 NAME
1414+1515+Multiformats - A bare-bones multiformat implementation
1616+1717+=head1 SYNOPSIS
1818+1919+ use Multiformats::Multibase qw/multibase_encode/;
2020+2121+ my $encoded = multibase_encode('base32upper', "my data that I would like encoded")
2222+2323+ my $multibase = Multiformats::Multibase->new;
2424+ my $also_encoded = $multibase->encode('base32', "even more data I want encoded");
2525+2626+=head1 FUNCTIONAL/OO
2727+2828+Every module can be used either in an OO fashion or purely functional. Please see the various modules that make up this package for more details.
2929+3030+=head1 CODEC SUPPORT
3131+3232+Not all codecs/hash functions/base encoders are supported, you will find out quick if they aren't because the various encode/decode functions will die when asked to encode or decode something with an unknown codec. CID only supports CIDv1, CIDv0 is not supported *at all*.
3333+3434+=head1 SEE ALSO
3535+3636+=over
3737+3838+=item * L<Multiformats::CID> - CID handling
3939+4040+=item * L<Multiformats::Multibase> - Multibase encoding/decoding
4141+4242+=item * L<Multiformats::Multihash> - Multihash encoding/unwrapping
4343+4444+=item * L<Multiformats::Multicodec> - Multicodec wrapping/unwrapping
4545+4646+=item * L<Multiformats::Varint> - Varint encoding/decoding
4747+4848+=back
4949+5050+=head1 AUTHOR
5151+5252+Ben van Staveren <madcat@cpan.org>, <ben@blockstackers.net>
5353+5454+=head1 LICENSE
5555+5656+This package is licensed under the same terms as Perl itself.
5757+5858+=cut
5959+11601;
+55-5
lib/Multiformats/CID.pm
···3333 my $mc = Multiformats::Multicodec::_get_by_tag($mc_codec);
34343535 # not sure what that codec tag does in here because it doesn't appear to do
3636- # anything short of encoding, well, nothing - the remaining data is the multihash
3636+ # anything - it's not encoding the remainder, so... what's it do Frank?!
3737 my ($mh, $hash) = multihash_unwrap(substr($bytes, $bread + $bread_codec));
3838-3938 return Multiformats::CID::CIDv1->new(version => 1, codec => $mc->[0], hash_function => $mh->[0], hash => $hash);
4039 }
4140}
···4342package
4443 Multiformats::CID::CIDv1 {
4544 use Mojo::Base -base, -signatures;
4646- use Multiformats::Multicodec qw/multicodec_wrap multicodec_unwrap/;
4545+ use Multiformats::Multicodec qw/multicodec_wrap/;
4746 use Multiformats::Multibase qw/multibase_encode/;
4847 use Multiformats::Varint qw/varint_encode/;
4948 use Multiformats::Multihash qw/multihash_wrap/;
5049 use overload bool => sub {1}, '""' => sub { shift->to_str }, fallback => 1;
51505252- # note that the codecs are the tag values, not the names, we need to take this into account
5353- # in multibase_encode and multihash_encode
5451 has [qw/version codec hash_function hash/] => undef;
55525653 sub to_str($self, $codec = 'base32') {
···6461 return $version . $content;
6562 }
6663}
6464+6565+=pod
6666+6767+=head1 NAME
6868+6969+Multiformats::CID - CID handling
7070+7171+=head1 SYNOPSIS
7272+7373+ use Multiformats::CID qw/cid/;
7474+7575+ # can use either the stringified representation or the raw binary representation
7676+ my $cid = cid('bafyreigngt2aslhuh7jbgpuliep4v4uvlantdmew2ojr7u3upknttpvqxa');
7777+7878+=head1 FUNCTIONS
7979+8080+=head2 cid(...)
8181+8282+When given a string representation or binary representation of a CID will decode the version, codec, hash function, and hash value used and will return those wrapped in a C<Multiformats::CID::CIDv1> object.
8383+8484+=head1 CIDv1 Object
8585+8686+This object wraps a CID and has the following attributes and methods
8787+8888+=head2 ATTRIBUTES
8989+9090+=head3 version
9191+9292+Returns the version of the CID (always 1)
9393+9494+=head3 codec
9595+9696+Returns the name of the multibase codec
9797+9898+=head3 hash_function
9999+100100+Returns the name of the hash function used
101101+102102+=head3 hash
103103+104104+Returns the binary hash (obtained via the hash function)
105105+106106+=head2 METHODS
107107+108108+=head3 to_str()
109109+110110+Returns the stringified version of the CID. The CID object itself is overloaded to return this when used in string context.
111111+112112+=head3 to_bytes()
113113+114114+Returns the binary representation of the CID.
115115+116116+=cut
67117681181;
69119
+39
lib/Multiformats/Multibase.pm
···7474 }
7575}
76767777+=pod
7878+7979+=head1 NAME
8080+8181+Multiformats::Multibase - Multibase decoding and encoding
8282+8383+=head1 SYNOPSIS
8484+8585+ use Multiformats::Multibase qw/multibase_encode multibase_decode/;
8686+8787+ my $encoded = multibase_encode('base32', 'this will be base32 encoded');
8888+ my $decoded = multibase_decode($encoded_string);
8989+9090+=head1 FUNCTIONS
9191+9292+=head2 multibase_encode($base, $data_to_encode)
9393+9494+Encodes the given data with the given base. See below for supported bases.
9595+9696+=head2 multibase_decode($encoded_data);
9797+9898+Decodes the given data. When called in scalar context returns the decoded data. When called in list context returns a list containing the multibase tag and the decoded data
9999+100100+=head1 SUPPORTED BASES
101101+102102+=over
103103+104104+=item * base32
105105+106106+=item * base32upper
107107+108108+=item * base36
109109+110110+=item * base58btc
111111+112112+=back
113113+114114+=cut
115115+771161;
+63
lib/Multiformats/Multicodec.pm
···1313 [ 'dag-cbor', 0x71 ],
1414 ];
15151616+ sub wrap($self, $as, $value) {
1717+ return multihash_wrap($as, $value);
1818+ }
1919+2020+ sub unwrap($self, $value) {
2121+ return multihash_unwrap($value);
2222+ }
2323+2424+ sub get_codec($self, $value) {
2525+ return multihash_codec($value);
2626+ }
2727+2828+ sub new($pkg) {
2929+ return bless({}, $pkg);
3030+ }
3131+1632 sub _get_by_name($as) {
1733 foreach my $entry (@{__PACKAGE__->MULTICODEC_MAP}) {
1834 return $entry if($entry->[0] eq $as);
···5470 }
5571 }
5672}
7373+7474+=pod
7575+7676+=head1 NAME
7777+7878+Multiformats::Multicodec - Multicodec encoding/decoding/wrapping
7979+8080+=head1 SYNOPSIS
8181+8282+ use Multiformats::Multicodec qw/multicodec_get_codec multicodec_unwrap multicodec_wrap/;
8383+8484+ my $data = '...';
8585+8686+ my $encoded = multicodec_wrap('dag-cbor', $data);
8787+ my $decoded = multicodec_unwrap($encoded);
8888+8989+ my $codec = multicodec_get_codec($encoded);
9090+9191+ $codec->[0]; # dag-cbor
9292+ $codec->[1]; # 0x71
9393+9494+9595+=head1 FUNCTIONS
9696+9797+=head2 multicodec_wrap($codec, $data);
9898+9999+Wraps the given data with the proper multicodec tag
100100+101101+=head2 multicodec_unwrap($data)
102102+103103+Unwraps the given data and returns the original raw data
104104+105105+=head2 multicodec_get_codec($data)
106106+107107+Returns an arrayref containing the codec information that the data is encoded with. First item in the arrayref is the codec name, second item is the codec tag value.
108108+109109+=head1 SUPPORTED CODECS
110110+111111+=over
112112+113113+=item * raw
114114+115115+=item * dag-cbor
116116+117117+=back
118118+119119+=cut
57120581211;
+73-5
lib/Multiformats/Multihash.pm
···1919 return multihash_encode($as, $value);
2020 }
21212222+ sub wrap($self, $as, $value) {
2323+ return multihash_wrap($as, $value);
2424+ }
2525+2626+ sub unwrap($self, $value) {
2727+ return multihash_unwrap($value);
2828+ }
2929+2230 sub new($pkg) {
2331 return bless({}, $pkg);
2432 }
···3543 [ 'sha2-384', 0x20, undef, sub { return sha_384(shift) } ],
3644 ];
37453838- sub codecs {
3939- return __PACKAGE__->MULTIFORMAT_MAP;
4040- }
4141-4246 sub _map_by_tag($tag) {
4347 foreach my $entry (@{__PACKAGE__->MULTIFORMAT_MAP}) {
4448 return $entry if($entry->[1] == $tag);
···7377 if(my $e = _map_by_tag($t)) {
7478 my ($l, $bread_len) = varint_decode_raw(substr($bytes, $bread_type));
7579 return wantarray
7676- ? ($e, substr($bytes, $bread_type + $bread_len)) # allows us to get the whole kit and kaboodle in one sitting
8080+ ? ([$e->[0], $e->[1] ], substr($bytes, $bread_type + $bread_len)) # allows us to get the whole kit and kaboodle in one sitting
7781 : substr($bytes, $bread_type + $bread_len)
7882 } else {
7983 die 'unknown format ' . $t . ', ';
···99103 }
100104 }
101105}
106106+107107+=pod
108108+109109+=head1 NAME
110110+111111+Multiformats::Multihash - Multihash encoding/decoding/wrapping
112112+113113+=head1 SYNOPSIS
114114+115115+ use Multiformats::Multihash qw/multihash_encode multihash_decode multihash_unwrap multihash_wrap/;
116116+ my $data = '...';
117117+118118+ my $encoded = multihash_encode('sha2-256', $data);
119119+120120+ my $hash = Digest::SHA::sha256($data);
121121+122122+ my $encoded_also = multihash_wrap('sha2-256', $hash);
123123+124124+=head1 FUNCTIONS
125125+126126+=head2 multihash_encode($hash_function, $data)
127127+128128+Hashes the data with the given hash function, and encodes the result into a Multihash
129129+130130+=head2 multihash_decode($data)
131131+132132+Parses the used hash function and hash length for validity, and returns the original raw hash
133133+134134+=head2 multihash_unwrap($data)
135135+136136+Acts similar to C<multihash_decode> when called in scalar context, but when called in list context returns a list containing the encoding/decoding array and the raw hash. The decoding arrayref has the hash function name as first element, and the hash function tag value as the second value.
137137+138138+ my ($encoding, $raw_hash) = multihash_unwrap($data)
139139+140140+ $encoding->[0]; # e.g. 'sha2-256'
141141+ $encoding->[1]; # e.g. 0x12
142142+143143+=head2 multihash_wrap($hash_function, $data)
144144+145145+Acts similar to C<multihash_encode> but assumes the data passed is already a raw hash so does not digest it before encoding to a Multihash
146146+147147+=head1 SUPPORTED HASHES
148148+149149+=over
150150+151151+=item * identity
152152+153153+=item * sha1
154154+155155+=item * sha2-256
156156+157157+=item * sha2-512
158158+159159+=item * sha3-384
160160+161161+=item * sha3-256
162162+163163+=item * sha3-224
164164+165165+=item * sha2-384
166166+167167+=back
168168+169169+=cut
1021701031711;
+32-1
lib/Multiformats/Varint.pm
···46464747 sub varint_decode($value) {
4848 my ($x, $read) = varint_decode_raw($value);
4949- die 'Multiformats::Varint::varint_decode: not all bytes used by encoding' if($read > length($value));
4949+ die 'Multiformats::Varint::varint_decode: not all bytes used by encoding' if($read < length($value));
5050 return $x;
5151 }
5252···7171 : $x;
7272 }
7373}
7474+7575+=pod
7676+7777+=head1 NAME
7878+7979+Multiformats::Varint - Varint decoding and encoding
8080+8181+=head1 SYNOPSIS
8282+8383+ use Multiformats::Varint qw/varint_encode varint_decode/;
8484+8585+ my $encoded = varint_encode(300); # \xAC\x02
8686+ my $decoded = varint_decode("\xAC\x02"); # 300
8787+8888+=head1 FUNCTIONS
8989+9090+=head2 varint_encode(...)
9191+9292+Encodes the given unsigned integer number to an unsigned Varint; returns a byte string. Will die if the varint is larger than the spec allows (>9 bytes).
9393+9494+=head2 varint_decode(...)
9595+9696+Decodes the given byte string to an unsigned integer. Will die if there are more bytes passed than required to decode a Varint.
9797+9898+=head2 varint_decode_raw(...)
9999+100100+Like varint_decode, but will not die when there are bytes left in the input.
101101+102102+When called in scalar context will return the decoded unsigned integer, when called in list context will return a list containing the unsigned integer, and the number of bytes used from the input. Does not alter the input value, so you will have to use C<substr> or some other mechanism to strip the used bytes out of the input value.
103103+104104+=cut
74105751061;