rlp-lite 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b94a62e8d77c1f5752f02e1088db2394fb281800a444fc744bcb17e2c8bb1d3f
4
+ data.tar.gz: 4708183e54acac23ef32ebd0f74c2b78cdced4778752dbe6b2d51260363dd6b8
5
+ SHA512:
6
+ metadata.gz: 5fadf8e0fe94f689ba0ee198bd7e2d94c5bd6d606261d26c2308a2a676fe9ddb9e5489ec00ff31b2e592987727982b02bdeb48dea3ee105c8ab8ca1fa8b9988a
7
+ data.tar.gz: 390a76f7d97500ee445e653a98eb250ff254f0936167e6900444f5e3540439453023f463c7272ed5d453416d2f2d2a46cd884736dc9399f26b6b1eb95c1c1f0a
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ ### 0.0.1 / 2022-11-16
2
+
3
+ * Everything is new. First release
data/Manifest.txt ADDED
@@ -0,0 +1,13 @@
1
+ CHANGELOG.md
2
+ Manifest.txt
3
+ README.md
4
+ Rakefile
5
+ lib/rlp-lite.rb
6
+ lib/rlp-lite/decoder.rb
7
+ lib/rlp-lite/encoder.rb
8
+ lib/rlp-lite/sedes.rb
9
+ lib/rlp-lite/sedes/big_endian_int.rb
10
+ lib/rlp-lite/sedes/binary.rb
11
+ lib/rlp-lite/sedes/list.rb
12
+ lib/rlp-lite/util.rb
13
+ lib/rlp-lite/version.rb
data/README.md ADDED
@@ -0,0 +1,33 @@
1
+ # Recursive Length Prefix (RLP) Lite
2
+
3
+
4
+ rlp-lite - light-weight machinery to serialize / deserialze via rlp
5
+
6
+
7
+
8
+ * home :: [github.com/pixelartexchange/artbase](https://github.com/pixelartexchange/artbase)
9
+ * bugs :: [github.com/pixelartexchange/artbase/issues](https://github.com/pixelartexchange/artbase/issues)
10
+ * gem :: [rubygems.org/gems/rlp-lite](https://rubygems.org/gems/rlp-lite)
11
+ * rdoc :: [rubydoc.info/gems/rlp-lite](http://rubydoc.info/gems/rlp-lite)
12
+
13
+
14
+
15
+
16
+ ## Usage
17
+
18
+ to be done
19
+
20
+
21
+
22
+
23
+ ## License
24
+
25
+ The scripts are dedicated to the public domain.
26
+ Use it as you please with no restrictions whatsoever.
27
+
28
+
29
+ ## Questions? Comments?
30
+
31
+
32
+ Post them on the [D.I.Y. Punk (Pixel) Art reddit](https://old.reddit.com/r/DIYPunkArt). Thanks.
33
+
data/Rakefile ADDED
@@ -0,0 +1,31 @@
1
+ require 'hoe'
2
+ require './lib/rlp-lite/version.rb'
3
+
4
+
5
+ Hoe.spec 'rlp-lite' do
6
+
7
+ self.version = Rlp::VERSION
8
+
9
+ self.summary = "rlp-lite - light-weight machinery to serialize / deserialze via rlp (recursive length prefix)"
10
+ self.description = summary
11
+
12
+ self.urls = { home: 'https://github.com/pixelartexchange/artbase' }
13
+
14
+ self.author = 'Gerald Bauer'
15
+ self.email = 'wwwmake@googlegroups.com'
16
+
17
+ # switch extension to .markdown for gihub formatting
18
+ self.readme_file = 'README.md'
19
+ self.history_file = 'CHANGELOG.md'
20
+
21
+ self.extra_deps = [
22
+ ]
23
+
24
+ self.licenses = ['Public Domain']
25
+
26
+ self.spec_extras = {
27
+ required_ruby_version: '>= 2.3'
28
+ }
29
+
30
+ end
31
+
@@ -0,0 +1,97 @@
1
+ module Rlp
2
+
3
+ # Provides an RLP-decoder.
4
+ module Decoder
5
+ extend self
6
+
7
+ # Decodes an RLP-encoded object.
8
+ #
9
+ # @param rlp [String] an RLP-encoded object.
10
+ # @return [Object] the decoded and maybe deserialized object.
11
+ # @raise [Eth::Rlp::DecodingError] if the input string does not end after
12
+ # the root item.
13
+ def perform(rlp)
14
+ rlp = Util.hex_to_bin( rlp ) if Util.is_hex?( rlp )
15
+ rlp = Util.str_to_bytes( rlp )
16
+ begin
17
+ item, next_start = consume_item( rlp, 0 )
18
+ rescue Exception => e
19
+ raise DecodingError, "Cannot decode rlp string: #{e}"
20
+ end
21
+ raise DecodingError, "RLP string ends with #{rlp.size - next_start} superfluous bytes" if next_start != rlp.size
22
+ return item
23
+ end
24
+
25
+
26
+ private
27
+
28
+ # Consume an RLP-encoded item from the given start.
29
+ def consume_item(rlp, start)
30
+ t, l, s = consume_length_prefix rlp, start
31
+ consume_payload rlp, s, t, l
32
+ end
33
+
34
+ # Consume an RLP length prefix at the given position.
35
+ def consume_length_prefix(rlp, start)
36
+ b0 = rlp[start].ord
37
+ if b0 < PRIMITIVE_PREFIX_OFFSET
38
+
39
+ # single byte
40
+ [:str, 1, start]
41
+ elsif b0 < PRIMITIVE_PREFIX_OFFSET + SHORT_LENGTH_LIMIT
42
+ raise DecodingError, "Encoded as short string although single byte was possible" if (b0 - PRIMITIVE_PREFIX_OFFSET == 1) && rlp[start + 1].ord < PRIMITIVE_PREFIX_OFFSET
43
+
44
+ # short string
45
+ [:str, b0 - PRIMITIVE_PREFIX_OFFSET, start + 1]
46
+ elsif b0 < LIST_PREFIX_OFFSET
47
+ enforce_no_zero_bytes rlp, start
48
+
49
+ # long string
50
+ ll = b0 - PRIMITIVE_PREFIX_OFFSET - SHORT_LENGTH_LIMIT + 1
51
+ l = Util.big_endian_to_int rlp[(start + 1)...(start + 1 + ll)]
52
+ raise DecodingError, "Long string prefix used for short string" if l < SHORT_LENGTH_LIMIT
53
+ [:str, l, start + 1 + ll]
54
+ elsif b0 < LIST_PREFIX_OFFSET + SHORT_LENGTH_LIMIT
55
+
56
+ # short list
57
+ [:list, b0 - LIST_PREFIX_OFFSET, start + 1]
58
+ else
59
+ enforce_no_zero_bytes rlp, start
60
+
61
+ # long list
62
+ ll = b0 - LIST_PREFIX_OFFSET - SHORT_LENGTH_LIMIT + 1
63
+ l = Util.big_endian_to_int rlp[(start + 1)...(start + 1 + ll)]
64
+ raise DecodingError, "Long list prefix used for short list" if l < SHORT_LENGTH_LIMIT
65
+ [:list, l, start + 1 + ll]
66
+ end
67
+ end
68
+
69
+ # Enforce RLP slices to not start with empty bytes.
70
+ def enforce_no_zero_bytes(rlp, start)
71
+ raise DecodingError, "Length starts with zero bytes" if rlp.slice(start + 1) == BYTE_ZERO
72
+ end
73
+
74
+ # Consume an RLP payload at the given position of given type and size.
75
+ def consume_payload(rlp, start, type, length)
76
+ case type
77
+ when :str
78
+ [rlp[start...(start + length)], start + length]
79
+ when :list
80
+ items = []
81
+ next_item_start = start
82
+ payload_end = next_item_start + length
83
+ while next_item_start < payload_end
84
+ item, next_item_start = consume_item rlp, next_item_start
85
+ items.push item
86
+ end
87
+ raise DecodingError, "List length prefix announced a too small length" if next_item_start > payload_end
88
+ [items, next_item_start]
89
+ else
90
+ raise TypeError, "Type must be either :str or :list"
91
+ end
92
+ end
93
+ end
94
+
95
+
96
+ end # module Rlp
97
+
@@ -0,0 +1,59 @@
1
+
2
+ # Provides an recursive-length prefix (RLP) encoder and decoder.
3
+ module Rlp
4
+
5
+ # Provides an RLP-encoder.
6
+ module Encoder
7
+ extend self
8
+
9
+ # Encodes a Ruby object in RLP format.
10
+ #
11
+ # @param obj [Object] a Ruby object.
12
+ # @return [String] the RLP encoded item.
13
+ # @raise [Eth::Rlp::EncodingError] in the rather unlikely case that the item
14
+ # is too big to encode (will not happen).
15
+ # @raise [Eth::Rlp::SerializationError] if the serialization fails.
16
+ def perform(obj)
17
+ item = Sedes.infer(obj).serialize(obj)
18
+ result = encode_raw( item )
19
+ end
20
+
21
+ private
22
+
23
+ # Encodes the raw item.
24
+ def encode_raw(item)
25
+ return item if item.instance_of? Rlp::Data
26
+ return encode_primitive item if Sedes.is_primitive? item
27
+ return encode_list item if Sedes.is_list? item
28
+ raise EncodingError "Cannot encode object of type #{item.class.name}"
29
+ end
30
+
31
+ # Encodes a single primitive.
32
+ def encode_primitive(item)
33
+ return Util.str_to_bytes item if item.size == 1 && item.ord < PRIMITIVE_PREFIX_OFFSET
34
+ payload = Util.str_to_bytes item
35
+ prefix = length_prefix payload.size, PRIMITIVE_PREFIX_OFFSET
36
+ "#{prefix}#{payload}"
37
+ end
38
+
39
+ # Encodes a single list.
40
+ def encode_list(list)
41
+ payload = list.map { |item| encode_raw item }.join
42
+ prefix = length_prefix payload.size, LIST_PREFIX_OFFSET
43
+ "#{prefix}#{payload}"
44
+ end
45
+
46
+ # Determines a length prefix.
47
+ def length_prefix(length, offset)
48
+ if length < SHORT_LENGTH_LIMIT
49
+ (offset + length).chr
50
+ elsif length < LONG_LENGTH_LIMIT
51
+ length_string = Util.int_to_big_endian( length )
52
+ length_len = (offset + SHORT_LENGTH_LIMIT - 1 + length_string.size).chr
53
+ "#{length_len}#{length_string}"
54
+ else
55
+ raise EncodingError, "Length greater than 256**8: #{length}"
56
+ end
57
+ end
58
+ end
59
+ end # module Rlp
@@ -0,0 +1,73 @@
1
+
2
+
3
+ module Rlp
4
+ module Sedes
5
+
6
+ # A serializable, big-endian, unsigned integer type.
7
+ class BigEndianInt
8
+
9
+ # Create a serializable, big-endian, unsigned integer.
10
+ #
11
+ # @param size [Integer] the size of the big endian.
12
+ def initialize(size = nil)
13
+ @size = size
14
+ end
15
+
16
+ # Serialize a big-endian integer.
17
+ #
18
+ # @param obj [Integer] the integer to be serialized.
19
+ # @return [String] a serialized big-endian integer.
20
+ # @raise [SerializationError] if provided object is not an integer.
21
+ # @raise [SerializationError] if provided integer is negative.
22
+ # @raise [SerializationError] if provided integer is too big for @size.
23
+ def serialize(obj)
24
+ raise SerializationError, "Can only serialize integers" unless obj.is_a?(Integer)
25
+ raise SerializationError, "Cannot serialize negative integers" if obj < 0
26
+ raise SerializationError, "Integer too large (does not fit in #{@size} bytes)" if @size && obj >= 256 ** @size
27
+ s = obj == 0 ? BYTE_EMPTY : _int_to_big_endian(obj)
28
+ @size ? "#{BYTE_ZERO * [0, @size - s.size].max}#{s}" : s
29
+ end
30
+
31
+ # Deserializes an unsigned integer.
32
+ #
33
+ # @param serial [String] the serialized integer.
34
+ # @return [Integer] a number.
35
+ # @raise [DeserializationError] if provided serial is of wrong size.
36
+ # @raise [DeserializationError] if provided serial is not of minimal length.
37
+ def deserialize(serial)
38
+ raise DeserializationError, "Invalid serialization (wrong size)" if @size && serial.size != @size
39
+ raise DeserializationError, "Invalid serialization (not minimal length)" if !@size && serial.size > 0 && serial[0] == BYTE_ZERO
40
+ serial = serial || BYTE_ZERO
41
+ _big_endian_to_int(serial)
42
+ end
43
+
44
+
45
+ ###
46
+ # private helpers
47
+
48
+
49
+ # Converts an integer to big endian.
50
+ #
51
+ # @param num [Integer] integer to be converted.
52
+ # @return [String] packed, big-endian integer string.
53
+ def _int_to_big_endian( num )
54
+ hex = num.to_s(16)
55
+ hex = "0#{hex}" if hex.size.odd?
56
+
57
+ [hex].pack("H*") ## note Util.hex_to_bin() "inline" shortcut
58
+ end
59
+
60
+ # Converts a big endian to an interger.
61
+ #
62
+ # @param str [String] big endian to be converted.
63
+ # @return [Integer] an unpacked integer number.
64
+ def _big_endian_to_int(str)
65
+ str.unpack("H*").first.to_i(16)
66
+ end
67
+
68
+
69
+
70
+ end # class BigEndianInt
71
+
72
+ end # module Sedes
73
+ end # module Rlp
@@ -0,0 +1,103 @@
1
+ module Rlp
2
+ module Sedes
3
+
4
+ # A sedes type for binary values.
5
+ class Binary
6
+
7
+ # Create a serializable binary of fixed size.
8
+ #
9
+ # @param l [Integer] the fixed size of the binary.
10
+ # @param allow_empty [Boolean] indicator wether empty binaries should be allowed.
11
+ # @return [Eth::Rlp::Sedes::Binary] a serializable binary of fixed size.
12
+ def self.fixed_length(l, allow_empty: false)
13
+ new(min_length: l, max_length: l, allow_empty: allow_empty)
14
+ end
15
+
16
+ # Checks wether the given object is of a valid binary type.
17
+ #
18
+ # @param obj [Object] the supposed binary item to check.
19
+ # @return [Boolean] true if valid.
20
+ def self.valid_type?(obj)
21
+ obj.instance_of? String
22
+ end
23
+
24
+
25
+ # Create a serializable binary of variable size.
26
+ #
27
+ # @param min_length [Integer] the minimum size of the binary.
28
+ # @param max_length [Integer] the maximum size of the binary.
29
+ # @param allow_empty [Boolean] indicator wether empty binaries should be allowed.
30
+ def initialize(min_length: 0, max_length: INFINITY, allow_empty: false)
31
+ @min_length = min_length
32
+ @max_length = max_length
33
+ @allow_empty = allow_empty
34
+ end
35
+
36
+ # Serializes a binary.
37
+ #
38
+ # @param obj [String] the binary to serialize.
39
+ # @return [Object] a serialized binary.
40
+ # @raise [SerializationError] if provided object is of invalid type.
41
+ # @raise [SerializationError] if provided binary is of invalid length.
42
+ def serialize(obj)
43
+ raise SerializationError, "Object is not a serializable (#{obj.class})" unless self.class.valid_type? obj
44
+ serial = _str_to_bytes( obj )
45
+ raise SerializationError, "Object has invalid length" unless valid_length? serial.size
46
+ serial
47
+ end
48
+
49
+ # Deserializes a binary.
50
+ #
51
+ # @param serial [Object] the serialized binary.
52
+ # @return [String] a deserialized binary.
53
+ # @raise [DeserializationError] if provided serial is of wrong type.
54
+ # @raise [DeserializationError] if provided serial is of wrong length.
55
+ def deserialize(serial)
56
+ raise DeserializationError, "Objects of type #{serial.class} cannot be deserialized" unless _is_primitive? serial
57
+ raise DeserializationError, "#{serial.class} has invalid length" unless valid_length? serial.size
58
+ serial
59
+ end
60
+
61
+ # Checks wether the given length fits the defined size boundaries of the
62
+ # binary type.
63
+ #
64
+ # @param length [Integer] the supposed length of the binary item.
65
+ # @return [Boolean] true if valid.
66
+ def valid_length?(length)
67
+ (@min_length <= length && length <= @max_length) ||
68
+ (@allow_empty && length == 0)
69
+ end
70
+
71
+ #######
72
+ # private helpers
73
+
74
+ # Converts a binary string to bytes.
75
+ #
76
+ # @param str [String] binary string to be converted.
77
+ # @return [Object] the string bytes.
78
+ def _str_to_bytes(str)
79
+ _is_bytes?(str) ? str : str.b
80
+ end
81
+
82
+ # Checks if a string is a byte-string.
83
+ #
84
+ # @param str [String] a string to check.
85
+ # @return [Boolean] true if it's an ASCII-8bit encoded byte-string.
86
+ def _is_bytes?(str)
87
+ str && str.instance_of?(String) && str.encoding.name == 'ASCII-8BIT'
88
+ end
89
+
90
+ # Checks if the given item is a string primitive.
91
+ #
92
+ # @param item [Object] the item to check.
93
+ # @return [Boolean] true if it's a string primitive.
94
+ def _is_primitive?(item)
95
+ item.instance_of?(String)
96
+ end
97
+
98
+
99
+ end # class Binary
100
+
101
+
102
+ end # module Sedes
103
+ end # module Rlp
@@ -0,0 +1,68 @@
1
+
2
+ module Rlp
3
+ module Sedes
4
+
5
+ # A sedes type for lists of fixed length.
6
+ class List < Array
7
+
8
+ # Create a serializable list of fixed size.
9
+ #
10
+ # @param elements [Array] an array indicating the structure of the list.
11
+ # @param strict [Boolean] an option to enforce the given structure.
12
+ def initialize(elements: [], strict: true)
13
+ super()
14
+
15
+ @strict = strict
16
+ elements.each do |e|
17
+ if Sedes.is_sedes?(e)
18
+ push e
19
+ elsif Sedes.is_list?(e)
20
+ push List.new(elements: e)
21
+ else
22
+ raise TypeError, "Instances of List must only contain sedes objects or nested sequences thereof."
23
+ end
24
+ end
25
+ end
26
+
27
+ # Serialize an array.
28
+ #
29
+ # @param obj [Array] the array to be serialized.
30
+ # @return [Array] a serialized list.
31
+ # @raise [SerializationError] if provided array is not a sequence.
32
+ # @raise [SerializationError] if provided array is of wrong length.
33
+ def serialize(obj)
34
+ raise SerializationError, "Can only serialize sequences" unless Sedes.is_list?(obj)
35
+ raise SerializationError, "List has wrong length" if (@strict && self.size != obj.size) || self.size < obj.size
36
+ result = []
37
+ obj.zip(self).each_with_index do |(element, sedes), i|
38
+ result.push sedes.serialize(element)
39
+ end
40
+ result
41
+ end
42
+
43
+ # Deserializes a list.
44
+ #
45
+ # @param serial [Array] the serialized list.
46
+ # @return [Array] a deserialized list.
47
+ # @raise [DeserializationError] if provided serial is not a sequence.
48
+ # @raise [DeserializationError] if provided serial is of wrong length.
49
+ def deserialize(serial)
50
+ raise DeserializationError, "Can only deserialize sequences" unless Sedes.is_list?(serial)
51
+ raise DeserializationError, "List has wrong length" if @strict && serial.size != self.size
52
+ result = []
53
+ len = [serial.size, self.size].min
54
+ len.times do |i|
55
+ sedes = self[i]
56
+ element = serial[i]
57
+ result.push sedes.deserialize(element)
58
+ end
59
+ result.freeze
60
+ end
61
+
62
+
63
+
64
+ end # class List
65
+
66
+
67
+ end # module Sedes
68
+ end # module Rlp
@@ -0,0 +1,73 @@
1
+
2
+
3
+ module Rlp
4
+ module Sedes
5
+
6
+ # Provides a singleton {Rlp::Sedes} class to infer objects and types.
7
+ class << self
8
+
9
+ # Tries to find a sedes objects suitable for a given Ruby object.
10
+ #
11
+ # The sedes objects considered are `obj`'s class, {big_endian_int} and
12
+ # {binary}. If `obj` is a list, an {Rlp::Sedes::List} will be
13
+ # constructed recursively.
14
+ #
15
+ # @param obj [Object] the Ruby object for which to find a sedes object.
16
+ # @raise [TypeError] if no appropriate sedes could be found.
17
+ def infer(obj)
18
+ return obj.class if is_sedes?( obj.class )
19
+ return big_endian_int if obj.is_a?(Integer) && obj >= 0
20
+ return binary if Binary.valid_type? obj
21
+ return List.new(elements: obj.map { |item| infer( item ) }) if is_list?( obj )
22
+ raise TypeError, "Did not find sedes handling type #{obj.class.name}"
23
+ end
24
+
25
+
26
+ # Determines if an object is a sedes object.
27
+ #
28
+ # @param obj [Object] the object to check.
29
+ # @return [Boolean] true if it's serializable and deserializable.
30
+ def is_sedes?(obj)
31
+ obj.respond_to?(:serialize) && obj.respond_to?(:deserialize)
32
+ end
33
+
34
+ # A utility to use a big-endian, unsigned integer sedes type with
35
+ # unspecified length.
36
+ #
37
+ # @return [Rlp::Sedes::BigEndianInt] a big-endian, unsigned integer sedes.
38
+ def big_endian_int
39
+ @big_endian_int ||= BigEndianInt.new
40
+ end
41
+
42
+ # A utility to use a binary sedes type.
43
+ #
44
+ # @return [Rlp::Sedes::Binary] a binary sedes.
45
+ def binary
46
+ @binary ||= Binary.new
47
+ end
48
+
49
+ ##############################
50
+ ### more helpers
51
+
52
+ # Checks if the given item is a string primitive.
53
+ #
54
+ # @param item [Object] the item to check.
55
+ # @return [Boolean] true if it's a string primitive.
56
+ def is_primitive?(item)
57
+ item.instance_of?(String)
58
+ end
59
+
60
+ # Checks if the given item is a list.
61
+ #
62
+ # @param item [Object] the item to check.
63
+ # @return [Boolean] true if it's a list.
64
+ def is_list?(item)
65
+ !is_primitive?(item) && item.respond_to?(:each)
66
+ end
67
+
68
+
69
+
70
+
71
+ end
72
+ end
73
+ end # module Rlp
@@ -0,0 +1,108 @@
1
+
2
+ module Rlp
3
+ module Util
4
+ extend self
5
+
6
+
7
+
8
+
9
+ # Checks if a string is hex-adecimal.
10
+ #
11
+ # @param str [String] a string to be checked.
12
+ # @return [String] a match if true; `nil` if not.
13
+ def is_hex?(str)
14
+ return false unless str.is_a? String
15
+ str = remove_hex_prefix str
16
+ str.match /\A[0-9a-fA-F]*\z/
17
+ end
18
+
19
+ # Removes the `0x` prefix of a hexa-decimal string.
20
+ #
21
+ # @param hex [String] a prefixed hex-string.
22
+ # @return [String] an unprefixed hex-string.
23
+ def remove_hex_prefix(hex)
24
+ return hex[2..-1] if is_prefixed? hex
25
+ return hex
26
+ end
27
+
28
+ # Checks if a string is prefixed with `0x`.
29
+ #
30
+ # @param hex [String] a string to be checked.
31
+ # @return [String] a match if true; `nil` if not.
32
+ def is_prefixed?(hex)
33
+ hex.match /\A0x/
34
+ end
35
+
36
+ # Packs a hexa-decimal string into a binary string. Also works with
37
+ # `0x`-prefixed strings.
38
+ #
39
+ # @param hex [String] a hexa-decimal string to be packed.
40
+ # @return [String] a packed binary string.
41
+ # @raise [TypeError] if value is not a string or string is not hex.
42
+ def hex_to_bin(hex)
43
+ raise TypeError, "Value must be an instance of String" unless hex.instance_of? String
44
+ hex = remove_hex_prefix hex
45
+ raise TypeError, "Non-hexadecimal digit found" unless is_hex? hex
46
+ [hex].pack("H*")
47
+ end
48
+
49
+ # Unpacks a binary string to a hexa-decimal string.
50
+ #
51
+ # @param bin [String] a binary string to be unpacked.
52
+ # @return [String] a hexa-decimal string.
53
+ # @raise [TypeError] if value is not a string.
54
+ def bin_to_hex(bin)
55
+ raise TypeError, "Value must be an instance of String" unless bin.instance_of? String
56
+ bin.unpack("H*").first
57
+ end
58
+
59
+
60
+ # Converts a binary string to bytes.
61
+ #
62
+ # @param str [String] binary string to be converted.
63
+ # @return [Object] the string bytes.
64
+ def str_to_bytes(str)
65
+ is_bytes?(str) ? str : str.b
66
+ end
67
+
68
+ # Checks if a string is a byte-string.
69
+ #
70
+ # @param str [String] a string to check.
71
+ # @return [Boolean] true if it's an ASCII-8bit encoded byte-string.
72
+ def is_bytes?(str)
73
+ str && str.instance_of?(String) && str.encoding.name == 'ASCII-8BIT'
74
+ end
75
+
76
+
77
+
78
+ # Converts an integer to big endian.
79
+ #
80
+ # @param num [Integer] integer to be converted.
81
+ # @return [String] packed, big-endian integer string.
82
+ def int_to_big_endian(num)
83
+ hex = num.to_s(16) unless is_hex? num
84
+ hex = "0#{hex}" if hex.size.odd?
85
+ hex_to_bin hex
86
+ end
87
+
88
+
89
+
90
+ # Converts a big endian to an interger.
91
+ #
92
+ # @param str [String] big endian to be converted.
93
+ # @return [Integer] an unpacked integer number.
94
+ def big_endian_to_int(str)
95
+ str.unpack("H*").first.to_i(16)
96
+ end
97
+
98
+ # Deserializes big endian data string to integer.
99
+ #
100
+ # @param str [String] serialized big endian integer string.
101
+ # @return [Integer] an deserialized unsigned integer.
102
+ def deserialize_big_endian_to_int(str)
103
+ Sedes.big_endian_int.deserialize str.sub(/\A(\x00)+/, "")
104
+ end
105
+
106
+
107
+ end # module Util
108
+ end # module Rlp
@@ -0,0 +1,5 @@
1
+
2
+ module Rlp
3
+ VERSION='0.0.1'
4
+ end
5
+
data/lib/rlp-lite.rb ADDED
@@ -0,0 +1,82 @@
1
+
2
+ require_relative "rlp-lite/version"
3
+ require_relative "rlp-lite/util"
4
+
5
+ require_relative "rlp-lite/decoder"
6
+ require_relative "rlp-lite/encoder"
7
+
8
+ require_relative "rlp-lite/sedes/big_endian_int"
9
+ require_relative "rlp-lite/sedes/binary"
10
+ require_relative "rlp-lite/sedes/list"
11
+ require_relative "rlp-lite/sedes"
12
+
13
+
14
+
15
+ # Provides an recursive-length prefix (RLP) encoder and decoder.
16
+
17
+ module Rlp
18
+ ## add constants "inline" here
19
+ ## (no need to use a Constant namespace - why? why not?)
20
+
21
+
22
+ ## todo/check - use encoding -ascii-8bit for source file or ? - why? why not?
23
+ ## use #b/.b to ensure binary encoding? - why? why not?
24
+ BYTE_EMPTY = "".freeze # The empty byte is defined as "".
25
+ BYTE_ZERO = "\x00".freeze # The zero byte is 0x00.
26
+ BYTE_ONE = "\x01".freeze # The byte one is 0x01.
27
+
28
+
29
+
30
+ # The RLP short length limit.
31
+ SHORT_LENGTH_LIMIT = 56
32
+
33
+ # The RLP long length limit.
34
+ LONG_LENGTH_LIMIT = (256 ** 8)
35
+
36
+ # The RLP primitive type offset.
37
+ PRIMITIVE_PREFIX_OFFSET = 0x80
38
+
39
+ # The RLP array type offset.
40
+ LIST_PREFIX_OFFSET = 0xc0
41
+
42
+
43
+ # Infinity as constant for convenience.
44
+ INFINITY = (1.0 / 0.0)
45
+
46
+
47
+ # The Rlp module exposes a variety of exceptions grouped as {RlpException}.
48
+ class RlpException < StandardError; end
49
+
50
+ # An error-type to point out RLP-encoding errors.
51
+ class EncodingError < RlpException; end
52
+
53
+ # An error-type to point out RLP-decoding errors.
54
+ class DecodingError < RlpException; end
55
+
56
+ # An error-type to point out RLP-type serialization errors.
57
+ class SerializationError < RlpException; end
58
+
59
+ # An error-type to point out RLP-type serialization errors.
60
+ class DeserializationError < RlpException; end
61
+
62
+ # A wrapper to represent already RLP-encoded data.
63
+ class Data < String; end
64
+
65
+
66
+ # Performes an {Rlp::Encoder} on any ruby object.
67
+ #
68
+ # @param obj [Object] any ruby object.
69
+ # @return [String] a packed, RLP-encoded item.
70
+ def self.encode(obj) Encoder.perform( obj ); end
71
+
72
+
73
+ # Performes an {Rlp::Decoder} on any RLP-encoded item.
74
+ #
75
+ # @param rlp [String] a packed, RLP-encoded item.
76
+ # @return [Object] a decoded ruby object.
77
+ def self.decode(rlp) Decoder.perform( rlp ); end
78
+ end # module Rlp
79
+
80
+
81
+
82
+
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rlp-lite
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Gerald Bauer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-11-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rdoc
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '7'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '4.0'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '7'
33
+ - !ruby/object:Gem::Dependency
34
+ name: hoe
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '3.23'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '3.23'
47
+ description: rlp-lite - light-weight machinery to serialize / deserialze via rlp (recursive
48
+ length prefix)
49
+ email: wwwmake@googlegroups.com
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files:
53
+ - CHANGELOG.md
54
+ - Manifest.txt
55
+ - README.md
56
+ files:
57
+ - CHANGELOG.md
58
+ - Manifest.txt
59
+ - README.md
60
+ - Rakefile
61
+ - lib/rlp-lite.rb
62
+ - lib/rlp-lite/decoder.rb
63
+ - lib/rlp-lite/encoder.rb
64
+ - lib/rlp-lite/sedes.rb
65
+ - lib/rlp-lite/sedes/big_endian_int.rb
66
+ - lib/rlp-lite/sedes/binary.rb
67
+ - lib/rlp-lite/sedes/list.rb
68
+ - lib/rlp-lite/util.rb
69
+ - lib/rlp-lite/version.rb
70
+ homepage: https://github.com/pixelartexchange/artbase
71
+ licenses:
72
+ - Public Domain
73
+ metadata: {}
74
+ post_install_message:
75
+ rdoc_options:
76
+ - "--main"
77
+ - README.md
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: '2.3'
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ requirements: []
91
+ rubygems_version: 3.3.7
92
+ signing_key:
93
+ specification_version: 4
94
+ summary: rlp-lite - light-weight machinery to serialize / deserialze via rlp (recursive
95
+ length prefix)
96
+ test_files: []