noise-ruby 0.13.0 → 0.15.0

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,183 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Noise
4
+ module Transport
5
+ # The BOLT #8 transport layer, which turns the message-oriented Noise::Connection into the
6
+ # byte stream the Lightning Network sends over TCP.
7
+ #
8
+ # A Lightning message goes out as two Noise messages: the length of the payload as a two-byte
9
+ # big-endian integer, encrypted on its own, and then the payload. The receiver decrypts the
10
+ # first to learn how many bytes to read for the second. Each direction rotates its key on a
11
+ # schedule of its own, so that a key stolen later cannot decrypt what came before it.
12
+ #
13
+ # Run the handshake with Noise::Connection first, and wrap the finished connection:
14
+ #
15
+ # connection = Noise::Connection::Initiator.new(Noise::Transport::Bolt8::PROTOCOL_NAME,
16
+ # keypairs: { s: local_static, rs: node_id })
17
+ # connection.prologue = Noise::Transport::Bolt8::PROLOGUE
18
+ # connection.start_handshake
19
+ # # ... exchange the three handshake messages over the socket ...
20
+ # transport = Noise::Transport::Bolt8.new(connection, socket)
21
+ #
22
+ # transport.write('a lightning message')
23
+ # message = transport.read
24
+ #
25
+ # The transport takes over the connection's transport phase: it holds the very CipherStates
26
+ # the connection does, so once one is wrapped, stop calling the connection's #encrypt,
27
+ # #decrypt, nonce accessors and rekey methods. Every one of them moves the same key and nonce,
28
+ # and the peer has no way to learn that they did.
29
+ #
30
+ # One transport belongs to one thread, for the reason Noise::Connection::Base gives.
31
+ class Bolt8
32
+ # BOLT #8 fixes the handshake to this protocol, and this prologue.
33
+ PROTOCOL_NAME = 'Noise_XK_secp256k1_ChaChaPoly_SHA256'
34
+ PROLOGUE = 'lightning'
35
+
36
+ # The payload length goes out as a two-byte big-endian integer, so the header is those two
37
+ # bytes plus the authentication tag over them.
38
+ LENGTH_PREFIX_LENGTH = 2
39
+ HEADER_LENGTH = LENGTH_PREFIX_LENGTH + Noise::State::CipherState::TAG_LENGTH
40
+
41
+ # What two bytes of length can express, and what BOLT #8 allows a Lightning message to be.
42
+ # Its authentication tag brings such a message to 65551 bytes, past the 65535 a single Noise
43
+ # transport message may be, so Noise::Connection#encrypt would refuse the largest messages
44
+ # the Lightning Network permits. That is why this class encrypts through the CipherState.
45
+ MAX_PAYLOAD_LENGTH = 65_535
46
+
47
+ # @param [Noise::Connection::Base] connection a finished BOLT #8 handshake.
48
+ # @param [IO] io the stream to read from and write to. See Noise::Transport::Stream.
49
+ # @param [Numeric, nil] read_timeout how long #read waits for the next bytes of a message
50
+ # before giving up, in seconds. See Noise::Transport::Stream.
51
+ # @raise [Noise::Exceptions::HandshakeNotFinishedError] if the handshake has not finished.
52
+ # @raise [Noise::Exceptions::ProtocolNameError] if the connection runs another protocol.
53
+ # @raise [Noise::Exceptions::NoiseValidationError] if the connection is half-duplex.
54
+ # @raise [ArgumentError] if read_timeout is negative, or if the IO cannot be waited on.
55
+ def initialize(connection, io, read_timeout: nil)
56
+ validate(connection)
57
+
58
+ @stream = Stream.new(io, read_timeout: read_timeout)
59
+ hkdf_fn = connection.protocol.hkdf_fn
60
+ # Both directions start from the chaining key the handshake ended with, and rotate away
61
+ # from it independently.
62
+ @send = Direction.new(connection.cipher_state_encrypt, connection.chaining_key, hkdf_fn)
63
+ @receive = Direction.new(connection.cipher_state_decrypt, connection.chaining_key, hkdf_fn)
64
+ end
65
+
66
+ # Encrypts one Lightning message and writes it to the IO: the encrypted length, then the
67
+ # encrypted payload. It returns once all of it has gone out.
68
+ #
69
+ # @param [String] payload the message, at most MAX_PAYLOAD_LENGTH bytes.
70
+ # @raise [Noise::Exceptions::MessageTooLongError] if the payload is longer than that.
71
+ # @raise [IOError] if the IO accepts none of the bytes it is handed.
72
+ # @return [Integer] how many bytes were written.
73
+ def write(payload)
74
+ if payload.bytesize > MAX_PAYLOAD_LENGTH
75
+ raise Noise::Exceptions::MessageTooLongError,
76
+ "Message is #{payload.bytesize} bytes, which exceeds the maximum of #{MAX_PAYLOAD_LENGTH}."
77
+ end
78
+
79
+ @stream.write(@send.encrypt([payload.bytesize].pack('n')) + @send.encrypt(payload))
80
+ end
81
+
82
+ # Reads one Lightning message, blocking until all of it has arrived.
83
+ #
84
+ # Every failure ends the transport. BOLT #8 requires the connection to be closed on a
85
+ # decryption failure, and a message that stops part way through leaves the stream in the
86
+ # middle of one, where the next read would take a payload for a length.
87
+ #
88
+ # An error the IO itself raises, such as Errno::ECONNRESET, comes through as it is.
89
+ #
90
+ # @raise [Noise::Exceptions::TruncatedMessageError] if the stream ends part way through a
91
+ # message.
92
+ # @raise [Noise::Exceptions::ReadTimeoutError] if no more bytes arrive in time.
93
+ # @raise [Noise::Exceptions::DecryptError] if either half fails to authenticate.
94
+ # @return [String, nil] the payload, or nil if the stream ended between messages.
95
+ def read
96
+ header = @stream.read_exactly_or_nil(HEADER_LENGTH)
97
+ return nil if header.nil?
98
+
99
+ length = @receive.decrypt(header).unpack1('n')
100
+ @receive.decrypt(@stream.read_exactly(length + Noise::State::CipherState::TAG_LENGTH))
101
+ end
102
+
103
+ private
104
+
105
+ # BOLT #8 gives each direction a key, a nonce and a chaining key of its own, so a half-duplex
106
+ # connection, which shares one CipherState both ways, cannot carry it. Two Directions over
107
+ # one CipherState would advance a single nonce on both sending and receiving, and rotate to
108
+ # two different chaining keys, which no BOLT #8 peer would follow. Two such parties still
109
+ # talk to each other, so nothing but this check would report it.
110
+ #
111
+ # @param [Noise::Connection::Base] connection the connection to wrap.
112
+ # @return [void]
113
+ def validate(connection)
114
+ unless connection.handshake_finished?
115
+ raise Noise::Exceptions::HandshakeNotFinishedError, 'The handshake has not finished.'
116
+ end
117
+
118
+ unless connection.protocol.name == PROTOCOL_NAME
119
+ raise Noise::Exceptions::ProtocolNameError,
120
+ "BOLT #8 runs #{PROTOCOL_NAME}, not #{connection.protocol.name}."
121
+ end
122
+
123
+ return unless connection.half_duplex?
124
+
125
+ raise Noise::Exceptions::NoiseValidationError,
126
+ 'BOLT #8 gives each direction a key of its own, so it cannot run half-duplex.'
127
+ end
128
+
129
+ # One direction of the transport: the key it encrypts or decrypts with, and the chaining key
130
+ # the next one is derived from. BOLT #8 calls these sk and sck for sending, rk and rck for
131
+ # receiving, and rotates each direction on its own count.
132
+ class Direction
133
+ # BOLT #8 rotates a key once the nonce dedicated to it reaches 1000. A Lightning message
134
+ # is encrypted twice, once for its length and once for its payload, so that is every 500
135
+ # messages.
136
+ KEY_ROTATION_NONCE = 1000
137
+
138
+ # @param [Noise::State::CipherState] cipher_state the transport CipherState Split() gave
139
+ # this direction.
140
+ # @param [String] chaining_key the chaining key the handshake ended with.
141
+ # @param [Proc] hkdf_fn the protocol's HKDF.
142
+ def initialize(cipher_state, chaining_key, hkdf_fn)
143
+ @cipher_state = cipher_state
144
+ @chaining_key = chaining_key
145
+ @hkdf_fn = hkdf_fn
146
+ end
147
+
148
+ # @param [String] plaintext
149
+ # @return [String] the ciphertext and its authentication tag.
150
+ def encrypt(plaintext)
151
+ @cipher_state.encrypt_with_ad('', plaintext).tap { rotate_key_if_due }
152
+ end
153
+
154
+ # @param [String] ciphertext
155
+ # @raise [Noise::Exceptions::DecryptError] if it fails to authenticate, in which case the
156
+ # key is not rotated and the nonce does not move.
157
+ # @return [String] the plaintext.
158
+ def decrypt(ciphertext)
159
+ @cipher_state.decrypt_with_ad('', ciphertext).tap { rotate_key_if_due }
160
+ end
161
+
162
+ private
163
+
164
+ # Replaces this direction's key with HKDF(ck, k), which also restarts the nonce at zero.
165
+ # This is not Noise's REKEY(k): it draws on the chaining key, so a key stolen now says
166
+ # nothing about the keys the direction used before it.
167
+ #
168
+ # @return [void]
169
+ def rotate_key_if_due
170
+ # Every message through this class advances the nonce by one, so the test could be an
171
+ # equality. It is not, so that a nonce moved from outside cannot carry the direction
172
+ # past the point it rotates at and leave it on one key for good.
173
+ return unless @cipher_state.n >= KEY_ROTATION_NONCE
174
+
175
+ @chaining_key, key = @hkdf_fn.call(@chaining_key, @cipher_state.k, 2)
176
+ @cipher_state.initialize_key(key)
177
+ nil
178
+ end
179
+ end
180
+ private_constant :Direction
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Noise
4
+ module Transport
5
+ # A Noise connection framed for a byte stream: every message goes out preceded by its length,
6
+ # so that the reader knows how many bytes to take before decrypting.
7
+ #
8
+ # transport = Noise::Transport::Framed.new(connection, socket)
9
+ # transport.write('a message')
10
+ # message = transport.read
11
+ #
12
+ # The connection learns nothing about the IO, and this class learns nothing about the
13
+ # handshake: it takes one that has already finished.
14
+ #
15
+ # The length goes out in the clear, as two big-endian bytes. It is not secret in any useful
16
+ # sense — anyone watching the stream can time the bytes and count them either way — but it does
17
+ # mean this framing hides nothing about how long each message is. A protocol that has to hide
18
+ # its message sizes pads them, or encrypts the length as BOLT #8 does.
19
+ #
20
+ # Two bytes are enough because a Noise transport message may not exceed 65535 bytes, so a
21
+ # length this can express is never one the connection would refuse. The payload limit is lower
22
+ # by the authentication tag, and Noise::Connection#encrypt is what enforces it.
23
+ #
24
+ # This class holds the connection's transport phase, so once a connection is framed, stop
25
+ # calling its #encrypt and #decrypt directly: a message that goes out unframed leaves the
26
+ # reader taking the next message's bytes for a length. One transport belongs to one thread,
27
+ # for the reason Noise::Connection::Base gives.
28
+ class Framed
29
+ # The length prefix, as two big-endian bytes.
30
+ LENGTH_PREFIX_LENGTH = 2
31
+
32
+ # The longest payload #write takes, which is a Noise transport message less its tag. Two
33
+ # bytes of length cannot announce more than the 65535 a transport message may be, so a
34
+ # declared length is never one the connection would refuse.
35
+ MAX_PAYLOAD_LENGTH = Noise::Connection::Base::MAX_PLAINTEXT_LENGTH
36
+
37
+ # @param [Noise::Connection::Base] connection a connection whose handshake has finished.
38
+ # @param [IO] io the stream to read from and write to. See Noise::Transport::Stream.
39
+ # @param [Numeric, nil] read_timeout how long #read waits for the next bytes of a frame
40
+ # before giving up, in seconds. See Noise::Transport::Stream.
41
+ # @raise [Noise::Exceptions::HandshakeNotFinishedError] if the handshake has not finished.
42
+ # @raise [ArgumentError] if read_timeout is negative, or if the IO cannot be waited on and
43
+ # the timeout would therefore do nothing.
44
+ def initialize(connection, io, read_timeout: nil)
45
+ unless connection.handshake_finished?
46
+ raise Noise::Exceptions::HandshakeNotFinishedError, 'The handshake has not finished.'
47
+ end
48
+
49
+ @connection = connection
50
+ @stream = Stream.new(io, read_timeout: read_timeout)
51
+ end
52
+
53
+ # Encrypts one message and writes it to the IO, preceded by its length. It returns once the
54
+ # whole frame has been written, however many writes that takes.
55
+ #
56
+ # An error the IO itself raises, such as Errno::EPIPE when the peer has gone, comes through
57
+ # as it is.
58
+ #
59
+ # @param [String] payload at most MAX_PAYLOAD_LENGTH bytes.
60
+ # @raise [Noise::Exceptions::MessageTooLongError] if the payload is longer than that.
61
+ # @raise [IOError] if the IO accepts none of the bytes it is handed, which no IO that keeps
62
+ # its side of the bargain does.
63
+ # @return [Integer] how many bytes were written, the payload plus its tag and its length.
64
+ def write(payload)
65
+ ciphertext = @connection.encrypt(payload)
66
+
67
+ @stream.write([ciphertext.bytesize].pack('n') + ciphertext)
68
+ end
69
+
70
+ # Reads one message, waiting until all of it has arrived.
71
+ #
72
+ # Every failure ends the transport, for a different reason each time. A DecryptError says
73
+ # the frame was not written by the party this connection shares a key with, or not written
74
+ # in the order it claims; the stream is still at a frame boundary and the nonce has not
75
+ # moved, so reading on is possible, but reading on from a peer that just failed to
76
+ # authenticate is not something to do. A TruncatedMessageError or a ReadTimeoutError leaves
77
+ # the bytes already taken out of the stream and nowhere to put them, so the next read would
78
+ # take the middle of a frame for a length. Build a new connection instead.
79
+ #
80
+ # An error the IO itself raises, such as Errno::ECONNRESET when the peer disappears without
81
+ # closing, comes through as it is rather than as one of these.
82
+ #
83
+ # @raise [Noise::Exceptions::TruncatedMessageError] if the stream ends part way through a
84
+ # frame.
85
+ # @raise [Noise::Exceptions::ReadTimeoutError] if no more bytes arrive in time.
86
+ # @raise [Noise::Exceptions::DecryptError] if the frame fails to authenticate, which is also
87
+ # how a length too short to hold an authentication tag is reported.
88
+ # @return [String, nil] the payload, or nil if the stream ended between frames, which is how
89
+ # the other party closes without cutting a message in half.
90
+ def read
91
+ prefix = @stream.read_exactly_or_nil(LENGTH_PREFIX_LENGTH)
92
+ return nil if prefix.nil?
93
+
94
+ @connection.decrypt(@stream.read_exactly(prefix.unpack1('n')))
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Noise
4
+ module Transport
5
+ # The IO a framed transport sits on, and the only place that deals with the ways a stream
6
+ # differs from a message: it hands over fewer bytes than were asked for, takes fewer than it
7
+ # was given, ends in the middle of something, or goes quiet.
8
+ #
9
+ # A transport holds one of these and asks it for whole frames. Like the transport above it,
10
+ # one belongs to one thread: a stream has a position, and two threads reading it take halves
11
+ # of each other's frames.
12
+ class Stream
13
+ # @param [IO] io the stream. Anything that answers #write and #readpartial will do, which is
14
+ # what makes a StringIO usable in a test.
15
+ # @param [Numeric, nil] read_timeout how long to wait for the next bytes before giving up,
16
+ # in seconds. nil waits as long as the IO does. It applies to each wait rather than to a
17
+ # frame as a whole, so a peer that sends a byte at a time holds a read open without ever
18
+ # tripping it.
19
+ # @raise [ArgumentError] if read_timeout is negative, or if the IO cannot be waited on and
20
+ # the timeout would therefore do nothing.
21
+ def initialize(io, read_timeout: nil)
22
+ validate_read_timeout!(io, read_timeout)
23
+
24
+ @io = io
25
+ @read_timeout = read_timeout
26
+ end
27
+
28
+ # Writes all of it, however many writes that takes.
29
+ #
30
+ # @param [String] frame the bytes to write.
31
+ # @raise [IOError] if a write takes none of them, which would otherwise spin here forever.
32
+ # @return [Integer] frame.bytesize, once all of it has gone out.
33
+ def write(frame)
34
+ written = 0
35
+ while written < frame.bytesize
36
+ taken = @io.write(frame.byteslice(written, frame.bytesize - written))
37
+ raise IOError, "#{@io.class} took #{taken.inspect} of the #{frame.bytesize} bytes it was given." unless
38
+ taken.is_a?(Integer) && taken.positive?
39
+
40
+ written += taken
41
+ end
42
+ written
43
+ end
44
+
45
+ # @param [Integer] length how many bytes to read.
46
+ # @raise [Noise::Exceptions::TruncatedMessageError] if the stream ends first.
47
+ # @raise [Noise::Exceptions::ReadTimeoutError] if no more arrive in time.
48
+ # @return [String] exactly length bytes.
49
+ def read_exactly(length)
50
+ gather(length) || truncated!(length, 0)
51
+ end
52
+
53
+ # The same, for the first bytes of a frame, where a stream that has ended has not been cut
54
+ # short: it is the other party saying goodbye between one frame and the next.
55
+ #
56
+ # @param [Integer] length how many bytes to read.
57
+ # @raise [Noise::Exceptions::TruncatedMessageError] if the stream ends after some of them.
58
+ # @raise [Noise::Exceptions::ReadTimeoutError] if no more arrive in time.
59
+ # @return [String, nil] exactly length bytes, or nil if the stream had already ended.
60
+ def read_exactly_or_nil(length)
61
+ gather(length)
62
+ end
63
+
64
+ private
65
+
66
+ # @param [Integer] length how many bytes to read.
67
+ # @raise [Noise::Exceptions::TruncatedMessageError] if the stream ends after some of them.
68
+ # @return [String, nil] the bytes, or nil if the stream ended before any of them arrived.
69
+ def gather(length)
70
+ # Binary, because a frame is bytes: appending a chunk to a buffer of another encoding
71
+ # would count characters where this counts bytes.
72
+ buffer = ''.b
73
+ while buffer.bytesize < length
74
+ chunk = read_chunk(length - buffer.bytesize)
75
+ return buffer.empty? ? nil : truncated!(length, buffer.bytesize) if chunk.nil?
76
+
77
+ buffer << chunk
78
+ end
79
+ buffer
80
+ end
81
+
82
+ # @param [Integer] length how many bytes were needed.
83
+ # @param [Integer] arrived how many turned up.
84
+ # @raise [Noise::Exceptions::TruncatedMessageError] always.
85
+ def truncated!(length, arrived)
86
+ raise Noise::Exceptions::TruncatedMessageError,
87
+ "Needed #{length} bytes, the stream ended after #{arrived}."
88
+ end
89
+
90
+ # Takes whatever has arrived, which on a socket is rarely a whole frame at once.
91
+ #
92
+ # @param [Integer] length the most to take.
93
+ # @return [String, nil] the bytes, or nil at end of stream.
94
+ def read_chunk(length)
95
+ wait_readable
96
+ @io.readpartial(length)
97
+ rescue EOFError
98
+ nil
99
+ end
100
+
101
+ # Asks the IO itself to wait, rather than selecting on its file descriptor, because bytes it
102
+ # has already read and buffered are ready to be taken while the descriptor is quiet.
103
+ #
104
+ # @raise [Noise::Exceptions::ReadTimeoutError] if nothing arrives within read_timeout.
105
+ # @return [void]
106
+ def wait_readable
107
+ return if @read_timeout.nil?
108
+ return if @io.wait_readable(@read_timeout)
109
+
110
+ raise Noise::Exceptions::ReadTimeoutError,
111
+ "No more of the frame arrived within #{@read_timeout} seconds."
112
+ end
113
+
114
+ # @param [IO] io the stream this was given.
115
+ # @param [Numeric, nil] read_timeout the timeout it was given.
116
+ # @raise [ArgumentError] if the timeout could not be honoured as asked.
117
+ # @return [void]
118
+ def validate_read_timeout!(io, read_timeout)
119
+ return if read_timeout.nil?
120
+
121
+ raise ArgumentError, "read_timeout is #{read_timeout}, which is not a length of time." if read_timeout.negative?
122
+ return if io.respond_to?(:wait_readable)
123
+
124
+ raise ArgumentError,
125
+ "read_timeout cannot be honoured on a #{io.class}, which does not answer #wait_readable. " \
126
+ 'Leave it out, or pass an IO that does.'
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Noise
4
+ # The layers that put a Noise::Connection on top of an IO. A connection encrypts and decrypts
5
+ # whole messages, which is the shape the Noise specification describes but not the shape a
6
+ # socket has, so something has to say where one message ends and the next begins.
7
+ # Stream is not one of those layers but the thing they stand on: the IO, and the ways a stream
8
+ # differs from a message.
9
+ module Transport
10
+ autoload :Bolt8, 'noise/transport/bolt8'
11
+ autoload :Framed, 'noise/transport/framed'
12
+ autoload :Stream, 'noise/transport/stream'
13
+ end
14
+ end
data/lib/noise/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Noise
4
- VERSION = '0.13.0'
4
+ VERSION = '0.15.0'
5
5
  end
