eth 0.5.0 → 0.5.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.
@@ -0,0 +1,71 @@
1
+ # Copyright (c) 2016-2022 The Ruby-Eth Contributors
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # -*- encoding : ascii-8bit -*-
16
+
17
+ # Provides the {Eth} module.
18
+ module Eth
19
+
20
+ # Provides commonly used constants, such as zero bytes or zero keys.
21
+ module Constant
22
+
23
+ # The empty byte is defined as "".
24
+ BYTE_EMPTY = "".freeze
25
+
26
+ # The zero byte is 0x00.
27
+ BYTE_ZERO = "\x00".freeze
28
+
29
+ # The byte one is 0x01.
30
+ BYTE_ONE = "\x01".freeze
31
+
32
+ # The size of a 32-bit number.
33
+ TT32 = (2 ** 32).freeze
34
+
35
+ # The size of a 256-bit number.
36
+ TT256 = (2 ** 256).freeze
37
+
38
+ # The maximum possible value of an UInt256.
39
+ UINT_MAX = (2 ** 256 - 1).freeze
40
+
41
+ # The minimum possible value of an UInt256.
42
+ UINT_MIN = 0.freeze
43
+
44
+ # The maximum possible value of an Int256.
45
+ INT_MAX = (2 ** 255 - 1).freeze
46
+
47
+ # The minimum possible value of an Int256.
48
+ INT_MIN = (-2 ** 255).freeze
49
+
50
+ # A hash containing only zeros.
51
+ HASH_ZERO = ("\x00" * 32).freeze
52
+
53
+ # The RLP short length limit.
54
+ SHORT_LENGTH_LIMIT = 56.freeze
55
+
56
+ # The RLP long length limit.
57
+ LONG_LENGTH_LIMIT = (256 ** 8).freeze
58
+
59
+ # The RLP primitive type offset.
60
+ PRIMITIVE_PREFIX_OFFSET = 0x80.freeze
61
+
62
+ # The RLP array type offset.
63
+ LIST_PREFIX_OFFSET = 0xc0.freeze
64
+
65
+ # The binary encoding is ASCII (8-bit).
66
+ BINARY_ENCODING = "ASCII-8BIT".freeze
67
+
68
+ # Infinity as constant for convenience.
69
+ INFINITY = (1.0 / 0.0).freeze
70
+ end
71
+ end
data/lib/eth/eip712.rb CHANGED
@@ -12,11 +12,11 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- # Provides the `Eth` module.
15
+ # Provides the {Eth} module.
16
16
  module Eth
17
17
 
18
18
  # Defines handy tools for encoding typed structured data as per EIP-712.
19
- # ref: https://eips.ethereum.org/EIPS/eip-712
19
+ # Ref: https://eips.ethereum.org/EIPS/eip-712
20
20
  module Eip712
21
21
  extend self
22
22
 
@@ -12,37 +12,40 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- # Provides the `Eth` module.
15
+ # Provides the {Eth} module.
16
16
  module Eth
17
17
 
18
- # The Eth::Key::Decrypter class to handle PBKDF2-SHA-256 decryption.
18
+ # The {Eth::Key::Decrypter} class to handle PBKDF2-SHA-256 decryption.
19
19
  class Key::Decrypter
20
20
 
21
21
  # Provides a specific decrypter error if decryption fails.
22
22
  class DecrypterError < StandardError; end
23
23
 
24
- # Class method `Eth::Key::Decrypter.perform`
24
+ # Class method {Eth::Key::Decrypter.perform} to perform an keystore
25
+ # decryption.
25
26
  #
26
- # @param data [JSON] encryption data including cypherkey
27
- # @param password [String] password to decrypt the key
28
- # @return [Eth::Key] decrypted key-pair
27
+ # @param data [JSON] encryption data including cypherkey.
28
+ # @param password [String] password to decrypt the key.
29
+ # @return [Eth::Key] decrypted key-pair.
29
30
  def self.perform(data, password)
30
31
  new(data, password).perform
