Table of Contents

1. Introduction

This specification is extending Noise revision 34[1] and Strobe v1.0.2[2]. It relies for the most part on Noise's specification, heavily modifying some of its foundations to rely on Strobe as an opaque cryptographic primitive.

Major changes between versions of Disco are listed at the end of this document.

1.1. Motivation

Noise[1] is a framework for crypto protocols based on the Diffie-Hellman key agreement. One of Noise's property is to authenticate the protocol transcript by continuously hashing messages being sent and received, as well as continuously deriving new keys based on the output of key exchanges and previously derived keys. This interesting property stops at the end of the handshake.
Strobe[2] is a protocol framework based on a duplex construction[3]. It naturally benefits from similar property, effectively absorbing every operation to influence the next ones. The Strobe specification is comparable in aspect to Noise, but focuses only on the symmetric parts of a protocol. By merging both protocol frameworks into one, Disco achieves the following goals:

1.2. How to Read This Document and Implement Disco

To implement the Disco extension, a Strobe implementation respecting the functions of the section 3 of this document is required. None of the cipher and hash functions of Noise are required. Furthermore, the CipherState is not necessary while the SymmetricState has been simplified by Strobe calls. When implementing Noise with the Disco extension, simply ignore the CipherState section of Noise and implement the SymmetricState described in section 5 of this document. For PSK handshakes see section 6 and for advanced features, refer to section 7.

Note that like the Noise protocol framework, additional layers might need to be added on top of Disco for it to be usable (for example a framing layer to indicate the messages' lengths). For more information see Noise's section 13 on application responsabilities.

2. Protocol naming

The name of a Noise protocol extended with Disco follows the same convention, but replaces the symmetric cryptographic algorithms by the version of Strobe used:


For example, with the current version of Strobe[2] being STROBEv1.0.2:


3. The StrobeState object

A StrobeState depends on a Strobe object (as defined in section 5 of the Strobe Specification) as well as the following associated constant:

While a Strobe object responds to many functions (see Strobe's specification[4]), only the following ones need to be implemented in order for the Disco extension to work properly:

InitializeStrobe(protocol_name): Initialize the Strobe object with a custom protocol name.

KEY(key): Permutes the Strobe's state and replaces the new state with the key.

PRF(output_len): Permutes the Strobe's state and removes output_len bytes from the new state. Outputs the removed bytes to the caller.

send_ENC(plaintext): Permutes the Strobe's state and XOR the plaintext with the new state to encrypt it. The new state is replaced by the resulting ciphertext, while the resulting ciphertext is output to the caller.

recv_ENC(ciphertext): Permutes the Strobe's state and XOR the ciphertext with the new state to decrypt it. The new state is replaced by the ciphertext, while the resulting plaintext is output to the caller.

AD(additionalData): Absorbs the additional data in the Strobe's state.

send_MAC(output_length): Permutes the Strobe's state and retrieves the next output_length bytes from the new state.

recv_MAC(tag): Permutes the Strobe's state and compare (in constant-time) the received tag with the next 16 bytes from the new state.

RATCHET(length): Permutes the Strobe's state and set the next length bytes from the new state to zero.

The following meta functions:

meta_AD(additionalData): XOR the additional data in the Strobe's state.

The following function which is not specified in Strobe:

Clone(): Returns a copy of the Strobe state.

4. Post-handshake phase and modifications to the Handshake State

Processing the final handshake message via WriteMessage() and ReadMessage() now returns two new StrobeState objects by calling Split(). The first for encrypting transport messages from initiator to responder, and the second for messages in the other direction. At this point the StrobeState of the SymmetricState should not be deleted as it is the first StrobeState object returned by Split() (and will be used by the initiator to encrypt messages).

The peers can then encrypt (resp. decrypt) messages by calling send_ENC followed by send_MAC (resp. recv_ENC followed by recv_MAC) on the relevant StrobeState object.

5. Modifications to the Symmetric State

A SymmetricState object contains:

A SymmetricState responds to the following functions:

InitializeSymmetric(protocol_name): Calls InitializeStrobe(protocol_name) on the Strobe state.

MixKey(input_key_material): Calls AD(input_key_material) on the Strobe state. It then sets isKeyed to true.

MixHash(data): Calls AD(data) on the Strobe state.

MixKeyAndHash(input_key_material): Calls AD(input_key_material) on the Strobe state.

GetHandshakeHash(): Calls PRF(32). This function should only be called at the end of a handshake, i.e. after the Split() function has been called. This function is used for channel binding, as described in Section 11.2 of the Noise specification.

EncryptAndHash(plaintext): Returns a ready to be sent payload to the caller by following these steps:

DecryptAndHash(ciphertext): Returns the received payload by following steps:

Split(): Returns a pair of Strobe states for encrypting transport messages by executing the following steps:

6. Modifications to pre-shared symmetric keys

For PSK handshakes, the "e" token does not need to call MixKey(e.public_key). Hence, no further modifications to the Symmetric State functions are needed for such handshakes.

7. Modifications to Advanced Features

7.1 Channel Binding

Right before calling Split(), a binding value could be obtained from the StrobeState by calling PRF().

7.2 Rekey

To enable this, Strobe supports a RATCHET() function.

7.3 Out-of-order transport messages

In order to build out-of-order protocols out of Disco, the Split() function must return nonce-based objects. For this, the Split() function is modified in the next section to return a pair of DiscoSecureChannel objects which are defined in the section following it.

Transport messages are then encrypted and decrypted by calling Encrypt() and Decrypt() on the relevant DiscoSecureChannel.

7.3.1 Modifications to the Split() function

Modify the Split() function to add the following steps before returning the pair (s1, s2) of Strobe objects:

7.3.2 Modifications to the CipherState object

A CipherState can encrypt and decrypt data based on its associated StrobeState object as well as the following variable:

A CipherState responds to the following functions:

EncryptWithAd(ad, plaintext):

DecryptWithAd(ad, ciphertext)::

Rekey(): calls RATCHET(16) on the Strobe Object.

7.4 Half-duplex protocols

To use Disco in half-duplex mode, modify Split() to return the StrobeState without modifications.

The same security considerations from the Noise specification applies to this section: if the two peers do not properly take turns to write and read on the channel, the protocol will fail catastrophically.

8. Security Considerations

The same security considerations that apply to both Noise and Strobe are to be considered.

9. Acknowledgements

Thanks to Trevor Perrin and Mike Hamburg for being the foundations and main help in building this specification.

Thanks to Trevor Perrin again for suggesting the name to this extension.

10. Change log

this section will be removed in the final document






11. References

[1] Trevor Perrin, “Noise protocol framework.” 2017.

[2] Mike Hamburg, “The STROBE protocol framework.” Cryptology ePrint Archive, Report 2017/003, 2017.

[3] G. Bertoni, J. Daemen, M. Peeters, and G. V. Assche, “Duplexing the sponge: Single-pass authenticated encryption and other applications.” Cryptology ePrint Archive, Report 2011/499, 2011.

[4] Mike Hamburg, “The STROBE protocol framework specification.” 2017.