data/lib/noise.rb CHANGED
@@ -4,7 +4,6 @@ require 'noise/version'
4
4
 
5
5
  require 'ecdsa'
6
6
  require 'openssl'
7
- require 'rbnacl'
8
7
  require 'ruby_hmac'
9
8
  require 'securerandom'
10
9
 
@@ -16,9 +15,14 @@ module Noise
16
15
  autoload :KeyPair, 'noise/key_pair'
17
16
  autoload :Protocol, 'noise/protocol'
18
17
  autoload :Pattern, 'noise/pattern'
18
+ # Noise::Modifier and Noise::Token are declared in the same file as Noise::Pattern.
19
+ autoload :Modifier, 'noise/pattern'
20
+ autoload :Token, 'noise/pattern'
21
+ autoload :ProtocolName, 'noise/protocol_name'
19
22
  autoload :Exceptions, 'noise/exceptions'
20
23
  autoload :Functions, 'noise/functions'
21
24
  autoload :State, 'noise/state'
25
+ autoload :Transport, 'noise/transport'
22
26
 
23
27
  # Some DH and hash functions are backed by a gem, and often a system library, that is only needed
24
28
  # when the function appears in a protocol name. Loading one is therefore allowed to fail; the
data/noise.gemspec CHANGED
@@ -15,8 +15,10 @@ Gem::Specification.new do |spec|
15
15
  spec.description = 'A Ruby implementation of the Noise Protocol framework(http://noiseprotocol.org/).'