31
32
  end
32
33
 
33
- # Constructor of the `Eth::Key::Decrypter` class for secret key
34
- # encryption.
34
+ # Constructor of the {Eth::Key::Decrypter} class for secret key
35
+ # decryption. Should not be used; use {Eth::Key::Decrypter.perform}
36
+ # instead.
35
37
  #
36
- # @param data [JSON] encryption data including cypherkey
37
- # @param password [String] password to decrypt the key
38
+ # @param data [JSON] encryption data including cypherkey.
39
+ # @param password [String] password to decrypt the key.
38
40
  def initialize(data, password)
39
- @data = JSON.parse(data)
41
+ data = JSON.parse(data) if data.is_a? String
42
+ @data = data
40
43
  @password = password
41
44
  end
42
45
 
43
- # Method to decrypt key using password
46
+ # Method to decrypt key using password.
44
47
  #
45
- # @return [String] decrypted key
48
+ # @return [Eth::Key] decrypted key.
46
49
  def perform
47
50
  derive_key password
48
51
  check_macs
@@ -12,45 +12,47 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- # Provides the `Eth` module.
15
+ # Provides the {Eth} module.
16
16
  module Eth
17
17
 
18
- # The Eth::Key::Encrypter class to handle PBKDF2-SHA-256 encryption.
18
+ # The {Eth::Key::Encrypter} class to handle PBKDF2-SHA-256 encryption.
19
19
  class Key::Encrypter
20
20
 
21
21
  # Provides a specific encrypter error if decryption fails.
22
22
  class EncrypterError < StandardError; end
23
23
 
24
- # Class method `Eth::Key::Encrypter.perform` to performa an key-store
24
+ # Class method {Eth::Key::Encrypter.perform} to performa an key-store
25
25
  # encryption.
26
26
  #
27
- # @param key [Eth::Key] representing a secret key-pair used for encryption
28
- # @param options [Hash] the options to encrypt with
29
- # @option options [String] :kdf key derivation function defaults to pbkdf2
30
- # @option options [String] :id uuid given to the secret key
31
- # @option options [String] :iterations number of iterations for the hash function
32
- # @option options [String] :salt passed to PBKDF
33
- # @option options [String] :iv 128-bit initialisation vector for the cipher
34
- # @option options [Integer] :parallelization parallelization factor for scrypt, defaults to 8
35
- # @option options [Integer] :block_size for scrypt, defaults to 1
36
- # @return [JSON] formatted with encrypted key (cyphertext) and [other identifying data](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition#pbkdf2-sha-256)
27
+ # @param key [Eth::Key] representing a secret key-pair used for encryption.
28
+ # @param options [Hash] the options to encrypt with.
29
+ # @option options [String] :kdf key derivation function defaults to pbkdf2.
30
+ # @option options [String] :id uuid given to the secret key.
31
+ # @option options [String] :iterations number of iterations for the hash function.
32
+ # @option options [String] :salt passed to PBKDF.
33
+ # @option options [String] :iv 128-bit initialisation vector for the cipher.
34
+ # @option options [Integer] :parallelization parallelization factor for scrypt, defaults to 8.
35
+ # @option options [Integer] :block_size for scrypt, defaults to 1.
36
+ # @return [JSON] formatted with encrypted key (cyphertext) and [other identifying data](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition#pbkdf2-sha-256).
37
37
  def self.perform(key, password, options = {})
38
38
  new(key, options).perform(password)
39
39
  end
40
40
 
41
- # Constructor of the `Eth::Key::Encrypter` class for secret key
42
- # encryption.
41
+ # Constructor of the {Eth::Key::Encrypter} class for secret key
42
+ # encryption. Should not be used; use {Eth::Key::Encrypter.perform}
43
+ # instead.
43
44
  #
