diff --git a/.protolint.yaml b/.protolint.yaml index 782a29e2..757fac79 100644 --- a/.protolint.yaml +++ b/.protolint.yaml @@ -56,7 +56,7 @@ lint: # INDENT rule option. indent: # Available styles are 4(4-spaces), 2(2-spaces) or tab. - style: 4 + style: 2 # Specifies if it should stop considering and inserting new lines at the appropriate positions # when the inner elements are on the same line. Default is false. not_insert_newline: true diff --git a/.vscode/settings.json b/.vscode/settings.json index 269fe736..7911ace8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,10 +1,12 @@ { - "protoc": { - "compile_on_save": false, - "options": [ - "--proto_path=build/tmp/vendor", - ] - }, - // protolint complains if lines are longer than length 80, display a ruler - "editor.rulers": [80] + "protoc": { + "compile_on_save": false, + "options": ["--proto_path=build/tmp/vendor"] + }, + "[proto3]": { + "editor.defaultFormatter": "bufbuild.vscode-buf", + "editor.formatOnSave": true + }, + // protolint complains if lines are longer than length 80, display a ruler + "editor.rulers": [80] } diff --git a/proto/keystore_api/v1/keystore.proto b/proto/keystore_api/v1/keystore.proto index caad1144..031c117f 100644 --- a/proto/keystore_api/v1/keystore.proto +++ b/proto/keystore_api/v1/keystore.proto @@ -14,223 +14,223 @@ option java_package = "org.xmtp.proto.keystore.api.v1"; // Application-specific error codes for the Keystore API. enum ErrorCode { - ERROR_CODE_UNSPECIFIED = 0; - ERROR_CODE_INVALID_INPUT = 1; - ERROR_CODE_NO_MATCHING_PREKEY = 2; + ERROR_CODE_UNSPECIFIED = 0; + ERROR_CODE_INVALID_INPUT = 1; + ERROR_CODE_NO_MATCHING_PREKEY = 2; } // Wrapper class for errors from the Keystore API message KeystoreError { - string message = 1; - ErrorCode code = 2; + string message = 1; + ErrorCode code = 2; } // Decrypt a batch of messages using X3DH key agreement message DecryptV1Request { - // A single decryption request - message Request { - xmtp.message_contents.Ciphertext payload = 1; - xmtp.message_contents.PublicKeyBundle peer_keys = 2; - bytes header_bytes = 3; - bool is_sender = 4; - } + // A single decryption request + message Request { + xmtp.message_contents.Ciphertext payload = 1; + xmtp.message_contents.PublicKeyBundle peer_keys = 2; + bytes header_bytes = 3; + bool is_sender = 4; + } - repeated Request requests = 1; + repeated Request requests = 1; } // Response type for both V1 and V2 decryption requests message DecryptResponse { - // A single decryption response - message Response { - // Wrapper object for success response - message Success { - bytes decrypted = 1; - } - - oneof response { - Success result = 1; - KeystoreError error = 2; - } + // A single decryption response + message Response { + // Wrapper object for success response + message Success { + bytes decrypted = 1; + } + + oneof response { + Success result = 1; + KeystoreError error = 2; } + } - repeated Response responses = 1; + repeated Response responses = 1; } // Decrypt a batch of messages using the appropriate topic keys message DecryptV2Request { - // A single decryption request - message Request { - xmtp.message_contents.Ciphertext payload = 1; - bytes header_bytes = 2; - string content_topic = 3; - } + // A single decryption request + message Request { + xmtp.message_contents.Ciphertext payload = 1; + bytes header_bytes = 2; + string content_topic = 3; + } - repeated Request requests = 1; + repeated Request requests = 1; } // Encrypt a batch of messages using X3DH key agreement message EncryptV1Request { - // A single encryption request - message Request { - xmtp.message_contents.PublicKeyBundle recipient = 1; - bytes payload = 2; - bytes header_bytes = 3; - } + // A single encryption request + message Request { + xmtp.message_contents.PublicKeyBundle recipient = 1; + bytes payload = 2; + bytes header_bytes = 3; + } - repeated Request requests = 1; + repeated Request requests = 1; } // Response type for both V1 and V2 encryption requests message EncryptResponse { - // A single encryption response - message Response { - // Wrapper object for success response - message Success { - xmtp.message_contents.Ciphertext encrypted = 1; - } - - oneof response { - Success result = 1; - KeystoreError error = 2; - } + // A single encryption response + message Response { + // Wrapper object for success response + message Success { + xmtp.message_contents.Ciphertext encrypted = 1; + } + + oneof response { + Success result = 1; + KeystoreError error = 2; } + } - repeated Response responses = 1; + repeated Response responses = 1; } // Encrypt a batch of messages using the appropriate topic keys message EncryptV2Request { - // A single encryption request - message Request { - bytes payload = 1; - bytes header_bytes = 2; - string content_topic = 3; - } + // A single encryption request + message Request { + bytes payload = 1; + bytes header_bytes = 2; + string content_topic = 3; + } - repeated Request requests = 1; + repeated Request requests = 1; } // Request to create an invite payload, and store the topic keys in the Keystore message CreateInviteRequest { - xmtp.message_contents.InvitationV1.Context context = 1; - xmtp.message_contents.SignedPublicKeyBundle recipient = 2; - uint64 created_ns = 3; + xmtp.message_contents.InvitationV1.Context context = 1; + xmtp.message_contents.SignedPublicKeyBundle recipient = 2; + uint64 created_ns = 3; } // Request to create an invite payload from an existing topic, and store the // topic keys in the Keystore message CreateInviteFromTopicRequest { - xmtp.message_contents.SignedPublicKeyBundle recipient = 1; - string content_topic = 2; - uint64 created_ns = 3; + xmtp.message_contents.SignedPublicKeyBundle recipient = 1; + string content_topic = 2; + uint64 created_ns = 3; } // Request to create an invite payload, and store the topic keys in the Keystore message CreateInvitesRequest { - xmtp.message_contents.InvitationV1.Context context = 1; - repeated xmtp.message_contents.SignedPublicKeyBundle recipients = 2; - uint64 created_ns = 3; + xmtp.message_contents.InvitationV1.Context context = 1; + repeated xmtp.message_contents.SignedPublicKeyBundle recipients = 2; + uint64 created_ns = 3; } // Response to a CreateInviteRequest message CreateInviteResponse { - xmtp.message_contents.ConversationReference conversation = 1; - bytes payload = 2; + xmtp.message_contents.ConversationReference conversation = 1; + bytes payload = 2; } // Response to a CreateInvitesRequest message CreateInvitesResponse { - repeated CreateInviteResponse responses = 1; + repeated CreateInviteResponse responses = 1; } // Request to save a batch of invite messages to the Keystore message SaveInvitesRequest { - // Mirrors xmtp.envelope schema - message Request { - string content_topic = 1; - uint64 timestamp_ns = 2; - bytes payload = 3; - } + // Mirrors xmtp.envelope schema + message Request { + string content_topic = 1; + uint64 timestamp_ns = 2; + bytes payload = 3; + } - repeated Request requests = 1; + repeated Request requests = 1; } // Response to a SaveInvitesRequest message SaveInvitesResponse { - // A single response - message Response { - // Wrapper object for success response - message Success { - xmtp.message_contents.ConversationReference conversation = 1; - } - - oneof response { - Success result = 1; - KeystoreError error = 2; - } + // A single response + message Response { + // Wrapper object for success response + message Success { + xmtp.message_contents.ConversationReference conversation = 1; } - repeated Response responses = 1; + oneof response { + Success result = 1; + KeystoreError error = 2; + } + } + + repeated Response responses = 1; } // CreateAuthTokenRequest is used to create an auth token for the XMTP API message CreateAuthTokenRequest { - optional uint64 timestamp_ns = 1; + optional uint64 timestamp_ns = 1; } // Response for GetV2Conversations message GetV2ConversationsResponse { - repeated xmtp.message_contents.ConversationReference conversations = 1; + repeated xmtp.message_contents.ConversationReference conversations = 1; } // Used to check if the Keystore implementation has been setup for the given // wallet address Only used for MM Snap Keystore currently message GetKeystoreStatusRequest { - string wallet_address = 1; + string wallet_address = 1; } // Response to GetKeystoreStatusRequest message GetKeystoreStatusResponse { - // Status of the Keystore for the specified wallet address - enum KeystoreStatus { - KEYSTORE_STATUS_UNSPECIFIED = 0; - KEYSTORE_STATUS_UNINITIALIZED = 1; - KEYSTORE_STATUS_INITIALIZED = 2; - } + // Status of the Keystore for the specified wallet address + enum KeystoreStatus { + KEYSTORE_STATUS_UNSPECIFIED = 0; + KEYSTORE_STATUS_UNINITIALIZED = 1; + KEYSTORE_STATUS_INITIALIZED = 2; + } - KeystoreStatus status = 1; + KeystoreStatus status = 1; } // Used to initialize the Keystore with a private key bundle retrieved from the // client message InitKeystoreRequest { - oneof bundle { - xmtp.message_contents.PrivateKeyBundleV1 v1 = 1; - } + oneof bundle { + xmtp.message_contents.PrivateKeyBundleV1 v1 = 1; + } } // Response to the request to initialize the Keystore message InitKeystoreResponse { - KeystoreError error = 1; + KeystoreError error = 1; } // SignDigestRequest is used to sign a digest with either the identity key // or a prekey message SignDigestRequest { - bytes digest = 1; - oneof signer { - bool identity_key = 2; - uint32 prekey_index = 3; - } + bytes digest = 1; + oneof signer { + bool identity_key = 2; + uint32 prekey_index = 3; + } } // A mapping of topics to their decrypted invitations message TopicMap { - // TopicData wraps the invitation and the timestamp it was created - message TopicData { - uint64 created_ns = 1; - string peer_address = 2; - xmtp.message_contents.InvitationV1 invitation = 3; - } - map topics = 1; -} \ No newline at end of file + // TopicData wraps the invitation and the timestamp it was created + message TopicData { + uint64 created_ns = 1; + string peer_address = 2; + xmtp.message_contents.InvitationV1 invitation = 3; + } + map topics = 1; +} diff --git a/proto/message_api/v1/authn.proto b/proto/message_api/v1/authn.proto index 38a37008..724e1df8 100644 --- a/proto/message_api/v1/authn.proto +++ b/proto/message_api/v1/authn.proto @@ -11,12 +11,12 @@ option java_package = "org.xmtp.proto.message.api.v1"; // Token is used by clients to prove to the nodes // that they are serving a specific wallet. message Token { - // identity key signed by a wallet - xmtp.message_contents.PublicKey identity_key = 1; - // encoded bytes of AuthData - bytes auth_data_bytes = 2; - // identity key signature of AuthData bytes - xmtp.message_contents.Signature auth_data_signature = 3; + // identity key signed by a wallet + xmtp.message_contents.PublicKey identity_key = 1; + // encoded bytes of AuthData + bytes auth_data_bytes = 2; + // identity key signature of AuthData bytes + xmtp.message_contents.Signature auth_data_signature = 3; } // AuthData carries token parameters that are authenticated @@ -25,8 +25,8 @@ message Token { // so that the bytes don't need to be reconstructed // to verify the token signature. message AuthData { - // address of the wallet - string wallet_addr = 1; - // time when the token was generated/signed - uint64 created_ns = 2; + // address of the wallet + string wallet_addr = 1; + // time when the token was generated/signed + uint64 created_ns = 2; } diff --git a/proto/message_api/v1/message_api.proto b/proto/message_api/v1/message_api.proto index d571d5fe..bf8cf083 100644 --- a/proto/message_api/v1/message_api.proto +++ b/proto/message_api/v1/message_api.proto @@ -8,106 +8,105 @@ import "protoc-gen-openapiv2/options/annotations.proto"; option go_package = "github.com/xmtp/proto/v3/go/message_api/v1"; option java_package = "org.xmtp.proto.message.api.v1"; option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { - info: { title: "MessageApi"; -version: "1.0"; -} -; -} -; + info: { + title: "MessageApi"; + version: "1.0"; + }; +}; // RPC service MessageApi { - // Publish messages to the network - rpc Publish(PublishRequest) returns (PublishResponse) { - option (google.api.http) = { - post: "/message/v1/publish" - body: "*" - }; - } - // Subscribe to a stream of new envelopes matching a predicate - rpc Subscribe(SubscribeRequest) returns (stream Envelope) { - option (google.api.http) = { - post: "/message/v1/subscribe" - body: "*" - }; - } - // Subscribe to a stream of new envelopes and your subscription using - // bidirectional streaming - // protolint:disable:next RPC_REQUEST_STANDARD_NAME - rpc Subscribe2(stream SubscribeRequest) returns (stream Envelope) {} - // Subscribe to a stream of all messages - rpc SubscribeAll(SubscribeAllRequest) returns (stream Envelope) { - option (google.api.http) = { - post: "/message/v1/subscribe-all" - body: "*" - }; - } - // Query the store for messages - rpc Query(QueryRequest) returns (QueryResponse) { - option (google.api.http) = { - post: "/message/v1/query" - body: "*" - }; - } - // BatchQuery containing a set of queries to be processed - rpc BatchQuery(BatchQueryRequest) returns (BatchQueryResponse) { - option (google.api.http) = { - post: "/message/v1/batch-query" - body: "*" - }; - } + // Publish messages to the network + rpc Publish(PublishRequest) returns (PublishResponse) { + option (google.api.http) = { + post: "/message/v1/publish" + body: "*" + }; + } + // Subscribe to a stream of new envelopes matching a predicate + rpc Subscribe(SubscribeRequest) returns (stream Envelope) { + option (google.api.http) = { + post: "/message/v1/subscribe" + body: "*" + }; + } + // Subscribe to a stream of new envelopes and your subscription using + // bidirectional streaming + // protolint:disable:next RPC_REQUEST_STANDARD_NAME + rpc Subscribe2(stream SubscribeRequest) returns (stream Envelope) {} + // Subscribe to a stream of all messages + rpc SubscribeAll(SubscribeAllRequest) returns (stream Envelope) { + option (google.api.http) = { + post: "/message/v1/subscribe-all" + body: "*" + }; + } + // Query the store for messages + rpc Query(QueryRequest) returns (QueryResponse) { + option (google.api.http) = { + post: "/message/v1/query" + body: "*" + }; + } + // BatchQuery containing a set of queries to be processed + rpc BatchQuery(BatchQueryRequest) returns (BatchQueryResponse) { + option (google.api.http) = { + post: "/message/v1/batch-query" + body: "*" + }; + } } // Sort direction enum SortDirection { - SORT_DIRECTION_UNSPECIFIED = 0; - SORT_DIRECTION_ASCENDING = 1; - SORT_DIRECTION_DESCENDING = 2; + SORT_DIRECTION_UNSPECIFIED = 0; + SORT_DIRECTION_ASCENDING = 1; + SORT_DIRECTION_DESCENDING = 2; } // This is based off of the go-waku Index type, but with the // receiverTime and pubsubTopic removed for simplicity. // Both removed fields are optional message IndexCursor { - bytes digest = 1; - uint64 sender_time_ns = 2; + bytes digest = 1; + uint64 sender_time_ns = 2; } // Wrapper for potentially multiple types of cursor message Cursor { - // Making the cursor a one-of type, as I would like to change the way we - // handle pagination to use a precomputed sort field. - // This way we can handle both methods - oneof cursor { - IndexCursor index = 1; - } + // Making the cursor a one-of type, as I would like to change the way we + // handle pagination to use a precomputed sort field. + // This way we can handle both methods + oneof cursor { + IndexCursor index = 1; + } } // This is based off of the go-waku PagingInfo struct, but with the direction // changed to our SortDirection enum format message PagingInfo { - // Note: this is a uint32, while go-waku's pageSize is a uint64 - uint32 limit = 1; - Cursor cursor = 2; - SortDirection direction = 3; + // Note: this is a uint32, while go-waku's pageSize is a uint64 + uint32 limit = 1; + Cursor cursor = 2; + SortDirection direction = 3; } // Envelope encapsulates a message while in transit. message Envelope { - // The topic the message belongs to, - // If the message includes the topic as well - // it MUST be the same as the topic in the envelope. - string content_topic = 1; - // Message creation timestamp - // If the message includes the timestamp as well - // it MUST be equivalent to the timestamp in the envelope. - uint64 timestamp_ns = 2; - bytes message = 3; + // The topic the message belongs to, + // If the message includes the topic as well + // it MUST be the same as the topic in the envelope. + string content_topic = 1; + // Message creation timestamp + // If the message includes the timestamp as well + // it MUST be equivalent to the timestamp in the envelope. + uint64 timestamp_ns = 2; + bytes message = 3; } // Publish message PublishRequest { - repeated Envelope envelopes = 1; + repeated Envelope envelopes = 1; } // Empty message as a response for Publish @@ -115,7 +114,7 @@ message PublishResponse {} // Subscribe message SubscribeRequest { - repeated string content_topics = 1; + repeated string content_topics = 1; } // SubscribeAll @@ -123,24 +122,24 @@ message SubscribeAllRequest {} // Query message QueryRequest { - repeated string content_topics = 1; - uint64 start_time_ns = 2; - uint64 end_time_ns = 3; - PagingInfo paging_info = 4; + repeated string content_topics = 1; + uint64 start_time_ns = 2; + uint64 end_time_ns = 3; + PagingInfo paging_info = 4; } // The response, containing envelopes, for a query message QueryResponse { - repeated Envelope envelopes = 1; - PagingInfo paging_info = 2; + repeated Envelope envelopes = 1; + PagingInfo paging_info = 2; } // BatchQuery message BatchQueryRequest { - repeated QueryRequest requests = 1; + repeated QueryRequest requests = 1; } // Response containing a list of QueryResponse messages message BatchQueryResponse { - repeated QueryResponse responses = 1; + repeated QueryResponse responses = 1; } diff --git a/proto/message_contents/ciphertext.proto b/proto/message_contents/ciphertext.proto index fc63a32a..98cb59c5 100644 --- a/proto/message_contents/ciphertext.proto +++ b/proto/message_contents/ciphertext.proto @@ -13,33 +13,33 @@ option java_package = "org.xmtp.proto.message.contents"; // The payload is accompanied by the cryptographic parameters // required by the chosen encryption scheme. message Ciphertext { - oneof union { - Aes256gcmHkdfsha256 aes256_gcm_hkdf_sha256 = 1; - } - - // Supported Encryption Schemes - - // Encryption: AES256-GCM - // Key derivation function: HKDF-SHA256 - message Aes256gcmHkdfsha256 { - bytes hkdf_salt = 1; // 32 bytes - bytes gcm_nonce = 2; // 12 bytes - bytes payload = 3; // encrypted payload - } + oneof union { + Aes256gcmHkdfsha256 aes256_gcm_hkdf_sha256 = 1; + } + + // Supported Encryption Schemes + + // Encryption: AES256-GCM + // Key derivation function: HKDF-SHA256 + message Aes256gcmHkdfsha256 { + bytes hkdf_salt = 1; // 32 bytes + bytes gcm_nonce = 2; // 12 bytes + bytes payload = 3; // encrypted payload + } } // SignedEciesCiphertext represents an ECIES encrypted payload and a signature message SignedEciesCiphertext { - // Ecies is ciphertext encrypted using ECIES with a MAC - message Ecies { - bytes ephemeral_public_key = 1; // 65 bytes - bytes iv = 2; // 16 bytes - bytes mac = 3; // 32 bytes - bytes ciphertext = 4; // encrypted payload with block size of 16 - } - - // serialized Ecies message - bytes ecies_bytes = 1; - // signature of sha256(ecies_bytes) signed with the IdentityKey - xmtp.message_contents.Signature signature = 2; -} \ No newline at end of file + // Ecies is ciphertext encrypted using ECIES with a MAC + message Ecies { + bytes ephemeral_public_key = 1; // 65 bytes + bytes iv = 2; // 16 bytes + bytes mac = 3; // 32 bytes + bytes ciphertext = 4; // encrypted payload with block size of 16 + } + + // serialized Ecies message + bytes ecies_bytes = 1; + // signature of sha256(ecies_bytes) signed with the IdentityKey + xmtp.message_contents.Signature signature = 2; +} diff --git a/proto/message_contents/composite.proto b/proto/message_contents/composite.proto index 464f3a11..9a23239e 100644 --- a/proto/message_contents/composite.proto +++ b/proto/message_contents/composite.proto @@ -10,13 +10,13 @@ option java_package = "org.xmtp.proto.message.contents"; // Composite is used to implement xmtp.org/composite content type message Composite { - // Part represents one section of a composite message - message Part { - oneof element { - EncodedContent part = 1; - Composite composite = 2; - } + // Part represents one section of a composite message + message Part { + oneof element { + EncodedContent part = 1; + Composite composite = 2; } + } - repeated Part parts = 1; + repeated Part parts = 1; } diff --git a/proto/message_contents/contact.proto b/proto/message_contents/contact.proto index 3f31a02a..3a3ed627 100644 --- a/proto/message_contents/contact.proto +++ b/proto/message_contents/contact.proto @@ -15,18 +15,18 @@ option java_package = "org.xmtp.proto.message.contents"; // LEGACY: User key bundle V1 using PublicKeys. // The PublicKeys MUST be signed. message ContactBundleV1 { - PublicKeyBundle key_bundle = 1; + PublicKeyBundle key_bundle = 1; } // User key bundle V2 using SignedPublicKeys. message ContactBundleV2 { - SignedPublicKeyBundle key_bundle = 1; + SignedPublicKeyBundle key_bundle = 1; } // Versioned ContactBundle message ContactBundle { - oneof version { - ContactBundleV1 v1 = 1; - ContactBundleV2 v2 = 2; - } + oneof version { + ContactBundleV1 v1 = 1; + ContactBundleV2 v2 = 2; + } } diff --git a/proto/message_contents/content.proto b/proto/message_contents/content.proto index 14c1de64..29251e0e 100644 --- a/proto/message_contents/content.proto +++ b/proto/message_contents/content.proto @@ -11,45 +11,45 @@ option java_package = "org.xmtp.proto.message.contents"; // ContentTypeId is used to identify the type of content stored in a Message. message ContentTypeId { - string authority_id = 1; // authority governing this content type - string type_id = 2; // type identifier - uint32 version_major = 3; // major version of the type - uint32 version_minor = 4; // minor version of the type + string authority_id = 1; // authority governing this content type + string type_id = 2; // type identifier + uint32 version_major = 3; // major version of the type + uint32 version_minor = 4; // minor version of the type } // Recognized compression algorithms // protolint:disable ENUM_FIELD_NAMES_ZERO_VALUE_END_WITH enum Compression { - COMPRESSION_DEFLATE = 0; - COMPRESSION_GZIP = 1; + COMPRESSION_DEFLATE = 0; + COMPRESSION_GZIP = 1; } // protolint:enable ENUM_FIELD_NAMES_ZERO_VALUE_END_WITH // EncodedContent bundles the content with metadata identifying its type // and parameters required for correct decoding and presentation of the content. message EncodedContent { - // content type identifier used to match the payload with - // the correct decoding machinery - ContentTypeId type = 1; - // optional encoding parameters required to correctly decode the content - map parameters = 2; - // optional fallback description of the content that can be used in case - // the client cannot decode or render the content - optional string fallback = 3; - // optional compression; the value indicates algorithm used to - // compress the encoded content bytes - optional Compression compression = 5; - // encoded content itself - bytes content = 4; + // content type identifier used to match the payload with + // the correct decoding machinery + ContentTypeId type = 1; + // optional encoding parameters required to correctly decode the content + map parameters = 2; + // optional fallback description of the content that can be used in case + // the client cannot decode or render the content + optional string fallback = 3; + // optional compression; the value indicates algorithm used to + // compress the encoded content bytes + optional Compression compression = 5; + // encoded content itself + bytes content = 4; } // SignedContent attaches a signature to EncodedContent. message SignedContent { - // MUST contain EncodedContent - bytes payload = 1; - SignedPublicKeyBundle sender = 2; - // MUST be a signature of a concatenation of - // the message header bytes and the payload bytes, - // signed by the sender's pre-key. - Signature signature = 3; + // MUST contain EncodedContent + bytes payload = 1; + SignedPublicKeyBundle sender = 2; + // MUST be a signature of a concatenation of + // the message header bytes and the payload bytes, + // signed by the sender's pre-key. + Signature signature = 3; } diff --git a/proto/message_contents/conversation_reference.proto b/proto/message_contents/conversation_reference.proto index 6ec83304..7beec75f 100644 --- a/proto/message_contents/conversation_reference.proto +++ b/proto/message_contents/conversation_reference.proto @@ -10,8 +10,8 @@ option java_package = "org.xmtp.proto.message.contents"; // A light pointer for a conversation that contains no decryption keys message ConversationReference { - string topic = 1; - string peer_address = 2; - uint64 created_ns = 3; - xmtp.message_contents.InvitationV1.Context context = 4; + string topic = 1; + string peer_address = 2; + uint64 created_ns = 3; + xmtp.message_contents.InvitationV1.Context context = 4; } diff --git a/proto/message_contents/ecies.proto b/proto/message_contents/ecies.proto index f6939a62..47489421 100644 --- a/proto/message_contents/ecies.proto +++ b/proto/message_contents/ecies.proto @@ -8,8 +8,8 @@ option java_package = "org.xmtp.proto.message.contents"; // EciesMessage is a wrapper for ECIES encrypted payloads message EciesMessage { - oneof version { - // Expected to be an ECIES encrypted SignedPayload - bytes v1 = 1; - } + oneof version { + // Expected to be an ECIES encrypted SignedPayload + bytes v1 = 1; + } } diff --git a/proto/message_contents/invitation.proto b/proto/message_contents/invitation.proto index 8852e675..5d0337e9 100644 --- a/proto/message_contents/invitation.proto +++ b/proto/message_contents/invitation.proto @@ -13,33 +13,33 @@ option java_package = "org.xmtp.proto.message.contents"; // Unsealed invitation V1 message InvitationV1 { - // Supported encryption schemes - // AES256-GCM-HKDF-SHA256 - message Aes256gcmHkdfsha256 { - bytes key_material = 1; // randomly generated key material (32 bytes) - } + // Supported encryption schemes + // AES256-GCM-HKDF-SHA256 + message Aes256gcmHkdfsha256 { + bytes key_material = 1; // randomly generated key material (32 bytes) + } - // The context type - message Context { - // Expected to be a URI (ie xmtp.org/convo1) - string conversation_id = 1; - // Key value map of additional metadata that would be exposed to - // application developers and could be used for filtering - map metadata = 2; - } - // topic name chosen for this conversation. - // It MUST be randomly generated bytes (length >= 32), - // then base64 encoded without padding - string topic = 1; + // The context type + message Context { + // Expected to be a URI (ie xmtp.org/convo1) + string conversation_id = 1; + // Key value map of additional metadata that would be exposed to + // application developers and could be used for filtering + map metadata = 2; + } + // topic name chosen for this conversation. + // It MUST be randomly generated bytes (length >= 32), + // then base64 encoded without padding + string topic = 1; - // A context object defining metadata - Context context = 2; + // A context object defining metadata + Context context = 2; - // message encryption scheme and keys for this conversation. - oneof encryption { - // Specify the encryption method to process the key material properly. - Aes256gcmHkdfsha256 aes256_gcm_hkdf_sha256 = 3; - } + // message encryption scheme and keys for this conversation. + oneof encryption { + // Specify the encryption method to process the key material properly. + Aes256gcmHkdfsha256 aes256_gcm_hkdf_sha256 = 3; + } } // Sealed Invitation V1 Header @@ -47,9 +47,9 @@ message InvitationV1 { // it is however authenticated as associated data with the AEAD scheme used // to encrypt the invitation body, thus providing tamper evidence. message SealedInvitationHeaderV1 { - SignedPublicKeyBundle sender = 1; - SignedPublicKeyBundle recipient = 2; - uint64 created_ns = 3; + SignedPublicKeyBundle sender = 1; + SignedPublicKeyBundle recipient = 2; + uint64 created_ns = 3; } // Sealed Invitation V1 @@ -57,16 +57,16 @@ message SealedInvitationHeaderV1 { // recipient's public key bundles using simplified X3DH where // the sender's ephemeral key is replaced with sender's pre-key. message SealedInvitationV1 { - // encoded SealedInvitationHeaderV1 used as associated data for Ciphertext - bytes header_bytes = 1; - // Ciphertext.payload MUST contain encrypted InvitationV1. - Ciphertext ciphertext = 2; + // encoded SealedInvitationHeaderV1 used as associated data for Ciphertext + bytes header_bytes = 1; + // Ciphertext.payload MUST contain encrypted InvitationV1. + Ciphertext ciphertext = 2; } // Versioned Sealed Invitation message SealedInvitation { - reserved 2; - oneof version { - SealedInvitationV1 v1 = 1; - }; + reserved 2; + oneof version { + SealedInvitationV1 v1 = 1; + } } diff --git a/proto/message_contents/message.proto b/proto/message_contents/message.proto index bcd17c60..dbccbc06 100644 --- a/proto/message_contents/message.proto +++ b/proto/message_contents/message.proto @@ -15,16 +15,16 @@ option java_package = "org.xmtp.proto.message.contents"; // Message header is encoded separately as the bytes are also used // as associated data for authenticated encryption message MessageHeaderV1 { - PublicKeyBundle sender = 1; - PublicKeyBundle recipient = 2; - uint64 timestamp = 3; + PublicKeyBundle sender = 1; + PublicKeyBundle recipient = 2; + uint64 timestamp = 3; } // Message is the top level protocol element message MessageV1 { - bytes header_bytes = 1; // encapsulates encoded MessageHeaderV1 - // Ciphertext.payload MUST contain encrypted EncodedContent - Ciphertext ciphertext = 2; + bytes header_bytes = 1; // encapsulates encoded MessageHeaderV1 + // Ciphertext.payload MUST contain encrypted EncodedContent + Ciphertext ciphertext = 2; } // Message V2 @@ -34,37 +34,37 @@ message MessageV1 { // of the AEAD encryption used to protect the message, // thus providing tamper evidence. message MessageHeaderV2 { - // sender specified message creation time - uint64 created_ns = 1; - // the topic the message belongs to - string topic = 2; + // sender specified message creation time + uint64 created_ns = 1; + // the topic the message belongs to + string topic = 2; } // Message combines the encoded header with the encrypted payload. message MessageV2 { - bytes header_bytes = 1; // encapsulates encoded MessageHeaderV2 - // Ciphertext.payload MUST contain encrypted SignedContent - Ciphertext ciphertext = 2; + bytes header_bytes = 1; // encapsulates encoded MessageHeaderV2 + // Ciphertext.payload MUST contain encrypted SignedContent + Ciphertext ciphertext = 2; } // Versioned Message message Message { - oneof version { - MessageV1 v1 = 1; - MessageV2 v2 = 2; - } + oneof version { + MessageV1 v1 = 1; + MessageV2 v2 = 2; + } } // DecodedMessage represents the decrypted message contents. // DecodedMessage instances are not stored on the network, but // may be serialized and stored by clients message DecodedMessage { - string id = 1; - string message_version = 2; - string sender_address = 3; - optional string recipient_address = 4; - uint64 sent_ns = 5; - string content_topic = 6; - ConversationReference conversation = 7; - bytes content_bytes = 8; // encapsulates EncodedContent -} \ No newline at end of file + string id = 1; + string message_version = 2; + string sender_address = 3; + optional string recipient_address = 4; + uint64 sent_ns = 5; + string content_topic = 6; + ConversationReference conversation = 7; + bytes content_bytes = 8; // encapsulates EncodedContent +} diff --git a/proto/message_contents/private_key.proto b/proto/message_contents/private_key.proto index f509e69a..165a8858 100644 --- a/proto/message_contents/private_key.proto +++ b/proto/message_contents/private_key.proto @@ -14,64 +14,64 @@ option java_package = "org.xmtp.proto.message.contents"; // PrivateKey generalized to support different key types message SignedPrivateKey { - // time the key was created - uint64 created_ns = 1; - // private key - oneof union { - Secp256k1 secp256k1 = 2; - } - // public key for this private key - SignedPublicKey public_key = 3; + // time the key was created + uint64 created_ns = 1; + // private key + oneof union { + Secp256k1 secp256k1 = 2; + } + // public key for this private key + SignedPublicKey public_key = 3; - // Supported key types + // Supported key types - // EC: SECP256k1 - message Secp256k1 { - bytes bytes = 1; // D big-endian, 32 bytes - } + // EC: SECP256k1 + message Secp256k1 { + bytes bytes = 1; // D big-endian, 32 bytes + } } // PrivateKeyBundle wraps the identityKey and the preKeys, // enforces usage of signed keys. message PrivateKeyBundleV2 { - SignedPrivateKey identity_key = 1; - // all the known pre-keys, newer keys first, - repeated SignedPrivateKey pre_keys = 2; + SignedPrivateKey identity_key = 1; + // all the known pre-keys, newer keys first, + repeated SignedPrivateKey pre_keys = 2; } // LEGACY: PrivateKey generalized to support different key types message PrivateKey { - // time the key was created - uint64 timestamp = 1; - // private key - oneof union { - Secp256k1 secp256k1 = 2; - } - // public key for this private key - PublicKey public_key = 3; + // time the key was created + uint64 timestamp = 1; + // private key + oneof union { + Secp256k1 secp256k1 = 2; + } + // public key for this private key + PublicKey public_key = 3; - // Supported key types + // Supported key types - // EC: SECP256k1 - message Secp256k1 { - bytes bytes = 1; // D big-endian, 32 bytes - } + // EC: SECP256k1 + message Secp256k1 { + bytes bytes = 1; // D big-endian, 32 bytes + } } // LEGACY: PrivateKeyBundleV1 wraps the identityKey and the preKeys message PrivateKeyBundleV1 { - PrivateKey identity_key = 1; - // all the known pre-keys, newer keys first, - repeated PrivateKey pre_keys = 2; + PrivateKey identity_key = 1; + // all the known pre-keys, newer keys first, + repeated PrivateKey pre_keys = 2; } // Versioned PrivateKeyBundle message PrivateKeyBundle { - reserved 3; - oneof version { - PrivateKeyBundleV1 v1 = 1; - PrivateKeyBundleV2 v2 = 2; - } + reserved 3; + oneof version { + PrivateKeyBundleV1 v1 = 1; + PrivateKeyBundleV2 v2 = 2; + } } // PrivateKeyBundle encrypted with key material generated by @@ -80,15 +80,15 @@ message PrivateKeyBundle { // the pre-key embedded in it. // (see xmtp-js::PrivateKeyBundle.toEncryptedBytes for details) message EncryptedPrivateKeyBundleV1 { - // randomly generated pre-key - bytes wallet_pre_key = 1; // 32 bytes - // MUST contain encrypted PrivateKeyBundle - Ciphertext ciphertext = 2; + // randomly generated pre-key + bytes wallet_pre_key = 1; // 32 bytes + // MUST contain encrypted PrivateKeyBundle + Ciphertext ciphertext = 2; } // Versioned encrypted PrivateKeyBundle message EncryptedPrivateKeyBundle { - oneof version { - EncryptedPrivateKeyBundleV1 v1 = 1; - } + oneof version { + EncryptedPrivateKeyBundleV1 v1 = 1; + } } diff --git a/proto/message_contents/public_key.proto b/proto/message_contents/public_key.proto index db6c18de..64f41a9c 100644 --- a/proto/message_contents/public_key.proto +++ b/proto/message_contents/public_key.proto @@ -12,32 +12,32 @@ option java_package = "org.xmtp.proto.message.contents"; // UnsignedPublicKey represents a generalized public key, // defined as a union to support cryptographic algorithm agility. message UnsignedPublicKey { - uint64 created_ns = 1; - oneof union { - Secp256k1Uncompressed secp256k1_uncompressed = 3; - } + uint64 created_ns = 1; + oneof union { + Secp256k1Uncompressed secp256k1_uncompressed = 3; + } - // Supported key types + // Supported key types - // EC: SECP256k1 - message Secp256k1Uncompressed { - // uncompressed point with prefix (0x04) [ P || X || Y ], 65 bytes - bytes bytes = 1; - } + // EC: SECP256k1 + message Secp256k1Uncompressed { + // uncompressed point with prefix (0x04) [ P || X || Y ], 65 bytes + bytes bytes = 1; + } } -// SignedPublicKey +// SignedPublicKey message SignedPublicKey { - bytes key_bytes = 1; // embeds an UnsignedPublicKey - Signature signature = 2; // signs key_bytes + bytes key_bytes = 1; // embeds an UnsignedPublicKey + Signature signature = 2; // signs key_bytes } // PublicKeyBundle packages the cryptographic keys associated with a wallet. message SignedPublicKeyBundle { - // Identity key MUST be signed by the wallet. - SignedPublicKey identity_key = 1; - // Pre-key MUST be signed by the identity key. - SignedPublicKey pre_key = 2; + // Identity key MUST be signed by the wallet. + SignedPublicKey identity_key = 1; + // Pre-key MUST be signed by the identity key. + SignedPublicKey pre_key = 2; } // LEGACY @@ -45,23 +45,23 @@ message SignedPublicKeyBundle { // PublicKey represents a generalized public key, // defined as a union to support cryptographic algorithm agility. message PublicKey { - // The key bytes - message Secp256k1Uncompressed { - // uncompressed point with prefix (0x04) [ P || X || Y ], 65 bytes - bytes bytes = 1; - } - uint64 timestamp = 1; - optional Signature signature = 2; - oneof union { - Secp256k1Uncompressed secp256k1_uncompressed = 3; - } + // The key bytes + message Secp256k1Uncompressed { + // uncompressed point with prefix (0x04) [ P || X || Y ], 65 bytes + bytes bytes = 1; + } + uint64 timestamp = 1; + optional Signature signature = 2; + oneof union { + Secp256k1Uncompressed secp256k1_uncompressed = 3; + } } // PublicKeyBundle packages the cryptographic keys associated with a wallet, // both senders and recipients are identified by their key bundles. message PublicKeyBundle { - // Identity key MUST be signed by the wallet. - PublicKey identity_key = 1; - // Pre-key MUST be signed by the identity key. - PublicKey pre_key = 2; + // Identity key MUST be signed by the wallet. + PublicKey identity_key = 1; + // Pre-key MUST be signed by the identity key. + PublicKey pre_key = 2; } diff --git a/proto/message_contents/signature.proto b/proto/message_contents/signature.proto index d470c29f..dc85614c 100644 --- a/proto/message_contents/signature.proto +++ b/proto/message_contents/signature.proto @@ -9,21 +9,21 @@ option java_package = "org.xmtp.proto.message.contents"; // Signature represents a generalized public key signature, // defined as a union to support cryptographic algorithm agility. message Signature { - // ECDSA signature bytes and the recovery bit - message ECDSACompact { - bytes bytes = 1; // compact representation [ R || S ], 64 bytes - uint32 recovery = 2; // recovery bit - } - // ECDSA signature bytes and the recovery bit - // produced by xmtp-js::PublicKey.signWithWallet function, i.e. - // EIP-191 signature of a "Create Identity" message with the key embedded. - // Used to sign identity keys. - message WalletECDSACompact { - bytes bytes = 1; // compact representation [ R || S ], 64 bytes - uint32 recovery = 2; // recovery bit - } - oneof union { - ECDSACompact ecdsa_compact = 1; - WalletECDSACompact wallet_ecdsa_compact = 2; - } + // ECDSA signature bytes and the recovery bit + message ECDSACompact { + bytes bytes = 1; // compact representation [ R || S ], 64 bytes + uint32 recovery = 2; // recovery bit + } + // ECDSA signature bytes and the recovery bit + // produced by xmtp-js::PublicKey.signWithWallet function, i.e. + // EIP-191 signature of a "Create Identity" message with the key embedded. + // Used to sign identity keys. + message WalletECDSACompact { + bytes bytes = 1; // compact representation [ R || S ], 64 bytes + uint32 recovery = 2; // recovery bit + } + oneof union { + ECDSACompact ecdsa_compact = 1; + WalletECDSACompact wallet_ecdsa_compact = 2; + } } diff --git a/proto/message_contents/signed_payload.proto b/proto/message_contents/signed_payload.proto index f36b9186..b423aa7a 100644 --- a/proto/message_contents/signed_payload.proto +++ b/proto/message_contents/signed_payload.proto @@ -10,6 +10,6 @@ option java_package = "org.xmtp.proto.message.contents"; // SignedPayload is a wrapper for a signature and a payload message SignedPayload { - bytes payload = 1; - Signature signature = 2; + bytes payload = 1; + Signature signature = 2; } diff --git a/proto/v3/message_contents/association.proto b/proto/v3/message_contents/association.proto index 4d910970..681c510c 100644 --- a/proto/v3/message_contents/association.proto +++ b/proto/v3/message_contents/association.proto @@ -9,24 +9,24 @@ option java_package = "org.xmtp.proto.v3.message.contents"; // Allows for us to update the format of the association text without // incrementing the entire proto enum AssociationTextVersion { - ASSOCIATION_TEXT_VERSION_UNSPECIFIED = 0; - ASSOCIATION_TEXT_VERSION_1 = 1; + ASSOCIATION_TEXT_VERSION_UNSPECIFIED = 0; + ASSOCIATION_TEXT_VERSION_1 = 1; } // EIP191Association is used for all EIP 191 compliant wallet signatures message Eip191Association { - AssociationTextVersion association_text_version = 1; - RecoverableEcdsaSignature signature = 2; - string wallet_address = 3; + AssociationTextVersion association_text_version = 1; + RecoverableEcdsaSignature signature = 2; + string wallet_address = 3; } // RecoverableEcdsaSignature message RecoverableEcdsaSignature { - // Includes recovery id as the last byte - bytes bytes = 1; + // Includes recovery id as the last byte + bytes bytes = 1; } // EdDSA signature bytes matching RFC 8032 message EdDsaSignature { - bytes bytes = 1; -} \ No newline at end of file + bytes bytes = 1; +} diff --git a/proto/v3/message_contents/invite.proto b/proto/v3/message_contents/invite.proto index 6fa7298e..4cbd2a69 100644 --- a/proto/v3/message_contents/invite.proto +++ b/proto/v3/message_contents/invite.proto @@ -12,26 +12,26 @@ option java_package = "org.xmtp.proto.v3.message.contents"; // ciphertext in InvitationEnvelopeV1 and decrypted by the recipient using the // provided inviter `InstallationContactBundle` message InvitationV1 { - // If the inviter contact bundle has the same wallet address as the current - // user, the invitee is the other wallet address in the conversation. If the - // inviter contact bundle has a different wallet address, the invitee wallet - // address MUST be the wallet address of the recipient of the invite. - string invitee_wallet_address = 1; - // TODO: Decide whether we need a Context field + // If the inviter contact bundle has the same wallet address as the current + // user, the invitee is the other wallet address in the conversation. If the + // inviter contact bundle has a different wallet address, the invitee wallet + // address MUST be the wallet address of the recipient of the invite. + string invitee_wallet_address = 1; + // TODO: Decide whether we need a Context field } // InvitationEnvelopeV1 is the encrypted invitation message and the contact of // the sender message InvitationEnvelopeV1 { - // This contains the public key that will be used to decrypt the ciphertext - InstallationContactBundle inviter = 1; - // Corresponds to an InvitationV1 message - bytes ciphertext = 2; + // This contains the public key that will be used to decrypt the ciphertext + InstallationContactBundle inviter = 1; + // Corresponds to an InvitationV1 message + bytes ciphertext = 2; } // Wrapper message type message InvitationEnvelope { - oneof version { - InvitationEnvelopeV1 v1 = 1; - } + oneof version { + InvitationEnvelopeV1 v1 = 1; + } } diff --git a/proto/v3/message_contents/message.proto b/proto/v3/message_contents/message.proto index 18588d9a..3e51da6e 100644 --- a/proto/v3/message_contents/message.proto +++ b/proto/v3/message_contents/message.proto @@ -12,25 +12,25 @@ option java_package = "org.xmtp.proto.v3.message.contents"; // Currently we do not actually encrypt this, actual implementation of // SealedSender will be added shortly. message PadlockMessageSealedMetadata { - string sender_user_address = 1; - string sender_installation_id = 2; - string recipient_user_address = 3; - string recipient_installation_id = 4; - bool is_prekey_message = 5; + string sender_user_address = 1; + string sender_installation_id = 2; + string recipient_user_address = 3; + string recipient_installation_id = 4; + bool is_prekey_message = 5; } // Plaintext header included with messages, visible to all // Recipients can verify this header has not been tampered with. // Servers are unable to verify if the header has been tampered with. message PadlockMessageHeader { - uint64 sent_ns = 1; - bytes sealed_metadata = 2; // PadlockMessageSealedMetadata + uint64 sent_ns = 1; + bytes sealed_metadata = 2; // PadlockMessageSealedMetadata } // The version used for the decrypted padlock message payload enum PadlockMessagePayloadVersion { - PADLOCK_MESSAGE_PAYLOAD_VERSION_UNSPECIFIED = 0; - PADLOCK_MESSAGE_PAYLOAD_VERSION_ONE = 1; + PADLOCK_MESSAGE_PAYLOAD_VERSION_UNSPECIFIED = 0; + PADLOCK_MESSAGE_PAYLOAD_VERSION_ONE = 1; } // Encrypted body included with messages, only visible to recipients @@ -48,14 +48,14 @@ enum PadlockMessagePayloadVersion { // 5. Verify that both the sender_user and recipient_user are partipants of the // conversation referenced by convo_id message PadlockMessagePayload { - PadlockMessagePayloadVersion message_version = 1; - EdDsaSignature header_signature = 2; // Signs PadlockMessageHeader - string convo_id = 3; - bytes content_bytes = 4; // EncodedContent + PadlockMessagePayloadVersion message_version = 1; + EdDsaSignature header_signature = 2; // Signs PadlockMessageHeader + string convo_id = 3; + bytes content_bytes = 4; // EncodedContent } // Combines the plaintext header with the encrypted payload message PadlockMessageEnvelope { - bytes header_bytes = 1; // PadlockMessageHeader - bytes ciphertext = 2; // Encrypted PadlockMessagePayload -} \ No newline at end of file + bytes header_bytes = 1; // PadlockMessageHeader + bytes ciphertext = 2; // Encrypted PadlockMessagePayload +} diff --git a/proto/v3/message_contents/public_key.proto b/proto/v3/message_contents/public_key.proto index bf99289a..523c0b08 100644 --- a/proto/v3/message_contents/public_key.proto +++ b/proto/v3/message_contents/public_key.proto @@ -11,33 +11,33 @@ option java_package = "org.xmtp.proto.v3.message.contents"; // An unsigned public key used by libxmtp message VmacUnsignedPublicKey { - uint64 created_ns = 1; + uint64 created_ns = 1; - oneof union { - VodozemacCurve25519 curve25519 = 2; - } + oneof union { + VodozemacCurve25519 curve25519 = 2; + } - // A Vodozemac curve25519 key serialized via serde - // (https://github.com/matrix-org/vodozemac/blob/ - // 929bbaf325686435bdd0ed0d0cc45b0cbad3430d/src/types/curve25519.rs#L100) - message VodozemacCurve25519 { - bytes bytes = 1; - } + // A Vodozemac curve25519 key serialized via serde + // (https://github.com/matrix-org/vodozemac/blob/ + // 929bbaf325686435bdd0ed0d0cc45b0cbad3430d/src/types/curve25519.rs#L100) + message VodozemacCurve25519 { + bytes bytes = 1; + } } // A key linked to an XMTP account (e.g. signed by a wallet) // The purpose of the key is encoded in the signature message VmacAccountLinkedKey { - VmacUnsignedPublicKey key = 1; - oneof association { - Eip191Association eip_191 = 2; - } + VmacUnsignedPublicKey key = 1; + oneof association { + Eip191Association eip_191 = 2; + } } // A key linked to an installation (e.g. signed by an installation identity key) // The purpose of the key is encoded in the signature message VmacInstallationLinkedKey { - VmacUnsignedPublicKey key = 1; + VmacUnsignedPublicKey key = 1; } // A bundle of one time keys uploaded by a client, to be used as @@ -46,8 +46,8 @@ message VmacInstallationLinkedKey { // In our initial prototype we will not actually use one-time prekeys, // defaulting to fallback keys. message VmacOneTimeKeyTopupBundle { - VmacAccountLinkedKey identity_key = 1; - repeated VmacInstallationLinkedKey one_time_keys = 2; + VmacAccountLinkedKey identity_key = 1; + repeated VmacInstallationLinkedKey one_time_keys = 2; } // A fallback key uploaded by a client, which replaces any existing @@ -56,20 +56,20 @@ message VmacOneTimeKeyTopupBundle { // In our initial prototype we will always use the fallback key in place // of any one-time prekeys. message VmacFallbackKeyRotation { - VmacAccountLinkedKey identity_key = 1; - VmacInstallationLinkedKey fallback_key = 2; + VmacAccountLinkedKey identity_key = 1; + VmacInstallationLinkedKey fallback_key = 2; } // A contact bundle served by the server to a requesting client message VmacInstallationPublicKeyBundleV1 { - VmacAccountLinkedKey identity_key = 1; - VmacInstallationLinkedKey fallback_key = 2; + VmacAccountLinkedKey identity_key = 1; + VmacInstallationLinkedKey fallback_key = 2; } // A wrapper for versions of the installation contact bundle to allow // upgradeability message InstallationContactBundle { - oneof version { - VmacInstallationPublicKeyBundleV1 v1 = 1; - } -} \ No newline at end of file + oneof version { + VmacInstallationPublicKeyBundleV1 v1 = 1; + } +}