16
16
  spec.homepage = 'https://github.com/Yamaguchi/noise'
17
17
 
18
+ # interop/ holds the Rust harness the interoperability suite runs against, which is test
19
+ # material like spec/ and has no business in the packaged gem.
18
20
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
19
- f.match(%r{^(test|spec|features)/})
21
+ f.match(%r{^(test|spec|features|interop)/})
20
22
  end
21
23
  spec.bindir = 'exe'
22
24
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
@@ -30,17 +32,15 @@ Gem::Specification.new do |spec|
30
32
  spec.add_development_dependency 'simplecov'
31
33
  spec.add_development_dependency 'simplecov-json'
32
34
 
33
- # Optional backend. BLAKE3 is needed only when it appears in a protocol name, and it needs Rust
34
- # to build, so it is not a runtime dependency. Add it to your own Gemfile if you need it; see the
35
- # README.
36
- spec.add_development_dependency 'blake3'
35
+ # Optional backend. BLAKE3 is needed only when it appears in a protocol name, so it is not a
36
+ # runtime dependency. Add it to your own Gemfile if you need it; see the README.
37
+ spec.add_development_dependency 'blake3-rb'
37
38
 
38
39
  spec.add_runtime_dependency 'ecdsa'
39
- # The 448 DH function needs the raw key API (OpenSSL::PKey.new_raw_private_key and friends),
40
- # which arrived in openssl 3.0. Every supported interpreter bundles a newer default gem, but the
41
- # floor is stated so an older openssl pinned in an application's Gemfile fails to resolve rather
42
- # than failing at runtime.
40
+ # The 25519 and 448 DH functions need the raw key API (OpenSSL::PKey.new_raw_private_key and
41
+ # friends), which arrived in openssl 3.0. Every supported interpreter bundles a newer default
42
+ # gem, but the floor is stated so an older openssl pinned in an application's Gemfile fails to
43
+ # resolve rather than failing at runtime.
43
44
  spec.add_runtime_dependency 'openssl', '>= 3.0'