44
- # @param key [Eth::Key] representing a secret key-pair used for encryption
45
- # @param options [Hash] the options to encrypt with
46
- # @option options [String] :kdf key derivation function defaults to pbkdf2
47
- # @option options [String] :id uuid given to the secret key
48
- # @option options [String] :iterations number of iterations for the hash function
49
- # @option options [String] :salt passed to PBKDF
50
- # @option options [String] :iv 128-bit initialisation vector for the cipher
51
- # @option options [Integer] :parallelization parallelization factor for scrypt, defaults to 8
52
- # @option options [Integer] :block_size for scrypt, defaults to 1
45
+ # @param key [Eth::Key] representing a secret key-pair used for encryption.
46
+ # @param options [Hash] the options to encrypt with.
47
+ # @option options [String] :kdf key derivation function defaults to pbkdf2.
48
+ # @option options [String] :id uuid given to the secret key.
49
+ # @option options [String] :iterations number of iterations for the hash function.
50
+ # @option options [String] :salt passed to PBKDF.
51
+ # @option options [String] :iv 128-bit initialisation vector for the cipher.
52
+ # @option options [Integer] :parallelization parallelization factor for scrypt, defaults to 8.
53
+ # @option options [Integer] :block_size for scrypt, defaults to 1.
53
54
  def initialize(key, options = {})
55
+ key = Key.new(priv: key) if key.is_a? String
54
56
  @key = key
55
57
  @options = options
56
58
 
@@ -64,7 +66,7 @@ module Eth
64
66
  # Encrypt the key with a given password.
65
67
  #
66
68
  # @param password [String] a secret key used for encryption
67
- # @return [String] a json-formatted keystore string.
69
+ # @return [String] a JSON-formatted keystore string.
68
70
  def perform(password)
69
71
  derive_key password
70
72
  encrypt
data/lib/eth/key.rb CHANGED
@@ -18,28 +18,28 @@ require "rbsecp256k1"
18
18
  require "scrypt"
19
19
  require "securerandom"
20
20
 
21
- # Provides the `Eth` module.
21
+ # Provides the {Eth} module.
22
22
  module Eth
23
23
 
24
- # The `Eth::Key` class to handle Secp256k1 private/public key-pairs.
24
+ # The {Eth::Key} class to handle Secp256k1 private/public key-pairs.
25
25
  class Key
26
26
 
27
- # The Eth::Key::Decrypter class to handle PBKDF2-SHA-256 decryption.
27
+ # The {Eth::Key::Decrypter} class to handle PBKDF2-SHA-256 decryption.
28
28
  autoload :Decrypter, "eth/key/decrypter"
29
29
 
30
- # The Eth::Key::Encrypter class to handle PBKDF2-SHA-256 encryption.
30
+ # The {Eth::Key::Encrypter} class to handle PBKDF2-SHA-256 encryption.
31
31
  autoload :Encrypter, "eth/key/encrypter"
32
32
 
33
- # The `Secp256k1::PrivateKey` of the `Eth::Key` pair.
33
+ # The `Secp256k1::PrivateKey` of the {Eth::Key} pair.
34
34
  attr_reader :private_key
35
35
 
36
- # The `Secp256k1::PublicKey` of the `Eth::Key` pair.
36
+ # The `Secp256k1::PublicKey` of the {Eth::Key} pair.
37
37
  attr_reader :public_key
38
38
 
39
- # Constructor of the `Eth::Key` class. Creates a new random key-pair
39
+ # Constructor of the {Eth::Key} class. Creates a new random key-pair
40
40
  # if no `priv` key is provided.
41
41
  #
42
- # @param priv [String] binary string of private key data (optional).
42
+ # @param priv [String] binary string of private key data.
43
43
  def initialize(priv: nil)
44
44
 
45
45
  # Creates a new, randomized libsecp256k1 context.
@@ -63,9 +63,10 @@ module Eth
63
63
  end
64
64
 
65
65
  # Signs arbitrary data without validation. Should not be used unless really
66
- # desired. See also: personal_sign, sign_typed_data.
66
+ # desired. See also: {Key.personal_sign}, {Key.sign_typed_data}, and
67
+ # {Signature.recover}.
67
68
  #
