syntax = "proto3"; package quilibrium.node.channel.pb; option go_package = "source.quilibrium.com/quilibrium/monorepo/node/protobufs"; import "keys.proto"; // Describes a general channel envelope for a message. message P2PChannelEnvelope { // A general protocol identifier as a uint32 – this is expected to rarely // iterate, and should be uniquely identifying both protocol and version. // Pragmatically speaking, this implies that the least significant byte // specifies version (which should iterate most minimally), and the three most // significant bytes should specify protocol. Recipients SHOULD ignore // messages with incompatible protocol identifiers, but also SHOULD warn on // identifiers with versions higher than the supported protocol. A large // number of unsupported protocol messages may indicate spam/some other // attack, whereas a large number of unsupported protocol versions may // indicate an out of date client, respective to which side is the maximum of // the version number. uint32 protocol_identifier = 1; // The encrypted message header. Message header encryption is mandatory – // P2P channels in some cases pre-empt the mixnet and leaky information from // unencrypted message headers could de-anonymize the recipient. It is thus // also mandatory at the protocol implementation level that header sizes are // consistent within a protocol so as to not leak metadata. An example of this // is in Double and Triple-Ratchet, where the sequence identifiers MUST be // encoded as fixed-length integers, as variable encoding can indicate a // message being in the first 256, 65,536, etc. if an exchange is highly // asymmetrical in sends/receives. This is especially critical in long // running protocols with a need for fixed length messages (see message_body // notes). MessageCiphertext message_header = 2; // The encrypted message body. Message bodies are variable length – ciphertext // could range widely, however if this metadata is pertinent to determining // protocol state, such as knowing what round an encapsulated protocol is in, // or potentially what might be transferred over the protocol, protocol // implementers SHOULD utilize chunking and send fixed length messages. // Additionally, if rounds themselves are highly asymmetric or have // long-standing processing times that could dangerously leak information of // round state, implementers SHOULD defer protocol use to leverage the mixnet. // If this is not feasible, the implementation details are left up to the // exercise of the protocol author. MessageCiphertext message_body = 3; } // Describes a general ciphertext payload. message MessageCiphertext { // The intialization vector used for encryption. While cipher specific, // typically this should be a unique value for every ciphertext. If this is // not the case for a protocol where it should be, this SHOULD be considered // an invalid message and warned, as it could either indicate compromise, // or a faulty cryptographic implementation – such as a faulty PKCS#11 // implementation that has a code path to handle HSM vendors which mandate // zeroed IVs before passing into encryption methods, as they will update the // IV within the HSM through hardware-supplied entropy. bytes initialization_vector = 1; // The raw ciphertext byte string. This will be cipher specific, however some // general attributes are expected to be followed. If there is a common // layout expected, such as AES-GCM having the GCM tag appended to the // ciphertext, please follow the common layout. bytes ciphertext = 2; // The associated data byte string, if available. This will be highly protocol // specific, but SHOULD NOT leak metadata. bytes associated_data = 3; } // Describes the announcement of a new proving key. message ProvingKeyAnnouncement { // The commitment to a Schnorr proof of the Identity Key. The commitment is // produced by taking a hash of the C and S components of the proof. bytes identity_commitment = 1; // The commitment to a Schnorr proof of the Signed Pre Key. The commitment is // produced by taking a hash of the C and S components of the proof. bytes prekey_commitment = 2; oneof proving_key_signature { quilibrium.node.keys.pb.Ed448Signature proving_key_signature_ed448 = 3; } } // Represents a request for a proving key. message ProvingKeyRequest { bytes proving_key_bytes = 1; } // Describes the aggregation of inclusion commitments for a given clock frame message InclusionAggregateProof { // The filter in which the inclusion proof was produced. bytes filter = 1; // The frame number in which the inclusion proof was added. uint64 frame_number = 2; // The collection of inclusion commitments, in order. repeated InclusionCommitment inclusion_commitments = 3; // The raw serialized proof, mirroring the type of commitment scheme used // within the inclusion proofs. bytes proof = 4; } // Describes the commitment of a data's inclusion in a given clock frame message InclusionCommitment { // The filter in which the inclusion aggregate proof was produced. bytes filter = 1; // The frame number in which the inclusion aggregate proof was added. uint64 frame_number = 2; // The position of the data in the proof. uint32 position = 3; // The specific type url represented by the data. string type_url = 4; // The raw serialized data as incorporated into the inclusion proof. Due to // the non-deterministic nature of protobuf serialization, this data is an // opaque binary string so that inclusion proofs can be accurately assessed // between various node implementations, and retain forwards-compatibility // with additional properties in future revisions to types. bytes data = 5; // The raw serialized commitment. Similar to data, this commitment data is an // opaque binary string so that future commitment types can be added without // having to break the underlying inclusion structure. bytes commitment = 6; } // Describes the announcement of both an identity key and signed pre key. This // is expected to be used for the initial announcement of a key bundle, and // subsequent full revocations if identity key and signed pre keys are both // suspected of/known to be compromised. Signatures under KeyBundleAnnouncement // are expected to be cross-signed, such that the signature on the identity key // is produced through the prover key, the signature on the signed pre key is // produced through the identity key. ProvingKeyAnnouncements may be repeated // whenever a key bundle update is expected – only the first proving key // announcement is retained in inclusion proofs, but the announcements // necessarily are required for key bundle updates, as they provide a commitment // to the updated keys' Schnorr proofs. An updated KeyBundleAnnouncement must // be captured in an inclusion proof before it may be used for communication // channels, and may only be used in communication channels once a lobby has // opened _after_ the inclusion proof. If a lobby is open during the time the // inclusion proof has been created, the announcement is not yet considered // valid. message KeyBundleAnnouncement { IdentityKey identity_key = 1; SignedPreKey signed_pre_key = 2; bytes proving_key_bytes = 3; } // Describes the Identity Key and corresponding Schnorr proof. Schnorr proofs // are expected to mirror the EC parameters of the proving and identity key. If // they do not, validation will fail. message IdentityKey { // The C component of the Schnorr proof, serialized as big endian. bytes challenge = 1; // The S component of the Schnorr proof, serialized as big endian. bytes response = 2; // The Statement component of the Schnorr proof, serialized as an (compressed, // if possible) affine representation of the point. bytes statement = 3; oneof identity_key_signature { quilibrium.node.keys.pb.Ed448Signature public_key_signature_ed448 = 4; } } // Describes the Signed Pre Key and corresponding Schnorr proof. Schnorr proofs // are expected to mirror the EC parameters of the identity and signed pre key. // If they do not, validation will fail. message SignedPreKey { // The C component of the Schnorr proof, serialized as big endian. bytes challenge = 1; // The S component of the Schnorr proof, serialized as big endian. bytes response = 2; // The Statement component of the Schnorr proof, serialized as an (compressed, // if possible) affine representation of the point. bytes statement = 3; oneof signed_pre_key_signature { quilibrium.node.keys.pb.Ed448Signature public_key_signature_ed448 = 4; } }