44
- spec.add_runtime_dependency 'rbnacl'
45
45
  spec.add_runtime_dependency 'ruby-hmac'
46
46
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: noise-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.0
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hajime Yamaguchi
@@ -94,7 +94,7 @@ dependencies:
94
94
  - !ruby/object:Gem::Version
95
95
  version: '0'
96
96
  - !ruby/object:Gem::Dependency
97
- name: blake3
97
+ name: blake3-rb
98
98
  requirement: !ruby/object:Gem::Requirement
99
99
  requirements:
100
100
  - - ">="
@@ -135,20 +135,6 @@ dependencies:
135
135
  - - ">="
136
136
  - !ruby/object:Gem::Version
137
137
  version: '3.0'
138
- - !ruby/object:Gem::Dependency
139
- name: rbnacl
140
- requirement: !ruby/object:Gem::Requirement
141
- requirements:
142
- - - ">="
143
- - !ruby/object:Gem::Version
144
- version: '0'
145
- type: :runtime
146
- prerelease: false
147
- version_requirements: !ruby/object:Gem::Requirement
148
- requirements:
149
- - - ">="
150
- - !ruby/object:Gem::Version
151
- version: '0'
152
138
  - !ruby/object:Gem::Dependency
153
139
  name: ruby-hmac
154
140
  requirement: !ruby/object:Gem::Requirement