68
- # @param blob [String] that arbitrary data to be signed.
69
+ # @param blob [Object] that arbitrary data to be signed.
69
70
  # @param chain_id [Integer] the chain id the signature should be generated on.
70
71
  # @return [String] a hexa-decimal signature.
71
72
  def sign(blob, chain_id = nil)
@@ -81,9 +82,11 @@ module Eth
81
82
  Util.bin_to_hex signature.pack "c*"
82
83
  end
83
84
 
84
- # Prefixes a message with "\x19Ethereum Signed Message:" and signs
85
+ # Prefixes a message with `\x19Ethereum Signed Message:` and signs
85
86
  # it in the common way used by many web3 wallets. Complies with
86
- # EIP-191 prefix 0x19 and version byte 0x45 (E).
87
+ # EIP-191 prefix `0x19` and version byte `0x45` (`E`). See also
88
+ # {Signature.personal_recover}.
89
+ # Ref: https://eips.ethereum.org/EIPS/eip-191
87
90
  #
88
91
  # @param message [String] the message string to be prefixed and signed.
89
92
  # @param chain_id [Integer] the chain id the signature should be generated on.
@@ -95,8 +98,10 @@ module Eth
95
98
  end
96
99
 
97
100
  # Prefixes, hashes, and signes a typed data structure in the common
98
- # way used by many web3 wallets. Complies with EIP-191 prefix 0x19
99
- # and EIP-712 version byte 0x01. Supports `V3`, `V4`.
101
+ # way used by many web3 wallets. Complies with EIP-191 prefix `0x19`
102
+ # and EIP-712 version byte `0x01`. Supports `V3`, `V4`. See also
103
+ # {Signature.recover_typed_data}.
104
+ # Ref: https://eips.ethereum.org/EIPS/eip-712
100
105
  #
101
106
  # @param typed_data [Array] all the data in the typed data structure to be signed.
102
107
  # @param chain_id [Integer] the chain id the signature should be generated on.
@@ -114,7 +119,7 @@ module Eth
114
119
  end
115
120
 
116
121
  # Exports the private key bytes in a wrapper function to maintain
117
- # backward-compatibility with older versions of `Eth::Key`.
122
+ # backward-compatibility with older versions of {Eth::Key}.
118
123
  #
119
124
  # @return [String] private key as packed byte-string.
120
125
  def private_bytes
@@ -138,7 +143,7 @@ module Eth
138
143
  end
139
144
 
140
145
  # Exports the uncompressed public key bytes in a wrapper function to
141
- # maintain backward-compatibility with older versions of `Eth::Key`.
146
+ # maintain backward-compatibility with older versions of {Eth::Key}.
142
147
  #
143
148
  # @return [String] uncompressed public key as packed byte-string.
144
149
  def public_bytes
@@ -0,0 +1,109 @@
1
+ # Copyright (c) 2016-2022 The Ruby-Eth Contributors
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # -*- encoding : ascii-8bit -*-
16
+
17
+ # Provides the {Eth} module.
18
+ module Eth
19
+
20
+ # Provides an recursive-length prefix (RLP) encoder and decoder.
21
+ module Rlp
22
+
23
+ # Provides an RLP-decoder.
24
+ module Decoder
25
+ extend self
26
+
27
+ # Decodes an RLP-encoded object.
28
+ #
29
+ # @param rlp [String] an RLP-encoded object.
30
+ # @return [Object] the decoded and maybe deserialized object.
31
+ # @raise [Eth::Rlp::DecodingError] if the input string does not end after
32
+ # the root item.
33
+ def perform(rlp)
34
+ rlp = Util.hex_to_bin rlp if Util.is_hex? rlp
35
+ rlp = Util.str_to_bytes rlp
36
+ begin
37
+ item, next_start = consume_item rlp, 0
38
+ rescue Exception => e
39
+ raise DecodingError, "Cannot decode rlp string: #{e}"
40
+ end
41
+ raise DecodingError, "RLP string ends with #{rlp.size - next_start} superfluous bytes" if next_start != rlp.size
42
+ return item
43
+ end
44
+
45
+ private
46
+
47
+ # Consume an RLP-encoded item from the given start.
48
+ def consume_item(rlp, start)
49
+ t, l, s = consume_length_prefix rlp, start
50
+ consume_payload rlp, s, t, l
51
+ end
52
+
53
+ # Consume an RLP length prefix at the given position.
54
+ def consume_length_prefix(rlp, start)
55
+ b0 = rlp[start].ord
56
+ if b0 < Constant::PRIMITIVE_PREFIX_OFFSET
57
+
58
+ # single byte
59
+ [:str, 1, start]
60
+ elsif b0 < Constant::PRIMITIVE_PREFIX_OFFSET + Constant::SHORT_LENGTH_LIMIT
61
+ raise DecodingError, "Encoded as short string although single byte was possible" if (b0 - Constant::PRIMITIVE_PREFIX_OFFSET == 1) && rlp[start + 1].ord < Constant::PRIMITIVE_PREFIX_OFFSET
62
+
63
+ # short string
64
+ [:str, b0 - Constant::PRIMITIVE_PREFIX_OFFSET, start + 1]
65
+ elsif b0 < Constant::LIST_PREFIX_OFFSET
66
+ raise DecodingError, "Length starts with zero bytes" if rlp.slice(start + 1) == Constant::BYTE_ZERO
67
+
68
+ # long string
69
+ ll = b0 - Constant::PRIMITIVE_PREFIX_OFFSET - Constant::SHORT_LENGTH_LIMIT + 1
70
+ l = Util.big_endian_to_int rlp[(start + 1)...(start + 1 + ll)]
71
+ raise DecodingError, "Long string prefix used for short string" if l < Constant::SHORT_LENGTH_LIMIT
72
+ [:str, l, start + 1 + ll]
73
+ elsif b0 < Constant::LIST_PREFIX_OFFSET + Constant::SHORT_LENGTH_LIMIT
74
+
75
+ # short list
76
+ [:list, b0 - Constant::LIST_PREFIX_OFFSET, start + 1]
77
+ else
78
+ raise DecodingError, "Length starts with zero bytes" if rlp.slice(start + 1) == Constant::BYTE_ZERO
79
+
80
+ # long list
81
+ ll = b0 - Constant::LIST_PREFIX_OFFSET - Constant::SHORT_LENGTH_LIMIT + 1
82
+ l = Util.big_endian_to_int rlp[(start + 1)...(start + 1 + ll)]
83
+ raise DecodingError, "Long list prefix used for short list" if l < Constant::SHORT_LENGTH_LIMIT
84
+ [:list, l, start + 1 + ll]
85
+ end
86
+ end
87
+
88
+ # Consume an RLP payload at the given position of given type and size.
89
+ def consume_payload(rlp, start, type, length)
90
+ case type
91
+ when :str
92
+ [rlp[start...(start + length)], start + length]
93
+ when :list
94
+ items = []
95
+ next_item_start = start
96
+ payload_end = next_item_start + length
97
+ while next_item_start < payload_end
98
+ item, next_item_start = consume_item rlp, next_item_start
99
+ items.push item
100
+ end
101
+ raise DecodingError, "List length prefix announced a too small length" if next_item_start > payload_end
102
+ [items, next_item_start]
103
+ else
104
+ raise TypeError, "Type must be either :str or :list"
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,78 @@
1
+ # Copyright (c) 2016-2022 The Ruby-Eth Contributors
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # -*- encoding : ascii-8bit -*-
16
+
17
+ # Provides the {Eth} module.
18
+ module Eth
19
+
20
+ # Provides an recursive-length prefix (RLP) encoder and decoder.
21
+ module Rlp
22
+
23
+ # Provides an RLP-encoder.
24
+ module Encoder
25
+ extend self
26
+
27
+ # Encodes a Ruby object in RLP format.
28
+ #
29
+ # @param obj [Object] a Ruby object.
30
+ # @return [String] the RLP encoded item.
31
+ # @raise [Eth::Rlp::EncodingError] in the rather unlikely case that the item
32
+ # is too big to encode (will not happen).
33
+ # @raise [Eth::Rlp::SerializationError] if the serialization fails.
34
+ def perform(obj)
35
+ item = Sedes.infer(obj).serialize(obj)
36
+ result = encode_raw item
37
+ end
38
+
39
+ private
40
+
41
+ # Encodes the raw item.
42
+ def encode_raw(item)
43
+ return item if item.instance_of? Rlp::Data
44
+ return encode_primitive item if Util.is_primitive? item
45
+ return encode_list item if Util.is_list? item
46
+ raise EncodingError "Cannot encode object of type #{item.class.name}"
47
+ end
48
+
49
+ # Encodes a single primitive.
50
+ def encode_primitive(item)
51
+ return Util.str_to_bytes item if item.size == 1 && item.ord < Constant::PRIMITIVE_PREFIX_OFFSET
52
+ payload = Util.str_to_bytes item
53
+ prefix = length_prefix payload.size, Constant::PRIMITIVE_PREFIX_OFFSET
54
+ "#{prefix}#{payload}"
55
+ end
56
+
57
+ # Encodes a single list.
58
+ def encode_list(list)
59
+ payload = list.map { |item| encode_raw item }.join
60
+ prefix = length_prefix payload.size, Constant::LIST_PREFIX_OFFSET
61
+ "#{prefix}#{payload}"
62
+ end
63
+
64
+ # Determines a length prefix.
65
+ def length_prefix(length, offset)
66
+ if length < Constant::SHORT_LENGTH_LIMIT
67
+ (offset + length).chr
68
+ elsif length < Constant::LONG_LENGTH_LIMIT
69
+ length_string = Util.int_to_big_endian length
70
+ length_len = (offset + Constant::SHORT_LENGTH_LIMIT - 1 + length_string.size).chr
71
+ "#{length_len}#{length_string}"
72
+ else
73
+ raise EncodingError, "Length greater than 256**8: #{length}"
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,66 @@
1
+ # Copyright (c) 2016-2022 The Ruby-Eth Contributors
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # -*- encoding : ascii-8bit -*-
16
+
17
+ # Provides the {Eth} module.
18
+ module Eth
19
+
20
+ # Provides an recursive-length prefix (RLP) encoder and decoder.
21
+ module Rlp
22
+
23
+ # Provides serializable and deserializable types (SeDes).
24
+ module Sedes
25
+
26
+ # A serializable, big-endian, unsigned integer type.
27
+ class BigEndianInt
28
+
29
+ # Create a serializable, big-endian, unsigned integer.
30
+ #
31
+ # @param size [Integer] the size of the big endian.
32
+ def initialize(size = nil)
33
+ @size = size
34
+ end
35
+
36
+ # Serialize a big-endian integer.
37
+ #
38
+ # @param obj [Integer] the integer to be serialized.
39
+ # @return [String] a serialized big-endian integer.
40
+ # @raise [SerializationError] if provided object is not an integer.
41
+ # @raise [SerializationError] if provided integer is negative.
42
+ # @raise [SerializationError] if provided integer is too big for @size.
43
+ def serialize(obj)
44
+ raise SerializationError, "Can only serialize integers" unless obj.is_a?(Integer)
45
+ raise SerializationError, "Cannot serialize negative integers" if obj < 0
46
+ raise SerializationError, "Integer too large (does not fit in #{@size} bytes)" if @size && obj >= 256 ** @size
47
+ s = obj == 0 ? Constant::BYTE_EMPTY : Util.int_to_big_endian(obj)
48
+ @size ? "#{Constant::BYTE_ZERO * [0, @size - s.size].max}#{s}" : s
49
+ end
50
+
51
+ # Deserializes an unsigned integer.
52
+ #
53
+ # @param serial [String] the serialized integer.
54
+ # @return [Integer] a number.
55
+ # @raise [DeserializationError] if provided serial is of wrong size.
56
+ # @raise [DeserializationError] if provided serial is not of minimal length.
57
+ def deserialize(serial)
58
+ raise DeserializationError, "Invalid serialization (wrong size)" if @size && serial.size != @size
59
+ raise DeserializationError, "Invalid serialization (not minimal length)" if !@size && serial.size > 0 && serial[0] == Constant::BYTE_ZERO
60
+ serial = serial || Constant::BYTE_ZERO
61
+ Util.big_endian_to_int(serial)
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,97 @@
1
+ # Copyright (c) 2016-2022 The Ruby-Eth Contributors
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # -*- encoding : ascii-8bit -*-
16
+
17
+ # Provides the {Eth} module.
18
+ module Eth
19
+
20
+ # Provides an recursive-length prefix (RLP) encoder and decoder.
21
+ module Rlp
22
+
23
+ # Provides serializable and deserializable types (SeDes).
24
+ module Sedes
25
+
26
+ # A sedes type for binary values.
27
+ class Binary
28
+
29
+ # A singleton class for binary values of fixed length.
30
+ class << self
31
+
32
+ # Create a serializable bianry of fixed size.
33
+ #
34
+ # @param l [Integer] the fixed size of the binary.
35
+ # @param allow_empty [Boolean] indicator wether empty binaries should be allowed.
36
+ # @return [Eth::Rlp::Sedes::Binary] a serializable binary of fixed size.
37
+ def fixed_length(l, allow_empty: false)
38
+ new(min_length: l, max_length: l, allow_empty: allow_empty)
39
+ end
40
+
41
+ # Checks wether the given object is of a valid binary type.
42
+ #
43
+ # @param obj [Object] the supposed binary item to check.
44
+ # @return [Boolean] true if valid.
45
+ def valid_type?(obj)
46
+ obj.instance_of? String
47
+ end
48
+ end
49
+
50
+ # Create a serializable bianry of variable size.
51
+ #
52
+ # @param min_length [Integer] the minimum size of the binary.
53
+ # @param max_length [Integer] the maximum size of the binary.
54
+ # @param allow_empty [Boolean] indicator wether empty binaries should be allowed.
55
+ def initialize(min_length: 0, max_length: Constant::INFINITY, allow_empty: false)
56
+ @min_length = min_length
57
+ @max_length = max_length
58
+ @allow_empty = allow_empty
59
+ end
60
+
61
+ # Serializes a binary.
62
+ #
63
+ # @param obj [String] the binary to serialize.
64
+ # @return [Object] a serialized binary.
65
+ # @raise [SerializationError] if provided object is of invalid type.
66
+ # @raise [SerializationError] if provided binary is of invalid length.
67
+ def serialize(obj)
68
+ raise SerializationError, "Object is not a serializable (#{obj.class})" unless self.class.valid_type? obj
69
+ serial = Util.str_to_bytes obj
70
+ raise SerializationError, "Object has invalid length" unless valid_length? serial.size
71
+ serial
72
+ end
73
+
74
+ # Deserializes a binary.
75
+ #
76
+ # @param serial [Object] the serialized binary.
77
+ # @return [String] a deserialized binary.
78
+ # @raise [DeserializationError] if provided serial is of wrong type.
79
+ # @raise [DeserializationError] if provided serial is of wrong length.
80
+ def deserialize(serial)
81
+ raise DeserializationError, "Objects of type #{serial.class} cannot be deserialized" unless Util.is_primitive? serial
82
+ raise DeserializationError, "#{serial.class} has invalid length" unless valid_length? serial.size
83
+ serial
84
+ end
85
+
86
+ # Checks wether the given length fits the defined size boundaries of the
87
+ # binary type.
88
+ #
89
+ # @param length [Integer] the supposed length of the binary item.
90
+ # @return [Boolean] true if valid.
91
+ def valid_length?(length)
92
+ (@min_length <= length && length <= @max_length) || (@allow_empty && length == 0)
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end