@@ -191,6 +177,10 @@ files:
191
177
  - lib/noise/exceptions.rb
192
178
  - lib/noise/exceptions/decrypt_error.rb
193
179
  - lib/noise/exceptions/encrypt_error.rb
180
+ - lib/noise/exceptions/handshake_already_finished_error.rb
181
+ - lib/noise/exceptions/handshake_not_finished_error.rb
182
+ - lib/noise/exceptions/handshake_not_started_error.rb
183
+ - lib/noise/exceptions/handshake_turn_error.rb
194
184
  - lib/noise/exceptions/invalid_nonce_error.rb
195
185
  - lib/noise/exceptions/invalid_public_key_error.rb
196
186
  - lib/noise/exceptions/max_nonce_error.rb
@@ -201,6 +191,8 @@ files:
201
191
  - lib/noise/exceptions/noise_validation_error.rb
202
192
  - lib/noise/exceptions/protocol_name_error.rb
203
193
  - lib/noise/exceptions/psk_value_error.rb
194
+ - lib/noise/exceptions/read_timeout_error.rb
195
+ - lib/noise/exceptions/truncated_message_error.rb
204
196
  - lib/noise/exceptions/unsupported_modifier_error.rb
205
197
  - lib/noise/functions.rb
206
198
  - lib/noise/functions/cipher.rb
@@ -220,10 +212,15 @@ files:
220
212
  - lib/noise/key_pair.rb
221
213
  - lib/noise/pattern.rb
222
214
  - lib/noise/protocol.rb
215
+ - lib/noise/protocol_name.rb
223
216
  - lib/noise/state.rb
224
217
  - lib/noise/state/cipher_state.rb
225
218
  - lib/noise/state/handshake_state.rb
226
219
  - lib/noise/state/symmetric_state.rb
220
+ - lib/noise/transport.rb
221
+ - lib/noise/transport/bolt8.rb
222
+ - lib/noise/transport/framed.rb
223
+ - lib/noise/transport/stream.rb
227
224
  - lib/noise/utils/string.rb
228
225
  - lib/noise/version.rb
229
226
  - noise.gemspec